@c8y/widget-plugin 1019.0.3
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/NOTICES +41743 -0
- package/README.md +33 -0
- package/cumulocity.config.ts +50 -0
- package/package.json +22 -0
- package/src/app/app.module.ts +17 -0
- package/src/app/widget/index.ts +1 -0
- package/src/app/widget/widget-plugin-config.component.ts +34 -0
- package/src/app/widget/widget-plugin.component.css +4 -0
- package/src/app/widget/widget-plugin.component.ts +16 -0
- package/src/app/widget/widget-plugin.module.ts +23 -0
- package/src/assets/assets.ts +16 -0
- package/src/assets/example.css +3 -0
- package/src/assets/index.d.ts +9 -0
- package/src/assets/widget-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 +19 -0
- package/src/polyfills.ts +33 -0
- package/tsconfig.app.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Cumulocity widget 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 `package.json`:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
"exports": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Example widget plugin",
|
|
9
|
+
"module": "WidgetPluginModule",
|
|
10
|
+
"path": "./widget/widget-plugin.module.ts",
|
|
11
|
+
"description": "Adds custom widget"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**How to start**
|
|
17
|
+
Run the command below to scaffold a `widget` plugin.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
c8ycli new <yourPluginName> widget-plugin
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
As the app.module is a typical Cumuloctiy application, any new plugin can be tested via the CLI:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
npm start -- --shell cockpit
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
In the Module Federation terminology, `widget` plugin is called `remote` and the `cokpit` is called `shell`. Modules provided by this `widget` 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.
|
|
30
|
+
|
|
31
|
+
> Note that the `--shell` flag creates a proxy to the cockpit application and provides` WidgetPluginModule` as an `remote` via URL options.
|
|
32
|
+
|
|
33
|
+
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,50 @@
|
|
|
1
|
+
import { EnvironmentOptions } from '@c8y/devkit/dist/options';
|
|
2
|
+
import { author, description, version } from './package.json';
|
|
3
|
+
|
|
4
|
+
const options: EnvironmentOptions = {
|
|
5
|
+
runTime: {
|
|
6
|
+
author,
|
|
7
|
+
description,
|
|
8
|
+
version,
|
|
9
|
+
name: 'Widget plugin',
|
|
10
|
+
contextPath: 'widget-plugin',
|
|
11
|
+
key: 'widget-plugin-application-key',
|
|
12
|
+
contentSecurityPolicy:
|
|
13
|
+
"base-uri 'none'; default-src 'self' 'unsafe-inline' http: https: ws: wss:; connect-src 'self' http: https: ws: wss:; script-src 'self' *.mapquestapi.com *.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:;",
|
|
14
|
+
dynamicOptionsUrl: '/apps/public/public-options/options.json',
|
|
15
|
+
remotes: {
|
|
16
|
+
'widget-plugin': ['WidgetPluginModule']
|
|
17
|
+
},
|
|
18
|
+
package: 'plugin',
|
|
19
|
+
isPackage: true,
|
|
20
|
+
noAppSwitcher: true,
|
|
21
|
+
exports: [
|
|
22
|
+
{
|
|
23
|
+
name: 'Example widget plugin',
|
|
24
|
+
module: 'WidgetPluginModule',
|
|
25
|
+
path: './src/app/widget/widget-plugin.module.ts',
|
|
26
|
+
description: 'Adds a custom widget to the shell application'
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
buildTime: {
|
|
31
|
+
federation: [
|
|
32
|
+
'@angular/animations',
|
|
33
|
+
'@angular/cdk',
|
|
34
|
+
'@angular/common',
|
|
35
|
+
'@angular/compiler',
|
|
36
|
+
'@angular/core',
|
|
37
|
+
'@angular/forms',
|
|
38
|
+
'@angular/platform-browser',
|
|
39
|
+
'@angular/platform-browser-dynamic',
|
|
40
|
+
'@angular/router',
|
|
41
|
+
'@angular/upgrade',
|
|
42
|
+
'@c8y/client',
|
|
43
|
+
'@c8y/ngx-components',
|
|
44
|
+
'ngx-bootstrap',
|
|
45
|
+
'@ngx-translate/core'
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default options;
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@c8y/widget-plugin",
|
|
3
|
+
"version": "1019.0.3",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@c8y/style": "1019.0.3",
|
|
7
|
+
"@c8y/ng1-modules": "1019.0.3",
|
|
8
|
+
"@c8y/ngx-components": "1019.0.3",
|
|
9
|
+
"@c8y/client": "1019.0.3",
|
|
10
|
+
"@c8y/bootstrap": "1019.0.3",
|
|
11
|
+
"@c8y/devkit": "1019.0.3",
|
|
12
|
+
"@angular/cdk": "^16.2.11",
|
|
13
|
+
"@angular/upgrade": "^16.2.11",
|
|
14
|
+
"angular": "1.6.9",
|
|
15
|
+
"ngx-bootstrap": "11.0.2",
|
|
16
|
+
"rxjs": "^7.4.0"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@angular/common": ">=15 <17"
|
|
20
|
+
},
|
|
21
|
+
"author": "Cumulocity GmbH"
|
|
22
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|
3
|
+
import { RouterModule as ngRouterModule } from '@angular/router';
|
|
4
|
+
import { BootstrapComponent, CoreModule, RouterModule } from '@c8y/ngx-components';
|
|
5
|
+
import { CockpitDashboardModule } from '@c8y/ngx-components/context-dashboard';
|
|
6
|
+
|
|
7
|
+
@NgModule({
|
|
8
|
+
imports: [
|
|
9
|
+
BrowserAnimationsModule,
|
|
10
|
+
ngRouterModule.forRoot([], { enableTracing: false, useHash: true }),
|
|
11
|
+
RouterModule.forRoot(),
|
|
12
|
+
CoreModule.forRoot(),
|
|
13
|
+
CockpitDashboardModule
|
|
14
|
+
],
|
|
15
|
+
bootstrap: [BootstrapComponent]
|
|
16
|
+
})
|
|
17
|
+
export class AppModule {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './widget-plugin.module';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Component, Input } from '@angular/core';
|
|
2
|
+
import { ControlContainer, NgForm } from '@angular/forms';
|
|
3
|
+
import { DynamicComponent, OnBeforeSave, AlertService } from '@c8y/ngx-components';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'c8y-widget-plugin-config',
|
|
7
|
+
template: `
|
|
8
|
+
<div class="form-group">
|
|
9
|
+
<c8y-form-group>
|
|
10
|
+
<label>Text</label>
|
|
11
|
+
<textarea
|
|
12
|
+
style="width:100%"
|
|
13
|
+
name="text"
|
|
14
|
+
[(ngModel)]="config.text"
|
|
15
|
+
[required]="true"
|
|
16
|
+
></textarea>
|
|
17
|
+
</c8y-form-group>
|
|
18
|
+
</div>
|
|
19
|
+
`,
|
|
20
|
+
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
|
|
21
|
+
})
|
|
22
|
+
export class WidgetPluginConfig implements DynamicComponent, OnBeforeSave {
|
|
23
|
+
@Input() config: any = {};
|
|
24
|
+
|
|
25
|
+
constructor(private alert: AlertService) {}
|
|
26
|
+
|
|
27
|
+
onBeforeSave(config: any): boolean {
|
|
28
|
+
if (config.text.trim() === '') {
|
|
29
|
+
this.alert.warning('Please enter a valid text.');
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Component, Input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'c8y-widget-plugin',
|
|
5
|
+
template: `
|
|
6
|
+
<div class="p-16">
|
|
7
|
+
<h1>Widget-plugin</h1>
|
|
8
|
+
<p class="text">{{ config?.text || 'No text' }}</p>
|
|
9
|
+
<small>My context is: {{ config?.device?.name || 'No context' }}</small>
|
|
10
|
+
</div>
|
|
11
|
+
`,
|
|
12
|
+
styleUrls: ['./widget-plugin.component.css']
|
|
13
|
+
})
|
|
14
|
+
export class WidgetPluginComponent {
|
|
15
|
+
@Input() config;
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Assets need to be imported into the module, or they are not available
|
|
2
|
+
import { assetPaths } from '../../assets/assets';
|
|
3
|
+
import { NgModule } from '@angular/core';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import { WidgetPluginComponent } from './widget-plugin.component';
|
|
6
|
+
import { WidgetPluginConfig } from './widget-plugin-config.component';
|
|
7
|
+
import { FormsModule, hookComponent, gettext } from '@c8y/ngx-components';
|
|
8
|
+
|
|
9
|
+
@NgModule({
|
|
10
|
+
declarations: [WidgetPluginComponent, WidgetPluginConfig],
|
|
11
|
+
imports: [CommonModule, FormsModule],
|
|
12
|
+
providers: [
|
|
13
|
+
hookComponent({
|
|
14
|
+
id: 'angular.widget.plugin',
|
|
15
|
+
label: gettext('Module Federation widget'),
|
|
16
|
+
description: gettext('Widget added via Module Federation'),
|
|
17
|
+
component: WidgetPluginComponent,
|
|
18
|
+
previewImage: assetPaths.previewImage,
|
|
19
|
+
configComponent: WidgetPluginConfig
|
|
20
|
+
})
|
|
21
|
+
]
|
|
22
|
+
})
|
|
23
|
+
export class WidgetPluginModule {}
|
|
@@ -0,0 +1,16 @@
|
|
|
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 './widget-plugin-pr.png';
|
|
10
|
+
|
|
11
|
+
// this will be a global style -> try to avoid as it could break existing styles
|
|
12
|
+
// better use component based styling (see ../widget/widget-plugin.component.css)
|
|
13
|
+
import './example.css';
|
|
14
|
+
|
|
15
|
+
// paths can be shared via this module if needed
|
|
16
|
+
export const assetPaths = { previewImage };
|
|
Binary file
|
package/src/bootstrap.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import './polyfills';
|
|
2
|
+
|
|
3
|
+
import { enableProdMode } from '@angular/core';
|
|
4
|
+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|
5
|
+
import { AppModule } from './app/app.module';
|
|
6
|
+
|
|
7
|
+
import './locales/de.po';
|
|
8
|
+
|
|
9
|
+
declare const __MODE__: string;
|
|
10
|
+
if (__MODE__ === 'production') {
|
|
11
|
+
enableProdMode();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function bootstrap() {
|
|
15
|
+
return platformBrowserDynamic()
|
|
16
|
+
.bootstrapModule(AppModule)
|
|
17
|
+
.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,19 @@
|
|
|
1
|
+
import './i18n';
|
|
2
|
+
import { applyOptions, loadOptions, loginOptions } from '@c8y/bootstrap';
|
|
3
|
+
|
|
4
|
+
const barHolder: HTMLElement = document.querySelector('body > .init-load');
|
|
5
|
+
export const removeProgress = () => barHolder && barHolder.parentNode.removeChild(barHolder);
|
|
6
|
+
|
|
7
|
+
applicationSetup();
|
|
8
|
+
|
|
9
|
+
async function applicationSetup() {
|
|
10
|
+
const options = await applyOptions({
|
|
11
|
+
...(await loadOptions()),
|
|
12
|
+
...((await loginOptions()) as object)
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const mod = await import('./bootstrap');
|
|
16
|
+
const bootstrapApp = mod.bootstrap || (window as any).bootstrap || (() => null);
|
|
17
|
+
|
|
18
|
+
return Promise.resolve(bootstrapApp(options)).then(removeProgress);
|
|
19
|
+
}
|
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/dist/zone'; // Included with Angular CLI.
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
}
|