diff --git a/Angular/.editorconfig b/Angular/.editorconfig new file mode 100644 index 0000000..59d9a3a --- /dev/null +++ b/Angular/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/Angular/.gitignore b/Angular/.gitignore new file mode 100644 index 0000000..0711527 --- /dev/null +++ b/Angular/.gitignore @@ -0,0 +1,42 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db diff --git a/Angular/angular.json b/Angular/angular.json new file mode 100644 index 0000000..6debef1 --- /dev/null +++ b/Angular/angular.json @@ -0,0 +1,101 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "Angular": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/angular", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "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": "Angular:build:production" + }, + "development": { + "browserTarget": "Angular:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "Angular: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", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [] + } + } + } + } + } +} diff --git a/Angular/karma.conf.js b/Angular/karma.conf.js new file mode 100644 index 0000000..54d5a3b --- /dev/null +++ b/Angular/karma.conf.js @@ -0,0 +1,44 @@ +// 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/angular'), + 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 + }); +}; diff --git a/Angular/package.json b/Angular/package.json new file mode 100644 index 0000000..31be6d5 --- /dev/null +++ b/Angular/package.json @@ -0,0 +1,38 @@ +{ + "name": "angular", + "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": "^16.2.0", + "@angular/common": "^16.2.0", + "@angular/compiler": "^16.2.0", + "@angular/core": "^16.2.0", + "@angular/forms": "^16.2.0", + "@angular/platform-browser": "^16.2.0", + "@angular/platform-browser-dynamic": "^16.2.0", + "@angular/router": "^16.2.0", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.13.0" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^16.2.10", + "@angular/cli": "^16.2.10", + "@angular/compiler-cli": "^16.2.0", + "@types/jasmine": "~4.3.0", + "jasmine-core": "~4.6.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.1.3" + } +} \ No newline at end of file diff --git a/Angular/src/app/app.component.html b/Angular/src/app/app.component.html new file mode 100644 index 0000000..90c6b64 --- /dev/null +++ b/Angular/src/app/app.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Angular/src/app/app.component.ts b/Angular/src/app/app.component.ts new file mode 100644 index 0000000..24acd4e --- /dev/null +++ b/Angular/src/app/app.component.ts @@ -0,0 +1,33 @@ +import { Component } from '@angular/core'; +import { appService } from './app.service'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html' +}) + + export class AppComponent { + + //Node.js application will run on http://localhost:8080, which needs to be set as apiHost. + public apiHost="http://localhost:8080"; + + //Url of the authorizationserver action in Node.js application. + public authorizationUrl= "/authorizationserver"; + + //Url of the GetDetails action in Node.js application. + public getEmbedConfigUrl= "/getData"; + + public embedConfig: any; + + public dashboards: any; + + public baseUrl: any; + + public dashboardServerApiUrl!: string; + + constructor(private _app: appService) { + } + + ngOnInit() { + } +} \ No newline at end of file diff --git a/Angular/src/app/app.module.ts b/Angular/src/app/app.module.ts new file mode 100644 index 0000000..9e87f2f --- /dev/null +++ b/Angular/src/app/app.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { HttpClientModule, HttpClient } from '@angular/common/http'; +import { AppComponent } from './app.component'; +import { RouterModule } from '@angular/router'; +import { Dashboard } from './dashboard/dashboard.component'; +import { appService } from './app.service'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forRoot([ + { path: '', component: Dashboard }, + ] + ), + HttpClientModule + ], + providers: [appService], + declarations: [ + AppComponent, + Dashboard + ], + + bootstrap: [AppComponent] +}) +export class AppModule { } \ No newline at end of file diff --git a/Angular/src/app/app.service.ts b/Angular/src/app/app.service.ts new file mode 100644 index 0000000..898bf3d --- /dev/null +++ b/Angular/src/app/app.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http'; + +@Injectable() + +export class appService { + + private authUrl!: string; + private getDashboardsUrl!: string; + private header!: HttpHeaders; + + constructor(private http: HttpClient) { + } + + /* public Gettoken(dashboardServerApiUrl: string,userId: string, userPassword: string) { + this.header = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded'); + + let body = new HttpParams(); + body = body.set('UserId', userId); + body = body.set('Password', userPassword); + + return this.http.post(dashboardServerApiUrl + '/get-user-key', body, { + headers: this.header, + }).pipe(res => { + return res; + }); + } + + public GetDashboards(getDashboardsUrl: string) { + this.header = new HttpHeaders(); + this.header = this.header.append('Access-Control-Allow-Origin', '*'); + this.header = this.header.append('Authorization', 'bearer ' + "token"); + + return this.http.get(getDashboardsUrl, { + headers: this.header + }).pipe(res => { + return res; + }); + } */ + + public GetEmbedConfig(getDashboardsUrl: string) { + return this.http.get(getDashboardsUrl, { + }).pipe(res => { + return res; + }); + } +} \ No newline at end of file diff --git a/Angular/src/app/app.ts b/Angular/src/app/app.ts new file mode 100644 index 0000000..e4185d5 --- /dev/null +++ b/Angular/src/app/app.ts @@ -0,0 +1,9 @@ +export class Item { + Name!: string; + Description!: string; + Id!: string; + Version!: string; + IsPublic!: boolean; + ItemLocation!: string; + CategoryName!: string; +} \ No newline at end of file diff --git a/Angular/src/app/dashboard.service.ts b/Angular/src/app/dashboard.service.ts new file mode 100644 index 0000000..a230b19 --- /dev/null +++ b/Angular/src/app/dashboard.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class DashboardService { + public embedConfig: any; + + getEmbedConfig(): any { + return this.embedConfig; + } + + setEmbedConfig(embedConfig: any): void { + this.embedConfig = embedConfig; + } +} \ No newline at end of file diff --git a/Angular/src/app/dashboard/dashboard.component.html b/Angular/src/app/dashboard/dashboard.component.html new file mode 100644 index 0000000..cf1f6bd --- /dev/null +++ b/Angular/src/app/dashboard/dashboard.component.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/Angular/src/app/dashboard/dashboard.component.ts b/Angular/src/app/dashboard/dashboard.component.ts new file mode 100644 index 0000000..757065b --- /dev/null +++ b/Angular/src/app/dashboard/dashboard.component.ts @@ -0,0 +1,72 @@ +import { Component, OnInit } from '@angular/core'; +import { Item } from '../app'; +import { appService } from '../app.service'; +import { AppComponent } from '../app.component'; +import { BoldBI } from '@boldbi/boldbi-embedded-sdk'; +import { DashboardService } from '../dashboard.service'; + +@Component({ + selector: 'app-dashboard', + templateUrl: './dashboard.component.html', + providers: [appService] +}) + +export class Dashboard implements OnInit { + + public dashboardsList!: Item[]; + result: any; + dashboard: any; + embedConfig: any; + constructor(private _app: appService, private _appComponent: AppComponent, private dashboardService: DashboardService) { + } + + ngOnInit() { + + this._app.GetEmbedConfig(this._appComponent.apiHost + this._appComponent.getEmbedConfigUrl).subscribe(data => { + this._appComponent.embedConfig = data; + this.dashboardService.setEmbedConfig(this._appComponent.embedConfig); + if (this.dashboardService.embedConfig.Environment == "enterprise" || this.dashboardService.embedConfig.Environment == "onpremise") { + this._appComponent.baseUrl = this.dashboardService.embedConfig.ServerUrl + "/" + this.dashboardService.embedConfig.SiteIdentifier; + this._appComponent.dashboardServerApiUrl = this.dashboardService.embedConfig.ServerUrl + "/api/" + this.dashboardService.embedConfig.SiteIdentifier; + } else { + this._appComponent.baseUrl = this.dashboardService.embedConfig.ServerUrl; + this._appComponent.dashboardServerApiUrl = this.dashboardService.embedConfig.ServerUrl + "/api"; + } + this.renderDashboard(); + }) + + /* this._app.Gettoken(this._appComponent.dashboardServerApiUrl,this._appComponent.userId,this._appComponent.userPassword).subscribe(data => { + this.result = data; + this._appComponent.token = JSON.parse(this.result.Token).access_token; + this._app.GetDashboards(this._appComponent.getDashboardsUrl).subscribe(data => { + this._appComponent.dashboards = data; + this.dashboardsList = this._appComponent.dashboards; + }); + }); + this._app.GetDashboards(this._appComponent.apiHost + this._appComponent.getDashboardsUrl).subscribe(data => { + this._appComponent.dashboards = data; + this.dashboardsList = this._appComponent.dashboards; + console.log("list ",this.dashboardsList); + //this.renderDashboard(this.dashboardsList[0]); + }); */ + } + + renderDashboard() { + this.dashboard= BoldBI.create({ + serverUrl: this._appComponent.baseUrl, + dashboardId: this.dashboardService.embedConfig.DashboardId, + embedContainerId: "dashboard", + embedType: this.dashboardService.embedConfig.EmbedType, + environment: this.dashboardService.embedConfig.Environment, + mode: BoldBI.Mode.View, + width:"100%", + height:"100%", + expirationTime:100000, + authorizationServer: { + url:this._appComponent.apiHost + this._appComponent.authorizationUrl + } + }); + + this.dashboard.loadDashboard(); + } +} diff --git a/Angular/src/assets/.gitkeep b/Angular/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Angular/src/assets/css/site.css b/Angular/src/assets/css/site.css new file mode 100644 index 0000000..0dd76cf --- /dev/null +++ b/Angular/src/assets/css/site.css @@ -0,0 +1,24 @@ +body html { width: 100%; height: 100%; } +html, body,app-root { width: 100%; height: 100%; margin: 0; font-family: Roboto; font-size: 13px;} +ul { list-style-type: none; padding-left: 0; } +.tab { padding-top: 2px; padding-bottom: 18px; cursor: pointer } +.active { background-color: burlywood; } + +.e-dbrd-blueWaitingIndcator { + -webkit-animation: rotate 2s linear infinite; animation: rotate 2s linear infinite; height: 54px; width: 54px; top: 50%; left: 50%; position: relative; } + +.e-waiting { position: fixed; display: block; margin: 0px auto; width: 54px; height: 54px; zoom: 0.5; margin-left: 55px;} + +#container { width: 13%; float: left; height: 100%; float: left; background: #f4f4f4; height: 100%; box-shadow: 2px 0 4px 0 rgba(0, 0, 0, .12); overflow: auto; overflow-x: hidden; } + +#grid-title { font-size: 17px; border-bottom: 1px solid #333; padding: 15px;} +#panel { width: 100%; float: left; background: #f4f4f4; overflow: auto;} +#dashboard { width: 100%; float: left; height: 100%; display: block; } +.dashboard-item { padding: 10px; border-bottom: 1px solid #ccc; cursor: pointer; } +#viewer-section { width: 100%; height: 100%; float: left; } +#viewer-header { padding: 10px; display: block; float: left; width: 100%; } +#create-dashboard { float: right; margin-right: 20px; background: #0565ff; border: 0; border-radius: 4px; color: #fff;cursor: pointer; display: inline-block;font-size: 12px; font-weight: 600;height: 28px;line-height: 28px; min-width: 90px; outline: none; text-align: center;border: 1px solid #0450cc; } + +#edit-dashboard { +float: right; background: #fff; margin-right: 20px; border: 0; border-radius: 4px; color: #333; cursor: pointer; display: inline-block; font-size: 12px; font-weight: 600; height: 28px; line-height: 28px; min-width: 90px; outline: none; text-align: center; border: 1px solid #b3b3b3; } +#dashboardDesigner{ height: 900px; border: 2px solid #333; } \ No newline at end of file diff --git a/Angular/src/environments/environment.prod.ts b/Angular/src/environments/environment.prod.ts new file mode 100644 index 0000000..3612073 --- /dev/null +++ b/Angular/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/Angular/src/environments/environment.ts b/Angular/src/environments/environment.ts new file mode 100644 index 0000000..f56ff47 --- /dev/null +++ b/Angular/src/environments/environment.ts @@ -0,0 +1,16 @@ +// 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. diff --git a/Angular/src/index.html b/Angular/src/index.html new file mode 100644 index 0000000..357cce6 --- /dev/null +++ b/Angular/src/index.html @@ -0,0 +1,17 @@ + + + + + + Embedded BI + + + + + + + + + + + \ No newline at end of file diff --git a/Angular/src/main.ts b/Angular/src/main.ts new file mode 100644 index 0000000..c7b673c --- /dev/null +++ b/Angular/src/main.ts @@ -0,0 +1,12 @@ +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)); diff --git a/Angular/src/polyfills.ts b/Angular/src/polyfills.ts new file mode 100644 index 0000000..429bb9e --- /dev/null +++ b/Angular/src/polyfills.ts @@ -0,0 +1,53 @@ +/** + * 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 recent versions of Safari, Chrome (including + * Opera), Edge on the desktop, and iOS and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** + * 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 + */ diff --git a/Angular/src/styles.css b/Angular/src/styles.css new file mode 100644 index 0000000..90d4ee0 --- /dev/null +++ b/Angular/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/Angular/src/test.ts b/Angular/src/test.ts new file mode 100644 index 0000000..c04c876 --- /dev/null +++ b/Angular/src/test.ts @@ -0,0 +1,26 @@ +// 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): { + (id: string): T; + keys(): string[]; + }; +}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting(), +); + +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().forEach(context); diff --git a/Angular/tsconfig.app.json b/Angular/tsconfig.app.json new file mode 100644 index 0000000..82d91dc --- /dev/null +++ b/Angular/tsconfig.app.json @@ -0,0 +1,15 @@ +/* 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" + ] +} diff --git a/Angular/tsconfig.json b/Angular/tsconfig.json new file mode 100644 index 0000000..ff06eae --- /dev/null +++ b/Angular/tsconfig.json @@ -0,0 +1,32 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "es2020", + "module": "es2020", + "lib": [ + "es2020", + "dom" + ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/Angular/tsconfig.spec.json b/Angular/tsconfig.spec.json new file mode 100644 index 0000000..092345b --- /dev/null +++ b/Angular/tsconfig.spec.json @@ -0,0 +1,18 @@ +/* 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" + ] +} diff --git a/README.md b/README.md index 3d3000a..c7aeb90 100644 --- a/README.md +++ b/README.md @@ -1 +1,82 @@ -# angular-with-nodejs-sample \ No newline at end of file + # BoldBI Embedded Angular with Node.js Sample + +This project was created using Angular 16 with Node.js. This application aims to demonstrate how to render the dashboard available on your Bold BI server. + + ## Dashboard view + +![Dashboard View](https://github.com/boldbi/angular-with-nodejs-sample/assets/129487075/0ae43cea-33eb-49df-938f-b3a4c101abb9) + + + ## Requirements/Prerequisites + + * [Node.js](https://nodejs.org/en/) + * [Visual Studio Code](https://code.visualstudio.com/download) + +> **NOTE:** Node.js versions 16.14 to 18.18 are supported. + + #### Supported browsers + + * Google Chrome, Microsoft Edge, and Mozilla Firefox. + + ## Configuration + + * Please ensure you have enabled embed authentication on the `embed settings` page. If it is not currently enabled, please refer to the following image or detailed [instructions](https://help.boldbi.com/site-administration/embed-settings/#get-embed-secret-code) to enable it. + + ![Embed Settings](https://github.com/boldbi/aspnet-core-sample/assets/91586758/b3a81978-9eb4-42b2-92bb-d1e2735ab007) + + * To download the `embedConfig.json` file, please follow this [link](https://help.boldbi.com/site-administration/embed-settings/#get-embed-configuration-file) for reference. Additionally, you can refer to the following image for visual guidance. + + ![Embed Settings Download](https://github.com/boldbi/aspnet-core-sample/assets/91586758/d27d4cfc-6a3e-4c34-975e-f5f22dea6172) + ![EmbedConfig Properties](https://github.com/boldbi/aspnet-core-sample/assets/91586758/d6ce925a-0d4c-45d2-817e-24d6d59e0d63) + + * Copy the downloaded `embedConfig.json` file and paste it into the designated [location](https://github.com/boldbi/angular-with-nodejs-sample/tree/master) within the application. Please ensure you have placed it in the application, as shown in the following image. + + ![EmbedConfig image](https://github.com/boldbi/angular-with-nodejs-sample/assets/129487075/bcefae3e-0b86-4d01-81da-dd2d622a800e) + + ## Run a Sample Using Command Line Interface + + * Open the command line interface and navigate to the specified file [location](https://github.com/boldbi/angular-with-nodejs-sample) where the project is located. + + * To install all dependent packages, use the following command `npm install`. + + * Finally, run the application using the following command `npm start`. After the application has started, it will display a URL in the `command line interface`, typically something like (e.g., http://localhost:4200/). Copy this URL and paste it into your default web browser. + + ## Developer IDE + + * [Visual Studio Code](https://code.visualstudio.com/download) + + ### Run a Sample Using Visual Studio Code + + * Open the Angular with Node.js sample in **Visual Studio Code**. + + * Open the terminal in Visual Studio Code and install all dependent packages by executing the following command in the terminal. + + ```bash + npm install + ``` + + * Finally, run the application using the following command. + + ```bash + npm start + ``` + + * After the application has started, it will display a URL in the `command line interface`, typically something like (e.g., http://localhost:4200/). Copy this URL and paste it into your default web browser. + + ![dashboard view](https://github.com/boldbi/angular-with-nodejs-sample/assets/129487075/e2d60aab-0be4-49c0-8f12-7738b7fbf2af) + +>**NOTE:** If the API host is already in use, modify the port number per your preference in embed.js and update that in app.component.ts file. + +Please refer to the [help documentation](https://help.boldbi.com/embedding-options/embedding-sdk/samples/angular-with-node-js/#how-to-run-the-sample) to know how to run the sample. + +## Important notes + +It is recommended not to store passwords and sensitive information in configuration files for security reasons in a real-world application. Instead, it would be best to consider using a secure application, such as Key Vault, to safeguard your credentials. + +## Online demos + +Look at the Bold BI Embedding sample to live demo [here](https://samples.boldbi.com/embed). + +## Documentation + +A complete Bold BI Embedding documentation can be found on [Bold BI Embedding Help](https://help.boldbi.com/embedded-bi/javascript-based/). \ No newline at end of file diff --git a/embed.js b/embed.js new file mode 100644 index 0000000..c0f2582 --- /dev/null +++ b/embed.js @@ -0,0 +1,74 @@ +var fs = require("fs"); +var http = require("http"); +var https = require("https"); +var url = require("url"); +var express = require('express'); +var cors = require('cors'); +var app = express(); +var crypto = require('crypto'); +const path = require('path'); +app.use(cors()); +//Parse JSON bodies (as sent by API clients). +app.use(express.json()); + +//Assign a port number for an API to run. +const port = 8080; + +let appconfig; +try { + appconfig = JSON.parse(fs.readFileSync('embedConfig.json')); +} catch (error) { + console.error('Error: embedConfig.json file not found.'); + process.exit(1); //Exit the program with a non-zero exit code to indicate an error. +} + +var embedSecret = appconfig.EmbedSecret; + +var userEmail = appconfig.UserEmail; + +app.post('/authorizationserver', async function (req, response){ + var embedQuerString = req.body.embedQuerString; + var dashboardServerApiUrl = req.body.dashboardServerApiUrl; + + embedQuerString += "&embed_user_email=" + userEmail; + embedQuerString += "&embed_server_timestamp=" + Math.round((new Date()).getTime() / 1000); + var embedSignature = "&embed_signature=" + GetSignatureUrl(embedQuerString); + var embedDetailsUrl = "/embed/authorize?" + embedQuerString+embedSignature; + + var serverProtocol = url.parse(dashboardServerApiUrl).protocol == 'https:' ? https : http; + serverProtocol.get(dashboardServerApiUrl+embedDetailsUrl, function(res){ + var str = ''; + res.on('data', function (chunk) { + str += chunk; + }); + res.on('end', function () { + response.send(str); + }); + }); +}) + +function GetSignatureUrl(queryString) +{ + var keyBytes = Buffer.from(embedSecret); + var hmac = crypto.createHmac('sha256', keyBytes); + data = hmac.update(queryString); + gen_hmac= data.digest().toString('base64'); + +return gen_hmac; +} + +app.get('/getData', (req, res) => { + const embedConfigPath = path.join(__dirname, 'embedConfig.json'); + const jsonData = fs.readFileSync(embedConfigPath, 'utf8'); + const parsedData = JSON.parse(jsonData); + + const clientEmbedConfigData = { + DashboardId: parsedData.DashboardId, ServerUrl: parsedData.ServerUrl, SiteIdentifier: parsedData.SiteIdentifier, EmbedType: parsedData.EmbedType, Environment: parsedData.Environment + }; + + res.send(clientEmbedConfigData); +}); + +app.listen(port, () => { + console.log(`Server is running on port ${port}`); +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..2803fc0 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "AngularWithNodeJS", + "version": "1.0.0", + "description": "", + "main": "embed.js", + "dependencies": { + "@boldbi/boldbi-embedded-sdk": "6.18.11", + "cors": "^2.8.5", + "express": "^4.18.2" + }, + "devDependencies": { + "npm-run-all": "^4.1.5" + }, + "scripts": { + "start": "npm-run-all --parallel start-embed start-client", + "start-embed": "node embed.js", + "start-client": "cd Angular && npm start", + "postinstall": "cd Angular && npm install" + }, + "keywords": [], + "author": "", + "license": "ISC" +}