Commit d9dcd28a authored by bishwadeep.chaudhary's avatar bishwadeep.chaudhary

initial commit

parent b362dd55
# plugin-widget
# pepsico_widget
### Author: bishwadeep (bishwadeep.chaudhary@knowledgelens.com)
## Project Description:
this is poc plugin to create a widget
if __name__ == "__main__":
from dotenv import load_dotenv
load_dotenv()
from main import app
app.root_path = None
import logging
import uvicorn
from fastapi import FastAPI
from scripts.config import Service
if __name__ == "__main__":
app = FastAPI()
logging.info(f"App Starting at {Service.HOST}:{Service.PORT}")
uvicorn.run("main:app", host=Service.HOST, port=int(Service.PORT))
{
"selector": "app-candle",
"settings": {
"config_tabs": {
"general": true,
"chartProp": true
}
}
}
\ No newline at end of file
from dataclasses import dataclass
from fastapi import FastAPI
from scripts.core.services.default import router
from scripts.core.services.report import router as report
@dataclass
class FastAPIConfig:
title: str = "Sample App"
version: str = "1.0.0"
description: str = "Sample App Description"
app = FastAPI(**FastAPIConfig().__dict__)
app.include_router(router)
app.include_router(report)
uvicorn~=0.23.1
fastapi[all]>=0.97.0
pydantic==1.10.9
numpy~=1.23.5
python-dotenv==1.0.0
XlsxWriter==3.0.8
pandas
\ No newline at end of file
{"option":{"title":[{"text":"Michelson-Morley Experiment","left":"center"},{"text":"upper: Q3 + 1.5 * IQR \nlower: Q1 - 1.5 * IQR","borderColor":"#999","borderWidth":1,"textStyle":{"fontWeight":"normal","fontSize":14,"lineHeight":20},"left":"10%","top":"90%"}],"dataset":[{"source":[[850,740,900,1070,930,850,950,980,980,880,1000,980,930,650,760,810,1000,1000,960,960],[960,940,960,940,880,800,850,880,900,840,830,790,810,880,880,830,800,790,760,800],[880,880,880,860,720,720,620,860,970,950,880,910,850,870,840,840,850,840,840,840],[890,810,810,820,800,770,760,740,750,760,910,920,890,860,880,720,840,850,850,780],[890,840,780,810,760,810,790,810,820,850,870,870,810,740,810,940,950,800,810,870]]},{"transform":{"type":"boxplot","config":{"itemNameFormatter":"expr {value}"}}},{"fromDatasetIndex":1,"fromTransformResult":1}],"tooltip":{"trigger":"item","axisPointer":{"type":"shadow"}},"grid":{"left":"10%","right":"10%","bottom":"15%"},"xAxis":{"type":"category","boundaryGap":true,"nameGap":30,"splitArea":{"show":false},"splitLine":{"show":false}},"yAxis":{"type":"value","name":"km/s minus 299,000","splitArea":{"show":true}},"series":[{"name":"boxplot","type":"boxplot","datasetIndex":1},{"name":"outlier","type":"scatter","datasetIndex":2}]}}
\ No newline at end of file
This diff is collapsed.
import pathlib
from pydantic import Field, BaseSettings
PROJECT_NAME = "candle"
class _Service(BaseSettings):
MODULE_NAME: str = Field(default="candle")
HOST: str = Field(default="0.0.0.0", env="service_host")
PORT: int = Field(default=8080, env="port")
BUILD_DIR: str = Field(default="scripts/templates")
PLUGIN_NAME: str = Field(default="candle")
PROXY: str = Field(default="/hack-repl")
BACKEND_DIR: str = Field(default=".")
class _BasePathConf(BaseSettings):
BASE_PATH: str = "/code/data"
class _PathToDir(BaseSettings):
ASSETS: str = Field(default=f"{_Service().BUILD_DIR}/assets")
BASE_PATH: pathlib.Path = pathlib.Path(_BasePathConf().BASE_PATH)
MODULE_PATH: pathlib.Path = BASE_PATH / _Service().MODULE_NAME
DATA: pathlib.Path = MODULE_PATH / "data"
Service = _Service()
PathToDir = _PathToDir()
class _APIEndpoints:
load_styles = "/load_styles"
load_file = "/load_file"
load_configuration = "/load_configuration"
preview = "/preview"
generate = "/report/generate"
fetch_data="/fetch_data"
class ExternalEndpoints:
api_ebpr_request = "/general/update_status"
APIEndpoints = _APIEndpoints()
import json
import logging
import os
import pandas as pd
from fastapi.responses import FileResponse
from scripts.config import Service, PathToDir
from scripts.core.schemas.response_models import DefaultResponse
from scripts.core.schemas.response_models import LoadStylesResponse
class DefaultHandler:
@staticmethod
def load_styles():
try:
response = LoadStylesResponse()
for each_file in os.listdir(Service.BUILD_DIR):
path = f"{Service.PROXY}/widget/load_file?filename={each_file}"
if each_file.endswith(".js"):
response.js_files.append(path)
elif each_file.endswith(".css"):
response.styles.append(path)
elif each_file == "assets":
response.assetPath = f"{Service.BUILD_DIR}/{each_file}"
return DefaultResponse(message="Styles loaded successfully", data=response)
except Exception as e:
logging.exception(e)
return DefaultResponse(message="Failed to load file paths", status="failed")
@staticmethod
def download_resources(filename: str):
try:
file_path = os.path.join(Service.BUILD_DIR, filename)
if os.path.isfile(os.path.join(Service.BUILD_DIR, filename)) and filename.endswith(".js"):
return FileResponse(file_path, media_type='application/octet-stream', filename=filename)
else:
return DefaultResponse(message="Failed to load resources")
except Exception as e:
logging.error("Exception " + str(e))
return DefaultResponse(message="Filename is not available")
@staticmethod
def load_configuration():
try:
with open(f"{PathToDir.ASSETS}/widgetConfig.json", "r") as file:
file_content = json.loads(file.read())
return file_content
except Exception as e:
logging.error(e)
return DefaultResponse(message="Failed to load configurations")
# @staticmethod
# def fetch_data():
# with open(f"{Service.BACKEND_DIR}/scripts/assets/mock_data.json", "r") as file:
# file_content = json.loads(file.read())
# return file_content
@staticmethod
def generate_report():
with open(f"{Service.BACKEND_DIR}/scripts/assets/mock_data.json", "r") as file:
file_content = json.loads(file.read())
df = pd.DataFrame(file_content.get("data", [])) if file_content else pd.DataFrame([])
df.index.name = "Timestamp"
if not os.path.exists(PathToDir.DATA):
os.makedirs(PathToDir.DATA)
df.to_csv(f"{PathToDir.DATA}/data.csv")
return FileResponse(f"{PathToDir.DATA}/data.csv", filename="data.csv")
from pydantic import BaseModel
class DownloadResource(BaseModel):
file_name: str
from typing import Any, Optional
from pydantic import BaseModel
class DefaultResponse(BaseModel):
status: str = "success"
message: str
data: Optional[Any]
class LoadStylesResponse(BaseModel):
styles: list = []
js_files: list = []
assetPath: str | None = None
This diff is collapsed.
This diff is collapsed.
import logging
from fastapi import APIRouter
from scripts.core.constants.api import APIEndpoints
from scripts.core.handlers.default import DefaultHandler
router = APIRouter(prefix="/report")
handler = DefaultHandler
@router.post(APIEndpoints.generate)
def generate_report():
try:
return handler.generate_report()
except Exception as e:
logging.exception(e)
This diff is collapsed.
<svg xmlns="http://www.w3.org/2000/svg" width="54" height="66.66899871826172" viewBox="0 0 54 66.669">
<g id="Group_11331" data-name="Group 11331" transform="translate(-818 -47.355)">
<g id="ilens-logo">
<path id="Path_10233" data-name="Path 10233" d="M-.131-.544,52.785,16.738v30.29L-.131,64.717Z" transform="translate(819 49)" fill="#00349a" class="svg-elem-1"></path>
<text id="i" transform="translate(843 94)" fill="#fff" font-size="38" font-family="ProductSans-Bold, Product Sans" font-weight="700" letter-spacing="0.009em"><tspan x="0" y="0">i</tspan></text>
</g>
<path id="Path_10234" data-name="Path 10234" d="M53,47V17.054L0-.453V64.829L53,47" transform="translate(818.5 48.5)" fill="none" stroke="#00349a" stroke-width="1" class="svg-elem-2"></path>
</g>
</svg>
\ No newline at end of file
{
"selector": "app-candle",
"settings": {
"config_tabs": {
"general": true,
"chartProp": true
}
}
}
\ No newline at end of file
<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<title>Candle Stick</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<style>body{height:100vh;width:100vw;margin:0!important}</style><link rel="stylesheet" href="styles.baa29a046a58aaa1168a.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.baa29a046a58aaa1168a.css"></noscript></head>
<body>
<app-root></app-root>
<script src="runtime.810371c46e51402efea7.js" defer></script><script src="polyfills.f13710012fbd87309b97.js" defer></script><script src="main.bd989ff48250408ec274.js" defer></script>
</body></html>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
(()=>{"use strict";var e,_={},d={};function a(e){var n=d[e];if(void 0!==n)return n.exports;var r=d[e]={exports:{}};return _[e](r,r.exports,a),r.exports}a.m=_,e=[],a.O=(n,r,f,l)=>{if(!r){var o=1/0;for(t=0;t<e.length;t++){for(var[r,f,l]=e[t],v=!0,u=0;u<r.length;u++)(!1&l||o>=l)&&Object.keys(a.O).every(b=>a.O[b](r[u]))?r.splice(u--,1):(v=!1,l<o&&(o=l));if(v){e.splice(t--,1);var c=f();void 0!==c&&(n=c)}}return n}l=l||0;for(var t=e.length;t>0&&e[t-1][2]>l;t--)e[t]=e[t-1];e[t]=[r,f,l]},a.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return a.d(n,{a:n}),n},a.d=(e,n)=>{for(var r in n)a.o(n,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},a.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e={666:0};a.O.j=f=>0===e[f];var n=(f,l)=>{var u,c,[t,o,v]=l,s=0;for(u in o)a.o(o,u)&&(a.m[u]=o[u]);if(v)var p=v(a);for(f&&f(l);s<t.length;s++)a.o(e,c=t[s])&&e[c]&&e[c][0](),e[t[s]]=0;return a.O(p)},r=self.webpackChunkapp_a=self.webpackChunkapp_a||[];r.forEach(n.bind(null,0)),r.push=n.bind(null,r.push.bind(r))})()})();
\ No newline at end of file
body{height:100vh;width:100vw;margin:0!important}
\ No newline at end of file
{
"selector": "app-candle",
"settings": {
"config_tabs": {
"general": true,
"chartProp": true
}
}
}
\ No newline at end of file
# 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
# 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
# AppA
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.2.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"App-A": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
},
"@schematics/angular:application": {
"strict": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/App-A",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "5mb",
"maximumError": "10mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2mb",
"maximumError": "10mb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "App-A:build:production"
},
"development": {
"browserTarget": "App-A:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "App-A:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js"
]
}
}
}
}
},
"defaultProject": "App-A"
}
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/App-A'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
]
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};
This diff is collapsed.
{
"name": "app-a",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "~12.2.0",
"@angular/common": "~12.2.0",
"@angular/compiler": "~12.2.0",
"@angular/core": "~12.2.0",
"@angular/elements": "^12.2.17",
"@angular/forms": "~12.2.0",
"@angular/platform-browser": "~12.2.0",
"@angular/platform-browser-dynamic": "~12.2.0",
"@angular/router": "~12.2.0",
"@ng-select/ng-select": "^6.1.0",
"document-register-element": "^1.7.2",
"echarts": "^5.4.2",
"jquery": "^3.4.1",
"ngx-build-plus": "^14.0.0",
"ngx-chips": "^2.2.1",
"rxjs": "~6.6.0",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~12.2.2",
"@angular/cli": "~12.2.2",
"@angular/compiler-cli": "~12.2.0",
"@types/jasmine": "~3.8.0",
"@types/jquery": "^3.5.16",
"@types/node": "^12.11.1",
"jasmine-core": "~3.8.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "~1.7.0",
"typescript": "~4.3.5"
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
<ng-container *ngIf="pageMode === 'config' && widgetInfo">
<app-design-tab *ngIf="activetab === 'chartProp'" [(widgetInfo)]="widgetInfo" [base_proxy]="base_proxy"
(widgetInfoChange)="widgetInfoChange.emit(widgetInfo)">
</app-design-tab>
</ng-container>
<ng-container *ngIf="pageMode === 'display' && widgetInfo">
<app-chart-display [widgetInfo]="widgetInfo" [base_proxy]="base_proxy"> </app-chart-display>
</ng-container>
\ No newline at end of file
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'App-A'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('App-A');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('App-A app is running!');
});
});
import { Component, EventEmitter, Output, Input } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
@Input() widgetInfo: any;
@Output() widgetInfoChange = new EventEmitter();
@Input() pageMode: 'config' | 'display' = 'config';
@Input() activetab: 'chartProp' | 'tools' = 'chartProp';
@Input() base_proxy: string = '';
}
\ No newline at end of file
import { Injector, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { createCustomElement } from '@angular/elements';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { NgSelectModule } from '@ng-select/ng-select';
import { SwitchInputComponent } from './switch-input/switch-input.component';
import { TagInputModule } from 'ngx-chips';
import { DesignTabComponent } from './chart-config/design-tab/design-tab.component';
import { ChartDisplayComponent } from './chart-display/chart-display.component';
@NgModule({
declarations: [
AppComponent,
SwitchInputComponent,
DesignTabComponent,
ChartDisplayComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule,
NgSelectModule,
TagInputModule,
],
providers: [],
bootstrap: []
})
export class AppModule {
constructor(private injector: Injector) { }
ngDoBootstrap() {
if (!customElements.get('app-candle')) {
const el = createCustomElement(AppComponent, { injector: this.injector })
customElements.define('app-candle', el);
}
}
}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DesignTabComponent } from './design-tab.component';
describe('DesignTabComponent', () => {
let component: DesignTabComponent;
let fixture: ComponentFixture<DesignTabComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DesignTabComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DesignTabComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
@Component({
selector: 'app-design-tab',
templateUrl: './design-tab.component.html',
styleUrls: ['./design-tab.component.scss']
})
export class DesignTabComponent implements OnInit {
@Input() widgetInfo: any;
@Output() widgetInfoChange = new EventEmitter();
@Input() base_proxy: any;
public baseOptions: any = {
visualMap: {
show: false,
inRangeColors: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8',
'#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'],
},
tooltip: {
show: true,
backgroundColor: '#ffffff',
borderColor: '#000000',
borderWidth: 1,
trigger: 'axis',
axisPointer: {
type: 'cross',
},
textStyle: {
color: '#000000',
},
},
dataZoom: {
insideZoom: true,
xAxis: false,
yAxis: false,
yAxisPos: 'left',
xAxisPos: 'top',
},
}
get _chartConfig() {
return this.widgetInfo?.cData?.chartOptions ? this.widgetInfo.cData.chartOptions : this.baseOptions
}
set _chartConfig(value) {
this.widgetInfo.cData.chartOptions = value;
this.widgetInfoChange.emit(this.widgetInfo);
}
public chartComponentTemplates: any = [
{
label: 'Placement',
value: 'placement',
class: 'addYaxisAction'
},
{
label: 'Data Tooltip',
value: 'dataTooltip',
},
{
label: 'Visual Map',
value: 'visualMap',
},
{
label: 'Data Zooming',
value: 'dataZooming',
},
]
public chartOptions = {
widgetPosition: [
{
label: 'Standard',
value: 'standard',
},
{
label: 'Flexible',
value: 'flexible',
},
],
colWidth: [
{
label: '2',
value: '2',
},
{
label: '3',
value: 3,
},
{
label: '4',
value: 4,
},
{
label: '5',
value: 5,
},
{
label: '6',
value: 6,
},
{
label: '7',
value: 7,
},
{
label: '8',
value: 8,
},
{
label: '9',
value: 9,
},
{
label: '10',
value: 10,
},
{
label: '11',
value: 11,
},
{
label: '12',
value: 12,
},
],
dataZoom: {
yAxisPos: [
{ value: 'left', label: 'Left' },
{ value: 'right', label: 'Right' },
],
xAxisPos: [
{ value: 'top', label: 'Top' },
{ value: 'bottom', label: 'Bottom' },
],
},
visualMapTypes: [
{
label: 'Continuous',
value: 'continuous',
},
{
label: 'Piece Wise',
value: 'piecewise',
},
],
tooltip: {
axisPointerTypes: [
{
label: 'Cross',
value: 'cross',
},
{
label: 'Line',
value: 'line',
},
{
label: 'Shadow',
value: 'shadow',
},
{
label: 'None',
value: 'none',
},
],
triggerTypes: [
{
label: 'Item',
value: 'item',
},
{
label: 'Axis',
value: 'axis',
},
],
},
}
constructor() { }
ngOnInit() {
for (const item of ['tooltip', 'dataZoom', 'visualMap']) {
this._chartConfig[item] ??= this.baseOptions[item];
}
}
emitChanges() { }
addVisualMapRange() {
try {
this._chartConfig.visualMap.pieces ??= [];
this._chartConfig.visualMap.pieces.push({ gt: '', lte: '', color: '' });
} catch (error) {
console.log(error);
}
}
deleteChartLimit(index: any) {
try {
if (!this._chartConfig.visualMap.pieces || !this._chartConfig.visualMap.pieces[index]) {
return;
}
this._chartConfig.visualMap.pieces.splice(index, 1);
} catch (error) {
console.log(error);
}
}
isAttributeShow(a: any) {
return true;
}
}
<div #ehartsTemplate *ngIf="widgetInfo" [style.height.px]="widgetInfo.h"></div>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChartDisplayComponent } from './chart-display.component';
describe('ChartDisplayComponent', () => {
let component: ChartDisplayComponent;
let fixture: ComponentFixture<ChartDisplayComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ChartDisplayComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ChartDisplayComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { HttpClient } from '@angular/common/http';
import { Component, Input, ViewChild } from '@angular/core';
import * as echarts from 'echarts';
@Component({
selector: 'app-chart-display',
templateUrl: './chart-display.component.html',
styleUrls: ['./chart-display.component.scss']
})
export class ChartDisplayComponent {
@Input() widgetInfo: any;
@Input() base_proxy: any;
@ViewChild('ehartsTemplate') ehartsTemplate: any;
public chartInstance: any;
public chartOption: any;
get _chartConfig() {
return this.widgetInfo?.cData?.chartOptions;
}
constructor(private http: HttpClient) { }
ngAfterViewInit() {
setTimeout(() => {
if (this.widgetInfo) {
this.setChartOptions();
}
}, 2000);
}
setChartOptions() {
if (!this.ehartsTemplate) { return; }
this.chartInstance = echarts.init(this.ehartsTemplate.nativeElement);
const url = this.base_proxy + 'widget/preview';
this.http.get<any>(url).subscribe(res => {
const chartOptions = res['option'];
chartOptions['tooltip'] = this._chartConfig.tooltip || { show: false };
if (this._chartConfig && this._chartConfig['dataZoom']) {
chartOptions['dataZoom'] = [];
if (this._chartConfig.dataZoom.insideZoom) {
chartOptions['dataZoom'].push({ type: 'inside' });
}
if (this._chartConfig.dataZoom.xAxis) {
chartOptions['dataZoom'].push({
type: 'slider',
[this._chartConfig.dataZoom.xAxisPos === 'bottom' ? 'bottom' : 'top']: 0,
xAxisIndex: [0],
filterMode: 'none',
});
}
if (this._chartConfig.dataZoom.yAxis) {
chartOptions['dataZoom'].push({
type: 'slider',
top: 'center',
[this._chartConfig.dataZoom.yAxisPos === 'right' ? 'right' : 'left']: this._chartConfig.dataZoom.yAxisPos === 'right' ? 30 : 0,
yAxisIndex: 0,
filterMode: 'none',
});
}
}
const chartConfig = this._chartConfig;
if (chartConfig.visualMap && chartConfig.visualMap.show && chartConfig.visualMap.type === 'piecewise') {
chartOptions['visualMap'] = {
top: 'center',
right: '25',
pieces: chartConfig.visualMap.pieces,
outOfRange: { color: chartConfig.visualMap.outOfRangeColor ? chartConfig.visualMap.outOfRangeColor : '#000000' },
};
} else if (chartConfig.visualMap && chartConfig.visualMap.show && ['', null, undefined, 'continuous'].indexOf(chartConfig.visualMap.continuous) > -1 && chartOptions.series && chartOptions.series.length) {
const dataMin = 0;
const dataMax = 1500;
chartOptions['visualMap'] = {
top: 'center',
right: '25',
calculable: true,
title: ['High', 'Low'],
min: [null, undefined, ''].indexOf(chartConfig.visualMap.min) === -1 ? chartConfig.visualMap.min : Math.floor(dataMin || 0),
max: [null, undefined, ''].indexOf(chartConfig.visualMap.max) === -1 ? chartConfig.visualMap.max : Math.ceil(dataMax || 200),
inRange: {
color: chartConfig.visualMap.inRangeColors && chartConfig.visualMap.inRangeColors.length ? chartConfig.visualMap.inRangeColors : ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'],
},
};
} else {
delete chartOptions['visualMap'];
}
this.chartInstance.setOption(chartOptions);
});
} catch(error: any) {
console.log(error)
}
}
<ng-container *ngIf="!labelPosition || labelPosition === 'top'">
<div class="mb-2 input-label">{{label}}</div>
<div class="pretty p-switch p-fill">
<input type="checkbox" [checked]="inputModel" name="thresholdShow" [(ngModel)]="inputModel"
(ngModelChange)="inputModelChange.emit(inputModel)">
<div class="state">
<label></label>
</div>
</div>
</ng-container>
<ng-container *ngIf="labelPosition === 'left'">
<span class="pr-2 input-label">{{label}}</span>
<div class="pretty p-switch p-fill">
<input type="checkbox" [checked]="inputModel" name="thresholdShow" [(ngModel)]="inputModel"
(ngModelChange)="inputModelChange.emit(inputModel)">
<div class="state">
<label></label>
</div>
</div>
</ng-container>
<ng-container *ngIf="labelPosition === 'right'">
<div class="pretty p-switch p-fill">
<input type="checkbox" [checked]="inputModel" name="thresholdShow" [(ngModel)]="inputModel"
(ngModelChange)="inputModelChange.emit(inputModel)">
<div class="state">
<label></label>
</div>
</div>
<span class="pl-4 input-label">{{label}}</span>
</ng-container>
\ No newline at end of file
.input-label{
font-family: 'Roboto-Medium', Sans-serif !important;
}
// tslint:disable:component-selector no-input-rename ter-indent ter-arrow-parens align max-line-length no-this-assignment prefer-template no-increment-decrement no-inferrable-types
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'kl-switch-input',
templateUrl: './switch-input.component.html',
styleUrls: ['./switch-input.component.scss']
})
export class SwitchInputComponent {
@Input() inputModel: any = false;
@Input() label: any = '';
@Input() labelPosition: any = 'top';
@Input() info: string = '';
@Output() inputModelChange = new EventEmitter<any>();
}
<svg xmlns="http://www.w3.org/2000/svg" width="54" height="66.66899871826172" viewBox="0 0 54 66.669">
<g id="Group_11331" data-name="Group 11331" transform="translate(-818 -47.355)">
<g id="ilens-logo">
<path id="Path_10233" data-name="Path 10233" d="M-.131-.544,52.785,16.738v30.29L-.131,64.717Z" transform="translate(819 49)" fill="#00349a" class="svg-elem-1"></path>
<text id="i" transform="translate(843 94)" fill="#fff" font-size="38" font-family="ProductSans-Bold, Product Sans" font-weight="700" letter-spacing="0.009em"><tspan x="0" y="0">i</tspan></text>
</g>
<path id="Path_10234" data-name="Path 10234" d="M53,47V17.054L0-.453V64.829L53,47" transform="translate(818.5 48.5)" fill="none" stroke="#00349a" stroke-width="1" class="svg-elem-2"></path>
</g>
</svg>
\ No newline at end of file
{ "selector": "app-candle", "settings": { "config_tabs": { "general": true, "chartProp": true } } }
\ No newline at end of file
export const environment = {
production: true
};
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Candle Stick</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
\ No newline at end of file
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/**
* IE11 requires the following for NgClass support on SVG elements
*/
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
import 'document-register-element';
/* You can add global styles to this file, and also import other style files */
body {
height: 100vh;
width : 100vw;
margin: 0 !important;
}
\ No newline at end of file
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): {
keys(): string[];
<T>(id: string): T;
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
{ teardown: { destroyAfterEach: true }},
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.d.ts"
]
}
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2017",
"module": "es2020",
"lib": [
"es2018",
"dom"
],
"types": ["jquery"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine"
]
},
"files": [
"src/test.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
{
"plugin_name": "Candle Widget",
"plugin_type": "widget",
"vcs-url": "https://gitlab-pm.knowledgelens.com/bishwadeep.chaudhary/plugin-widget.git",
"branch": "master",
"frontend_base_image": "node:14.16.1",
"environment_variables": {
},
"version": "1.0"
}
.termynal-comment {
color: #4a968f;
font-style: italic;
display: block;
}
.termy {
/* For right to left languages */
direction: ltr;
}
.termy [data-termynal] {
white-space: pre-wrap;
}
a.external-link {
/* For right to left languages */
direction: ltr;
display: inline-block;
}
a.external-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0[↪]";
}
a.internal-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0↪";
}
.shadow {
box-shadow: 5px 5px 10px #999;
}
/* Give space to lower icons so Gitter chat doesn't get on top of them */
.md-footer-meta {
padding-bottom: 2em;
}
.user-list {
display: flex;
flex-wrap: wrap;
margin-bottom: 2rem;
}
.user-list-center {
justify-content: space-evenly;
}
.user {
margin: 1em;
min-width: 7em;
}
.user .avatar-wrapper {
width: 80px;
height: 80px;
margin: 10px auto;
overflow: hidden;
border-radius: 50%;
position: relative;
}
.user .avatar-wrapper img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.user .title {
text-align: center;
}
.user .count {
font-size: 80%;
text-align: center;
}
a.announce-link:link,
a.announce-link:visited {
color: #fff;
}
a.announce-link:hover {
color: var(--md-accent-fg-color);
}
.announce-wrapper {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
align-items: center;
}
.announce-wrapper div.item {
display: none;
}
.announce-wrapper .sponsor-badge {
display: block;
position: absolute;
top: -10px;
right: 0;
font-size: 0.5rem;
color: #999;
background-color: #666;
border-radius: 10px;
padding: 0 10px;
z-index: 10;
}
.announce-wrapper .sponsor-image {
display: block;
border-radius: 20px;
}
.announce-wrapper>div {
min-height: 40px;
display: flex;
align-items: center;
}
.twitter {
color: #00acee;
}
/* Right to left languages */
code {
direction: ltr;
display: inline-block;
}
.md-content__inner h1 {
direction: ltr !important;
}
.illustration {
margin-top: 2em;
margin-bottom: 2em;
}
/* Screenshots */
/*
Simulate a browser window frame.
Inspired by Termynal's CSS tricks with modifications
*/
.screenshot {
display: block;
background-color: #d3e0de;
border-radius: 4px;
padding: 45px 5px 5px;
position: relative;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.screenshot img {
display: block;
border-radius: 2px;
}
.screenshot:before {
content: '';
position: absolute;
top: 15px;
left: 15px;
display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
/* A little hack to display the window buttons in one pseudo element. */
background: #d9515d;
-webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
}
\ No newline at end of file
This diff is collapsed.
# Candle Docs File inside a Directory
![blue fac.png](../assets/blue%20fac.png)
\ No newline at end of file
# Candle Docs File on the docs level
![blue fac.png](assets/blue fac.png)
\ No newline at end of file
site_name: "User Guide"
theme:
name: material
favicon: assets/logos/favicon.ico
nav_style: dark
navigation_depth: 4
collapse_navigation: True
font:
code: Roboto Mono
text: Roboto
logo: assets/logos/logo-full-4x.png
palette:
- scheme: default
primary: black
accent: indigo
features:
- search.suggest
- search.highlight
- content.tabs.link
- navigation.tracking
- navigation.top
- navigation.sections
- navigation.tabs
- navigation.tabs.sticky
- navigation.instant
- toc.follow
- navigation.indexes
extra:
consent:
title: Cookie consent
description: >-
We use cookies to recognize your repeated visits and preferences, as well
as to measure the effectiveness of our documentation and whether users
find what they're searching for. With your consent, you're helping us to
make our documentation better.
copyright: This document is proprietary to UnifyTwin. No part of it shall be reproduced or transmitted in any form, by any means (electronic, photocopying, recording, or otherwise) without prior consent from UnifyTwin.<br>Copyright &copy 2022-<script>document.write(new Date().getFullYear())</script> UnifyTwin
markdown_extensions:
- admonition
- pymdownx.details
- pymdownx.superfences
- md_in_html
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- pymdownx.tabbed:
alternate_style: true
- toc:
permalink: true
- attr_list
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- pymdownx.tasklist:
custom_checkbox: true
plugins:
- search
mkdocs-material>=9.2.5
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment