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

Public interfaces for dashboard app #10222

Merged
merged 1 commit into from
Oct 15, 2018
Merged

Conversation

ArtificialOwl
Copy link
Member

No description provided.

@ArtificialOwl ArtificialOwl added the 3. to review Waiting for reviews label Jul 12, 2018
@@ -0,0 +1,53 @@
<?php

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Licence header

/**
* @return string
*/
public function getId();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NC14 is >php 7.0. So you can use return types

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can I use : void ? (php 7.1)

@@ -0,0 +1,53 @@
<?php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strict typing since we are >7.0 anyway

@ArtificialOwl
Copy link
Member Author

@rullzer: please have a look to the asked edit

*
* @param string $widgetId
*/
public function __construct(string $widgetId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't add the constructor to the interfaces.
Just call setWidgetId instead

@juliushaertl
Copy link
Member

juliushaertl commented Jul 17, 2018

@daita You will also need to adjust the following xsd files to make the dashboard section valid in the appinfo.xml:

https://github.com/nextcloud/server/blob/master/resources/app-info-shipped.xsd
https://github.com/nextcloud/server/blob/master/resources/app-info.xsd

And the app store needs those updates as well.

@juliushaertl
Copy link
Member

Just a general thing, when we add new sections to the appinfo.xml like for this case, does this break apps that also support versions previous to 14?

The app store only has one version-independent file to validate the appinfo, so that should work fine, but does the server also checks for a valid appinfo at some point?

@nickvergessen
Copy link
Member

Yes the app check-code checks it, but additional stuff is not a problem as far as I know.
Only if you have stuff, which is not parsing valid, it will cry

interface IDashboardWidget {

/**
* @return string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing @since 14.0.0 on the methods and the interface.

@@ -0,0 +1,79 @@
<?php declare(strict_types=1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put the declare() on a new line.

@MorrisJobke
Copy link
Member

It's a bit late for that ... freeze was on Friday ... at least for the server PR.

And also it was never brought up to be needed for 14. :/

@jancborchardt
Copy link
Member

No need to rush in the dashboard, no? We can merge it very early for 15, and then properly work on adding endpoints to the different apps and have the Dashboard app use those, like any other app.

@ArtificialOwl
Copy link
Member Author

Well, you know. After working on something else for months and finally having few days to do something fun. But I get it; @nickvergessen already told me last week that I should not waste my time on it.

So, no rush.

@ArtificialOwl
Copy link
Member Author

So, ready for NC15.

@nickvergessen : Added also a IDashboardManager that can be called with Automatic DI so there is no more API, just call the right method from the dashboardManager, that will check if app is installed or not.

* @throws DashboardAppNotAvailableException
*/
public function createGlobalEvent(string $widgetId, array $payload, string $uniqueId = ''
) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opsy

maxOccurs="unbounded"/>
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to go to the appstore too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More general why is this needed here? I don't see it being used yet.

Copy link
Member

@ChristophWurst ChristophWurst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nitpicks. Please also make sure you have a line break at the end of each file (as github shows here) to be consistent with our other source files.

Thanks!

/**
* @since 15.0.0
*
* @return array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add more documentation to these methods. What are they supposed to return? array is very generic 😉

/**
* @since 15.0.0
*
* @return array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

*
* @param string $widgetId
*/
public function __construct(string $widgetId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the interface determines the constructor interface? This doesn't seem right 🙈

/**
* @since 15.0.0
*
* @param string $request
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what kind of request is this string?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daita 🏓

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷‍♂️ 🏓

* @param string $userId
* @param string $widgetId
*/
public function __construct(string $widgetId, string $userId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this. Same issue as above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daita 🏓

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw that ... removed.

<xs:sequence>
<xs:element name="widget" type="php-class" minOccurs="1"
maxOccurs="unbounded"/>
maxOccurs="unbounded"/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that doesn't look right.

<xs:sequence>
<xs:element name="widget" type="php-class" minOccurs="1"
maxOccurs="unbounded"/>
maxOccurs="unbounded"/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

}

try {
return \OC::$server->query($service);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can inject IServerContainer in your constructor. Then you can also better unit test this.

@MorrisJobke MorrisJobke added 2. developing Work in progress and removed 3. to review Waiting for reviews labels Sep 25, 2018
@ArtificialOwl
Copy link
Member Author

🏓

Would be great to go on with this one, as it is a blocker to work on the dev of widgets for 15.
(I know it's missing tests, this would come later)

@MorrisJobke MorrisJobke added 3. to review Waiting for reviews and removed 2. developing Work in progress labels Oct 8, 2018
* 'content' => (string) path to the HTML Template of the widget,
* 'function' => (string) JavaScript function to be called when
* loading the widget on the dashboard
* ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A template object would be nice, because it is automatically properly typed and has then proper autocompletion as well. 😉

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to objects in various spot, pushed. Will comment during the day.

* ]
*
* 'push' contains the JS function to be called on push event:
* 'push' => (string) JavaScript function to be called on push event
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A settings object would be nice instead of a multidimensional array. 🤔

Copy link
Member

@MorrisJobke MorrisJobke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beside the comments it looks good 👍

@ArtificialOwl ArtificialOwl added 2. developing Work in progress 3. to review Waiting for reviews and removed 3. to review Waiting for reviews 2. developing Work in progress labels Oct 9, 2018
@ArtificialOwl

This comment has been minimized.

*/
public function getWidgetConfig(string $widgetId, string $userId): IWidgetConfig {
/** @var \OCA\Dashboard\Service\WidgetsService $widgetsService */
$widgetsService = $this->getService('\OCA\Dashboard\Service\WidgetsService');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use the ::class syntax, this makes finding class usages and refactoring later a lot easier 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would require another try-catch in here of course, in case the dashboard app is not here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would it? ::class is simply replaced by the FQCN (string) by the interpreter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this would invoke autoloading and therefor throw? 🤷

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is that I am not sure the app is available at this point, and calling the ::class does not clean enough

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ php -a
Interactive shell

php > echo Joas::class;
Joas

*/
public function createUsersEvent(string $widgetId, array $users, array $payload, string $uniqueId = '') {
/** @var \OCA\Dashboard\Service\EventsService $eventsService */
$eventsService = $this->getService('\OCA\Dashboard\Service\EventsService');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

*/
public function createGroupsEvent(string $widgetId, array $groups, array $payload, string $uniqueId = '') {
/** @var \OCA\Dashboard\Service\EventsService $eventsService */
$eventsService = $this->getService('\OCA\Dashboard\Service\EventsService');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

*/
public function createGlobalEvent(string $widgetId, array $payload, string $uniqueId = '') {
/** @var \OCA\Dashboard\Service\EventsService $eventsService */
$eventsService = $this->getService('\OCA\Dashboard\Service\EventsService');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

/**
* @since 15.0.0
*
* @param string $request
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷‍♂️ 🏓

public function getInitFunction(): string;

/**
* JavaScript function to be called when loading the widget on the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how will that function be invoked? Does it have to exist globally?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it does not have to exist globally, it is called by the app

*
* @return array
*/
public function getCss(): array {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how will this CSS be loaded? Is this property the actual CSS contents or just the URL?

Copy link
Member

@rullzer rullzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a reason for much of this implementation to be in the server. Like the actual implementation of a lot of those classes can just be in the dashboard app itself right?

*
* @param string $type
*/
public function __construct($type = '') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typehint

maxOccurs="unbounded"/>
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More general why is this needed here? I don't see it being used yet.

@ChristophWurst

This comment has been minimized.

@ChristophWurst

This comment has been minimized.

Copy link
Member

@ChristophWurst ChristophWurst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks a lot better 👍

Let's move the implementations to the dashboard app. I don't think they should be in the server as they aren't even used directly.

Nitpick: @see WidgetSetting is a bit misleading. Not sure what it should tell me. It's also a bit misplaced in the interfaces because that would point to the private implementation. All usage should be documented in the public interfaces though 😉

lib/private/Dashboard/DashboardManager.php Outdated Show resolved Hide resolved
lib/private/Dashboard/DashboardManager.php Outdated Show resolved Hide resolved
*
* @package OC\Dashboard\Model
*/
class WidgetSetting implements JsonSerializable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this implementation can be safely move to the dashboard app

*
* @package OC\Dashboard\Model
*/
class WidgetSetup implements JsonSerializable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this implementation can be safely move to the dashboard app

*
* @package OC\Dashboard\Model
*/
class WidgetTemplate implements JsonSerializable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this implementation can be safely move to the dashboard app

@ArtificialOwl
Copy link
Member Author

@ChristophWurst

  • I removed the unused variable from DashboardManager

  • WidgetSetting, WidgetSetup and WidgetTemplate are created by the app that generate the widget, so it should stays here. This should be documented in the IDashboardWidget

@ChristophWurst
Copy link
Member

WidgetSetting, WidgetSetup and WidgetTemplate are created by the app that generate the widget, so it should stays here. This should be documented in the IDashboardWidget

WidgetSettings is not used outside the private namespace. Hence it must not be used by apps.

IDashboardWidget::getWidgetSetup returns a WidgetSetup, which violates the public/private API separation. It should instead return an IWidgetSetup. Fixing this will effectively make the WidgetSetup implementation independent of server and apps, hence moving it to the dashboard app is fine/recommended.

@ChristophWurst
Copy link
Member

ChristophWurst commented Oct 12, 2018

* WidgetSetting, WidgetSetup and WidgetTemplate are created by the app that generate the widget, so it should stays here. This should be documented in the IDashboardWidget

If a construct (class/interface) is used by an app, it has to be a public API. There are two three possible use cases:

  • The server only cares about an objects methods: create an interface that is implemented in an app's class.
  • The app should extend an existing (potentially abstract) class: export the class in the public API
  • The app use objects generated by the server or dashboard app: extract an interface from those interfaces, export them in the public API and provide factory classes/methods to create the objects as public API.

@ChristophWurst
Copy link
Member

After a bit of discussion I think I've finally understood how the different components will be used. I created a little diagram that outlines where certain classes/interfaces live:
bildschirmfoto von 2018-10-12 13-08-30

This works for @daita and clearly separates what should be in server/dashboard and other apps. This removes and dependency from server on the dashboard app. The implementation part in server (esp the private part) is minimal. The three classes for setup, settings and template were deliberately moved to OCP as classes as they are simple models (or better data transfer objects).

@rullzer
Copy link
Member

rullzer commented Oct 12, 2018

After a bit of discussion I think I've finally understood how the different components will be used. I created a little diagram that outlines where certain classes/interfaces live:
bildschirmfoto von 2018-10-12 13-08-30

This works for @daita and clearly separates what should be in server/dashboard and other apps. This removes and dependency from server on the dashboard app. The implementation part in server (esp the private part) is minimal. The three classes for setup, settings and template were deliberately moved to OCP as classes as they are simple models (or better data transfer objects).

Yes makes sense.
As some of the classes are only tiny and there to transport data. I would like to make the getters and setters at least final. We can always losen this later. But lets start from a strict implementation.

Copy link
Member

@rullzer rullzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I think it is time to get this in.
It looks sane to me.

Lets see how far we get.
@daita could you squash your commits?

Copy link
Member

@ChristophWurst ChristophWurst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't the plan to have WidgetSettings, WidgetSetup and WidgetTemplate in OCP? They're in the private namespace right now.

Copy link
Member

@ChristophWurst ChristophWurst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now!

You probably have to run ./build/autoloaderchecker.sh to make CI happy.

Also, please make squash this and make this a single commit change 😉

@ArtificialOwl ArtificialOwl force-pushed the interface-dashboard branch 2 times, most recently from 3689505 to 323c330 Compare October 15, 2018 16:01
@MorrisJobke
Copy link
Member

Copy link
Member

@ChristophWurst ChristophWurst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove additional files and rerun autoloader command

'OCP\\Dashboard\\IDashboardManager' => $baseDir . '/lib/public/Dashboard/IDashboardManager.php',
'OCP\\Dashboard\\IDashboardWidget' => $baseDir . '/lib/public/Dashboard/IDashboardWidget.php',
'OCP\\Dashboard\\Model\\IWidgetConfig' => $baseDir . '/lib/public/Dashboard/Model/IWidgetConfig.php',
'OCP\\Dashboard\\Model\\IWidgetRequest' => $baseDir . '/lib/public/Dashboard/Model/IWidgetRequest.php',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interfaces were removed

Copy link
Member

@ChristophWurst ChristophWurst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm the last review, I was confused by the interface names it seems

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Merge remote-tracking branch 'origin/interface-dashboard' into interface-dashboard

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
moving data object to OCP

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
update autoload files

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
+@SInCE

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
@ArtificialOwl ArtificialOwl merged commit f5a495b into master Oct 15, 2018
@ArtificialOwl ArtificialOwl deleted the interface-dashboard branch October 15, 2018 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3. to review Waiting for reviews
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants