Add dashboard app

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl 2020-06-08 15:39:26 +02:00
parent 544fcdb549
commit 5a1874910b
No known key found for this signature in database
GPG Key ID: 4C614C6ED2CDE6DF
11 changed files with 308 additions and 0 deletions

1
.gitignore vendored
View File

@ -17,6 +17,7 @@
!/apps/cloud_federation_api !/apps/cloud_federation_api
!/apps/comments !/apps/comments
!/apps/contactsinteraction !/apps/contactsinteraction
!/apps/dashboard
!/apps/dav !/apps/dav
!/apps/files !/apps/files
!/apps/federation !/apps/federation

View File

@ -0,0 +1,24 @@
<?php
/**
* @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
$app = new \OCP\AppFramework\App('dashboard');

View File

@ -0,0 +1,30 @@
<?xml version="1.0"?>
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>dashboard</id>
<name>Dashboard</name>
<summary>Dashboard app</summary>
<description><![CDATA[Show something]]></description>
<version>7.0.0</version>
<licence>agpl</licence>
<author>Julius Härtl</author>
<namespace>Dashboard</namespace>
<default_enable/>
<category>customization</category>
<bugs>https://github.com/nextcloud/server/issues</bugs>
<dependencies>
<nextcloud min-version="20" max-version="20"/>
</dependencies>
<navigations>
<navigation>
<name>Dashboard</name>
<route>dashboard.dashboard.index</route>
<icon>dashboard.svg</icon>
<order>-1</order>
</navigation>
</navigations>
</info>

View File

@ -0,0 +1,28 @@
<?php
/**
* @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
return [
'routes' => [
['name' => 'dashboard#index', 'url' => '/', 'verb' => 'GET'],
]
];

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"><g stroke-width=".905" fill="#fff" paint-order="stroke fill markers"><path d="M2.096 2.902h3.26v10.046h-3.26zM6.49 2.85h3.26v10.046H6.49zM11.052 2.824h3.26V12.87h-3.26z"/></g></svg>

After

Width:  |  Height:  |  Size: 244 B

View File

@ -0,0 +1,79 @@
<?php
/**
* @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Dashboard\Controller;
use OCA\Viewer\Event\LoadViewer;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Dashboard\IManager;
use OCP\Dashboard\IPanel;
use OCP\Dashboard\IRegisterPanelEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IInitialStateService;
use OCP\IRequest;
class DashboardController extends Controller {
/** @var IInitialStateService */
private $inititalStateService;
/** @var IEventDispatcher */
private $eventDispatcher;
/** @var IManager */
private $dashboardManager;
public function __construct($appName, IRequest $request, IInitialStateService $initialStateService, IEventDispatcher $eventDispatcher, IManager $dashboardManager) {
parent::__construct($appName, $request);
$this->inititalStateService = $initialStateService;
$this->eventDispatcher = $eventDispatcher;
$this->dashboardManager = $dashboardManager;
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @return TemplateResponse
*/
public function index(): TemplateResponse {
$this->eventDispatcher->dispatchTyped(new IRegisterPanelEvent($this->dashboardManager));
$dashboardManager = $this->dashboardManager;
$this->inititalStateService->provideLazyInitialState('dashboard', 'panels', function () use ($dashboardManager) {
return array_map(function (IPanel $panel) {
return [
'id' => $panel->getId(),
'title' => $panel->getTitle(),
'iconClass' => $panel->getIconClass(),
'url' => $panel->getUrl()
];
}, $dashboardManager->getPanels());
});
if (class_exists(LoadViewer::class)) {
$this->eventDispatcher->dispatchTyped(new LoadViewer());
}
return new TemplateResponse('dashboard', 'index');
}
}

119
apps/dashboard/src/App.vue Normal file
View File

