@c8y/sample-plugin 1022.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.browserslistrc +16 -0
- package/CHANGELOG.md +5 -0
- package/README.md +36 -0
- package/cumulocity.config.ts +56 -0
- package/package.json +23 -0
- package/public/favicon.ico +0 -0
- package/src/app/README.md +26 -0
- package/src/app/app.config.ts +13 -0
- package/src/app/index.ts +52 -0
- package/src/app/sample-plugin.model.ts +8 -0
- package/src/app/view/sample-view.component.html +59 -0
- package/src/app/view/sample-view.component.ts +110 -0
- package/src/app/widget/sample-widget-config.component.ts +52 -0
- package/src/app/widget/sample-widget.component.css +4 -0
- package/src/app/widget/sample-widget.component.ts +21 -0
- package/src/assets/assets.ts +14 -0
- package/src/assets/example.css +10 -0
- package/src/assets/index.d.ts +9 -0
- package/src/assets/sample-plugin-pr.png +0 -0
- package/src/bootstrap.ts +18 -0
- package/src/i18n.ts +6 -0
- package/src/locales/de.po +10 -0
- package/src/main.ts +17 -0
- package/src/polyfills.ts +33 -0
- package/tsconfig.app.json +19 -0
package/.browserslistrc
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
|
2
|
+
# For additional information regarding the format and rule options, please see:
|
|
3
|
+
# https://github.com/browserslist/browserslist#queries
|
|
4
|
+
|
|
5
|
+
# For the full list of supported browsers by the Angular framework, please see:
|
|
6
|
+
# https://angular.io/guide/browser-support
|
|
7
|
+
|
|
8
|
+
# You can see what browsers were selected by your queries by running:
|
|
9
|
+
# npx browserslist
|
|
10
|
+
|
|
11
|
+
last 2 Chrome versions
|
|
12
|
+
last 1 Firefox version
|
|
13
|
+
last 2 Edge major versions
|
|
14
|
+
last 2 Safari major versions
|
|
15
|
+
last 2 iOS major versions
|
|
16
|
+
Firefox ESR
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
## Change log
|
|
2
|
+
|
|
3
|
+
If you want a change log to be provided to you package, place the `CHANGELOG.md` file in the root folder of your package.
|
|
4
|
+
|
|
5
|
+
Examples and best practices of how the change log should be formatted can be found at the [Keep a Changelog](https://keepachangelog.com) website.
|
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Cumulocity sample plugin
|
|
2
|
+
|
|
3
|
+
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 `cumulocity.config.ts`:
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
"exports": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Example sample plugin widget",
|
|
9
|
+
"module": "samplePluginWidgetProviders",
|
|
10
|
+
"path": "./src/app/index.ts",
|
|
11
|
+
"description": "Adds a custom widget to the shell application"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
```
|
|
15
|
+
Once the application has been built, the exports are also defined in the `cumulocity.json` file.
|
|
16
|
+
|
|
17
|
+
**How to start**
|
|
18
|
+
Run the commands below to scaffold a `sample-plugin`.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @angular/cli@v19-lts new --style=less # Install the correct version of Angular, which should be the same as your application.
|
|
22
|
+
cd <new-application-name>
|
|
23
|
+
ng add @c8y/websdk --application @c8y/sample-plugin
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
As the app.module is a typical Cumulocity application, any new plugin can be tested via the CLI:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
ng serve --shell cockpit
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
In the Module Federation terminology, `sample` plugin is called `remote` and the `cockpit` is called `shell`. Modules provided by this `sample` will be loaded by the `cockpit` application at the runtime. This plugin provides a basic custom widget that can be accessed through the `Add widget` menu and a new view in a left-hand navigator, where you can find links to Codex hooks entries.
|
|
33
|
+
|
|
34
|
+
> Note that the `--shell` flag creates a proxy to the cockpit application and provides `samplePluginWidgetProviders` as an `remote` via URL options.
|
|
35
|
+
|
|
36
|
+
Also deploying needs no special handling and can be simply done via `npm run deploy`. As soon as the application has exports it will be uploaded as a plugin.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ConfigurationOptions } from '@c8y/devkit';
|
|
2
|
+
import { author, description, license, name, version } from './package.json';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
runTime: {
|
|
6
|
+
author,
|
|
7
|
+
description,
|
|
8
|
+
version,
|
|
9
|
+
name,
|
|
10
|
+
contentSecurityPolicy:
|
|
11
|
+
"base-uri 'none'; default-src 'self' 'unsafe-inline' http: https: ws: wss:; connect-src 'self' http: https: ws: wss:; script-src 'self' *.bugherd.com *.twitter.com *.twimg.com *.aptrinsic.com 'unsafe-inline' 'unsafe-eval' data:; style-src * 'unsafe-inline' blob:; img-src * data: blob:; font-src * data:; frame-src *; worker-src 'self' blob:;",
|
|
12
|
+
dynamicOptionsUrl: true,
|
|
13
|
+
remotes: {
|
|
14
|
+
[name]: ['samplePluginWidgetProviders']
|
|
15
|
+
},
|
|
16
|
+
package: 'plugin',
|
|
17
|
+
isPackage: true,
|
|
18
|
+
noAppSwitcher: true,
|
|
19
|
+
license,
|
|
20
|
+
exports: [
|
|
21
|
+
{
|
|
22
|
+
name: 'Example sample plugin widget',
|
|
23
|
+
module: 'samplePluginWidgetProviders',
|
|
24
|
+
path: './src/app/index.ts',
|
|
25
|
+
readmePath: './src/app/README.md',
|
|
26
|
+
description: 'Adds a custom widget to the shell application'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'Example sample plugin view',
|
|
30
|
+
module: 'samplePluginViewProviders',
|
|
31
|
+
path: './src/app/index.ts',
|
|
32
|
+
readmePath: './src/app/README.md',
|
|
33
|
+
description: 'Adds a custom navigator node to the shell application'
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
buildTime: {
|
|
38
|
+
federation: [
|
|
39
|
+
'@angular/animations',
|
|
40
|
+
'@angular/cdk',
|
|
41
|
+
'@angular/common',
|
|
42
|
+
'@angular/compiler',
|
|
43
|
+
'@angular/core',
|
|
44
|
+
'@angular/forms',
|
|
45
|
+
'@angular/platform-browser',
|
|
46
|
+
'@angular/platform-browser-dynamic',
|
|
47
|
+
'@angular/router',
|
|
48
|
+
'@angular/upgrade',
|
|
49
|
+
'@c8y/client',
|
|
50
|
+
'@c8y/ngx-components',
|
|
51
|
+
'ngx-bootstrap',
|
|
52
|
+
'@ngx-translate/core',
|
|
53
|
+
'@ngx-formly/core'
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
} as const satisfies ConfigurationOptions;
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@c8y/sample-plugin",
|
|
3
|
+
"version": "1022.3.2",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@c8y/style": "1022.3.2",
|
|
7
|
+
"@c8y/ngx-components": "1022.3.2",
|
|
8
|
+
"@c8y/client": "1022.3.2",
|
|
9
|
+
"@c8y/bootstrap": "1022.3.2",
|
|
10
|
+
"@angular/cdk": "^19.2.18",
|
|
11
|
+
"ngx-bootstrap": "19.0.2",
|
|
12
|
+
"rxjs": "7.8.1"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@c8y/options": "1022.3.2",
|
|
16
|
+
"@c8y/devkit": "1022.3.2"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@angular/common": ">=19 <20"
|
|
20
|
+
},
|
|
21
|
+
"author": "Cumulocity GmbH",
|
|
22
|
+
"license": "Apache-2.0"
|
|
23
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# SAMPLE-PLUGIN Readme Example
|
|
2
|
+
|
|
3
|
+
## Adding a Readme File to Your Plugin
|
|
4
|
+
|
|
5
|
+
Follow these steps to include a readme file in your plugin:
|
|
6
|
+
|
|
7
|
+
1. Add the `readmePath` property to the `exports` array in your `cumulocity.config.ts` file.
|
|
8
|
+
2. Place the readme file in the same folder as your `index.ts` file.
|
|
9
|
+
|
|
10
|
+
### Example
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
exports: [
|
|
14
|
+
{
|
|
15
|
+
name: 'Example sample plugin view',
|
|
16
|
+
module: 'samplePluginWidgetProviders',
|
|
17
|
+
path: './src/app/index.ts',
|
|
18
|
+
readmePath: './src/app/README.md',
|
|
19
|
+
description: 'Adds a custom widget and navigator node to the shell application'
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### What Happens When You Build?
|
|
25
|
+
|
|
26
|
+
When you build your plugin (e.g., by running `ng build sample-plugin`), the generated zip file will include the readme file. It will be placed in a folder named after your module, such as `SamplePluginModule` or `samplePluginWidgetProviders`.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
|
|
2
|
+
import { provideAnimations } from '@angular/platform-browser/animations';
|
|
3
|
+
import { CoreModule, RouterModule } from '@c8y/ngx-components';
|
|
4
|
+
import { CockpitDashboardModule } from '@c8y/ngx-components/context-dashboard/cockpit-home-dashboard';
|
|
5
|
+
|
|
6
|
+
export const appConfig: ApplicationConfig = {
|
|
7
|
+
providers: [
|
|
8
|
+
provideAnimations(),
|
|
9
|
+
importProvidersFrom(RouterModule.forRoot()),
|
|
10
|
+
importProvidersFrom(CoreModule.forRoot()),
|
|
11
|
+
importProvidersFrom(CockpitDashboardModule)
|
|
12
|
+
]
|
|
13
|
+
};
|
package/src/app/index.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DynamicWidgetDefinition,
|
|
3
|
+
gettext,
|
|
4
|
+
hookNavigator,
|
|
5
|
+
hookRoute,
|
|
6
|
+
hookWidget,
|
|
7
|
+
NavigatorNode,
|
|
8
|
+
NavigatorNodeData
|
|
9
|
+
} from '@c8y/ngx-components';
|
|
10
|
+
import {
|
|
11
|
+
exportConfigWithDevice,
|
|
12
|
+
importConfigWithDevice
|
|
13
|
+
} from '@c8y/ngx-components/widgets/import-export-config';
|
|
14
|
+
import { assetPaths } from '../assets/assets';
|
|
15
|
+
import { CODEX_HOOK_LINKS } from './sample-plugin.model';
|
|
16
|
+
import { SamplePluginConfigComponent } from './widget/sample-widget-config.component';
|
|
17
|
+
import { SamplePluginComponent } from './widget/sample-widget.component';
|
|
18
|
+
|
|
19
|
+
export const samplePluginWidgetDefinition = {
|
|
20
|
+
id: 'angular.widget.plugin',
|
|
21
|
+
label: gettext('Module Federation widget'),
|
|
22
|
+
description: gettext('Sample added via Module Federation'),
|
|
23
|
+
component: SamplePluginComponent,
|
|
24
|
+
configComponent: SamplePluginConfigComponent,
|
|
25
|
+
previewImage: assetPaths.previewImage,
|
|
26
|
+
data: {
|
|
27
|
+
schema: () =>
|
|
28
|
+
import('c8y-schema-loader?interfaceName=SamplePluginConfig!./sample-plugin.model'),
|
|
29
|
+
export: exportConfigWithDevice,
|
|
30
|
+
import: importConfigWithDevice,
|
|
31
|
+
settings: {
|
|
32
|
+
noNewWidgets: false
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
} satisfies DynamicWidgetDefinition;
|
|
36
|
+
|
|
37
|
+
export const samplePluginWidgetProviders = [hookWidget(samplePluginWidgetDefinition)];
|
|
38
|
+
|
|
39
|
+
export const samplePluginViewProviders = [
|
|
40
|
+
hookRoute({
|
|
41
|
+
path: 'codex-hook-links',
|
|
42
|
+
loadComponent: () => import('./view/sample-view.component').then(m => m.SampleViewComponent)
|
|
43
|
+
}),
|
|
44
|
+
hookNavigator(
|
|
45
|
+
new NavigatorNode({
|
|
46
|
+
priority: -1,
|
|
47
|
+
path: 'codex-hook-links',
|
|
48
|
+
icon: 'navigation',
|
|
49
|
+
label: CODEX_HOOK_LINKS
|
|
50
|
+
} as NavigatorNodeData)
|
|
51
|
+
)
|
|
52
|
+
];
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<c8y-title>{{ CODEX_HOOK_LINKS }}</c8y-title>
|
|
2
|
+
|
|
3
|
+
<!-- Include in the action bar -->
|
|
4
|
+
<c8y-list-display-switch
|
|
5
|
+
class="form-inline"
|
|
6
|
+
(onListClassChange)="listClass = $event"
|
|
7
|
+
[listLength]="cards.length"
|
|
8
|
+
></c8y-list-display-switch>
|
|
9
|
+
|
|
10
|
+
<!-- The record list wrapper -->
|
|
11
|
+
<div
|
|
12
|
+
class="card-group"
|
|
13
|
+
[ngClass]="listClass"
|
|
14
|
+
>
|
|
15
|
+
<!-- The sticky header -->
|
|
16
|
+
<div class="page-sticky-header hidden-xs">
|
|
17
|
+
<div class="d-flex">
|
|
18
|
+
<div class="card-header card-column-20">
|
|
19
|
+
<span>Name</span>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="card-block card-column-40">
|
|
22
|
+
<span>Description</span>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<!-- The records list -->
|
|
27
|
+
<div
|
|
28
|
+
class="col-sm-6 col-md-4 col-lg-4 col-xs-12"
|
|
29
|
+
*ngFor="let card of cards"
|
|
30
|
+
>
|
|
31
|
+
<div class="card pointer">
|
|
32
|
+
<div class="card-header separator card-column-20">
|
|
33
|
+
<span
|
|
34
|
+
class="card-title text-truncate"
|
|
35
|
+
title="{{ card.name }}"
|
|
36
|
+
>
|
|
37
|
+
{{ card.name }}
|
|
38
|
+
</span>
|
|
39
|
+
<div class="card-actions">
|
|
40
|
+
<a
|
|
41
|
+
class="btn btn-link p-0 text-muted"
|
|
42
|
+
title="Open in new tab"
|
|
43
|
+
[attr.role]="'button'"
|
|
44
|
+
[target]="'_blank'"
|
|
45
|
+
[attr.rel]="'noopener noreferrer'"
|
|
46
|
+
[attr.href]="card.url"
|
|
47
|
+
>
|
|
48
|
+
<i c8yIcon="external-link"></i>
|
|
49
|
+
</a>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="card-block card-column-40">
|
|
53
|
+
<small>
|
|
54
|
+
{{ card.description }}
|
|
55
|
+
</small>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component } from '@angular/core';
|
|
3
|
+
import { HeaderModule, IconDirective, ListDisplaySwitchModule } from '@c8y/ngx-components';
|
|
4
|
+
import { CODEX_HOOK_LINKS } from '../sample-plugin.model';
|
|
5
|
+
|
|
6
|
+
interface HookCards {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
url: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@Component({
|
|
13
|
+
selector: 'c8y-app-sample-view',
|
|
14
|
+
templateUrl: './sample-view.component.html',
|
|
15
|
+
standalone: true,
|
|
16
|
+
imports: [CommonModule, HeaderModule, IconDirective, ListDisplaySwitchModule]
|
|
17
|
+
})
|
|
18
|
+
export class SampleViewComponent {
|
|
19
|
+
readonly CODEX_HOOK_LINKS = CODEX_HOOK_LINKS;
|
|
20
|
+
cards: HookCards[] = [];
|
|
21
|
+
listClass = '';
|
|
22
|
+
|
|
23
|
+
constructor() {
|
|
24
|
+
this.cards = this.getHookCards();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private getHookCards(): HookCards[] {
|
|
28
|
+
return [
|
|
29
|
+
{
|
|
30
|
+
name: 'hookActionBar',
|
|
31
|
+
description:
|
|
32
|
+
'The action bar offers a user-friendly interface to efficiently navigate and manage records. ',
|
|
33
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/action-bar/overview'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'hookAction',
|
|
37
|
+
description:
|
|
38
|
+
'This hook adds a global action to the page header, which is displayed or enabled under certain conditions via `c8y-action-outlet`.',
|
|
39
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/action/overview'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'hookBreadcrumb',
|
|
43
|
+
description: 'This hook shows the navigation breadcrumbs in the header bar.',
|
|
44
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/breadcrumbs/overview'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'hookComponent',
|
|
48
|
+
description: 'This hook adds dynamic components, for example, widgets, to the UI.',
|
|
49
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/dynamic-component/overview'
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'hookDrawer',
|
|
53
|
+
description: 'This hook adds a component to left or right drawer.',
|
|
54
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/drawer/overview'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'hookNavigator',
|
|
58
|
+
description: 'This hook allows for the registration and display of navigator nodes.',
|
|
59
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/navigator-route/overview'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'hookRoute',
|
|
63
|
+
description: 'A hook used to add new routes.',
|
|
64
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/navigator-route/overview'
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'hookService',
|
|
68
|
+
description: 'This hook adds services that can be shared between plugins and host app.',
|
|
69
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/service/overview'
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'hookStepper',
|
|
73
|
+
description: 'This hook adds a step into an existing stepper.',
|
|
74
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/stepper/overview'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'hookTab',
|
|
78
|
+
description: 'This hook allows you to show tabs on certain conditions.',
|
|
79
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/tabs/overview'
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'hookUserMenu',
|
|
83
|
+
description: 'Add user menu to the right drawer.',
|
|
84
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/user-menu/overview'
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'hookVersion',
|
|
88
|
+
description: 'Add versions to the right drawer.',
|
|
89
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/versions/overview'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'hookWidget',
|
|
93
|
+
description: 'This hook adds widgets to the UI.',
|
|
94
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/dynamic-widget-component/overview'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'hookWizard',
|
|
98
|
+
description: 'This hook adds an entry into an existing wizard.',
|
|
99
|
+
url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/wizard/overview'
|
|
100
|
+
}
|
|
101
|
+
// TODO: Uncomment when the codex entry is available
|
|
102
|
+
// {
|
|
103
|
+
// name: 'hookWidgetConfig',
|
|
104
|
+
// description:
|
|
105
|
+
// 'This hook adds sections to the widget configuration view, like: "Time context".',
|
|
106
|
+
// url: 'https://styleguide.cumulocity.com/apps/codex/#/develop/hooks/widget-config/overview'
|
|
107
|
+
// }
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Component, inject, Input, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
|
2
|
+
import { ControlContainer, NgForm } from '@angular/forms';
|
|
3
|
+
import { AlertService, CommonModule, DynamicComponent, FormsModule } from '@c8y/ngx-components';
|
|
4
|
+
import { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';
|
|
5
|
+
import { SamplePluginConfig } from '../sample-plugin.model';
|
|
6
|
+
import { SamplePluginComponent } from './sample-widget.component';
|
|
7
|
+
|
|
8
|
+
@Component({
|
|
9
|
+
selector: 'c8y-sample-plugin-config',
|
|
10
|
+
template: `
|
|
11
|
+
<div class="form-group">
|
|
12
|
+
<c8y-form-group>
|
|
13
|
+
<label>Text</label>
|
|
14
|
+
<textarea
|
|
15
|
+
style="width:100%"
|
|
16
|
+
name="text"
|
|
17
|
+
[(ngModel)]="config.text"
|
|
18
|
+
[required]="true"
|
|
19
|
+
></textarea>
|
|
20
|
+
</c8y-form-group>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<ng-template #sampleWidgetPreview>
|
|
24
|
+
<c8y-sample-plugin [config]="config"></c8y-sample-plugin>
|
|
25
|
+
</ng-template>
|
|
26
|
+
`,
|
|
27
|
+
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
|
|
28
|
+
standalone: true,
|
|
29
|
+
imports: [CommonModule, FormsModule, SamplePluginComponent]
|
|
30
|
+
})
|
|
31
|
+
export class SamplePluginConfigComponent implements DynamicComponent, OnInit {
|
|
32
|
+
@Input() config: SamplePluginConfig = {};
|
|
33
|
+
|
|
34
|
+
private readonly alert = inject(AlertService);
|
|
35
|
+
private readonly widgetConfigService = inject(WidgetConfigService);
|
|
36
|
+
|
|
37
|
+
@ViewChild('sampleWidgetPreview')
|
|
38
|
+
set previewMapSet(template: TemplateRef<any>) {
|
|
39
|
+
if (template) {
|
|
40
|
+
this.widgetConfigService.setPreview(template);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
this.widgetConfigService.setPreview(null);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
ngOnInit(): void {
|
|
47
|
+
this.widgetConfigService.addOnBeforeSave(config => {
|
|
48
|
+
this.alert.success('Widget added successfully', JSON.stringify(config, null, 2));
|
|
49
|
+
return true;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, Input } from '@angular/core';
|
|
3
|
+
import { FormsModule } from '@c8y/ngx-components';
|
|
4
|
+
import { SamplePluginConfig } from '../sample-plugin.model';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'c8y-sample-plugin',
|
|
8
|
+
template: `
|
|
9
|
+
<div class="p-16">
|
|
10
|
+
<h1>Sample-plugin</h1>
|
|
11
|
+
<p class="text">{{ config?.text || 'No text' }}</p>
|
|
12
|
+
<small>My context is: {{ config?.device?.name || 'No context' }}</small>
|
|
13
|
+
</div>
|
|
14
|
+
`,
|
|
15
|
+
styleUrls: ['./sample-widget.component.css'],
|
|
16
|
+
standalone: true,
|
|
17
|
+
imports: [CommonModule, FormsModule]
|
|
18
|
+
})
|
|
19
|
+
export class SamplePluginComponent {
|
|
20
|
+
@Input() config: SamplePluginConfig;
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is to include certain images or CSS files into the bundle. As for plugins,
|
|
3
|
+
* you need to bundle *all* assets due to a relative or absolute path might not work.
|
|
4
|
+
*
|
|
5
|
+
* Currently supported file extensions are: jpeg, jpg, gif, png, woff(2), eot, ttf, svg, css, sass and less
|
|
6
|
+
*
|
|
7
|
+
* If you need more types supported, add them to the d.ts file and add a webpack rule.
|
|
8
|
+
*/
|
|
9
|
+
import previewImage from './sample-plugin-pr.png';
|
|
10
|
+
|
|
11
|
+
// paths can be shared via this module if needed
|
|
12
|
+
export const assetPaths = { previewImage };
|
|
13
|
+
|
|
14
|
+
import './example.css';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Global styles:
|
|
3
|
+
Add the path to "example.css" in the "styles" entry of the angular.json file.
|
|
4
|
+
This will be a global style -> try to avoid as it could break existing styles
|
|
5
|
+
better use component based styling (see ../widget/sample-plugin.component.css)
|
|
6
|
+
For more information, please check: https://angular.io/guide/workspace-config#styles-and-scripts-configuration
|
|
7
|
+
*/
|
|
8
|
+
.text {
|
|
9
|
+
color: var(--brand-primary);
|
|
10
|
+
}
|
|
Binary file
|
package/src/bootstrap.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import './polyfills';
|
|
2
|
+
import '@angular/compiler';
|
|
3
|
+
|
|
4
|
+
import { enableProdMode } from '@angular/core';
|
|
5
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
6
|
+
import { BootstrapComponent, provideBootstrapMetadata } from '@c8y/ngx-components';
|
|
7
|
+
import { BootstrapMetaData } from '@c8y/bootstrap';
|
|
8
|
+
import { appConfig } from './app/app.config';
|
|
9
|
+
|
|
10
|
+
declare const __MODE__: string;
|
|
11
|
+
if (__MODE__ === 'production') {
|
|
12
|
+
enableProdMode();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function bootstrap(metadata: BootstrapMetaData) {
|
|
16
|
+
appConfig.providers.push(...provideBootstrapMetadata(metadata));
|
|
17
|
+
return bootstrapApplication(BootstrapComponent, appConfig).catch(err => console.log(err));
|
|
18
|
+
}
|
package/src/i18n.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internationalizing files in po format (https://en.wikipedia.org/wiki/Gettext#Translating)
|
|
3
|
+
* You can always add additional strings by adding your own po file. All po files are
|
|
4
|
+
* combined to one JSON file per language and are loaded if the specific language is needed.
|
|
5
|
+
*/
|
|
6
|
+
import './locales/de.po'; // <- adding additional strings to the german translation.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
msgid ""
|
|
2
|
+
msgstr ""
|
|
3
|
+
"Project-Id-Version: c8y.plugin\n"
|
|
4
|
+
"Language: de\n"
|
|
5
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
|
6
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
7
|
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
8
|
+
|
|
9
|
+
msgid "Module Federation widget"
|
|
10
|
+
msgstr "Modul Federation Dingsbums"
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import './i18n';
|
|
2
|
+
|
|
3
|
+
const barHolder: HTMLElement | null = document.querySelector('body > .init-load');
|
|
4
|
+
export const removeProgress = () => barHolder?.parentNode?.removeChild(barHolder);
|
|
5
|
+
|
|
6
|
+
applicationSetup();
|
|
7
|
+
|
|
8
|
+
async function applicationSetup() {
|
|
9
|
+
const { loadMetaDataAndPerformBootstrap } = await import('@c8y/bootstrap');
|
|
10
|
+
const loadBootstrapModule = () =>
|
|
11
|
+
import(
|
|
12
|
+
/* webpackPreload: true */
|
|
13
|
+
'./bootstrap'
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
loadMetaDataAndPerformBootstrap(loadBootstrapModule).then(removeProgress);
|
|
17
|
+
}
|
package/src/polyfills.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file includes polyfills needed by Angular and is loaded before the app.
|
|
3
|
+
* You can add your own extra polyfills to this file.
|
|
4
|
+
*
|
|
5
|
+
* This file is divided into 2 sections:
|
|
6
|
+
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
|
7
|
+
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
|
8
|
+
* file.
|
|
9
|
+
*
|
|
10
|
+
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
|
11
|
+
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
|
12
|
+
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
|
13
|
+
*
|
|
14
|
+
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/***************************************************************************************************
|
|
18
|
+
* BROWSER POLYFILLS
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* By default, zone.js will patch all possible macroTask and DomEvents
|
|
23
|
+
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
(window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
|
27
|
+
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
|
28
|
+
(window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove', 'message'];
|
|
29
|
+
|
|
30
|
+
/***************************************************************************************************
|
|
31
|
+
* Zone JS is required by default for Angular itself.
|
|
32
|
+
*/
|
|
33
|
+
import 'zone.js'; // Included with Angular CLI.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./out-tsc/app",
|
|
5
|
+
"noImplicitOverride": false,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": false
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src/main.ts"
|
|
11
|
+
],
|
|
12
|
+
"include": [
|
|
13
|
+
"src/**/*.ts",
|
|
14
|
+
"../ngx-components/**/*.ts"
|
|
15
|
+
],
|
|
16
|
+
"exclude": [
|
|
17
|
+
"../ngx-components/dist",
|
|
18
|
+
]
|
|
19
|
+
}
|