Cumulocity-IoT / cumulocity-plugin-example

This is an inofficial demo showing how to build a simple plugin for the Cumulocity UI.
Apache License 2.0
0 stars 2 forks source link
cumulocity-iot iot-analytics

Note: This example is quite outdated and you should use the official documentation and scaffold a new application based on the plugin example with ng add @c8y/websdk

Cumulocity Plugin Demo

This is an inofficial demo showing how to build a simple plugin for the Cumulocity UI.

In this example the widget-plugin app was scaffold in version 1015.164.0. It is recommended to use your platform version. You can do this by running c8ycli new and select your preferred version. However, for plugins it is recommended to use at least 1016.0.0, as it is only in beta mode in 1015.x.x.

Prepare

1. Step

Add your tenant and shell to npm start command. Run npm start and checkout the two application started.

Diff ``` diff --git a/package.json b/package.json index b100dfe..a2dfd14 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "This is the Cumulocity module federation plugin. Plugins can be developed like any Cumulocity application, but can be used at runtime by other applications. Therefore, they export an Angular module which can then be imported by any other application. The exports are defined in `package.json`:", "scripts": { - "start": "c8ycli server", + "start": "c8ycli server -u http://demos.cumulocity.com --shell cockpit", "build": "c8ycli build", "deploy": "c8ycli deploy", "postinstall": "ngcc" ```

If not working -> checkout step1 branch

2. Step

Add a new plugin adding a navigator node

Diff ``` diff --git a/bookmarks/bookmarks.module.ts b/bookmarks/bookmarks.module.ts new file mode 100644 index 0000000..9907e4a --- /dev/null +++ b/bookmarks/bookmarks.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { BookmarksService } from "./bookmarks.service"; +import { HOOK_NAVIGATOR_NODES } from "@c8y/ngx-components"; + +@NgModule({ + declarations: [], + imports: [CommonModule], + exports: [], + providers: [ + BookmarksService, + { provide: HOOK_NAVIGATOR_NODES, useClass: BookmarksService, multi: true }, + ], +}) +export class BookmarksModule {} diff --git a/bookmarks/bookmarks.service.ts b/bookmarks/bookmarks.service.ts new file mode 100644 index 0000000..a3e0765 --- /dev/null +++ b/bookmarks/bookmarks.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import { NavigatorNode } from '@c8y/ngx-components'; + +@Injectable({ + providedIn: 'root' +}) +export class BookmarksService { + get() { + return new NavigatorNode({ + label: 'Bookmarks', + icon: 'bookmark', + priority: -1000 + }); + } +} \ No newline at end of file diff --git a/package.json b/package.json index a2dfd14..bd81906 100644 --- a/package.json +++ b/package.json @@ -62,11 +62,17 @@ "module": "WidgetPluginModule", "path": "./widget/widget-plugin.module.ts", "description": "Adds a custom widget to the shell application" + }, + { + "name": "Device bookmarks", + "module": "BookmarksModule", + "path": "./bookmarks/bookmarks.module.ts", + "description": "Allows you to bookmark your favorite device" } ], "remotes": { "summit-ui-demo": [ - "WidgetPluginModule" + "WidgetPluginModule", "BookmarksModule" ] } } ```

If not working -> checkout step2 branch

3. Step

Add logic and injection to the HOOK

Diff ``` diff --git a/bookmarks/bookmarks.service.ts b/bookmarks/bookmarks.service.ts index a3e0765..00c23fc 100644 --- a/bookmarks/bookmarks.service.ts +++ b/bookmarks/bookmarks.service.ts @@ -1,15 +1,30 @@ -import { Injectable } from '@angular/core'; -import { NavigatorNode } from '@c8y/ngx-components'; +import { Injectable } from "@angular/core"; +import { InventoryService } from "@c8y/client"; +import { NavigatorNode } from "@c8y/ngx-components"; +import { AssetNode, AssetNodeService } from "@c8y/ngx-components/assets-navigator"; @Injectable({ - providedIn: 'root' + providedIn: "root", }) export class BookmarksService { - get() { - return new NavigatorNode({ - label: 'Bookmarks', - icon: 'bookmark', - priority: -1000 + constructor(private inventory: InventoryService, private assetService: AssetNodeService) {} + + async get() { + const { data: bookmarkedDevices } = await this.inventory.list({ + fragmentType: "c8y_IsBookmarked", + pageSize: 2000 + }); + + const children = bookmarkedDevices.map((mo) => new AssetNode(this.assetService, { mo })); + + const rootNode = new NavigatorNode({ + label: "Bookmarks", + icon: "bookmark", + priority: -1000, }); + + rootNode.children = children; + + return rootNode; } -} \ No newline at end of file +} ```

If not working -> checkout step3 branch

4. Step

Add a action bar for all devices