@ -0,0 +1,119 @@
<template>
<div id="app-dashboard">
<h2>{{ greeting }}, {{ name }}</h2>
<div class="panels">
<div v-for="panel in panels" :key="panel.id" class="panel">
<a :href="panel.url">
<h3 :class="panel.iconClass">
{{ panel.title }}
</h3>
</a>
<div :ref="panel.id" :data-id="panel.id" />
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import { loadState } from '@nextcloud/initial-state'
import { getCurrentUser } from '@nextcloud/auth'
const panels = loadState('dashboard', 'panels')
console.debug('Loading dashboard panels', panels)
export default {
name: 'App',
data() {
return {
timer: new Date(),
callbacks: {},
panels,
name: getCurrentUser()?.displayName,
}
},
computed: {
greeting() {
const time = this.timer.getHours()
if (time > 18) {
return t('dashboard', '🌙 Good evening')
}
if (time > 12) {
return t('dashboard', '☀ Good afternoon')
}
if (time === 12) {
return t('dashboard', '🍽 Time for lunch')
}
return t('dashboard', '🌄 Good morning')
},
},
watch: {
callbacks() {
for (const app in this.callbacks) {
const element = this.$refs[app]
if (this.panels[app].mounted) {
return
}
if (element) {
this.callbacks[app](element[0])
Vue.set(this.panels[app], 'mounted', true)
} else {
console.error('Failed to register panel in the frontend as no backend data was provided for ' + app)
}
}
},
},
mounted() {
setInterval(() => {
this.timer = new Date()
}, 30000)
},
methods: {
register(app, callback) {
Vue.set(this.callbacks, app, callback)
},
},
}
</script>
<style lang="scss" scoped>
#app-dashboard {
width: 100%;
padding-left: 50px;
padding-right: 50px;
}
h2 {
text-align: center;
padding: 40px;
}
.panels {
width: 100%;
display: flex;
justify-content: center;
}
.panel {
width: 250px;
margin: 0 30px 30px 0;
&:first-child {
margin-left: 30px;
}
h3 {
position: sticky;
top: 50px;
margin-top: 0;
background-position: 10px 32px;
padding: 30px 12px 12px 35px;
background-color: var(--color-main-background);
}
}
</style>

View File

@ -0,0 +1,9 @@
import Vue from 'vue'
import App from './App.vue'
const Dashboard = Vue.extend(App)
const Instance = new Dashboard({}).$mount('#app')
window.OCA.Dashboard = {
register: (app, callback) => Instance.register(app, callback),
}

View File

@ -0,0 +1,4 @@
<?php
\OC_Util::addScript('dashboard', 'dashboard');
?>
<div id="app"></div>

11
apps/dashboard/webpack.js Normal file
View File

@ -0,0 +1,11 @@
const path = require('path')
module.exports = {
entry: path.join(__dirname, 'src', 'main.js'),
output: {
path: path.resolve(__dirname, './js'),
publicPath: '/js/',
filename: 'dashboard.js',
jsonpFunction: 'webpackJsonpDashboard'
}
}

View File

@ -6,6 +6,7 @@ const { VueLoaderPlugin } = require('vue-loader')
const accessibility = require('./apps/accessibility/webpack') const accessibility = require('./apps/accessibility/webpack')
const comments = require('./apps/comments/webpack') const comments = require('./apps/comments/webpack')
const core = require('./core/webpack') const core = require('./core/webpack')
const dashboard = require('./apps/dashboard/webpack')
const files = require('./apps/files/webpack') const files = require('./apps/files/webpack')
const files_sharing = require('./apps/files_sharing/webpack') const files_sharing = require('./apps/files_sharing/webpack')
const files_trashbin = require('./apps/files_trashbin/webpack') const files_trashbin = require('./apps/files_trashbin/webpack')
@ -21,6 +22,7 @@ const modules = {
accessibility, accessibility,
comments, comments,
core, core,
dashboard,
files, files,
files_sharing, files_sharing,
files_trashbin, files_trashbin,