Skip to content

Commit a131dd3

Browse files
committed
draft first dashboard
Signed-off-by: Benjamin Brahmer <[email protected]>
1 parent 7dfa189 commit a131dd3

11 files changed

+335
-2
lines changed

Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ appstore:
172172

173173
# on macOS there is no option "--parents" for the "cp" command
174174
mkdir -p $(appstore_sign_dir)/$(app_name)/js/build $(appstore_sign_dir)/$(app_name)/js/admin
175-
cp js/build/app.min.js $(appstore_sign_dir)/$(app_name)/js/build
176-
cp js/build/news-admin-settings.js* $(appstore_sign_dir)/$(app_name)/js/build
175+
cp js/build/* $(appstore_sign_dir)/$(app_name)/js/build
177176

178177
# export the key and cert to a file
179178
@if [ ! -f $(cert_dir)/$(app_name).key ] || [ ! -f $(cert_dir)/$(app_name).crt ]; then \

css/dashboard.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.icon-newsdashboard {
2+
background-image: url('../img/app-dark.svg');
3+
filter: var(--background-invert-if-dark);
4+
}
5+
6+
.widget-list li {
7+
list-style-type: disc;
8+
}
9+
10+
#app-dashboard .panels .panel--header h2 {
11+
display: flex;
12+
}

lib/AppInfo/Application.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
use OCA\News\Search\FeedSearchProvider;
2525
use OCA\News\Search\FolderSearchProvider;
2626
use OCA\News\Search\ItemSearchProvider;
27+
use OCA\News\Dashboard\ItemWidget;
28+
use OCA\News\Dashboard\FeedWidget;
2729

2830
use OCP\AppFramework\Bootstrap\IBootContext;
2931
use OCP\AppFramework\Bootstrap\IBootstrap;
@@ -85,6 +87,8 @@ public function register(IRegistrationContext $context): void
8587
$context->registerSearchProvider(FeedSearchProvider::class);
8688
$context->registerSearchProvider(ItemSearchProvider::class);
8789

90+
$context->registerDashboardWidget(ItemWidget::class);
91+
$context->registerDashboardWidget(FeedWidget::class);
8892

8993
$context->registerEventListener(BeforeUserDeletedEvent::class, UserDeleteHook::class);
9094

lib/Dashboard/FeedWidget.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
namespace OCA\News\Dashboard;
4+
5+
use OCA\News\Service\FeedServiceV2;
6+
use OCP\AppFramework\Services\IInitialState;
7+
use OCP\Dashboard\IAPIWidget;
8+
use OCP\IL10N;
9+
use OCP\IURLGenerator;
10+
use OCP\Dashboard\Model\WidgetItem;
11+
12+
use Psr\Log\LoggerInterface;
13+
14+
use OCA\News\AppInfo\Application;
15+
use OCA\News\Db\ListType;
16+
use OCP\Util;
17+
18+
class FeedWidget implements IAPIWidget
19+
{
20+
21+
22+
private $l10n;
23+
private $feedService;
24+
private $initialStateService;
25+
private $userId;
26+
private $urlGenerator;
27+
private $logger;
28+
29+
public function __construct(IL10N $l10n,
30+
IURLGenerator $urlGenerator,
31+
FeedServiceV2 $feedService,
32+
IInitialState $initialStateService,
33+
LoggerInterface $loggerInterface,
34+
?string $userId
35+
) {
36+
$this->l10n = $l10n;
37+
$this->feedService = $feedService;
38+
$this->initialStateService = $initialStateService;
39+
$this->userId = $userId;
40+
$this->urlGenerator = $urlGenerator;
41+
$this->logger = $loggerInterface;
42+
}
43+
44+
public function getId(): string
45+
{
46+
return 'news-feed-widget';
47+
}
48+
49+
public function getTitle(): string
50+
{
51+
$this->logger->debug("Requested title");
52+
return $this->l10n->t('News Feed widget');
53+
}
54+
55+
public function getOrder(): int
56+
{
57+
$this->logger->debug("Requested order");
58+
return 20;
59+
}
60+
61+
public function getIconClass(): string
62+
{
63+
return 'icon-newsdashboard';
64+
$this->logger->debug("Requested icon");
65+
}
66+
67+
public function getUrl(): ?string
68+
{
69+
return $this->urlGenerator->linkToRoute('news.page.index');
70+
$this->logger->debug("Requested url");
71+
}
72+
73+
public function load(): void
74+
{
75+
$this->logger->debug("Requested load with user: " . $this->userId);
76+
if ($this->userId !== null) {
77+
$items = $this->getItems($this->userId);
78+
$this->initialStateService->provideInitialState('dashboard-widget-feeds', $items);
79+
}
80+
81+
Util::addScript(Application::NAME, 'build/' . Application::NAME . '-dashboard-feeds');
82+
Util::addStyle(Application::NAME, 'dashboard');
83+
}
84+
85+
public function getItems(string $userId, ?string $since = null, int $limit = 7): array
86+
{
87+
$items = $this->feedService->findAllForUser($userId);
88+
89+
return $items;
90+
}
91+
}

lib/Dashboard/ItemWidget.php

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
namespace OCA\News\Dashboard;
4+
5+
use OCA\News\Service\ItemServiceV2;
6+
use OCP\AppFramework\Services\IInitialState;
7+
use OCP\Dashboard\IAPIWidget;
8+
use OCP\IL10N;
9+
use OCP\IURLGenerator;
10+
//maybe this can be used to craft items with things from the feed
11+
use OCP\Dashboard\Model\WidgetItem;
12+
13+
use Psr\Log\LoggerInterface;
14+
15+
use OCA\News\AppInfo\Application;
16+
use OCA\News\Db\ListType;
17+
use OCP\Util;
18+
19+
class ItemWidget implements IAPIWidget
20+
{
21+
22+
23+
private $l10n;
24+
private $itemService;
25+
private $initialStateService;
26+
private $userId;
27+
private $urlGenerator;
28+
private $logger;
29+
30+
public function __construct(IL10N $l10n,
31+
IURLGenerator $urlGenerator,
32+
ItemServiceV2 $itemService,
33+
IInitialState $initialStateService,
34+
LoggerInterface $loggerInterface,
35+
?string $userId
36+
) {
37+
$this->l10n = $l10n;
38+
$this->itemService = $itemService;
39+
$this->initialStateService = $initialStateService;
40+
$this->userId = $userId;
41+
$this->urlGenerator = $urlGenerator;
42+
$this->logger = $loggerInterface;
43+
}
44+
45+
public function getId(): string
46+
{
47+
return 'news-item-widget';
48+
}
49+
50+
public function getTitle(): string
51+
{
52+
$this->logger->debug("Requested title");
53+
return $this->l10n->t('News Item widget');
54+
}
55+
56+
public function getOrder(): int
57+
{
58+
$this->logger->debug("Requested order");
59+
return 20;
60+
}
61+
62+
public function getIconClass(): string
63+
{
64+
return 'icon-newsdashboard'; // TODO
65+
$this->logger->debug("Requested icon");
66+
}
67+
68+
public function getUrl(): ?string
69+
{
70+
return $this->urlGenerator->linkToRoute('news.page.index');
71+
$this->logger->debug("Requested url");
72+
}
73+
74+
public function load(): void
75+
{
76+
$this->logger->debug("Requested load with user: " . $this->userId);
77+
if ($this->userId !== null) {
78+
$items = $this->getItems($this->userId);
79+
$this->initialStateService->provideInitialState('dashboard-widget-items', $items);
80+
}
81+
82+
Util::addScript(Application::NAME, 'build/' . Application::NAME . '-dashboard-items');
83+
Util::addStyle(Application::NAME, 'dashboard');
84+
}
85+
86+
public function getItems(string $userId, ?string $since = null, int $limit = 7): array
87+
{
88+
$offset = (int) ($since ?? 0);
89+
$items = $this->itemService->findAllWithFilters($userId, ListType::ALL_ITEMS, $limit, $offset, false);
90+
91+
return $items;
92+
}
93+
}

src/components/FeedDashboard.vue

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<template>
2+
<NcDashboardWidget :items="items">
3+
<template #default="{ item }">
4+
<NcDashboardWidgetItem
5+
:main-text="item.mainText"
6+
:sub-text="item.subText"
7+
:target-url="item.targetURL"
8+
:avatar-is-no-user="true"
9+
:avatar-url="item.favicon">
10+
11+
<NcDashboardWidgetItem>
12+
</template>
13+
</NcDashboardWidget>
14+
</template>
15+
16+
<script>
17+
import NcDashboardWidget from '@nextcloud/vue/dist/Components/NcDashboardWidget.js'
18+
import NcDashboardWidgetItem from '@nextcloud/vue/dist/Components/NcDashboardWidgetItem'
19+
import { loadState } from '@nextcloud/initial-state'
20+
import { generateUrl } from '@nextcloud/router'
21+
22+
const newsItems = loadState('news', 'dashboard-widget-feeds')
23+
24+
console.log(newsItems)
25+
26+
export default {
27+
name: 'NewsFeedWidget',
28+
components: {
29+
NcDashboardWidget,
30+
NcDashboardWidgetItem,
31+
},
32+
props: [],
33+
data() {
34+
return {
35+
newsItems: newsItems
36+
}
37+
},
38+
39+
computed: {
40+
items() {
41+
return this.newsItems.map((g) => {
42+
return {
43+
id: g.id,
44+
mainText: g.title,
45+
subText: `Unread: ${g.unreadCount}`,
46+
targetURL: generateUrl(`/apps/news/#/items/feeds/${g.id}`),
47+
favicon: g.faviconLink,
48+
}
49+
})
50+
}
51+
}
52+
}
53+
</script>

src/components/ItemDashboard.vue

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<template>
2+
<NcDashboardWidget :items="items">
3+
<template #default="{ item }">
4+
<NcDashboardWidgetItem
5+
:main-text="item.mainText"
6+
:sub-text="item.subText"
7+
:target-url="item.targetURL">
8+
9+
<NcDashboardWidgetItem>
10+
</template>
11+
</NcDashboardWidget>
12+
</template>
13+
14+
<script>
15+
import NcDashboardWidget from '@nextcloud/vue/dist/Components/NcDashboardWidget.js'
16+
import NcDashboardWidgetItem from '@nextcloud/vue/dist/Components/NcDashboardWidgetItem'
17+
import { loadState } from '@nextcloud/initial-state'
18+
import { generateUrl } from '@nextcloud/router'
19+
20+
const newsItems = loadState('news', 'dashboard-widget-items')
21+
22+
console.log(newsItems)
23+
24+
export default {
25+
name: 'NewsItemWidget',
26+
components: {
27+
NcDashboardWidget,
28+
NcDashboardWidgetItem,
29+
},
30+
props: [],
31+
data() {
32+
return {
33+
newsItems: newsItems
34+
}
35+
},
36+
37+
computed: {
38+
items() {
39+
return this.newsItems.map((g) => {
40+
return {
41+
id: g.id,
42+
mainText: g.title,
43+
subText: g.intro,
44+
targetURL: generateUrl(`/apps/news/#/items/feeds/${g.feedId}`)
45+
}
46+
})
47+
}
48+
}
49+
}
50+
</script>

src/dashboard-feeds.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Vue from 'vue'
2+
import NewsFeedWidget from './components/FeedDashboard.vue'
3+
4+
document.addEventListener('DOMContentLoaded', () => {
5+
console.log("I'm alive")
6+
OCA.Dashboard.register('news-feed-widget', (el) => {
7+
console.log("Dashboard registered")
8+
const View = Vue.extend(NewsFeedWidget)
9+
new View().$mount(el)
10+
})
11+
})

src/dashboard-items.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Vue from 'vue'
2+
import NewsItemWidget from './components/ItemDashboard.vue'
3+
4+
document.addEventListener('DOMContentLoaded', () => {
5+
console.log("I'm alive")
6+
OCA.Dashboard.register('news-item-widget', (el) => {
7+
console.log("Dashboard registered")
8+
const View = Vue.extend(NewsItemWidget)
9+
new View().$mount(el)
10+
})
11+
})

src/vueBootstrap.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Vue from 'vue'
2+
import { translate, translatePlural } from '@nextcloud/l10n'
3+
4+
Vue.prototype.t = translate
5+
Vue.prototype.n = translatePlural
6+
Vue.prototype.OC = window.OC
7+
Vue.prototype.OCA = window.OCA

webpack.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const webpackConfig = require('@nextcloud/webpack-vue-config')
66

77
webpackConfig.entry = {
88
'admin-settings': path.join(__dirname, 'src', 'main-admin.js'),
9+
'dashboard-items': path.join(__dirname, 'src', 'dashboard-items.js'),
10+
'dashboard-feeds': path.join(__dirname, 'src', 'dashboard-feeds.js'),
911
}
1012
webpackConfig.output.path = path.resolve('./js/build/')
1113
webpackConfig.output.publicPath = path.join('/apps/', process.env.npm_package_name, '/js/build/')

0 commit comments

Comments
 (0)