Skip to content

Commit

Permalink
Initial commit v2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
hnaether-c8y committed Aug 17, 2023
1 parent ae5fac7 commit 9342f76
Show file tree
Hide file tree
Showing 28 changed files with 20,642 additions and 2 deletions.
9 changes: 9 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package.json
package-lock.json
dist
node_modules
cypress
extra-webpack.config.js
test
index.ts
polyfills.ts
28 changes: 28 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"parser": "@typescript-eslint/parser", // Specifies the ESLint parser
"plugins": ["@typescript-eslint", "prettier"],
"extends": [
"plugin:@typescript-eslint/recommended", // Uses the recommended rules from the @typescript-eslint/eslint-plugin
"eslint-config-prettier", // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
"plugin:prettier/recommended" // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
],
"parserOptions": {
"ecmaVersion": 2020, // Allows for the parsing of modern ECMAScript features
"sourceType": "module" // Allows for the use of imports
},
"rules": {
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
"@typescript-eslint/ban-ts-comment": "warn",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error"],
// don't blame usage of object since it's used in the WebSDK for the filters
"@typescript-eslint/ban-types": [
"off",
{
"types": {
"object": {}
}
}
]
}
}
109 changes: 109 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages

on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
pull_request:
branches: [main]

name: Main CI

env:
NODE_VERSION: '14'

jobs:
build:
name: 🚧 Lint, Test, Build & (optionally) Release
runs-on: ubuntu-latest
steps:
- name: Set RELEASE_VERSION env variable
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV

- name: Check out Git repository
uses: actions/checkout@v2

- name: Set up Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v1
with:
node-version: ${{ env.NODE_VERSION }}

- name: Set C8Y_VERSION env variable
run: echo "C8Y_VERSION=$(node -p -e "require('./package.json').dependencies['@c8y/ngx-components']")" >> $GITHUB_ENV

- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Install Node.js dependencies
run: |
npm ci
- name: 🕵️‍♂️ Lint
run: |
npm run lint --if-present
- name: 🧪 Test
run: |
npm test --if-present
- name: 🚧 Build Frontend
run: |
npm run build:ci
- name: Upload Frontend Artifact
uses: actions/upload-artifact@v2
with:
name: sag-ps-iot-pkg-events-graph-${{ env.C8Y_VERSION }}-${{ github.event.number }}-${{ github.run_id }}
if-no-files-found: error
retention-days: 5
path: dist/apps/sag-ps-iot-pkg-events-graph/

- name: Upload Frontend Artifact (microfrontend)
uses: actions/upload-artifact@v2
with:
name: sag-ps-iot-pkg-events-graph-${{ env.C8Y_VERSION }}-${{ github.event.number }}-${{ github.run_id }}
if-no-files-found: error
retention-days: 5
path: dist/apps/sag-ps-iot-pkg-events-graph/

- name: 🎁 Zip Frontend (microfrontend)
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
run: |
cd dist/apps/sag-ps-iot-pkg-events-graph
zip -r -q ../../../sag-ps-iot-pkg-events-graph.zip *
- name: Create Release
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ env.RELEASE_VERSION }} based on ${{ env.C8Y_VERSION }}
draft: false
prerelease: true

- name: Upload Release Asset Frontend (microfrontend)
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
id: upload-release-asset-frontend
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./sag-ps-iot-pkg-events-graph.zip
asset_name: sag-ps-iot-pkg-events-graph-${{ env.C8Y_VERSION }}-${{ env.RELEASE_VERSION }}.zip
asset_content_type: application/zip
46 changes: 46 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
**/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out

# dependencies
**/node_modules

# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*

# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings

# System Files
.DS_Store
Thumbs.db
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**/.tmp
**/.cache
8 changes: 8 additions & 0 deletions .prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
singleQuote: true
trailingComma: 'es5'
printWidth: 100
overrides:
- files: '{modules,packages}/**/*.html'
options:
parser: angular
editor.formatOnSave: true
62 changes: 60 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,60 @@
# iot-cumulocity-events-graph
Show event occruence in a timeline chart, using echarts profiling example approach. For the different texts a color can be chosen. (Currently only works in a device dashboard!)
# IoT Cumulocity Events Graph package