Diff ``` diff --git a/bookmarks/add-bookmark.component.ts b/bookmarks/add-bookmark.component.ts new file mode 100644 index 0000000..8adaff1 --- /dev/null +++ b/bookmarks/add-bookmark.component.ts @@ -0,0 +1,24 @@ +import { Component, ViewChild, ViewContainerRef } from "@angular/core"; + +@Component({ + selector: "[c8y-add-bookmark]", + template: ` + +
  • + +
  • +
    + `, +}) +export class AddBookmarkComponent { + @ViewChild("template", { static: true }) template; + + constructor(private viewContainerRef: ViewContainerRef) {} + + ngOnInit() { + this.viewContainerRef.createEmbeddedView(this.template); + } +} diff --git a/bookmarks/add-bookmark.service.ts b/bookmarks/add-bookmark.service.ts new file mode 100644 index 0000000..242e9e5 --- /dev/null +++ b/bookmarks/add-bookmark.service.ts @@ -0,0 +1,22 @@ +import { Injectable } from "@angular/core"; +import { Router } from "@angular/router"; +import { ActionBarItem } from "@c8y/ngx-components"; +import { AddBookmarkComponent } from "./add-bookmark.component"; + +@Injectable({ + providedIn: "root", +}) +export class AddBookmarkService { + constructor(private router: Router) {} + + get() { + if (/device\/\w+/.test(this.router.url)) { + return { + template: AddBookmarkComponent, + priority: 0, + placement: "more", + } as ActionBarItem; + } + return []; + } +} diff --git a/bookmarks/bookmarks.module.ts b/bookmarks/bookmarks.module.ts index 9907e4a..c370178 100644 --- a/bookmarks/bookmarks.module.ts +++ b/bookmarks/bookmarks.module.ts @@ -1,15 +1,18 @@ import { NgModule } from "@angular/core"; -import { CommonModule } from "@angular/common"; +import { CommonModule } from "@c8y/ngx-components"; import { BookmarksService } from "./bookmarks.service"; -import { HOOK_NAVIGATOR_NODES } from "@c8y/ngx-components"; +import { AddBookmarkService } from "./add-bookmark.service"; +import { HOOK_ACTION_BAR, HOOK_NAVIGATOR_NODES } from "@c8y/ngx-components"; +import { AddBookmarkComponent } from "./add-bookmark.component"; @NgModule({ - declarations: [], + declarations: [AddBookmarkComponent], imports: [CommonModule], exports: [], providers: [ BookmarksService, { provide: HOOK_NAVIGATOR_NODES, useClass: BookmarksService, multi: true }, + { provide: HOOK_ACTION_BAR, useClass: AddBookmarkService, multi: true } ], }) export class BookmarksModule {} ```

    5. Step

    Add the logic to bookmark a device

    Diff ``` diff --git a/bookmarks/add-bookmark.component.ts b/bookmarks/add-bookmark.component.ts index d16c009..bc69b7d 100644 --- a/bookmarks/add-bookmark.component.ts +++ b/bookmarks/add-bookmark.component.ts @@ -1,4 +1,11 @@ import { Component, ViewChild, ViewContainerRef } from "@angular/core"; +import { Router } from "@angular/router"; +import { InventoryService } from "@c8y/client"; +import { + ContextRouteService, + getActivatedRoute, + NavigatorService, +} from "@c8y/ngx-components"; @Component({ selector: "[c8y-add-bookmark]", @@ -8,8 +15,9 @@ import { Component, ViewChild, ViewContainerRef } from "@angular/core"; @@ -17,11 +25,35 @@ import { Component, ViewChild, ViewContainerRef } from "@angular/core"; `, }) export class AddBookmarkComponent { + isBookmarked = true; @ViewChild("template", { static: true }) template; - constructor(private viewContainerRef: ViewContainerRef) {} + constructor( + private viewContainerRef: ViewContainerRef, + private router: Router, + private inventory: InventoryService, + private contextRoute: ContextRouteService, + private navigator: NavigatorService + ) {} ngOnInit() { this.viewContainerRef.createEmbeddedView(this.template); + this.isBookmarked = !!this.contextRoute.getContextData( + getActivatedRoute(this.router) + )?.contextData?.c8y_IsBookmarked; + } + + async bookmark() { + const currentDevice = this.contextRoute.getContextData( + getActivatedRoute(this.router) + )?.contextData; + if (currentDevice) { + await this.inventory.update({ + id: currentDevice.id as string, + c8y_IsBookmarked: this.isBookmarked ? null : {}, + }); + this.isBookmarked = !this.isBookmarked; + } + this.navigator.refresh(); } } ```

    These tools are provided as-is and without warranty or support. They do not constitute part of the Software AG product suite. Users are free to use, fork and modify them, subject to the license agreement. While Software AG welcomes contributions, we cannot guarantee to include every contribution in the master project.