Merge pull request #21346 from nextcloud/enh/20930/dashboard

Dashboard API
This commit is contained in:
Roeland Jago Douma 2020-07-15 11:10:15 +02:00 committed by GitHub
commit f04f9321df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 743 additions and 0 deletions

1
.gitignore vendored
View File

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

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,31 @@
<?php
declare(strict_types=1);
/**
* @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 width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="m7.9062 1a7 7 0 0 0-6.9062 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0-7-7 7 7 0 0 0-0.09375 0zm0.09375 2.6992a4.3 4.3 0 0 1 4.3008 4.3008 4.3 4.3 0 0 1-4.3008 4.3008 4.3 4.3 0 0 1-4.3008-4.3008 4.3 4.3 0 0 1 4.3008-4.3008z" fill="#fff" stroke-dashoffset="10" stroke-linecap="round" stroke-linejoin="round" stroke-width=".5" style="paint-order:markers stroke fill"/></svg>

After

Width:  |  Height:  |  Size: 455 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
/**
* @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\RegisterPanelEvent;
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(
string $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 RegisterPanelEvent($this->dashboardManager));
$dashboardManager = $this->dashboardManager;
$panels = array_map(function (IPanel $panel) {
return [
'id' => $panel->getId(),
'title' => $panel->getTitle(),
'iconClass' => $panel->getIconClass(),
'url' => $panel->getUrl()
];
}, $dashboardManager->getPanels());
$this->inititalStateService->provideInitialState('dashboard', 'panels', $panels);
if (class_exists(LoadViewer::class)) {
$this->eventDispatcher->dispatchTyped(new LoadViewer());
}
return new TemplateResponse('dashboard', 'index');
}
}

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

@ -0,0 +1,126 @@
<template>
<div id="app-dashboard">
<h2>{{ greeting.icon }} {{ greeting.text }}</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')
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 { icon: '🌙', text: t('dashboard', 'Good evening, {name}', { name: this.name }) }
}
if (time > 12) {
return { icon: '☀', text: t('dashboard', 'Good afternoon, {name}', { name: this.name }) }
}
if (time === 12) {
return { icon: '🍽', text: t('dashboard', 'Time for lunch, {name}', { name: this.name }) }
}
if (time > 5) {
return { icon: '🌄', text: t('dashboard', 'Good morning, {name}', { name: this.name }) }
}
return { icon: '🦉', text: t('dashboard', 'Have a night owl, {name}', { name: this.name }) }
},
},
watch: {
callbacks() {
for (const app in this.callbacks) {
const element = this.$refs[app]
if (this.panels[app].mounted) {
continue
}
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%;
}
h2 {
text-align: center;
font-size: 32px;
line-height: 130%;
padding: 80px 16px 32px;
}
.panels {
width: 100%;
display: flex;
justify-content: center;
flex-direction: row;
align-items: flex-start;
flex-wrap: wrap;
}
.panel {
width: 250px;
margin: 16px;
& > a {
position: sticky;
top: 50px;
display: block;
background: linear-gradient(var(--color-main-background-translucent), var(--color-main-background-translucent) 80%, rgba(255, 255, 255, 0));
backdrop-filter: blur(4px);
h3 {
margin: 0;
font-size: 20px;
font-weight: bold;
background-size: 32px;
background-position: 10px 10px;
padding: 16px 8px 16px 52px;
}
}
}
</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
\OCP\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

@ -166,11 +166,14 @@ return array(
'OCP\\Dashboard\\Exceptions\\DashboardAppNotAvailableException' => $baseDir . '/lib/public/Dashboard/Exceptions/DashboardAppNotAvailableException.php',
'OCP\\Dashboard\\IDashboardManager' => $baseDir . '/lib/public/Dashboard/IDashboardManager.php',
'OCP\\Dashboard\\IDashboardWidget' => $baseDir . '/lib/public/Dashboard/IDashboardWidget.php',
'OCP\\Dashboard\\IManager' => $baseDir . '/lib/public/Dashboard/IManager.php',
'OCP\\Dashboard\\IPanel' => $baseDir . '/lib/public/Dashboard/IPanel.php',
'OCP\\Dashboard\\Model\\IWidgetConfig' => $baseDir . '/lib/public/Dashboard/Model/IWidgetConfig.php',
'OCP\\Dashboard\\Model\\IWidgetRequest' => $baseDir . '/lib/public/Dashboard/Model/IWidgetRequest.php',
'OCP\\Dashboard\\Model\\WidgetSetting' => $baseDir . '/lib/public/Dashboard/Model/WidgetSetting.php',
'OCP\\Dashboard\\Model\\WidgetSetup' => $baseDir . '/lib/public/Dashboard/Model/WidgetSetup.php',
'OCP\\Dashboard\\Model\\WidgetTemplate' => $baseDir . '/lib/public/Dashboard/Model/WidgetTemplate.php',
'OCP\\Dashboard\\RegisterPanelEvent' => $baseDir . '/lib/public/Dashboard/RegisterPanelEvent.php',
'OCP\\Dashboard\\Service\\IEventsService' => $baseDir . '/lib/public/Dashboard/Service/IEventsService.php',
'OCP\\Dashboard\\Service\\IWidgetsService' => $baseDir . '/lib/public/Dashboard/Service/IWidgetsService.php',
'OCP\\Defaults' => $baseDir . '/lib/public/Defaults.php',
@ -942,6 +945,7 @@ return array(
'OC\\DB\\SchemaWrapper' => $baseDir . '/lib/private/DB/SchemaWrapper.php',
'OC\\DB\\SetTransactionIsolationLevel' => $baseDir . '/lib/private/DB/SetTransactionIsolationLevel.php',
'OC\\Dashboard\\DashboardManager' => $baseDir . '/lib/private/Dashboard/DashboardManager.php',
'OC\\Dashboard\\Manager' => $baseDir . '/lib/private/Dashboard/Manager.php',
'OC\\DatabaseException' => $baseDir . '/lib/private/DatabaseException.php',
'OC\\DatabaseSetupException' => $baseDir . '/lib/private/DatabaseSetupException.php',
'OC\\DateTimeFormatter' => $baseDir . '/lib/private/DateTimeFormatter.php',

View File

@ -195,11 +195,14 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Dashboard\\Exceptions\\DashboardAppNotAvailableException' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Exceptions/DashboardAppNotAvailableException.php',
'OCP\\Dashboard\\IDashboardManager' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IDashboardManager.php',
'OCP\\Dashboard\\IDashboardWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IDashboardWidget.php',
'OCP\\Dashboard\\IManager' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IManager.php',
'OCP\\Dashboard\\IPanel' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IPanel.php',
'OCP\\Dashboard\\Model\\IWidgetConfig' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/IWidgetConfig.php',
'OCP\\Dashboard\\Model\\IWidgetRequest' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/IWidgetRequest.php',
'OCP\\Dashboard\\Model\\WidgetSetting' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetSetting.php',
'OCP\\Dashboard\\Model\\WidgetSetup' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetSetup.php',
'OCP\\Dashboard\\Model\\WidgetTemplate' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetTemplate.php',
'OCP\\Dashboard\\RegisterPanelEvent' => __DIR__ . '/../../..' . '/lib/public/Dashboard/RegisterPanelEvent.php',
'OCP\\Dashboard\\Service\\IEventsService' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Service/IEventsService.php',
'OCP\\Dashboard\\Service\\IWidgetsService' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Service/IWidgetsService.php',
'OCP\\Defaults' => __DIR__ . '/../../..' . '/lib/public/Defaults.php',
@ -971,6 +974,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\DB\\SchemaWrapper' => __DIR__ . '/../../..' . '/lib/private/DB/SchemaWrapper.php',
'OC\\DB\\SetTransactionIsolationLevel' => __DIR__ . '/../../..' . '/lib/private/DB/SetTransactionIsolationLevel.php',
'OC\\Dashboard\\DashboardManager' => __DIR__ . '/../../..' . '/lib/private/Dashboard/DashboardManager.php',
'OC\\Dashboard\\Manager' => __DIR__ . '/../../..' . '/lib/private/Dashboard/Manager.php',
'OC\\DatabaseException' => __DIR__ . '/../../..' . '/lib/private/DatabaseException.php',
'OC\\DatabaseSetupException' => __DIR__ . '/../../..' . '/lib/private/DatabaseSetupException.php',
'OC\\DateTimeFormatter' => __DIR__ . '/../../..' . '/lib/private/DateTimeFormatter.php',

View File

@ -30,6 +30,7 @@ use OC_App;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\QueryException;
use OCP\Dashboard\IManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
use OCP\IServerContainer;
@ -47,6 +48,9 @@ class Coordinator {
/** @var Registry */
private $registry;
/** @var IManager */
private $dashboardManager;
/** @var IEventDispatcher */
private $eventDispatcher;
@ -58,10 +62,12 @@ class Coordinator {
public function __construct(IServerContainer $container,
Registry $registry,
IManager $dashboardManager,
IEventDispatcher $eventListener,
ILogger $logger) {
$this->serverContainer = $container;
$this->registry = $registry;
$this->dashboardManager = $dashboardManager;
$this->eventDispatcher = $eventListener;
$this->logger = $logger;
}
@ -117,6 +123,7 @@ class Coordinator {
*/
$this->registrationContext->delegateCapabilityRegistrations($apps);
$this->registrationContext->delegateCrashReporterRegistrations($apps, $this->registry);
$this->registrationContext->delegateDashboardPanelRegistrations($apps, $this->dashboardManager);
$this->registrationContext->delegateEventListenerRegistrations($this->eventDispatcher);
$this->registrationContext->delegateContainerRegistrations($apps);
$this->registrationContext->delegateMiddlewareRegistrations($apps);

View File

@ -29,6 +29,7 @@ use Closure;
use OC\Support\CrashReport\Registry;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\Dashboard\IManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
use Throwable;
@ -41,6 +42,9 @@ class RegistrationContext {
/** @var array[] */
private $crashReporters = [];
/** @var array[] */
private $dashboardPanels = [];
/** @var array[] */
private $services = [];
@ -93,6 +97,13 @@ class RegistrationContext {
);
}
public function registerDashboardPanel(string $panelClass): void {
$this->context->registerDashboardPanel(
$this->appId,
$panelClass
);
}
public function registerService(string $name, callable $factory, bool $shared = true): void {
$this->context->registerService(
$this->appId,
@ -157,6 +168,13 @@ class RegistrationContext {
];
}
public function registerDashboardPanel(string $appId, string $panelClass): void {
$this->dashboardPanels[] = [
'appId' => $appId,
'class' => $panelClass
];
}
public function registerService(string $appId, string $name, callable $factory, bool $shared = true): void {
$this->services[] = [
"appId" => $appId,
@ -241,6 +259,23 @@ class RegistrationContext {
}
}
/**
* @param App[] $apps
*/
public function delegateDashboardPanelRegistrations(array $apps, IManager $dashboardManager): void {
foreach ($this->dashboardPanels as $panel) {
try {
$dashboardManager->lazyRegisterPanel($panel['class']);
} catch (Throwable $e) {
$appId = $panel['appId'];
$this->logger->logException($e, [
'message' => "Error during dashboard registration of $appId: " . $e->getMessage(),
'level' => ILogger::ERROR,
]);
}
}
}
public function delegateEventListenerRegistrations(IEventDispatcher $eventDispatcher): void {
foreach ($this->eventListeners as $registration) {
try {

View File

@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
/**
* @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 OC\Dashboard;
use InvalidArgumentException;
use OCP\AppFramework\QueryException;
use OCP\Dashboard\IManager;
use OCP\Dashboard\IPanel;
use OCP\ILogger;
use OCP\IServerContainer;
use Throwable;
class Manager implements IManager {
/** @var array */
private $lazyPanels = [];
/** @var IPanel[] */
private $panels = [];
/** @var IServerContainer */
private $serverContainer;
public function __construct(IServerContainer $serverContainer) {
$this->serverContainer = $serverContainer;
}
private function registerPanel(IPanel $panel): void {
if (array_key_exists($panel->getId(), $this->panels)) {
throw new InvalidArgumentException('Dashboard panel with this id has already been registered');
}
$this->panels[$panel->getId()] = $panel;
}
public function lazyRegisterPanel(string $panelClass): void {
$this->lazyPanels[] = $panelClass;
}
public function loadLazyPanels(): void {
$classes = $this->lazyPanels;
foreach ($classes as $class) {
try {
/** @var IPanel $panel */
$panel = $this->serverContainer->query($class);
} catch (QueryException $e) {
/*
* There is a circular dependency between the logger and the registry, so
* we can not inject it. Thus the static call.
*/
\OC::$server->getLogger()->logException($e, [
'message' => 'Could not load lazy dashbaord panel: ' . $e->getMessage(),
'level' => ILogger::FATAL,
]);
}
/**
* Try to register the loaded reporter. Theoretically it could be of a wrong
* type, so we might get a TypeError here that we should catch.
*/
try {
$this->registerPanel($panel);
} catch (Throwable $e) {
/*
* There is a circular dependency between the logger and the registry, so
* we can not inject it. Thus the static call.
*/
\OC::$server->getLogger()->logException($e, [
'message' => 'Could not register lazy dashboard panel: ' . $e->getMessage(),
'level' => ILogger::FATAL,
]);
}
try {
$panel->load();
} catch (Throwable $e) {
\OC::$server->getLogger()->logException($e, [
'message' => 'Error during dashboard panel loading: ' . $e->getMessage(),
'level' => ILogger::FATAL,
]);
}
}
$this->lazyPanels = [];
}
public function getPanels(): array {
$this->loadLazyPanels();
return $this->panels;
}
}

View File

@ -1357,6 +1357,7 @@ class Server extends ServerContainer implements IServerContainer {
});
$this->registerAlias(IDashboardManager::class, DashboardManager::class);
$this->registerAlias(\OCP\Dashboard\IManager::class, \OC\Dashboard\Manager::class);
$this->registerAlias(IFullTextSearchManager::class, FullTextSearchManager::class);
$this->registerAlias(ISubAdmin::class, SubAdmin::class);

View File

@ -55,6 +55,15 @@ interface IRegistrationContext {
*/
public function registerCrashReporter(string $reporterClass): void;
/**
* Register an implementation of \OCP\Dashboard\IPanel that
* will handle the implementation of a dashboard panel
*
* @param string $panelClass
* @return void
* @since 20.0.0
*/
public function registerDashboardPanel(string $panelClass): void;
/**
* Register a service
*

View File

@ -38,6 +38,7 @@ use OCP\Dashboard\Service\IWidgetsService;
* The call can be done from any Service.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard
*/
@ -48,6 +49,7 @@ interface IDashboardManager {
* Register a IWidgetsService.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param IWidgetsService $widgetsService
*/
@ -58,6 +60,7 @@ interface IDashboardManager {
* Register a IEventsService.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param IEventsService $eventsService
*/
@ -70,6 +73,7 @@ interface IDashboardManager {
* @see IWidgetConfig
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $widgetId
* @param string $userId
@ -92,6 +96,7 @@ interface IDashboardManager {
* that are running dashboard.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $widgetId
* @param array $users
@ -106,6 +111,7 @@ interface IDashboardManager {
* Create push notifications for groups. (ie. createUsersEvent())
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $widgetId
* @param array $groups
@ -120,6 +126,7 @@ interface IDashboardManager {
* Create push notifications for everyone. (ie. createUsersEvent())
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $widgetId
* @param array $payload

View File

@ -45,6 +45,7 @@ use OCP\Dashboard\Model\WidgetTemplate;
* Multiple widget can be defined in the same appinfo/info.xml.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard
*/
@ -54,6 +55,7 @@ interface IDashboardWidget {
* Should returns the (unique) Id of the widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -64,6 +66,7 @@ interface IDashboardWidget {
* Should returns the [display] name of the widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -75,6 +78,7 @@ interface IDashboardWidget {
* This description is displayed in the listing of the available widgets.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -88,6 +92,7 @@ interface IDashboardWidget {
* @see WidgetTemplate
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return WidgetTemplate
*/
@ -101,6 +106,7 @@ interface IDashboardWidget {
* @see WidgetSetup
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return WidgetSetup
*/
@ -119,6 +125,7 @@ interface IDashboardWidget {
* @see IWidgetConfig
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param IWidgetConfig $settings
*/
@ -134,6 +141,7 @@ interface IDashboardWidget {
* @see IWidgetRequest
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param IWidgetRequest $request
*/

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
/**
* @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 OCP\Dashboard;
/**
* Interface IManager
*
* @package OCP\Dashboard
* @since 20.0.0
*/
interface IManager {
/**
* @param string $panelClass
* @since 20.0.0
*/
public function lazyRegisterPanel(string $panelClass): void;
/**
* @since 20.0.0
*
* @return IPanel[]
*/
public function getPanels(): array;
}

View File

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
/**
* @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 OCP\Dashboard;
/**
* Interface IPanel
*
* @package OCP\Dashboard
* @since 20.0.0
*/
interface IPanel {
/**
* @return string Unique id that identifies the panel, e.g. the app id
* @since 20.0.0
*/
public function getId(): string;
/**
* @return string User facing title of the panel
* @since 20.0.0
*/
public function getTitle(): string;
/**
* @return int Initial order for panel sorting
* @since 20.0.0
*/
public function getOrder(): int;
/**
* @return string css class that displays an icon next to the panel title
* @since 20.0.0
*/
public function getIconClass(): string;
/**
* @return string|null The absolute url to the apps own view
* @since 20.0.0
*/
public function getUrl(): ?string;
/**
* Execute panel bootstrap code like loading scripts and providing initial state
* @since 20.0.0
*/
public function load(): void;
}

View File

@ -36,6 +36,7 @@ use OCP\Dashboard\IDashboardWidget;
* @see IDashboardWidget::loadWidget
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard\Model
*/
@ -46,6 +47,7 @@ interface IWidgetConfig {
* Returns the userId
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -56,6 +58,7 @@ interface IWidgetConfig {
* Returns the widgetId
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -75,6 +78,7 @@ interface IWidgetConfig {
* ]
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -105,6 +109,7 @@ interface IWidgetConfig {
* Dashboard app.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -115,6 +120,7 @@ interface IWidgetConfig {
* Returns if the widget is enabled/displayed in this user's dashboard.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return bool
*/

View File

@ -38,6 +38,7 @@ use OCP\Dashboard\IDashboardWidget;
* @see IDashboardWidget::requestWidget
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard\Model
*/
@ -47,6 +48,7 @@ interface IWidgetRequest {
* Get the widgetId.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -57,6 +59,7 @@ interface IWidgetRequest {
* Get the WidgetClass.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return IDashboardWidget
*/
@ -76,6 +79,7 @@ interface IWidgetRequest {
* callback);
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -88,6 +92,7 @@ interface IWidgetRequest {
* @see getRequest
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -98,6 +103,7 @@ interface IWidgetRequest {
* Returns the result.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -108,6 +114,7 @@ interface IWidgetRequest {
* add a result (as string)
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $key
* @param string $result
@ -120,6 +127,7 @@ interface IWidgetRequest {
* add a result (as array)
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $key
* @param array $result

View File

@ -45,6 +45,7 @@ use JsonSerializable;
* @see WidgetTemplate::addSetting
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard\Model
*/
@ -73,6 +74,7 @@ final class WidgetSetting implements JsonSerializable {
* WidgetSetting constructor.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $type
*/
@ -85,6 +87,7 @@ final class WidgetSetting implements JsonSerializable {
* Set the name of the setting (full string, no space)
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $name
*
@ -100,6 +103,7 @@ final class WidgetSetting implements JsonSerializable {
* Get the name of the setting
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -112,6 +116,7 @@ final class WidgetSetting implements JsonSerializable {
* Set the title/display name of the setting.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $title
*
@ -127,6 +132,7 @@ final class WidgetSetting implements JsonSerializable {
* Get the title of the setting
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -139,6 +145,7 @@ final class WidgetSetting implements JsonSerializable {
* Set the type of the setting (input, checkbox, ...)
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $type
*
@ -154,6 +161,7 @@ final class WidgetSetting implements JsonSerializable {
* Get the type of the setting.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -166,6 +174,7 @@ final class WidgetSetting implements JsonSerializable {
* Set the placeholder (in case of type=input)
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $text
*
@ -181,6 +190,7 @@ final class WidgetSetting implements JsonSerializable {
* Get the placeholder.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -193,6 +203,7 @@ final class WidgetSetting implements JsonSerializable {
* Set the default value of the setting.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $value
*
@ -208,6 +219,7 @@ final class WidgetSetting implements JsonSerializable {
* Get the default value.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -218,6 +230,7 @@ final class WidgetSetting implements JsonSerializable {
/**
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/

View File

@ -38,6 +38,7 @@ use JsonSerializable;
* @see IDashboardWidget::getWidgetSetup
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard\Model
*/
@ -73,6 +74,7 @@ final class WidgetSetup implements JsonSerializable {
*
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $type
*
@ -90,6 +92,7 @@ final class WidgetSetup implements JsonSerializable {
* Returns all sizes defined for the widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -101,6 +104,7 @@ final class WidgetSetup implements JsonSerializable {
* Add a new size to the setup.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $type
* @param int $width
@ -121,6 +125,7 @@ final class WidgetSetup implements JsonSerializable {
* Returns menu entries.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -136,6 +141,7 @@ final class WidgetSetup implements JsonSerializable {
* $text is the display name of the menu entry.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $function
* @param string $icon
@ -161,6 +167,7 @@ final class WidgetSetup implements JsonSerializable {
* $delay is the time in seconds between each call.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $function
* @param int $delay
@ -180,6 +187,7 @@ final class WidgetSetup implements JsonSerializable {
* Get delayed jobs.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -192,6 +200,7 @@ final class WidgetSetup implements JsonSerializable {
* Get the push function, called when an event is send to the front-end
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -204,6 +213,7 @@ final class WidgetSetup implements JsonSerializable {
* frontend.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $function
*
@ -220,6 +230,7 @@ final class WidgetSetup implements JsonSerializable {
* Returns the default settings for a widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -235,6 +246,7 @@ final class WidgetSetup implements JsonSerializable {
* @see WidgetSetting
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param array $settings
*
@ -249,6 +261,7 @@ final class WidgetSetup implements JsonSerializable {
/**
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/

View File

@ -37,6 +37,7 @@ use JsonSerializable;
* @see IDashboardWidget::getWidgetTemplate
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard\Model
*/
@ -66,6 +67,7 @@ final class WidgetTemplate implements JsonSerializable {
* Get the icon class of the widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -80,6 +82,7 @@ final class WidgetTemplate implements JsonSerializable {
* @see addCss
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $icon
*
@ -95,6 +98,7 @@ final class WidgetTemplate implements JsonSerializable {
* Get CSS files to be included when displaying a widget
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -106,6 +110,7 @@ final class WidgetTemplate implements JsonSerializable {
* path and name of CSS files
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param array $css
*
@ -121,6 +126,7 @@ final class WidgetTemplate implements JsonSerializable {
* Add a CSS file to be included when displaying a widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $css
*
@ -136,6 +142,7 @@ final class WidgetTemplate implements JsonSerializable {
* Get JS files to be included when loading a widget
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/
@ -147,6 +154,7 @@ final class WidgetTemplate implements JsonSerializable {
* Set an array of JS files to be included when loading a widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param array $js
*
@ -162,6 +170,7 @@ final class WidgetTemplate implements JsonSerializable {
* Add a JS file to be included when loading a widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $js
*
@ -177,6 +186,7 @@ final class WidgetTemplate implements JsonSerializable {
* Get the HTML file that contains the content of the widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -188,6 +198,7 @@ final class WidgetTemplate implements JsonSerializable {
* Set the HTML file that contains the content of the widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $content
*
@ -203,6 +214,7 @@ final class WidgetTemplate implements JsonSerializable {
* Get the JS function to be called when loading the widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return string
*/
@ -215,6 +227,7 @@ final class WidgetTemplate implements JsonSerializable {
* dashboard
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $function
*
@ -232,6 +245,7 @@ final class WidgetTemplate implements JsonSerializable {
* @see WidgetSetting
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @return WidgetSetting[]
*/
@ -243,6 +257,7 @@ final class WidgetTemplate implements JsonSerializable {
* Define all WidgetSetting for the widget.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @see WidgetSetting
*
@ -262,6 +277,7 @@ final class WidgetTemplate implements JsonSerializable {
* @see WidgetSetting
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param WidgetSetting $setting
*
@ -279,6 +295,7 @@ final class WidgetTemplate implements JsonSerializable {
* @see WidgetSetting::setName
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $key
*
@ -295,6 +312,7 @@ final class WidgetTemplate implements JsonSerializable {
/**
* @since 15.0.0
* @deprecated 20.0.0
*
* @return array
*/

View File

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
/**
* @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 OCP\Dashboard;
use OCP\EventDispatcher\Event;
/**
* Class RegisterPanelEvent
*
* This event is dispatched to allow apps supporting older Nextcloud versions to
* still register their dashboard panels so that they are only constructed when
* they are needed. Deprecated right away so we can drop it again after 19 is EOL
* and backward compatible apps can use OCP\AppFramework\Bootstrap\IBootstrap
*
* @package OCP\Dashboard
* @since 20.0.0
* @deprecated 20.0.0
*/
class RegisterPanelEvent extends Event {
private $manager;
public function __construct(IManager $manager) {
parent::__construct();
$this->manager = $manager;
}
/**
* @param string $panelClass
* @since 20.0.0
*/
public function registerPanel(string $panelClass) {
$this->manager->lazyRegisterPanel($panelClass);
}
}

View File

@ -35,6 +35,7 @@ use OCP\Dashboard\IDashboardManager;
* are used by the IDashboardManager when creating push event.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard\Service
*/
@ -47,6 +48,7 @@ interface IEventsService {
* @see IDashboardManager::createUsersEvent
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $widgetId
* @param array $users
@ -62,6 +64,7 @@ interface IEventsService {
* @see IDashboardManager::createGroupsEvent
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $widgetId
* @param array $groups
@ -77,6 +80,7 @@ interface IEventsService {
* @see IDashboardManager::createGlobalEvent
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $widgetId
* @param array $payload

View File

@ -36,6 +36,7 @@ use OCP\Dashboard\Model\IWidgetConfig;
* configuration of a widget for a user.
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @package OCP\Dashboard\Service
*/
@ -45,6 +46,7 @@ interface IWidgetsService {
* Returns the IWidgetConfig for a widgetId and userId
*
* @since 15.0.0
* @deprecated 20.0.0
*
* @param string $widgetId
* @param string $userId

View File

@ -33,6 +33,7 @@ use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\QueryException;
use OCP\Dashboard\IManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
use OCP\IServerContainer;
@ -50,6 +51,9 @@ class CoordinatorTest extends TestCase {
/** @var Registry|MockObject */
private $crashReporterRegistry;
/** @var IManager|MockObject */
private $dashboardManager;
/** @var IEventDispatcher|MockObject */
private $eventDispatcher;
@ -65,12 +69,14 @@ class CoordinatorTest extends TestCase {
$this->appManager = $this->createMock(IAppManager::class);
$this->serverContainer = $this->createMock(IServerContainer::class);
$this->crashReporterRegistry = $this->createMock(Registry::class);
$this->dashboardManager = $this->createMock(IManager::class);
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
$this->logger = $this->createMock(ILogger::class);
$this->coordinator = new Coordinator(
$this->serverContainer,
$this->crashReporterRegistry,
$this->dashboardManager,
$this->eventDispatcher,
$this->logger
);

View File

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