## Events Graph widget plugin
Show event occurence in a timeline chart, using echarts profiling example approach (see https://echarts.apache.org/examples/en/editor.html?c=custom-profile). For the different texts a color can be chosen. (Currently only works in a device dashboard!)


## Features
Shows "duration" of every event by assuming that a state is finished once the next state starts - an event always ends with the submission of the next event. The chart shows a view of the past x hours and helps visualizing the state changes for a specific event type.

* choose color for different states
* select timeframe (max. 24 hours in the past)
* states can be deselected in the legend
* chart is zoomable

## Sample images

Easily check which events occured when
![alt Events graph example](/docs/screenshot.png)


The chart can be zoomed
![alt Show zoom capability](/docs/zoom-example.gif)

Interactive legend
![alt Show legend interaction](/docs/legend-example.gif)

## Limitations
* only works for device dashboards
* only works for single event type, showing the different event texts
* no realtime
* no dashboard date integration

## Versions
2.0.0 - WebSDK v. 1017

**How to start**
Change the target tenant and application you want to run this plugin on in the `package.json`.

```
c8ycli server -u https://{{your-tenant}}.cumulocity.com/ --shell {{cockpit}}
```
Keep in mind that this plugin needs to have an app (e.g. cockpit) running with at least the same version as this plugin. if your tenant contains an older version, use the c8ycli to create a cockpit clone running with at least v 1017! Upload this clone to the target tenant and reference this name in the --shell command.

The widget plugin can be locally tested via the start script:

```
npm start
```

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.

> Note that the `--shell` flag creates a proxy to the cockpit application and provides` LayeredMapWidgetModule` as an `remote` via URL options.
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.

------------------------------
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.
_____________________
For more information you can Ask a Question in the [TECHcommunity Forums](http://tech.forums.softwareag.com/techjforum/forums/list.page?product=cumulocity).
You can find additional information in the [Software AG TECHcommunity](http://techcommunity.softwareag.com/home/-/product/name/cumulocity).
21 changes: 21 additions & 0 deletions app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule as ngRouterModule } from '@angular/router';
import { BootstrapComponent, CoreModule, RouterModule } from '@c8y/ngx-components';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { EventsGraphModule } from './events-graph.module';

@NgModule({
imports: [
BrowserAnimationsModule,
HttpClientModule,
ngRouterModule.forRoot([], { enableTracing: false, useHash: true }),
RouterModule.forRoot(),
CoreModule.forRoot(),
EventsGraphModule,
],
providers: [BsModalRef],
bootstrap: [BootstrapComponent],
})
export class AppModule {}
Binary file added docs/legend-example.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/zoom-example.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions events-graph.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { CommonModule, CommonModule as NgCommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule as NgFormModule, ReactiveFormsModule } from '@angular/forms';
import {
CoreModule,
DynamicComponentDefinition,
DynamicFormsModule,
HOOK_COMPONENTS,
} from '@c8y/ngx-components';
import { ContextWidgetConfig } from '@c8y/ngx-components/context-dashboard';
import { ModalModule } from 'ngx-bootstrap/modal';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { NgxEchartsModule } from 'ngx-echarts';
import { EventStatusTrackerWidgetConfig } from './events-graph/event-status-tracker-config.component';
import { EventStatusTrackerComponent } from './events-graph/event-status-tracker.component';
import { EventStatusTrackerService } from './events-graph/event-status-tracker.service';

@NgModule({
imports: [
CoreModule,
CommonModule,
ModalModule,
TooltipModule,
NgCommonModule,
NgFormModule,
ReactiveFormsModule,
DynamicFormsModule,
ModalModule.forRoot(),
NgxEchartsModule.forRoot({
echarts: () => import('echarts'),
}),
],
declarations: [EventStatusTrackerComponent, EventStatusTrackerWidgetConfig],
entryComponents: [EventStatusTrackerComponent, EventStatusTrackerWidgetConfig],
providers: [
EventStatusTrackerService,
{
provide: HOOK_COMPONENTS,
multi: true,
useValue: [
{
id: 'events-graph-widget',
label: 'Events Graph',
description: 'Show event occurence in a timeline chart.',
component: EventStatusTrackerComponent,
configComponent: EventStatusTrackerWidgetConfig,
previewImage: require('./docs/preview.png'),
data: {
settings: {
noNewWidgets: false, // Set this to true, to don't allow adding new widgets.
widgetDefaults: {
_width: 12,
_height: 5,
},
ng1: {
options: {
noDeviceTarget: false, // Set this to true to hide the device selector.
groupsSelectable: false, // Set this, if not only devices should be selectable.
},
},
},
} as ContextWidgetConfig,
},
] as DynamicComponentDefinition[],
},
],
})
export class EventsGraphModule {}
Loading

0 comments on commit 9342f76

Please sign in to comment.