├── .DS_Store
├── dashboard-interface
├── .angular-cli.json
├── .editorconfig
├── .gitignore
├── README.md
├── e2e
│ ├── app.e2e-spec.ts
│ ├── app.po.ts
│ └── tsconfig.e2e.json
├── karma.conf.js
├── package.json
├── protractor.conf.js
├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.html
│ │ ├── app.component.scss
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── dashboards
│ │ │ ├── dashboard
│ │ │ │ ├── dashboard.component.html
│ │ │ │ ├── dashboard.component.scss
│ │ │ │ ├── dashboard.component.ts
│ │ │ │ └── gridster
│ │ │ │ │ ├── GridListItem.ts
│ │ │ │ │ ├── GridsterOptions.ts
│ │ │ │ │ ├── IGridsterDraggableOptions.ts
│ │ │ │ │ ├── IGridsterOptions.ts
│ │ │ │ │ ├── gridList.ts
│ │ │ │ │ ├── gridList
│ │ │ │ │ ├── GridListItem.ts
│ │ │ │ │ └── gridList.ts
│ │ │ │ │ ├── gridster-item
│ │ │ │ │ ├── gridster-item.component.scss
│ │ │ │ │ └── gridster-item.component.ts
│ │ │ │ │ ├── gridster-prototype
│ │ │ │ │ ├── gridster-item-prototype.directive.ts
│ │ │ │ │ └── gridster-prototype.service.ts
│ │ │ │ │ ├── gridster.component.scss
│ │ │ │ │ ├── gridster.component.ts
│ │ │ │ │ ├── gridster.service.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils
│ │ │ │ │ ├── DraggableEvent.ts
│ │ │ │ │ ├── draggable.ts
│ │ │ │ │ └── utils.ts
│ │ │ ├── dashboards.component.html
│ │ │ ├── dashboards.component.scss
│ │ │ └── dashboards.component.ts
│ │ ├── data.service.ts
│ │ ├── elasticsearch
│ │ │ ├── elasticsearch.service.ts
│ │ │ └── index.ts
│ │ ├── example
│ │ │ ├── astronaut.component.ts
│ │ │ ├── mission.service.ts
│ │ │ └── missioncontrol.component.ts
│ │ ├── object-classes
│ │ │ ├── aggregationData.ts
│ │ │ ├── searchSourceJSON.ts
│ │ │ ├── visualizationObj.ts
│ │ │ └── visualizationState.ts
│ │ ├── shared
│ │ │ ├── collapse.directive.ts
│ │ │ ├── dynamicComponent.component.ts
│ │ │ ├── hidden.directive.ts
│ │ │ ├── validators.directive.ts
│ │ │ └── visualization-tools.ts
│ │ └── visualizations
│ │ │ ├── bar-chart
│ │ │ ├── bar-chart.component.html
│ │ │ ├── bar-chart.component.scss
│ │ │ ├── bar-chart.component.ts
│ │ │ └── bar-chart.service.ts
│ │ │ ├── buckets
│ │ │ ├── bucket.component.html
│ │ │ ├── bucket.component.scss
│ │ │ ├── bucket.component.ts
│ │ │ ├── buckets.component.html
│ │ │ ├── buckets.component.scss
│ │ │ └── buckets.component.ts
│ │ │ ├── data-table
│ │ │ ├── data-table.service.ts
│ │ │ ├── dataTable.component.html
│ │ │ ├── dataTable.component.scss
│ │ │ ├── dataTable.component.ts
│ │ │ ├── table.component.html
│ │ │ ├── table.component.scss
│ │ │ └── table.component.ts
│ │ │ ├── metrics
│ │ │ ├── aggregations
│ │ │ │ ├── percentileRanksMetric.component.html
│ │ │ │ ├── percentileRanksMetric.component.scss
│ │ │ │ ├── percentileRanksMetric.component.ts
│ │ │ │ ├── percentilesMetric.component.html
│ │ │ │ ├── percentilesMetric.component.scss
│ │ │ │ ├── percentilesMetric.component.ts
│ │ │ │ ├── topHitMetric.component.html
│ │ │ │ ├── topHitMetric.component.scss
│ │ │ │ └── topHitMetric.component.ts
│ │ │ ├── metric.component.html
│ │ │ ├── metric.component.scss
│ │ │ ├── metric.component.ts
│ │ │ ├── metrics.component.html
│ │ │ ├── metrics.component.scss
│ │ │ ├── metrics.component.ts
│ │ │ └── metrics.service.ts
│ │ │ ├── pie-chart
│ │ │ ├── pie-chart.service.ts
│ │ │ ├── pieChart.component.html
│ │ │ ├── pieChart.component.scss
│ │ │ └── pieChart.component.ts
│ │ │ ├── visualizations.component.html
│ │ │ ├── visualizations.component.scss
│ │ │ ├── visualizations.component.ts
│ │ │ └── visualizations.service.ts
│ ├── assets
│ │ ├── .gitkeep
│ │ ├── Chart.min.js
│ │ ├── bodybuilder.min.js
│ │ └── img
│ │ │ ├── sakura.png
│ │ │ ├── sakura.svg
│ │ │ └── sakura2.png
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── styles.css
│ ├── test.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.spec.json
│ └── typings.d.ts
├── tsconfig.json
└── tslint.json
├── index.html
├── plantilla-memoria
├── .DS_Store
├── LICENSE
├── Makefile
├── README.md
├── img
│ ├── .DS_Store
│ ├── Scrum_Framework.png
│ ├── angular-architecture.png
│ ├── arquitectura.png
│ ├── bar-chart-calculation.png
│ ├── bar-chart-lengend-filter-example.png
│ ├── center-example.png
│ ├── chartjs-result-example.png
│ ├── dashboard-example.png
│ ├── dashboards-diagram.png
│ ├── dashboards-initial-view.png
│ ├── data-table-histogram-calculation.png
│ ├── data-table-initial-view.png
│ ├── data-table-multiaggregation-calculation.png
│ ├── data-table-range-calculation.png
│ ├── final-satge-sprint1.png
│ ├── final-user-interface.png
│ ├── flex-end-example.png
│ ├── foro1.png
│ ├── jquery-result-example.png
│ ├── kibana-dashboard-example.png
│ ├── kibana-nav-bar.png
│ ├── kibana-visualization-example.png
│ ├── logo_vect.png
│ ├── metric-average-calculation.png
│ ├── metric-count-calcuation.png
│ ├── metric-max-calculation.png
│ ├── metric-median-calculation.png
│ ├── metric-min-calculation.png
│ ├── metric-percentiles-calculation.png
│ ├── metric-ranks-calculation.png
│ ├── metric-std-calculation.png
│ ├── metric-sum-calculation.png
│ ├── metric-top-calculation.png
│ ├── metric-unique-calculation.png
│ ├── metric-visualization-initial-view.png
│ ├── no-wrap-example.png
│ ├── parent-child-via-service.png
│ ├── pie-chart-calculation.png
│ ├── pie-chart-example.png
│ ├── saved-visualizations.png
│ ├── sprint1_architecture.png
│ ├── sprint2_architecture_1.png
│ ├── sprint2_architecture_2.png
│ ├── user_interface_mockup.png
│ ├── visualization-options.png
│ ├── visualizations-section.png
│ └── wrap-example.png
├── memoria.bib
├── memoria.pdf
├── memoria.tex
└── template.tex
└── web
├── css
└── grayscale.css
├── font-awesome
├── css
│ ├── font-awesome.css
│ └── font-awesome.min.css
├── fonts
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── less
│ ├── animated.less
│ ├── bordered-pulled.less
│ ├── core.less
│ ├── fixed-width.less
│ ├── font-awesome.less
│ ├── icons.less
│ ├── larger.less
│ ├── list.less
│ ├── mixins.less
│ ├── path.less
│ ├── rotated-flipped.less
│ ├── screen-reader.less
│ ├── spinning.less
│ ├── stacked.less
│ └── variables.less
└── scss
│ ├── _animated.scss
│ ├── _bordered-pulled.scss
│ ├── _core.scss
│ ├── _fixed-width.scss
│ ├── _icons.scss
│ ├── _larger.scss
│ ├── _list.scss
│ ├── _mixins.scss
│ ├── _path.scss
│ ├── _rotated-flipped.scss
│ ├── _screen-reader.scss
│ ├── _spinning.scss
│ ├── _stacked.scss
│ ├── _variables.scss
│ └── font-awesome.scss
├── fonts
├── glyphicons-halflings-regular.eot
├── glyphicons-halflings-regular.svg
├── glyphicons-halflings-regular.ttf
├── glyphicons-halflings-regular.woff
└── glyphicons-halflings-regular.woff2
├── img
├── bar-chart-lengend-filter-example.png
├── dashboard-example.png
├── data-table-multiaggregation-calculation.png
├── fondo_principal.jpg
├── ismael.jpeg
├── metric-ranks-calculation.png
└── pie-chart-calculation.png
└── js
├── grayscale.js
└── jquery.easing.min.js
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/.DS_Store
--------------------------------------------------------------------------------
/dashboard-interface/.angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "project": {
4 | "name": "dashboard-interface"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
12 | "favicon.ico"
13 | ],
14 | "index": "index.html",
15 | "main": "main.ts",
16 | "polyfills": "polyfills.ts",
17 | "test": "test.ts",
18 | "tsconfig": "tsconfig.app.json",
19 | "testTsconfig": "tsconfig.spec.json",
20 | "prefix": "app",
21 | "styles": [
22 | "styles.css"
23 | ],
24 | "scripts": [
25 | "../node_modules/chart.js/dist/Chart.min.js",
26 | "../node_modules/jquery/dist/jquery.min.js"
27 | ],
28 | "environmentSource": "environments/environment.ts",
29 | "environments": {
30 | "dev": "environments/environment.ts",
31 | "prod": "environments/environment.prod.ts"
32 | }
33 | }
34 | ],
35 | "e2e": {
36 | "protractor": {
37 | "config": "./protractor.conf.js"
38 | }
39 | },
40 | "lint": [
41 | {
42 | "project": "src/tsconfig.app.json"
43 | },
44 | {
45 | "project": "src/tsconfig.spec.json"
46 | },
47 | {
48 | "project": "e2e/tsconfig.e2e.json"
49 | }
50 | ],
51 | "test": {
52 | "karma": {
53 | "config": "./karma.conf.js"
54 | }
55 | },
56 | "defaults": {
57 | "styleExt": "scss",
58 | "component": {}
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/dashboard-interface/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = tab
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/dashboard-interface/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 |
8 | # dependencies
9 | /node_modules
10 |
11 | # IDEs and editors
12 | /.idea
13 | .project
14 | .classpath
15 | .c9/
16 | *.launch
17 | .settings/
18 | *.sublime-workspace
19 |
20 | # IDE - VSCode
21 | .vscode/*
22 | !.vscode/settings.json
23 | !.vscode/tasks.json
24 | !.vscode/launch.json
25 | !.vscode/extensions.json
26 |
27 | # misc
28 | /.sass-cache
29 | /connect.lock
30 | /coverage
31 | /libpeerconnection.log
32 | npm-debug.log
33 | testem.log
34 | /typings
35 |
36 | # e2e
37 | /e2e/*.js
38 | /e2e/*.map
39 |
40 | # System Files
41 | .DS_Store
42 | Thumbs.db
43 |
--------------------------------------------------------------------------------
/dashboard-interface/README.md:
--------------------------------------------------------------------------------
1 | # DashboardInterface
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0.
4 |
5 | ## Development server
6 |
7 | 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.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
24 | Before running the tests make sure you are serving the app via `ng serve`.
25 |
26 | ## Further help
27 |
28 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
29 |
--------------------------------------------------------------------------------
/dashboard-interface/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { DashboardInterfacePage } from './app.po';
2 |
3 | describe('dashboard-interface App', () => {
4 | let page: DashboardInterfacePage;
5 |
6 | beforeEach(() => {
7 | page = new DashboardInterfacePage();
8 | });
9 |
10 | it('should display message saying app works', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('app works!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/dashboard-interface/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, element, by } from 'protractor';
2 |
3 | export class DashboardInterfacePage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/dashboard-interface/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/e2e",
5 | "module": "commonjs",
6 | "target": "es5",
7 | "types":[
8 | "jasmine",
9 | "node"
10 | ]
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/dashboard-interface/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/0.13/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular/cli'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular/cli/plugins/karma')
14 | ],
15 | client:{
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | files: [
19 | { pattern: './src/test.ts', watched: false }
20 | ],
21 | preprocessors: {
22 | './src/test.ts': ['@angular/cli']
23 | },
24 | mime: {
25 | 'text/x-typescript': ['ts','tsx']
26 | },
27 | coverageIstanbulReporter: {
28 | reports: [ 'html', 'lcovonly' ],
29 | fixWebpackSourcePaths: true
30 | },
31 | angularCli: {
32 | environment: 'dev'
33 | },
34 | reporters: config.angularCli && config.angularCli.codeCoverage
35 | ? ['progress', 'coverage-istanbul']
36 | : ['progress', 'kjhtml'],
37 | port: 9876,
38 | colors: true,
39 | logLevel: config.LOG_INFO,
40 | autoWatch: true,
41 | browsers: ['Chrome'],
42 | singleRun: false
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/dashboard-interface/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dashboard-interface",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "scripts": {
6 | "ng": "ng",
7 | "start": "ng serve",
8 | "build": "ng build",
9 | "test": "ng test",
10 | "lint": "ng lint",
11 | "e2e": "ng e2e"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/animations": "^4.1.3",
16 | "@angular/cdk": "github:angular/cdk-builds",
17 | "@angular/common": "^4.0.3",
18 | "@angular/compiler": "^4.0.3",
19 | "@angular/core": "^4.0.3",
20 | "@angular/flex-layout": "^2.0.0-beta.10-4905443",
21 | "@angular/forms": "^4.0.3",
22 | "@angular/http": "^4.0.0",
23 | "@angular/material": "github:angular/material2-builds",
24 | "@angular/platform-browser": "^4.0.3",
25 | "@angular/platform-browser-dynamic": "^4.0.0",
26 | "@angular/router": "^4.0.0",
27 | "@types/elasticsearch": "^5.0.13",
28 | "@types/lodash": "^4.14.69",
29 | "angular2-modal": "^3.0.3",
30 | "bodybuilder": "2.2.0",
31 | "chart.js": "^2.6.0",
32 | "core-js": "^2.4.1",
33 | "elasticsearch": "^13.0.0",
34 | "jquery": "^3.2.1",
35 | "lodash": "^4.17.4",
36 | "mobx": "^3.2.2",
37 | "mobx-angular": "^1.5.0",
38 | "ng2-charts": "^1.6.0",
39 | "ng2-mobx": "^1.2.9",
40 | "ngx-modialog": "^3.0.4",
41 | "rxjs": "^5.1.0",
42 | "text-table": "^0.2.0",
43 | "zone.js": "^0.8.5"
44 | },
45 | "devDependencies": {
46 | "@angular/cli": "1.2.6",
47 | "@angular/compiler-cli": "^4.0.0",
48 | "@types/jasmine": "2.5.53",
49 | "@types/jquery": "^3.2.10",
50 | "@types/node": "~8.0.17",
51 | "codelyzer": "~3.1.2",
52 | "jasmine-core": "~2.6.4",
53 | "jasmine-spec-reporter": "~4.1.1",
54 | "karma": "~1.7.0",
55 | "karma-chrome-launcher": "~2.2.0",
56 | "karma-cli": "~1.0.1",
57 | "karma-coverage-istanbul-reporter": "^1.3.0",
58 | "karma-jasmine": "~1.1.0",
59 | "karma-jasmine-html-reporter": "^0.2.2",
60 | "node-sass": "^4.5.3",
61 | "protractor": "~5.1.0",
62 | "raw-loader": "^0.5.1",
63 | "sass-loader": "^6.0.6",
64 | "ts-node": "~3.3.0",
65 | "tslint": "~5.5.0",
66 | "typescript": "~2.4.2"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/dashboard-interface/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | const { SpecReporter } = require('jasmine-spec-reporter');
5 |
6 | exports.config = {
7 | allScriptsTimeout: 11000,
8 | specs: [
9 | './e2e/**/*.e2e-spec.ts'
10 | ],
11 | capabilities: {
12 | 'browserName': 'chrome'
13 | },
14 | directConnect: true,
15 | baseUrl: 'http://localhost:4200/',
16 | framework: 'jasmine',
17 | jasmineNodeOpts: {
18 | showColors: true,
19 | defaultTimeoutInterval: 30000,
20 | print: function() {}
21 | },
22 | beforeLaunch: function() {
23 | require('ts-node').register({
24 | project: 'e2e/tsconfig.e2e.json'
25 | });
26 | },
27 | onPrepare() {
28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | import { VisualizationsComponent } from './visualizations/visualizations.component';
5 | import { DashboardsComponent } from './dashboards/dashboards.component';
6 |
7 | const routes: Routes = [
8 | { path: '', redirectTo: '/visualizations', pathMatch: 'full' },
9 | { path: 'visualizations', component: VisualizationsComponent },
10 | { path: 'dashboards', component: DashboardsComponent }
11 | ];
12 |
13 | @NgModule({
14 | imports: [ RouterModule.forRoot(routes) ],
15 | exports: [ RouterModule ]
16 | })
17 |
18 | export class AppRoutingModule {}
19 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600');
2 | @import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');
3 |
4 | * {
5 | padding: 0;
6 | margin: 0;
7 | /* pour maîtriser width et flex-basis */
8 | list-style: none;
9 | }
10 |
11 | div.header{
12 | display: flex;
13 | position: fixed;
14 | width: 100%;
15 | height: 3rem;
16 | background-color: #57c17b;
17 | box-shadow: 0px 0px 15px 0px;
18 | z-index: 20;
19 |
20 | div {
21 | //height: 9vh;
22 | display: flex;
23 | /* crée un contexte flex pour centrer le contenu de la balise a */
24 | justify-content: center;
25 | /*alignement horizontal*/
26 | align-items: center;
27 | /*alignement vertical*/
28 | flex: 1;
29 | /*on autorise la balise a à prendre toute la place disponible*/
30 | }
31 |
32 | div.img-container {
33 | flex: 1;
34 |
35 | img{
36 | max-width: 70%;
37 | }
38 | }
39 |
40 | div.title-container {
41 | box-shadow: 20px -20px 10px 20px black;
42 | flex: 21;
43 | font: 600 16px 'Open Sans', sans-serif;
44 | line-height: 50px;
45 | text-align: center;
46 | text-transform: uppercase;
47 | letter-spacing: 7px;
48 | color: #eee;
49 | //border-bottom: 1px solid #222;
50 | }
51 | }
52 |
53 | .active {
54 | background-color: #607D8B;
55 | }
56 |
57 | div.main {
58 | display: flex;
59 | flex: 1;
60 | //padding: 3rem 0 0 0;
61 | flex-flow: wrap;
62 | height: 100%;
63 |
64 | div.nav-bar {
65 | display: flex;
66 | flex-flow: column wrap;
67 | flex: 1;
68 | position: fixed;
69 | z-index: 10;
70 | min-width: 4.54%;
71 | height: 100%;
72 | //height: calc(100% - 25vh);
73 | /*hauteur des li : 12vh + hauteur du footer 10vh = 25vh*/
74 | background: #749cf7;
75 |
76 | ul {
77 | flex: 1;/* occupe toute la place restante */
78 | display: flex;
79 | flex-flow: column wrap;
80 |
81 | li.nav-item {
82 | flex: 1;
83 | display: flex;
84 | justify-content: center;
85 | align-items: center;
86 | /*on centre horiz et vertic grace flexbox*/
87 | font-size: 1.25rem;
88 | outline: none;
89 | }
90 |
91 | li.nav-item:hover {
92 | background-color: rgba(0, 0, 0, 0.32);
93 | cursor: pointer;
94 | }
95 |
96 | li.nav-void {
97 | flex: 8;
98 | }
99 | }
100 | }
101 |
102 | div.content {
103 | flex: 1;
104 | margin-left: 4.45%;
105 | box-shadow: -10px 0px 10px 1px rgba(0, 0, 0, 0.14);
106 | z-index: 10;
107 | overflow: hidden;
108 | }
109 | }
110 |
111 | @media screen and (max-width: 940px) {
112 | div.nav-bar {
113 | display: none;
114 | }
115 | div.content {
116 | margin: 0
117 | }
118 | }
119 |
120 | /* FOOTER */
121 | footer {
122 | position: fixed;
123 | bottom: 0;
124 | width: 100%;
125 | z-index: 5;
126 | height: 10vh;
127 | display: flex;
128 | flex-flow: column wrap;
129 |
130 | p {
131 | flex: 1;
132 | width: 20%;
133 | display: flex;
134 | justify-content: center;
135 | align-items: center;
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, async } from '@angular/core/testing';
2 |
3 | import { AppComponent } from './app.component';
4 |
5 | describe('AppComponent', () => {
6 | beforeEach(async(() => {
7 | TestBed.configureTestingModule({
8 | declarations: [
9 | AppComponent
10 | ],
11 | }).compileComponents();
12 | }));
13 |
14 | it('should create the app', async(() => {
15 | const fixture = TestBed.createComponent(AppComponent);
16 | const app = fixture.debugElement.componentInstance;
17 | expect(app).toBeTruthy();
18 | }));
19 |
20 | it(`should have as title 'app works!'`, async(() => {
21 | const fixture = TestBed.createComponent(AppComponent);
22 | const app = fixture.debugElement.componentInstance;
23 | expect(app.title).toEqual('app works!');
24 | }));
25 |
26 | it('should render title in a h1 tag', async(() => {
27 | const fixture = TestBed.createComponent(AppComponent);
28 | fixture.detectChanges();
29 | const compiled = fixture.debugElement.nativeElement;
30 | expect(compiled.querySelector('h1').textContent).toContain('app works!');
31 | }));
32 | });
33 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewChild } from '@angular/core';
2 |
3 | import { VisualizationsComponent } from './visualizations/visualizations.component';
4 |
5 | import { DataService } from './data.service';
6 |
7 |
8 | @Component({
9 | selector: 'app-root',
10 | templateUrl: './app.component.html',
11 | styleUrls: ['./app.component.scss']
12 | })
13 |
14 | export class AppComponent {
15 | title: string = '';
16 |
17 | constructor(
18 | private dataService: DataService
19 | ) { }
20 |
21 | ngOnInit(): void {
22 | this.getTitle();
23 | }
24 |
25 | getTitle(): void {
26 | this.title = this.dataService.getTitle();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule } from '@angular/core';
3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
4 | import { HttpModule } from '@angular/http';
5 | import { FlexLayoutModule } from "@angular/flex-layout";
6 | import { AppRoutingModule } from './app-routing.module';
7 | //import { GridsterModule } from './dashboards/dashboard/gridster2/gridster.module';
8 |
9 | import { AppComponent } from './app.component';
10 | import { VisualizationsComponent } from './visualizations/visualizations.component';
11 | import { MetricsComponent } from './visualizations/metrics/metrics.component';
12 | import { MetricComponent } from './visualizations/metrics/metric.component';
13 | import { PercentilesMetricComponent } from './visualizations/metrics/aggregations/percentilesMetric.component';
14 | import { PercentileRanksMetricComponent } from './visualizations/metrics/aggregations/percentileRanksMetric.component';
15 | import { TopHitMetricComponent } from './visualizations/metrics/aggregations/topHitMetric.component';
16 | import { DataTableComponent } from './visualizations/data-table/dataTable.component';
17 | import { TableComponent } from './visualizations/data-table/table.component';
18 | import { BucketsComponent } from './visualizations/buckets/buckets.component';
19 | import { BucketComponent } from './visualizations/buckets/bucket.component';
20 | import { PieChartComponent } from './visualizations/pie-chart/pieChart.component';
21 | import { BarChartComponent } from './visualizations/bar-chart/bar-chart.component';
22 | import { DynamicComponent } from './shared/dynamicComponent.component';
23 | import { DashboardsComponent } from './dashboards/dashboards.component';
24 | import { DashboardComponent } from './dashboards/dashboard/dashboard.component';
25 |
26 | // Gridster
27 | import { GridsterComponent } from './dashboards/dashboard/gridster/gridster.component';
28 | import { GridsterItemComponent } from './dashboards/dashboard/gridster/gridster-item/gridster-item.component';
29 | import { GridsterItemPrototypeDirective } from './dashboards/dashboard/gridster/gridster-prototype/gridster-item-prototype.directive';
30 | import { GridsterPrototypeService } from './dashboards/dashboard/gridster/gridster-prototype/gridster-prototype.service';
31 |
32 | import { DataService } from './data.service';
33 | import { MetricsService } from './visualizations/metrics/metrics.service';
34 | import { VisualizationsService } from './visualizations/visualizations.service';
35 |
36 | import { HiddenDirective } from './shared/hidden.directive';
37 |
38 | import { Elasticsearch } from './elasticsearch';
39 | import { ChartsModule } from 'ng2-charts/ng2-charts';
40 |
41 | import { Collapse } from './shared/collapse.directive';
42 |
43 | @NgModule({
44 | declarations: [
45 | AppComponent,
46 | VisualizationsComponent,
47 | MetricsComponent,
48 | MetricComponent,
49 | DataTableComponent,
50 | PercentilesMetricComponent,
51 | PercentileRanksMetricComponent,
52 | TopHitMetricComponent,
53 | TableComponent,
54 | PieChartComponent,
55 | BarChartComponent,
56 | DynamicComponent,
57 | HiddenDirective,
58 | BucketsComponent,
59 | BucketComponent,
60 | Collapse,
61 | DashboardsComponent,
62 | DashboardComponent,
63 | GridsterComponent,
64 | GridsterItemComponent,
65 | GridsterItemPrototypeDirective
66 | ],
67 | imports: [
68 | BrowserModule,
69 | FormsModule,
70 | ReactiveFormsModule,
71 | HttpModule,
72 | ChartsModule,
73 | FlexLayoutModule,
74 | AppRoutingModule,
75 | //GridsterModule
76 | ],
77 | providers: [
78 | DataService,
79 | Elasticsearch,
80 | MetricsService,
81 | VisualizationsService,
82 | GridsterPrototypeService
83 | ],
84 | bootstrap: [
85 | AppComponent
86 | ],
87 | entryComponents: [
88 | MetricsComponent,
89 | DataTableComponent,
90 | MetricComponent,
91 | BucketComponent,
92 | PieChartComponent,
93 | BarChartComponent,
94 | GridsterItemComponent
95 | ]
96 | })
97 | export class AppModule { }
98 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/dashboard.component.scss:
--------------------------------------------------------------------------------
1 | div.container{
2 | height: 100%;
3 |
4 | div.section-title {
5 | font-family: "Trebuchet MS", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Tahoma, sans-serif;
6 | font-size: 1.2rem;
7 | padding: 1rem;
8 | background-color: #ddd;
9 | border-bottom: 1px solid #fbfbfb;
10 | cursor: pointer;
11 | }
12 |
13 | div.section-title:hover {
14 | background-color: #b7b7b7;
15 | }
16 |
17 | div.section-content {
18 | background-color: #fbfbfb;
19 |
20 | .option-container {
21 | display: flex;
22 | //justify-content: space-between;
23 | //align-items: center;
24 |
25 | .title-container {
26 | flex: 20;
27 | padding: 0.5rem;
28 | padding-left: 1rem;
29 | }
30 |
31 | .delete-icon-container {
32 | padding: 0.5rem;
33 | cursor: pointer;
34 | color: red;
35 | border-radius: 0.25rem;
36 | flex: 1;
37 | display: flex;
38 | justify-content: center;
39 | }
40 |
41 | .delete-icon-container:hover {
42 | background-color: #ffd3d3;
43 | }
44 | }
45 | }
46 |
47 | div.saved-vis {
48 | ul {
49 | margin: 0px;
50 | padding: 0px;
51 | list-style-type: none;
52 |
53 | li {
54 | //padding: 0.25rem;
55 | //padding-right: 1rem;
56 | //padding-left: 1rem;
57 | border-bottom: 1px solid #efefef;
58 | color: #676767;
59 | }
60 |
61 | li:hover {
62 | background-color: #ecf5ff;
63 | cursor: pointer;
64 | }
65 | }
66 | }
67 |
68 | div#configFunctions {
69 | display: flex;
70 | align-items: center;
71 | background-color: #dddddd;
72 | border-bottom: 1px solid #fbfbfb;
73 |
74 | span.function-icon {
75 | cursor: pointer;
76 | background-color: #dddddd;
77 | color: #3c75ca;
78 | //border-radius: 0.25rem;
79 | padding: 0.75rem;
80 | }
81 |
82 | span.function-icon:hover {
83 | background-color: #b3b3b3;
84 | }
85 |
86 | /*div#calculateButton {
87 | flex: 1;
88 | //padding: 0.25rem;
89 | }*/
90 |
91 | input {
92 | height: 1.25rem;
93 | width: 100%;
94 | //border-radius: 0.25rem;
95 | font-size: 1rem;
96 | border: 0px;
97 | padding-left: 0.5rem;
98 | padding-right: 0.5rem;
99 | margin-left: 0.5rem;
100 | margin-right: 0.5rem;
101 | border-radius: 0.25rem;
102 | }
103 |
104 | /*div#saveForm {
105 | flex: 5;
106 | //padding: 0.25rem;
107 |
108 | input {
109 | height: 1.25rem;
110 | //border-radius: 0.25rem;
111 | font-size: 1rem;
112 | border: 0px;
113 | }
114 | }*/
115 | }
116 |
117 | .main-content {
118 | //position: absolute;
119 | top: 200px;
120 | left: 0;
121 | width: 100%;
122 | }
123 |
124 | h1 {
125 | font-size: 22px;
126 | padding: 0 20px;
127 | height: 50px;
128 | margin: 0;
129 | }
130 |
131 | .toolbar {
132 | position: relative;
133 | padding: 0 20px;
134 | }
135 |
136 | .widgetbar {
137 | width: 100%;
138 | position: relative;
139 | height: 100px;
140 | padding: 10px 0;
141 |
142 | .gridster-item-prototype {
143 | display: block;
144 | background-color: #afafaf;
145 | position: relative;
146 | float: left;
147 | z-index: 99;
148 | text-align: center;
149 | font-weight: bold;
150 | margin: 5px;
151 | width: 80px;
152 | height: 60px;
153 | }
154 |
155 | .gridster-item-prototype.is-over .gridster-item-inner {
156 | visibility: visible;
157 | }
158 |
159 | .gridster-item-inner {
160 | position: absolute;
161 | top:0;
162 | left: 0;
163 | overflow: auto;
164 | width: 80px;
165 | height: 60px;
166 | visibility: hidden;
167 | background-color: #eeeded;
168 |
169 | -webkit-transition: width 0.2s ease-in-out, height 0.2s ease-in-out;
170 | -moz-transition: width 0.2s ease-in-out, height 0.2s ease-in-out;
171 | -o-transition: width 0.2s ease-in-out, height 0.2s ease-in-out;
172 | transition: width 0.2s ease-in-out, height 0.2s ease-in-out;
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/GridsterOptions.ts:
--------------------------------------------------------------------------------
1 | import {IGridsterOptions} from './IGridsterOptions';
2 | import { Observable } from 'rxjs/Observable';
3 |
4 | export class GridsterOptions {
5 | direction: string;
6 | lanes: number;
7 | widthHeightRatio: number;
8 | heightToFontSizeRatio: number;
9 | responsiveView: boolean;
10 | dragAndDrop: boolean;
11 | resizable: boolean;
12 | shrink: boolean;
13 | minWidth: number;
14 | useCSSTransforms: boolean;
15 |
16 | defaults: IGridsterOptions = {
17 | lanes: 5,
18 | direction: 'horizontal',
19 | widthHeightRatio: 1,
20 | shrink: false,
21 | responsiveView: true,
22 | dragAndDrop: true,
23 | resizable: false,
24 | useCSSTransforms: false
25 | };
26 |
27 | change: Observable;
28 |
29 | responsiveOptions: Array = [];
30 | basicOptions: IGridsterOptions;
31 |
32 | breakpointsMap = {
33 | sm: 576, // Small devices
34 | md: 768, // Medium devices
35 | lg: 992, // Large devices
36 | xl: 1200 // Extra large
37 | };
38 |
39 | constructor(config: IGridsterOptions) {
40 | this.basicOptions = config;
41 |
42 | this.responsiveOptions = this.extendResponsiveOptions(config.responsiveOptions || []);
43 |
44 | this.change = Observable.merge(
45 | Observable.of(this.getOptionsByWidth(document.documentElement.clientWidth)),
46 | Observable.fromEvent(window, 'resize')
47 | .debounceTime(config.responsiveDebounce || 0)
48 | .map((event: Event) => this.getOptionsByWidth(document.documentElement.clientWidth))
49 | )
50 | .distinctUntilChanged(null, (options: any) => options.minWidth);
51 | }
52 |
53 | getOptionsByWidth(width: number): IGridsterOptions {
54 | let i = 0;
55 | let options: IGridsterOptions = Object.assign({}, this.defaults, this.basicOptions);
56 |
57 | while (this.responsiveOptions[i]) {
58 | if (this.responsiveOptions[i].minWidth <= width) {
59 | options = this.responsiveOptions[i];
60 | }
61 | i++;
62 | }
63 |
64 | return options;
65 | }
66 |
67 | private extendResponsiveOptions(responsiveOptions: Array): Array {
68 | return responsiveOptions
69 | // responsive options are valid only with "breakpoint" property
70 | .filter(options => options.breakpoint)
71 | // set default minWidth if not given
72 | .map((options) => {
73 | return Object.assign({
74 | minWidth: this.breakpointsMap[options.breakpoint] || 0
75 | }, options);
76 | })
77 | .sort((curr, next) => curr.minWidth - next.minWidth)
78 | .map((options) => Object.assign({}, this.defaults, this.basicOptions, options));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/IGridsterDraggableOptions.ts:
--------------------------------------------------------------------------------
1 | export interface IGridsterDraggableOptions {
2 | handlerClass?: string;
3 | zIndex?: number;
4 | scroll?: boolean;
5 | containment?: string;
6 | }
7 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/IGridsterOptions.ts:
--------------------------------------------------------------------------------
1 | export interface IGridsterOptions {
2 | direction?: string;
3 | lanes?: number;
4 | widthHeightRatio?: number;
5 | heightToFontSizeRatio?: number;
6 | dragAndDrop?: boolean;
7 | itemSelector?: string;
8 | resizable?: boolean;
9 | shrink?: boolean;
10 | responsiveView?: boolean;
11 | responsiveDebounce?: number;
12 | breakpoint?: string;
13 | minWidth?: number;
14 | useCSSTransforms?: boolean;
15 | responsiveOptions?: Array;
16 | }
17 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/gridster-item/gridster-item.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | display: block;
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | z-index: 1;
7 | transition: all 200ms ease;
8 | transition-property: left, top;
9 | }
10 |
11 | :host-context(.css-transform) {
12 | transition-property: transform;
13 | }
14 |
15 | :host.is-dragging, :host.is-resizing {
16 | -webkit-transition: none;
17 | transition: none;
18 | z-index: 9999;
19 | }
20 |
21 | :host.no-transition {
22 | -webkit-transition: none;
23 | transition: none;
24 | }
25 | .gridster-item-resizable-handler {
26 | position: absolute;
27 | z-index: 2;
28 | display: none;
29 | }
30 |
31 | .gridster-item-resizable-handler.handle-n {
32 | cursor: n-resize;
33 | height: 10px;
34 | right: 0;
35 | top: 0;
36 | left: 0;
37 | }
38 |
39 | .gridster-item-resizable-handler.handle-e {
40 | cursor: e-resize;
41 | width: 10px;
42 | bottom: 0;
43 | right: 0;
44 | top: 0;
45 | }
46 |
47 | .gridster-item-resizable-handler.handle-s {
48 | cursor: s-resize;
49 | height: 10px;
50 | right: 0;
51 | bottom: 0;
52 | left: 0;
53 | }
54 |
55 | .gridster-item-resizable-handler.handle-w {
56 | cursor: w-resize;
57 | width: 10px;
58 | left: 0;
59 | top: 0;
60 | bottom: 0;
61 | }
62 |
63 | .gridster-item-resizable-handler.handle-ne {
64 | cursor: ne-resize;
65 | width: 10px;
66 | height: 10px;
67 | right: 0;
68 | top: 0;
69 | }
70 |
71 | .gridster-item-resizable-handler.handle-nw {
72 | cursor: nw-resize;
73 | width: 10px;
74 | height: 10px;
75 | left: 0;
76 | top: 0;
77 | }
78 |
79 | .gridster-item-resizable-handler.handle-se {
80 | cursor: se-resize;
81 | width: 0;
82 | height: 0;
83 | right: 0;
84 | bottom: 0;
85 | border-style: solid;
86 | border-width: 0 0 10px 10px;
87 | border-color: transparent;
88 | }
89 |
90 | .gridster-item-resizable-handler.handle-sw {
91 | cursor: sw-resize;
92 | width: 10px;
93 | height: 10px;
94 | left: 0;
95 | bottom: 0;
96 | }
97 |
98 | :host(:hover) .gridster-item-resizable-handler.handle-se {
99 | border-color: transparent transparent #ccc
100 | }
101 |
102 | .gridster-item-inner {
103 | position: absolute;
104 | background: #fff;
105 | border: 1px solid transparent;
106 | top: 5px;
107 | bottom: 5px;
108 | left: 5px;
109 | right: 5px;
110 | -webkit-transition: background 3s;
111 | transition: background 3s;
112 | border-radius: 3px;
113 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
114 | }
115 |
116 | :host.is-dragging .gridster-item-inner {
117 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.24), 0 2px 4px rgba(0, 0, 0, 0.48);
118 | top: -3px;
119 | bottom: 13px;
120 | }
121 |
122 | :host.is-dragging /deep/ .panel-heading .panel-title {
123 | cursor: -webkit-grabbing;
124 | }
125 |
126 | :host /deep/ .panel-heading {
127 | border-bottom: 1px solid #F0F0F0;
128 | //display: inline-block;
129 | position: relative;
130 | width: 100%;
131 | top: 0;
132 | display: flex;
133 | justify-content: space-between;
134 | align-items: center;
135 |
136 | .panel-title {
137 | padding: 10px;
138 | margin: 0;
139 | cursor: -webkit-grab;
140 | }
141 | }
142 |
143 | :host /deep/ .panel-body {
144 | overflow: auto;
145 | //padding: 0 10px 10px;
146 | position: absolute;
147 | top: 37px;
148 | bottom: 0;
149 | left: 0;
150 | right: 0;
151 | }
152 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/gridster.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | position: relative;
3 | display: block;
4 | left: 0;
5 | width: 100%;
6 | }
7 |
8 | :host.gridster--dragging {
9 | -moz-user-select: none;
10 | -khtml-user-select: none;
11 | -webkit-user-select: none;
12 | -ms-user-select: none;
13 | user-select: none;
14 | }
15 |
16 | .gridster-container {
17 | position: relative;
18 | width: 100%;
19 | list-style: none;
20 | -webkit-transition: width 0.2s, height 0.2s;
21 | transition: width 0.2s, height 0.2s;
22 | }
23 |
24 | .position-highlight {
25 | display: block;
26 | position: absolute;
27 | z-index: 1;
28 | }
29 |
30 | .position-highlight .inner {
31 | position: absolute;
32 | top: 5px;
33 | bottom: 5px;
34 | left: 5px;
35 | right: 5px;
36 |
37 | background-color: #768294;
38 | border: 1px solid transparent;
39 | -webkit-transition: background 3s;
40 | transition: background 3s;
41 | border-radius: 3px;
42 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
43 | }
44 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/index.ts:
--------------------------------------------------------------------------------
1 | //export {GridsterModule} from './gridster.module';
2 | export {GridsterComponent} from './gridster.component';
3 | export {GridsterItemComponent} from './gridster-item/gridster-item.component';
4 | export {GridsterItemPrototypeDirective} from './gridster-prototype/gridster-item-prototype.directive';
5 | export {IGridsterOptions} from './IGridsterOptions';
6 | export {IGridsterDraggableOptions} from './IGridsterDraggableOptions';
7 | export {GridsterOptions} from './GridsterOptions';
8 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/utils/DraggableEvent.ts:
--------------------------------------------------------------------------------
1 | export class DraggableEvent {
2 | clientX: number;
3 |
4 | clientY: number;
5 |
6 | pageX: number;
7 |
8 | pageY: number;
9 |
10 | target: EventTarget;
11 |
12 |
13 | private touchEvent: TouchEvent;
14 |
15 | private mouseEvent: MouseEvent;
16 |
17 | constructor(event: any) {
18 | if (event.touches) {
19 | this.touchEvent = (event);
20 | this.setDataFromTouchEvent(this.touchEvent);
21 | } else {
22 | this.mouseEvent = (event);
23 | this.setDataFromMouseEvent(this.mouseEvent);
24 | }
25 | }
26 |
27 | isTouchEvent(): boolean {
28 | return !!this.touchEvent;
29 | }
30 |
31 | pauseEvent() {
32 | const event: Event = this.touchEvent || this.mouseEvent;
33 |
34 | if (event.stopPropagation) {
35 | event.stopPropagation();
36 | }
37 | if (event.preventDefault) {
38 | event.preventDefault();
39 | }
40 | event.cancelBubble = true;
41 | event.returnValue = false;
42 | return false;
43 | }
44 |
45 | getRelativeCoordinates(container: HTMLElement): {x: number, y: number} {
46 | const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
47 | const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
48 |
49 | const rect = container.getBoundingClientRect();
50 |
51 | return {
52 | x: this.pageX - rect.left - scrollLeft,
53 | y: this.pageY - rect.top - scrollTop,
54 | };
55 | }
56 |
57 | private setDataFromMouseEvent(event: MouseEvent): void {
58 | this.target = event.target;
59 | this.clientX = event.clientX;
60 | this.clientY = event.clientY;
61 | this.pageX = event.pageX;
62 | this.pageY = event.pageY;
63 | }
64 |
65 | private setDataFromTouchEvent(event: TouchEvent): void {
66 | this.target = event.target;
67 | this.clientX = event.touches[0].clientX;
68 | this.clientY = event.touches[0].clientY;
69 | this.pageX = event.touches[0].pageX;
70 | this.pageY = event.touches[0].pageY;
71 |
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/utils/draggable.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs/Observable';
2 | import 'rxjs/add/observable/fromEvent';
3 | import 'rxjs/add/operator/takeUntil';
4 | import 'rxjs/add/operator/switchMap';
5 | import 'rxjs/add/operator/filter';
6 | import 'rxjs/add/operator/merge';
7 | import 'rxjs/add/operator/map';
8 |
9 | import {DraggableEvent} from './DraggableEvent';
10 | import {utils} from './utils';
11 |
12 | export class Draggable {
13 | element: Element;
14 |
15 | dragStart: Observable;
16 | dragMove: Observable;
17 | dragStop: Observable;
18 |
19 | private mousemove: Observable<{} | Event> = Observable.merge(
20 | Observable.fromEvent(document, 'mousemove'),
21 | Observable.fromEvent(document, 'touchmove', {passive: true})
22 | ).share();
23 |
24 | private mouseup: Observable<{} | Event> = Observable.merge(
25 | Observable.fromEvent(document, 'mouseup'),
26 | Observable.fromEvent(document, 'touchend'),
27 | Observable.fromEvent(document, 'touchcancel')
28 | ).share();
29 |
30 | private mousedown: Observable<{} | Event>;
31 |
32 | private config = {
33 | handlerClass: null
34 | };
35 |
36 | constructor(element: Element, config: {handlerClass?: string} = {}) {
37 | this.element = element;
38 | this.mousedown = Observable.merge(
39 | Observable.fromEvent(element, 'mousedown'),
40 | Observable.fromEvent(element, 'touchstart')
41 | ).share();
42 |
43 | this.config.handlerClass = config.handlerClass;
44 |
45 | this.dragStart = this.createDragStartObservable().share();
46 | this.dragMove = this.createDragMoveObservable(this.dragStart);
47 | this.dragStop = this.createDragStopObservable(this.dragStart);
48 |
49 | this.fixProblemWithDnDForIE(element);
50 | }
51 |
52 | private createDragStartObservable(): Observable {
53 | return this.mousedown
54 | .map(md => new DraggableEvent(md))
55 | .filter((event: DraggableEvent) => this.isDragingByHandler(event))
56 | .do(e => {
57 | e.pauseEvent();
58 | (document.activeElement).blur();
59 | // prevents rendering performance issues while dragging item with selection inside
60 | utils.clearSelection();
61 | })
62 | .switchMap((startEvent: DraggableEvent) => {
63 |
64 | return this.mousemove
65 | .map(mm => new DraggableEvent(mm))
66 | .filter((moveEvent: DraggableEvent) => this.inRange(startEvent, moveEvent, 5))
67 | .map(() => startEvent)
68 | .takeUntil(this.mouseup)
69 | .take(1);
70 | });
71 | }
72 |
73 | private createDragMoveObservable(dragStart: Observable): Observable {
74 | return dragStart
75 | .switchMap(() => {
76 | return this.mousemove
77 | .skip(1)
78 | .map(mm => new DraggableEvent(mm))
79 | .takeUntil(this.mouseup);
80 | })
81 | .filter(val => !!val);
82 | }
83 |
84 | private createDragStopObservable(dragStart: Observable): Observable {
85 | return dragStart
86 | .switchMap(() => {
87 | return this.mouseup.take(1);
88 | });
89 | }
90 |
91 | private isDragingByHandler(event: DraggableEvent): boolean {
92 | if (!this.isValidDragHandler(event.target)) {
93 | return false;
94 | }
95 |
96 | return !this.config.handlerClass ||
97 | (this.config.handlerClass && this.hasElementWithClass(this.config.handlerClass, event.target));
98 | }
99 |
100 | private isValidDragHandler(targetEl: any): boolean {
101 | return ['input', 'textarea'].indexOf(targetEl.tagName.toLowerCase()) === -1;
102 | }
103 |
104 | private inRange(startEvent: DraggableEvent, moveEvent: DraggableEvent, range: number): boolean {
105 | return Math.abs(moveEvent.clientX - startEvent.clientX) > range ||
106 | Math.abs(moveEvent.clientY - startEvent.clientY) > range;
107 | }
108 |
109 | private hasElementWithClass(className: string, target: any): boolean {
110 | while (target !== this.element) {
111 | if (target.classList.contains(className)) {
112 | return true;
113 | }
114 | target = target.parentElement;
115 | }
116 | return false;
117 | }
118 |
119 | private pauseEvent(e: Event): void {
120 | if (e.stopPropagation) {
121 | e.stopPropagation();
122 | }
123 | if (e.preventDefault) {
124 | e.preventDefault();
125 | }
126 | e.cancelBubble = true;
127 | e.returnValue = false;
128 | }
129 |
130 | private fixProblemWithDnDForIE(element: Element) {
131 | (element).style['touch-action'] = 'none';
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboard/gridster/utils/utils.ts:
--------------------------------------------------------------------------------
1 |
2 | export const utils = {
3 | setCssElementPosition: ($element: HTMLElement, position: {x: number, y: number}) => {
4 | $element.style.left = position.x + 'px';
5 | $element.style.top = position.y + 'px';
6 | },
7 | resetCSSElementPosition: ($element: HTMLElement) => {
8 | $element.style.left = '';
9 | $element.style.top = '';
10 | },
11 | setTransform: ($element: HTMLElement, position: {x: number, y: number}) => {
12 | const left = position.x;
13 | const top = position.y;
14 |
15 | // Replace unitless items with px
16 | const translate = `translate(${left}px,${top}px)`;
17 |
18 | $element.style['transform'] = translate;
19 | $element.style['WebkitTransform'] = translate;
20 | $element.style['MozTransform'] = translate;
21 | $element.style['msTransform'] = translate;
22 | $element.style['OTransform'] = translate;
23 | },
24 | resetTransform: ($element: HTMLElement) => {
25 | $element.style['transform'] = '';
26 | $element.style['WebkitTransform'] = '';
27 | $element.style['MozTransform'] = '';
28 | $element.style['msTransform'] = '';
29 | $element.style['OTransform'] = '';
30 | },
31 | clearSelection: function clearSelection() {
32 | if (document['selection']) {
33 | document['selection'].empty();
34 | } else if (window.getSelection) {
35 | window.getSelection().removeAllRanges();
36 | }
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboards.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Saved Dashboards
5 |
6 |
7 |
8 | -
9 |
10 |
11 | {{dashboard._source.title}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboards.component.scss:
--------------------------------------------------------------------------------
1 | div.container {
2 | height: 100%;
3 | overflow-y: scroll;
4 | background-color: #eeeded;
5 |
6 | div.section-title {
7 | font-family: "Trebuchet MS", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Tahoma, sans-serif;
8 | font-size: 1.2rem;
9 | padding: 1rem;
10 | background-color: #ddd;
11 | border-bottom: 1px solid #fbfbfb;
12 | cursor: pointer;
13 | }
14 |
15 | div.section-title:hover {
16 | background-color: #b7b7b7;
17 | }
18 |
19 | div.section-content {
20 | background-color: #fbfbfb;
21 |
22 | .option-container {
23 | display: flex;
24 | //justify-content: space-between;
25 | //align-items: center;
26 |
27 | .title-container {
28 | flex: 20;
29 | padding: 0.5rem;
30 | padding-left: 1rem;
31 | }
32 |
33 | .delete-icon-container {
34 | padding: 0.5rem;
35 | cursor: pointer;
36 | color: red;
37 | border-radius: 0.25rem;
38 | flex: 1;
39 | display: flex;
40 | justify-content: center;
41 | }
42 |
43 | .delete-icon-container:hover {
44 | background-color: #ffd3d3;
45 | }
46 | }
47 | }
48 |
49 | div.saved-dash {
50 | ul {
51 | margin: 0px;
52 | padding: 0px;
53 | list-style-type: none;
54 |
55 | li {
56 | //padding: 0.25rem;
57 | //padding-right: 1rem;
58 | //padding-left: 1rem;
59 | border-bottom: 1px solid #efefef;
60 | color: #676767;
61 | }
62 |
63 | li:hover {
64 | background-color: #ecf5ff;
65 | cursor: pointer;
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/dashboards/dashboards.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, ViewChild } from '@angular/core';
2 |
3 | import { DashboardComponent } from './dashboard/dashboard.component';
4 |
5 | import { Elasticsearch } from '../elasticsearch';
6 |
7 | @Component({
8 | selector: 'dashboards',
9 | templateUrl: './dashboards.component.html',
10 | styleUrls: ['./dashboards.component.scss']
11 | })
12 |
13 | export class DashboardsComponent {
14 | @ViewChild(DashboardComponent)
15 | private dashboardComponent: DashboardComponent;
16 |
17 | private _displaySavedDash: boolean = false;
18 | private _savedDashboards: any[] = [];
19 |
20 | constructor(
21 | public _elasticsearch: Elasticsearch
22 | ) { }
23 |
24 | ngOnInit(): void {
25 | console.log('DASHBOARDS COMPONENT - ngOnInit()');
26 | this._setSavedDashboards();
27 | }
28 |
29 | private _setSavedDashboards(): void {
30 | console.log('DASHBOARDS COMPONENT - _setSavedVisualizations()');
31 | this._savedDashboards = [];
32 | this._elasticsearch.getSavedDashboards().then(hits => {
33 | for(let i=0; i this._setSavedDashboards());
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/data.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | //import { Headers, Http } from '@angular/http';
3 |
4 | @Injectable()
5 | export class DataService {
6 |
7 | getTitle(): string {
8 | return 'Sakura - Elasticsearch Dashboard Interface';
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/elasticsearch/index.ts:
--------------------------------------------------------------------------------
1 | export * from './elasticsearch.service';
2 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/example/astronaut.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, OnDestroy } from '@angular/core';
2 |
3 | import { MissionService } from './mission.service';
4 | import { Subscription } from 'rxjs/Subscription';
5 |
6 | @Component({
7 | selector: 'my-astronaut',
8 | template: `
9 |
10 | {{astronaut}}: {{mission}}
11 |
16 |
17 | `
18 | })
19 |
20 | export class AstronautComponent implements OnDestroy {
21 | @Input() astronaut: string;
22 | mission = '';
23 | confirmed = false;
24 | announced = false;
25 | subscription: Subscription;
26 |
27 | constructor(private missionService: MissionService) {
28 | this.subscription = missionService.missionAnnounced$.subscribe(
29 | mission => {
30 | console.log('mission:', mission);
31 | this.mission = mission;
32 | this.announced = true;
33 | this.confirmed = false;
34 | }
35 | );
36 | }
37 |
38 | confirm() {
39 | this.confirmed = true;
40 | this.missionService.confirmMission(this.astronaut);
41 | }
42 |
43 | ngOnDestroy() {
44 | // prevent memory leak when component destroyed
45 | this.subscription.unsubscribe();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/example/mission.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Subject } from 'rxjs/Subject';
3 |
4 | @Injectable()
5 | export class MissionService {
6 |
7 | // Observable string sources
8 | private missionAnnouncedSource = new Subject();
9 | private missionConfirmedSource = new Subject();
10 |
11 | // Observable string streams
12 | missionAnnounced$ = this.missionAnnouncedSource.asObservable();
13 | missionConfirmed$ = this.missionConfirmedSource.asObservable();
14 |
15 | // Service message commands
16 | announceMission(mission: string) {
17 | console.log('announceMission:', mission);
18 | this.missionAnnouncedSource.next(mission);
19 | }
20 |
21 | confirmMission(astronaut: string) {
22 | console.log('confirmMission:', astronaut);
23 | this.missionConfirmedSource.next(astronaut);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/example/missioncontrol.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | import { MissionService } from './mission.service';
4 |
5 | @Component({
6 | selector: 'mission-control',
7 | template: `
8 | Mission Control
9 |
10 | History
11 |
14 | `
15 | })
16 |
17 | export class MissionControlComponent {
18 | history: string[] = [];
19 | missions = [
20 | 'Fly to the moon!',
21 | 'Fly to mars!',
22 | 'Fly to Vegas!'];
23 | nextMission = 0;
24 |
25 | constructor(private _missionService: MissionService) {
26 | _missionService.missionConfirmed$.subscribe(
27 | astronaut => {
28 | this.history.push(`${astronaut} confirmed the mission`);
29 | });
30 | }
31 |
32 | announce() {
33 | let mission = this.missions[this.nextMission++];
34 | this._missionService.announceMission(mission);
35 | this.history.push(`Mission "${mission}" announced`);
36 | if (this.nextMission >= this.missions.length) { this.nextMission = 0; }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/object-classes/aggregationData.ts:
--------------------------------------------------------------------------------
1 | export class AggregationData {
2 | id: string;
3 | enabled: true;
4 | type: string;
5 | schema: string;
6 | params: any
7 |
8 | constructor (aggData?: AggregationData){
9 | this.id = aggData && aggData.id || '';
10 | this.enabled = aggData && aggData.enabled || true;
11 | this.type = aggData && aggData.type || '';
12 | this.schema = aggData && aggData.schema || '';
13 | this.params = aggData && aggData.params || '';
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/object-classes/searchSourceJSON.ts:
--------------------------------------------------------------------------------
1 | export class SearchSourceJSON {
2 | index: string;
3 | query: any;
4 |
5 | constructor(index: string, query: any){
6 | this.index = index;
7 | this.query = query;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/object-classes/visualizationObj.ts:
--------------------------------------------------------------------------------
1 | import { VisualizationState } from './visualizationState';
2 | import { SearchSourceJSON } from './searchSourceJSON';
3 |
4 | export class VisualizationObj {
5 | title: string;
6 | visState: string;
7 | kibanaSavedObjectMeta: {
8 | searchSourceJSON: string
9 | };
10 |
11 | constructor(title: string, visState: string, searchSourceJSON: string){
12 | this.title = title;
13 | this.visState = visState;
14 | this.kibanaSavedObjectMeta = { searchSourceJSON: searchSourceJSON };
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/object-classes/visualizationState.ts:
--------------------------------------------------------------------------------
1 | import { AggregationData } from './aggregationData';
2 |
3 | export class VisualizationState {
4 | title: string;
5 | type: string;
6 | params: any;
7 | aggs: AggregationData[];
8 | listeners: {}
9 | }
10 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/shared/collapse.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, Input, HostBinding, ElementRef, Renderer } from '@angular/core'
2 |
3 | @Directive(
4 | {selector: '[collapse]'}
5 | )
6 |
7 | export class Collapse {
8 |
9 | @HostBinding('class.collapsing')
10 | private isCollapsing:boolean
11 |
12 | // style
13 | @HostBinding('style.height')
14 | private height: string;
15 | private h: any = null;
16 |
17 | @Input()
18 |
19 | private set collapse(value:boolean) {
20 | if(value!==undefined){
21 | if(value){
22 | this.hide();
23 | }else {
24 | this.show();
25 | }
26 | }
27 | }
28 |
29 | constructor(public el: ElementRef) {
30 | console.log('COLLAPSE DIRECTIVE - el:' + el.nativeElement.scrollHeight);
31 | this.measureHeight();
32 | }
33 |
34 | measureHeight() {
35 | let elem = this.el.nativeElement;
36 | console.log('COLLAPSE DIRECTIVE - elem:', elem);
37 | //lets be sure the element has display:block style
38 | elem.className = elem.className.replace('collapse', '');
39 | //this.h = elem.scrollHeight;
40 |
41 | console.log('COLLAPSE DIRECTIVE - offsetHeight:' + elem.offsetHeight);
42 | console.log('COLLAPSE DIRECTIVE - h:', this.h);
43 | }
44 |
45 | hide(){
46 | if(this.h===null) this.h = this.el.nativeElement.scrollHeight;
47 | this.height = this.h +'px'
48 | console.log('COLLAPSE DIRECTIVE - h:', this.h);
49 | setTimeout(() => {
50 | this.height = '0px';
51 | this.isCollapsing = true;//apply 'collapsing' class
52 | },1);
53 | }
54 |
55 | show() {
56 | this.height = '0px'
57 | setTimeout(() => {
58 | this.height = this.h + 'px';
59 | console.log('COLLAPSE DIRECTIVE - h:', this.h);
60 | this.isCollapsing = true;//apply 'collapsing' class
61 | },1);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/shared/dynamicComponent.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, ViewContainerRef, ViewChild, ComponentFactoryResolver, EventEmitter } from '@angular/core';
2 |
3 |
4 | @Component({
5 | selector: 'dynamic-component',
6 | template: `
7 |
8 | `
9 | })
10 |
11 |
12 | export class DynamicComponent {
13 | // We need to get a reference to our div element
14 | @ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef;
15 |
16 | // An object with key/value pairs mapped to input name/input value
17 | @Input() componentType: any;
18 | // This event will return a object, with the event name
19 | // as a string key
20 | @Output() event: EventEmitter = new EventEmitter();
21 | @Output() init: EventEmitter = new EventEmitter();
22 |
23 | private _componentsMap: Map = new Map();
24 |
25 | constructor(private resolver: ComponentFactoryResolver) {}
26 |
27 | ngOnInit(): void {
28 | console.log('DYNAMIC COMPONENT - ngOnInit()');
29 | this.init.emit();
30 | }
31 |
32 | // Append a new component instance on the container
33 | addComponent(uniqueId: string, inputs: any, events: Array, componentType: any): any {
34 | console.log('DYNAMIC COMPONENT - addComponent():', uniqueId);
35 | const factory = this.resolver.resolveComponentFactory(componentType);
36 | let componentRef: any = this.dynamicComponentContainer.createComponent(factory);
37 | this._componentsMap.set(uniqueId, componentRef);
38 | this.setInputs(uniqueId, inputs);
39 | this.subscribeEvents(uniqueId, events);
40 | componentRef.changeDetectorRef.detectChanges();
41 | return componentRef.instance;
42 | }
43 |
44 | setInputs(uniqueId:string, inputs: any): void{
45 | let componentRef = this._componentsMap.get(uniqueId);
46 | if(componentRef){
47 | for(var inputField in inputs){
48 | console.log('BEFORE - this.componentRef.instance[' + inputField + ']:', componentRef.instance[inputField]);
49 | componentRef.instance[inputField] = inputs[inputField];
50 | console.log('AFTER - this.componentRef.instance[' + inputField + ']:', componentRef.instance[inputField]);
51 | }
52 | }else{
53 | console.error('Error: unique ID not found.');
54 | }
55 | }
56 |
57 | subscribeEvents(uniqueId:string, events: Array): void{
58 | //console.log('DYNAMIC COMPONENT - subscribeEvents()');
59 | let componentRef = this._componentsMap.get(uniqueId);
60 | if(componentRef){
61 | for(let i=0; i this.event.emit({
64 | uniqueId: uniqueId,
65 | name: events[i],
66 | data: event
67 | }));
68 | //console.log('AFTER - this.componentRef.instance[' + events[i] + ']');
69 | }
70 | }else{
71 | console.error('Error: unique ID not found.');
72 | }
73 | }
74 |
75 | getCmp(uniqueId: string): Function {
76 | return this._componentsMap.get(uniqueId).instance;
77 | }
78 |
79 | destroyCmp(uniqueId: string): void {
80 | console.log('DYNAMIC COMPONENT - destroyCmp():', uniqueId);
81 | this._componentsMap.get(uniqueId).destroy();
82 | this._componentsMap.delete(uniqueId);
83 | }
84 |
85 | debug(): void {
86 | console.log('%c DEBUG', 'background: #222; color: #bada55');
87 | console.log('%c componentType', 'background: #222; color: #bada55', this.componentType);
88 | console.log('%c _componentsMap', 'background: #222; color: #bada55', this._componentsMap);
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/shared/hidden.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, Input, Renderer } from '@angular/core';
2 |
3 | @Directive({ selector: '[hidden]' })
4 | export class HiddenDirective {
5 |
6 | constructor(public el: ElementRef, public renderer: Renderer) {}
7 |
8 | @Input() hidden: boolean;
9 |
10 | ngOnInit(){
11 | // Use renderer to render the emelemt with styles
12 | console.log(this.hidden)
13 | if(this.hidden) {
14 | this.renderer.setElementStyle(this.el.nativeElement, 'display', 'none');
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/shared/validators.directive.ts:
--------------------------------------------------------------------------------
1 | import { AbstractControl, ValidatorFn } from '@angular/forms';
2 |
3 | export function maxValidator(maxValue: number): ValidatorFn {
4 | return (control: AbstractControl): {[key: string]: any} => {
5 | const value = control.value;
6 | console.log('value', value);
7 | return (value!==null && (value>maxValue)) ? {'maxValue': {name}} : null;
8 | };
9 | }
10 |
11 | export function minValidator(minValue: number): ValidatorFn {
12 | return (control: AbstractControl): {[key: string]: any} => {
13 | const value = control.value;
14 | console.log('value', value);
15 | return (value!==null && (value
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/bar-chart/bar-chart.component.scss:
--------------------------------------------------------------------------------
1 | div.vis-container {
2 | display: flex;
3 | height: 100%;
4 |
5 | div#chart-config {
6 | flex: 1;
7 | min-width: 115px;
8 | /*background-color: #f1f6ff;
9 | box-shadow: -5px 0px 10px 0px rgba(0, 0, 0, 0.14);*/
10 |
11 | div#metricsAndBuckets {
12 | overflow-y: scroll;
13 | }
14 |
15 | div#configFunctions {
16 | display: flex;
17 | align-items: center;
18 | background-color: #dddddd;
19 |
20 | span.function-icon {
21 | cursor: pointer;
22 | background-color: #dddddd;
23 | color: #3c75ca;
24 | //border-radius: 0.25rem;
25 | padding: 0.75rem;
26 | }
27 |
28 | span.function-icon:hover {
29 | background-color: #b3b3b3;
30 | }
31 |
32 | /*div#calculateButton {
33 | flex: 1;
34 | //padding: 0.25rem;
35 | }*/
36 |
37 | input {
38 | height: 1.25rem;
39 | width: 100%;
40 | //border-radius: 0.25rem;
41 | font-size: 1rem;
42 | border: 0px;
43 | padding-left: 0.5rem;
44 | padding-right: 0.5rem;
45 | margin-left: 0.5rem;
46 | margin-right: 0.5rem;
47 | border-radius: 0.25rem;
48 | }
49 |
50 | /*div#saveForm {
51 | flex: 5;
52 | //padding: 0.25rem;
53 |
54 | input {
55 | height: 1.25rem;
56 | //border-radius: 0.25rem;
57 | font-size: 1rem;
58 | border: 0px;
59 | }
60 | }*/
61 | }
62 | }
63 |
64 | div#chart-container {
65 | flex: 3;
66 | position: relative;
67 | min-width: 0px;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/bar-chart/bar-chart.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { Elasticsearch } from '../../elasticsearch';
4 | import { MetricsService } from '../metrics/metrics.service';
5 |
6 | import { AggregationData } from '../../object-classes/aggregationData';
7 | import { VisualizationObj } from '../../object-classes/visualizationObj';
8 |
9 | import { VisualizationTools } from "../../shared/visualization-tools";
10 |
11 | import * as _ from "lodash";
12 | declare let bodybuilder: any;
13 |
14 | @Injectable()
15 | export class BarChartService {
16 |
17 | constructor(
18 | private _elasticCli: Elasticsearch,
19 | private _metricsService: MetricsService
20 | ) { }
21 |
22 | saveBarChart(visualizationObj: VisualizationObj): void {
23 | this._elasticCli.saveVisualization(visualizationObj);
24 | }
25 |
26 | getResults(index: string, metrics: AggregationData[], buckets: AggregationData[]): PromiseLike {
27 | let body = this._getRequestBody(buckets, metrics);
28 | return this._elasticCli.request(index, body).then(response => {
29 | console.log('BAR CHART SERVICE - response:', response);
30 | return this._getFormattedResults(response, this._getAggByIdMap(_.concat(metrics, buckets)), buckets[0], metrics);
31 | });
32 | }
33 |
34 | private _getFormattedResults(response: any, aggsById: Map, bucket: AggregationData, metrics: AggregationData[]): any {
35 | let bucketResponse = response.aggregations[bucket.id];
36 | if(!bucketResponse) return null;
37 | let buckets = bucketResponse.buckets;
38 |
39 | console.log('BAR CHART SERVICE - aggsById:', aggsById);
40 |
41 | let results = [];
42 | for(let i=0; i();
66 | for(let i=0; i {
73 | console.log('BAR CHART SERVICE - _getResultsMap()');
74 | let resultsMap = new Map();
75 | for(let i=0; i,
88 | parentResultId: string
89 | ): any{
90 | let currentBucket = aggsById.get(aggBucketId);
91 | let results = [];
92 | for(let i in responseBucket.buckets){
93 | let bucketObj = responseBucket.buckets[i];
94 | for(let field in bucketObj){
95 | //console.log('BAR CHART SERVICE - field:', field);
96 | //console.log('BAR CHART SERVICE - obj:', bucketObj[field]);
97 | if(this._isMetric(field)){
98 | let metricId = field;
99 | let metricResult = this._getMetricResult(bucketObj, aggsById.get(metricId));
100 | //console.log('BAR CHART SERVICE - metricResult:', metricResult);
101 | metricResult = _.map(metricResult, (r) => {
102 | return {
103 | id: VisualizationTools.guidGenerator(),
104 | responseBucket: currentBucket,
105 | metricResult: r,
106 | bucketValue: this._getBucketValue(currentBucket.type, bucketObj),
107 | percent: null,
108 | parentResultId: parentResultId
109 | }
110 | });
111 | results = _.concat(results, metricResult);
112 | }
113 | }
114 | }
115 | return results;
116 | }
117 |
118 | private _getMetricResult(bucket: any, metric: AggregationData): any {
119 | return this._metricsService.getAggResult(bucket, metric);
120 | }
121 |
122 | private _isMetric(aggId: string): boolean {
123 | return aggId.split('_')[0]==='metric';
124 | }
125 |
126 | private _getBucketValue(bucketType: string, bucket: any){
127 | switch(bucketType){
128 | case 'range':
129 | return bucket.from + ' to ' + bucket.to;
130 | case 'histogram':
131 | return bucket.key;
132 | default:
133 | return null;
134 | }
135 | }
136 |
137 | private _getAggByIdMap(aggs: AggregationData[]): Map {
138 | let aggByIdMap = new Map();
139 | for(let i=0; i=0; i--){
150 | console.log('BAR CHART SERVICE - bucket:', buckets[i]);
151 | console.log('BAR CHART SERVICE - aggType:', this._elasticCli.getAggType(buckets[i]));
152 | console.log('BAR CHART SERVICE - aggParams:', this._elasticCli.getAggParams(buckets[i]));
153 | console.log('BAR CHART SERVICE - body:', body.build());
154 | body = bodybuilder().aggregation(
155 | this._elasticCli.getAggType(buckets[i]),
156 | null,
157 | buckets[i].id,
158 | this._elasticCli.getAggParams(buckets[i]),
159 | (a) => body
160 | );
161 | }
162 | console.log('BAR CHART SERVICE - body:', body.build());
163 | return body;
164 | }
165 |
166 | private _getMetricsBody(metrics: AggregationData[]): any {
167 | var body = bodybuilder();
168 |
169 | for(let i=0; i
2 |
10 |
11 |
12 |
13 | Aggregation:
14 |
23 |
24 |
25 |
26 | Field:
27 |
36 |
37 |
38 |
39 |
40 |
41 | Interval:
42 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | From:
63 |
64 |
70 |
71 |
72 | to:
73 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/buckets/bucket.component.scss:
--------------------------------------------------------------------------------
1 | div.bucket {
2 |
3 | div.bucket-header {
4 | display: flex;
5 | align-items: center;
6 |
7 | div {
8 | flex: 1;
9 | padding: 1rem;
10 |
11 | span.fa-trash-o {
12 | float: right;
13 | color: red;
14 | }
15 | }
16 |
17 | div.display-info {
18 | flex: 5;
19 | }
20 |
21 | div.display-info:hover {
22 | cursor: pointer;
23 | background-color: #e8e8e8;
24 | }
25 |
26 | div.remove {
27 | flex: 1;
28 | display: flex;
29 | align-items: center;
30 | flex-direction: column;
31 | }
32 |
33 | div.remove:hover {
34 | cursor: pointer;
35 | background-color: #ffe6e6;
36 | }
37 | }
38 |
39 | div.bucket-body {
40 | padding: 0rem 1rem 1rem 1rem;
41 |
42 | div.bucket-opt {
43 | display: flex;
44 | flex-direction: column;
45 | margin: 0.5rem 0 0.5rem 0;
46 |
47 | span {
48 | font-weight: bold;
49 | font-size: 0.75rem;
50 | padding-bottom: 0.25rem;
51 | }
52 |
53 | select {
54 | font-size: 1rem;
55 | border-radius: .25rem;
56 | height: 1.75rem;
57 | color: rgb(0, 112, 210);
58 | white-space: normal;
59 | -webkit-user-select: none;
60 | background-color: white;
61 | padding-left: 0.5rem;
62 | cursor: pointer;
63 | border-color: #d4d4d4;
64 | }
65 |
66 | input {
67 | height: 1.75rem;
68 | font-size: 1rem;
69 | border-radius: .25rem;
70 | border: 1px solid #d4d4d4;
71 | color: #0070d2;
72 | padding-left: 0.5rem;
73 | cursor: pointer;
74 | box-sizing: border-box;
75 | width: 100%;
76 | }
77 |
78 | div.from-to {
79 | display: flex;
80 | margin-bottom: 0.5rem;
81 |
82 | div.range-field {
83 | flex: 2;
84 | padding-right: 0.5rem;
85 | }
86 |
87 | div.icon {
88 | flex: 1;
89 | padding-top: 1rem;
90 | display: flex;
91 | align-items: center;
92 | justify-content: center;
93 | color: red;
94 | cursor: pointer;
95 |
96 | span {
97 | padding: 0.5rem;
98 | }
99 |
100 | span:hover {
101 | background-color: #ffe6e6;
102 | border-radius: 0.25rem;
103 | }
104 | }
105 | }
106 |
107 | div.add-range-button {
108 | display: flex;
109 | align-items: center;
110 | justify-content: center;
111 | padding: 0.5rem;
112 | border: 1px solid #d4d4d4;
113 | border-radius: 0.25rem;
114 | cursor: pointer;
115 |
116 | span {
117 | padding: 0px;
118 | }
119 | }
120 |
121 | div.add-range-button:hover {
122 | background-color: #ccdffb;
123 | }
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/buckets/bucket.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, SimpleChange, EventEmitter } from '@angular/core';
2 | import { FormGroup, FormBuilder} from '@angular/forms';
3 |
4 | import { AggregationData } from '../../object-classes/aggregationData';
5 |
6 | import { minValidator } from '../../shared/validators.directive';
7 |
8 | @Component({
9 | selector: 'bucket',
10 | templateUrl: './bucket.component.html',
11 | styleUrls: ['./bucket.component.scss']
12 | })
13 |
14 | export class BucketComponent {
15 | @Output() dataChange = new EventEmitter();
16 | @Output() remove = new EventEmitter();
17 |
18 | private _numFields: string[] = [];
19 | @Input() set numFields(numFields: string[]) {
20 | console.log('BUCKET - numFields:', numFields);
21 | this._numFields = numFields;
22 | if(numFields && numFields.length>0)
23 | this._selectedNumField = numFields[0];
24 | };
25 | private _selectedNumField: string;
26 |
27 | private _savedData: any = null;
28 | @Input() set savedData(savedData: any) {
29 | console.log('METRIC - SET - savedData');
30 | this._savedData = savedData;
31 | if(savedData) this._loadSavedBucket(savedData);
32 | };
33 |
34 | private _aggregations: any[] = [
35 | //{ label: 'Date Histogram', value: 'date_histogram'},
36 | { label: 'Histogram', value: 'histogram'},
37 | { label: 'Range', value: 'range'},
38 | //{ label: 'Date Range', value: 'date_range'},
39 | //{ label: 'IPv4 Range', value: 'ipv4_range'},
40 | //{ label: 'Terms', value: 'terms'},
41 | //{ label: 'Filters', value: 'filters'},
42 | //{ label: 'Significant Terms', value: 'sig_terms'},
43 | //{ label: 'Geohash', value: 'geo'}
44 | ];
45 | private _selectedAgg: string = this._aggregations[0].value;
46 |
47 | interval: number = null;
48 | ranges: any[] = [];
49 |
50 | form: FormGroup;
51 | formErrors = {
52 | 'naturalNumber': ''
53 | };
54 | validationMessages = {
55 | 'naturalNumber': {
56 | 'minValue': 'Percentile value can\'t be lower than 0.'
57 | }
58 | };
59 |
60 |
61 | constructor( private fb: FormBuilder ) {}
62 |
63 | ngOnInit(): void{
64 | console.log('BUCKET - ngOnInit()');
65 | this.buildForm();
66 | }
67 |
68 | triggerRemoveEvent(): void {
69 | this.remove.emit();
70 | }
71 |
72 | dataChangeEvent(): void {
73 | console.log('BUCKET - dataChangeEvent()');
74 | let aggregationData = this.getAggregationData();
75 | console.log('BUCKET - aggregationData:', aggregationData);
76 | if(aggregationData.params){
77 | this.dataChange.emit(aggregationData);
78 | }
79 | }
80 |
81 | private _loadSavedBucket(bucket: AggregationData): void {
82 | console.log('BUCKET - _loadSavedBucket():', bucket);
83 | this._selectedAgg = bucket.type;
84 | this._selectedNumField = bucket.params.field;
85 | this.interval = bucket.params.interval || null;
86 | this.ranges = bucket.params.ranges || [];
87 | }
88 |
89 | getAggregationData(): AggregationData {
90 | var aggregationData = new AggregationData();
91 | aggregationData.enabled = true;
92 | aggregationData.type = this._selectedAgg;
93 | aggregationData.schema = 'metric';
94 | aggregationData.params = this.getAggParams();
95 |
96 | return aggregationData;
97 | }
98 |
99 | getAggParams(): any {
100 | switch (this._selectedAgg){
101 | case 'histogram':
102 | return {
103 | field: this._selectedNumField,
104 | interval: this.interval
105 | };
106 | case 'range':
107 | return {
108 | field: this._selectedNumField,
109 | ranges: this.ranges
110 | };
111 | default:
112 | return null;
113 | }
114 | }
115 |
116 | // AGGREGATIONS CODE
117 | addRange(): void {
118 | this.ranges.push({
119 | from: 0,
120 | to: 0
121 | });
122 | }
123 |
124 | removeRange(index: number): void {
125 | this.ranges.splice(index, 1);
126 | }
127 |
128 | // FORM CODE
129 |
130 | buildForm(): void {
131 | this.form = this.fb.group({
132 | 'naturalNumber': ['', [
133 | minValidator(0)
134 | ]
135 | ]
136 | });
137 |
138 | this.form.valueChanges
139 | .subscribe(data => this.onValueChanged(data));
140 |
141 | this.onValueChanged(); // (re)set validation messages now
142 | }
143 |
144 | onValueChanged(data?: any) {
145 | if (!this.form) { return; }
146 | const form = this.form;
147 |
148 | for (const field in this.formErrors) {
149 | // clear previous error message (if any)
150 | this.formErrors[field] = '';
151 | const control = form.get(field);
152 |
153 | if (control && control.dirty && !control.valid) {
154 | const messages = this.validationMessages[field];
155 | for (const key in control.errors) {
156 | this.formErrors[field] += messages[key] + ' ';
157 | }
158 | }
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/buckets/buckets.component.html:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/buckets/buckets.component.scss:
--------------------------------------------------------------------------------
1 | div.buckets-container{
2 | border-bottom: 1px solid #d8d8d8;
3 |
4 | div.buckets-header {
5 | display: flex;
6 |
7 | div.title {
8 | flex: 5;
9 | font-family: "Trebuchet MS", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Tahoma, sans-serif;
10 | font-size: 1.2rem;
11 | padding: 1rem;
12 | }
13 |
14 | div.buckets-actions {
15 | display: flex;
16 | flex-direction: row-reverse;
17 | flex: 1;
18 |
19 | div {
20 | padding: 1rem;
21 | border-radius: 0.25rem;
22 | cursor: pointer;
23 | }
24 |
25 | div.add-bucket:hover {
26 | background-color: #ccdffb;
27 | }
28 |
29 | div.remove-all {
30 | color: red;
31 | }
32 |
33 | div.remove-all:hover {
34 | background-color: #ffe6e6;
35 | }
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/buckets/buckets.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, ViewChild } from '@angular/core';
2 | import { BucketComponent } from './bucket.component';
3 | import { DynamicComponent } from '../../shared/dynamicComponent.component';
4 |
5 | import { VisualizationState } from '../../object-classes/visualizationState';
6 | import { AggregationData } from '../../object-classes/aggregationData';
7 | import { SearchSourceJSON } from '../../object-classes/searchSourceJSON';
8 | import { VisualizationObj } from '../../object-classes/visualizationObj';
9 |
10 | import { VisualizationsService } from '../visualizations.service';
11 |
12 | import { Subscription } from 'rxjs/Subscription';
13 |
14 |
15 | @Component({
16 | selector: 'buckets',
17 | templateUrl: './buckets.component.html',
18 | styleUrls: ['./buckets.component.scss']
19 | })
20 |
21 |
22 | export class BucketsComponent {
23 | @ViewChild(DynamicComponent) dynamicComponents;
24 |
25 | @Input() index: string;
26 |
27 | // This fields come from _visualizationsService
28 | numFields: string[] = [];
29 | textFields: string[] = [];
30 |
31 | subscriptions: Subscription[] = [];
32 |
33 | bucketEvents: Array = [ 'remove', 'dataChange' ];
34 | bucketsMap: Map = new Map();
35 |
36 | constructor(
37 | private _visualizationsService: VisualizationsService
38 | ) {
39 | let sub1 = _visualizationsService.numFieldsSent$.subscribe(numFields => {
40 | console.log('BUCKETS - RECIEVED - numFields:', numFields);
41 | this.numFields = numFields;
42 | if(numFields) this.updateBucketsInputs();
43 | })
44 |
45 | let sub2 = _visualizationsService.textFieldsSent$.subscribe(textFields => {
46 | console.log('BUCKETS - RECIEVED - textFields:', textFields);
47 | this.textFields = textFields;
48 | if(textFields) this.updateBucketsInputs();
49 | })
50 |
51 | this.subscriptions.push(sub1, sub2);
52 | }
53 |
54 | onEvent(event): void {
55 | console.log('event:', event);
56 | switch(event.name){
57 | case 'dataChange':
58 | this.onDataChange(event.uniqueId, event.data);
59 | break;
60 | case 'remove':
61 | this._removeBucket(event.uniqueId);
62 | break;
63 | default:
64 | console.error('ERROR: event name [' + event.name + '] not found.');
65 | }
66 | }
67 |
68 | onDataChange(uniqueId: string, data: any): void {
69 | console.log('DATA CHANGE FOR BUCKET:', uniqueId);
70 | console.log('DATA:', data);
71 |
72 | this.bucketsMap.set(uniqueId, data);
73 | }
74 |
75 | ngOnDestroy() {
76 | for(let i=0; i {
90 | let inputs = {
91 | numFields: this.numFields
92 | }
93 |
94 | this.dynamicComponents.setInputs(key, inputs);
95 | });
96 | }
97 |
98 | loadBuckets(aggs: AggregationData[]): void {
99 | console.log('BUCKETS - loadSavedBuckets():', aggs);
100 | this._removeAll();
101 | for(let i=0; i {
134 | this.dynamicComponents.destroyCmp(key);
135 | this.bucketsMap.delete(key);
136 | });
137 | }
138 |
139 | private _setBucketIds(): void {
140 | let i = 0;
141 | this.bucketsMap.forEach((value, key, map) => {
142 | i++;
143 | value.id = 'bucket_' + i;
144 | });
145 | }
146 |
147 | private _guidGenerator(): string {
148 | var S4 = function() {
149 | return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
150 | };
151 | return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
152 | }
153 |
154 | debug(): void {
155 | console.log('%c DEBUG', 'background: #222; color: #bada55');
156 | console.log('%c bucketsMap', 'background: #222; color: #bada55', this.bucketsMap);
157 | console.log('%c buckets', 'background: #222; color: #bada55', Array.from(this.bucketsMap.values()));
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/data-table/dataTable.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/data-table/dataTable.component.scss:
--------------------------------------------------------------------------------
1 | div.vis-container {
2 | display: flex;
3 |
4 | div#table-config {
5 | flex: 1;
6 | min-width: 115px;
7 |
8 | div#metricsAndBuckets {
9 | overflow-y: scroll;
10 | }
11 |
12 | div#configFunctions {
13 | display: flex;
14 | align-items: center;
15 | background-color: #dddddd;
16 |
17 | span.function-icon {
18 | cursor: pointer;
19 | background-color: #dddddd;
20 | color: #3c75ca;
21 | padding: 0.75rem;
22 | }
23 |
24 | span.function-icon:hover {
25 | background-color: #b3b3b3;
26 | }
27 |
28 | input {
29 | height: 1.25rem;
30 | width: 100%;
31 | //border-radius: 0.25rem;
32 | font-size: 1rem;
33 | border: 0px;
34 | padding-left: 0.5rem;
35 | padding-right: 0.5rem;
36 | margin-left: 0.5rem;
37 | margin-right: 0.5rem;
38 | border-radius: 0.25rem;
39 | }
40 | }
41 | }
42 |
43 | div#tableContainer {
44 | flex: 3;
45 | position: relative;
46 | min-width: 0px;
47 | overflow-y: scroll;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/data-table/dataTable.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, ViewChild, EventEmitter } from '@angular/core';
2 |
3 | import { MetricsComponent } from '../metrics/metrics.component';
4 | import { BucketsComponent } from '../buckets/buckets.component';
5 |
6 | import { DataTableService } from './data-table.service';
7 |
8 | import { VisualizationState } from '../../object-classes/visualizationState';
9 | import { AggregationData } from '../../object-classes/aggregationData';
10 | import { SearchSourceJSON } from '../../object-classes/searchSourceJSON';
11 | import { VisualizationObj } from '../../object-classes/visualizationObj';
12 |
13 | import * as _ from "lodash";
14 | declare var $: any;
15 |
16 | @Component({
17 | selector: 'data-table',
18 | templateUrl: './dataTable.component.html',
19 | styleUrls: ['./dataTable.component.scss'],
20 | providers: [ DataTableService ]
21 | })
22 |
23 | export class DataTableComponent {
24 | @ViewChild(MetricsComponent) private _metricsComponent: MetricsComponent;
25 | @ViewChild(BucketsComponent) private _bucketsComponent: BucketsComponent;
26 |
27 | @Output() init: EventEmitter = new EventEmitter();
28 |
29 | @Input() dashMode: boolean = false;
30 | @Input() index: string;
31 | private _numFields: string[];
32 | private _textFields: string[];
33 |
34 | results: any[] = [];
35 | columns: string[] = []
36 | rows: string[][] = [];
37 |
38 | private _columnsHeaders: string[] = []
39 | private _rows: string[][] = [];
40 |
41 | constructor( private _dataTableService: DataTableService ) {}
42 |
43 | ngOnInit(): void {
44 | console.log('DATA TABLE - ngOnInit()');
45 | console.log('this._numFields:', this._numFields);
46 | this.init.emit();
47 | }
48 |
49 | calculate(): void{
50 | console.log('DATA TABLE - calculate()');
51 | let metricAggs = this._metricsComponent.getAggs();
52 | let bucketAggs = this._bucketsComponent.getAggs();
53 | let resultsObj: any = this._dataTableService.getResults(this.index, metricAggs, bucketAggs).then(
54 | resultsObj => {
55 | this._columnsHeaders = resultsObj.columnsHeaders;
56 | this._rows = this._getFormattedRows(resultsObj.rows);
57 | console.log('DATA TABLE - resultsObj:', resultsObj);
58 | }
59 | );
60 | }
61 |
62 | private _getHeight(elemId: string): Number {
63 | //console.log('PIE CHART - elemId:', elemId);
64 | let configHeight = ($(window).height() - $('#' + elemId).position().top);
65 | //console.log('PIE CHART - config height:', configHeight);
66 | return configHeight;
67 | }
68 |
69 | private _getDisplayStyle(): string {
70 | if(this.dashMode) return 'none';
71 | return '';
72 | }
73 |
74 | private _getFormattedRows(rows: any[]): any[]{
75 | let formattedRows = [];
76 | for(let i=0; i {
78 | return (valueObj.value) ? valueObj.value : valueObj.result;
79 | });
80 | console.log('DATA TABLE - formattedRow:', formattedRow);
81 | formattedRows.push(formattedRow);
82 | }
83 | return formattedRows;
84 | }
85 |
86 | private _save(visTitle: string): void {
87 | let allAggs = this._getAllAggs();
88 | if(visTitle !== ''){
89 | var visualizationState = new VisualizationState();
90 | visualizationState.title = visTitle;
91 | visualizationState.type = 'table';
92 | visualizationState.aggs = allAggs;
93 | console.log(visualizationState);
94 |
95 | var searchSourceJSON = new SearchSourceJSON(
96 | (this.index) ? this.index : '', {}
97 | );
98 |
99 | var visualizationObject = new VisualizationObj(
100 | visTitle,
101 | JSON.stringify(visualizationState),
102 | JSON.stringify(searchSourceJSON)
103 | );
104 |
105 | this._dataTableService.saveDataTable(visualizationObject);
106 | }
107 | }
108 |
109 | loadVis(aggs: AggregationData[]): void {
110 | console.log('DATA TABLE - loadVis():', aggs);
111 | let metrics = _.filter(aggs, (agg) => agg.id.split('_')[0]==='metric');
112 | let buckets = _.filter(aggs, (agg) => agg.id.split('_')[0]==='bucket');
113 | console.log('DATA TABLE - metrics:', metrics);
114 | console.log('DATA TABLE - buckets:', buckets);
115 | this._metricsComponent.loadMetrics(metrics);
116 | this._bucketsComponent.loadBuckets(buckets);
117 | this.calculate();
118 | }
119 |
120 | private _getAllAggs(): AggregationData[] {
121 | let metricAggs = this._metricsComponent.getAggs();
122 | let bucketAggs = this._bucketsComponent.getAggs();
123 | return _.concat(metricAggs, bucketAggs);
124 | }
125 |
126 | resetTable(): void{
127 | this.columns = [];
128 | this.rows = [];
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/data-table/table.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ column }}
6 | |
7 |
8 |
9 |
10 | {{ field }} |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/data-table/table.component.scss:
--------------------------------------------------------------------------------
1 | div.table-container {
2 | display: flex;
3 | padding: 1rem;
4 | align-items: center;
5 | justify-content: center;
6 |
7 | table {
8 | border-collapse: collapse;
9 | width: 100%;
10 |
11 | th, td {
12 | border: 1px solid #bfbfbf;
13 | padding: 0.5rem;
14 | border-top: 0;
15 | border-left: 0;
16 | border-right: 0;
17 | text-align: -webkit-left;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/data-table/table.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'dataTable-table',
5 | templateUrl: './table.component.html',
6 | styleUrls: [ './table.component.scss' ]
7 | })
8 |
9 | export class TableComponent {
10 |
11 | @Input() columns: string[];
12 | @Input() rows: string[][];
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/percentileRanksMetric.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
Percentile:
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | {{'[' + value + ']'}}
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/percentileRanksMetric.component.scss:
--------------------------------------------------------------------------------
1 | div.metric-opt {
2 | display: flex;
3 | flex-direction: column;
4 | margin: 0.75rem 0 0.75rem 0;
5 |
6 | span.opt-title {
7 | font-weight: bold;
8 | font-size: 0.75rem;
9 | padding-bottom: 0.25rem;
10 | }
11 |
12 | div.add-percentile-rank {
13 | display: flex;
14 |
15 | div.input {
16 | flex: 9;
17 |
18 | input {
19 | height: 1.75rem;
20 | font-size: 1rem;
21 | border-radius: .25rem;
22 | border: 1px solid #d4d4d4;
23 | color: #0070d2;
24 | padding-left: 0.5rem;
25 | cursor: pointer;
26 | box-sizing: border-box;
27 | width: 100%;
28 | }
29 | }
30 |
31 | div.icon {
32 | flex: 1;
33 | display: flex;
34 | justify-content: center;
35 | align-items: center;
36 | margin-left: 0.25rem;
37 | }
38 |
39 | div.icon:hover {
40 | background-color: #ccdffb;
41 | cursor: pointer;
42 | border-radius: 0.25rem;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/percentileRanksMetric.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, EventEmitter } from '@angular/core';
2 | import { FormGroup, FormBuilder} from '@angular/forms';
3 |
4 | import { maxValidator } from '../../../shared/validators.directive';
5 |
6 | @Component({
7 | selector: 'percentileRanks-metric',
8 | templateUrl: './percentileRanksMetric.component.html',
9 | styleUrls: ['./percentileRanksMetric.component.scss']
10 | })
11 |
12 | export class PercentileRanksMetricComponent {
13 | @Output() dataChange = new EventEmitter();
14 |
15 | private _savedData: any = null;
16 | @Input() set savedData(savedData: any) {
17 | console.log('PERCENTILERANKS - SET savedData:', savedData);
18 | this._savedData = savedData;
19 | if(this._savedData && savedData.type==='percentile_ranks'){
20 | this.percentileRankValues = this._savedData.params.values;
21 | }
22 | }
23 |
24 | form: FormGroup;
25 | formErrors = {
26 | 'percentileRanks': ''
27 | };
28 | validationMessages = {
29 | 'percentileRanks': {}
30 | };
31 |
32 | percentileRankValues: number[] = [];
33 |
34 | constructor( private fb: FormBuilder ) { }
35 |
36 | ngOnInit(): void {
37 | console.log('PERCENTILE RANKS - ngOnInit()');
38 | this.buildForm();
39 | if(!this._savedData)
40 | this.dataChange.emit();
41 | }
42 |
43 | dataChangeEvent(): void {
44 | this.dataChange.emit();
45 | }
46 |
47 | buildForm(): void {
48 | this.form = this.fb.group({
49 | 'percentileRanks': ['', []]
50 | });
51 |
52 | this.form.valueChanges
53 | .subscribe(data => this.onValueChanged(data));
54 |
55 | this.onValueChanged(); // (re)set validation messages now
56 | }
57 |
58 | onValueChanged(data?: any) {
59 | if (!this.form) { return; }
60 | const form = this.form;
61 |
62 | for (const field in this.formErrors) {
63 | // clear previous error message (if any)
64 | this.formErrors[field] = '';
65 | const control = form.get(field);
66 |
67 | if (control && control.dirty && !control.valid) {
68 | const messages = this.validationMessages[field];
69 | for (const key in control.errors) {
70 | this.formErrors[field] += messages[key] + ' ';
71 | }
72 | }
73 | }
74 | }
75 |
76 | addPercentileRank(value: string): void{
77 | console.log(value);
78 | var percentile = parseInt(value);
79 | if(!isNaN(percentile)){
80 | this.percentileRankValues = Array.from(
81 | new Set(this.percentileRankValues).add(percentile)
82 | ).sort((a,b) => a - b);
83 | }
84 | this.dataChangeEvent();
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/percentilesMetric.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
Percentile:
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | {{'[' + value + ']'}}
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/percentilesMetric.component.scss:
--------------------------------------------------------------------------------
1 | div.metric-opt {
2 | display: flex;
3 | flex-direction: column;
4 | margin: 0.75rem 0 0.75rem 0;
5 |
6 | span.opt-title {
7 | font-weight: bold;
8 | font-size: 0.75rem;
9 | padding-bottom: 0.25rem;
10 | }
11 |
12 | div.add-percentile {
13 | display: flex;
14 |
15 | div.input {
16 | flex: 9;
17 |
18 | input {
19 | height: 1.75rem;
20 | font-size: 1rem;
21 | border-radius: .25rem;
22 | border: 1px solid #d4d4d4;
23 | color: #0070d2;
24 | padding-left: 0.5rem;
25 | cursor: pointer;
26 | box-sizing: border-box;
27 | width: 100%;
28 | }
29 | }
30 |
31 | div.icon {
32 | flex: 1;
33 | display: flex;
34 | justify-content: center;
35 | align-items: center;
36 | margin-left: 0.25rem;
37 | }
38 |
39 | div.icon:hover {
40 | background-color: #ccdffb;
41 | cursor: pointer;
42 | border-radius: 0.25rem;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/percentilesMetric.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, EventEmitter } from '@angular/core';
2 | import { FormGroup, FormBuilder} from '@angular/forms';
3 |
4 | import { maxValidator } from '../../../shared/validators.directive';
5 |
6 | @Component({
7 | selector: 'percentiles-metric',
8 | templateUrl: './percentilesMetric.component.html',
9 | styleUrls: ['./percentilesMetric.component.scss']
10 | })
11 |
12 | export class PercentilesMetricComponent {
13 | @Output() dataChange = new EventEmitter();
14 |
15 | private _savedData: any = null;
16 | @Input() set savedData(savedData: any) {
17 | console.log('PERCENTILES - SET savedData:', savedData);
18 | this._savedData = savedData;
19 | if(savedData && savedData.type==='percentiles'){
20 | this.percentileValues = savedData.params.percents;
21 | }
22 | };
23 |
24 | form: FormGroup;
25 | formErrors = {
26 | 'percentileBox': ''
27 | };
28 | validationMessages = {
29 | 'percentileBox': {
30 | 'maxValue': 'Percentile value can\'t be greater tha 100.'
31 | }
32 | };
33 |
34 | percentileValues: number[] = [];
35 |
36 | constructor( private fb: FormBuilder ) {}
37 |
38 | ngOnInit(): void {
39 | console.log('PERCENTILES - ngOnInit()');
40 | this.buildForm();
41 | if(!this._savedData)
42 | this.dataChange.emit();
43 | }
44 |
45 | dataChangeEvent(): void {
46 | this.dataChange.emit();
47 | }
48 |
49 | buildForm(): void {
50 | this.form = this.fb.group({
51 | 'percentileBox': ['', [ maxValidator(100) ] ]
52 | });
53 |
54 | this.form.valueChanges
55 | .subscribe(data => this.onValueChanged(data));
56 |
57 | this.onValueChanged(); // (re)set validation messages now
58 | }
59 |
60 | onValueChanged(data?: any) {
61 | if (!this.form) { return; }
62 | const form = this.form;
63 |
64 | for (const field in this.formErrors) {
65 | // clear previous error message (if any)
66 | this.formErrors[field] = '';
67 | const control = form.get(field);
68 |
69 | if (control && control.dirty && !control.valid) {
70 | const messages = this.validationMessages[field];
71 | for (const key in control.errors) {
72 | this.formErrors[field] += messages[key] + ' ';
73 | }
74 | }
75 | }
76 | }
77 |
78 | addPercentile(value: string): void{
79 | console.log(value);
80 | var percentile = parseInt(value);
81 | if(!isNaN(percentile)){
82 | this.percentileValues = Array.from(
83 | new Set(this.percentileValues).add(percentile)
84 | ).sort((a,b) => a - b);
85 | }
86 | this.dataChangeEvent();
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/topHitMetric.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Aggregate With:
4 |
13 |
14 |
15 |
16 |
30 | Size:
31 |
37 |
38 |
39 |
40 | Sort On:
41 |
50 |
51 |
52 |
53 | Order:
54 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/topHitMetric.component.scss:
--------------------------------------------------------------------------------
1 | div.metric-opt {
2 | display: flex;
3 | flex-direction: column;
4 | margin: 0.75rem 0 0.75rem 0;
5 |
6 | span {
7 | font-weight: bold;
8 | font-size: 0.75rem;
9 | padding-bottom: 0.25rem;
10 | }
11 |
12 | input {
13 | font-size: 1rem;
14 | border-radius: .25rem;
15 | border: 1px solid #d4d4d4;
16 | color: #0070d2;
17 | padding-left: 0.5rem;
18 | cursor: pointer;
19 | }
20 |
21 | select {
22 | font-size: 1rem;
23 | border-radius: .25rem;
24 | height: 1.75rem;
25 | color: rgb(0, 112, 210);
26 | white-space: normal;
27 | -webkit-user-select: none;
28 | background-color: white;
29 | padding-left: 0.5rem;
30 | cursor: pointer;
31 | border-color: #d4d4d4;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/aggregations/topHitMetric.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, EventEmitter, SimpleChange } from '@angular/core';
2 | import {Observable} from 'rxjs/Observable';
3 | import { FormGroup, FormBuilder} from '@angular/forms';
4 |
5 | import { maxValidator } from '../../../shared/validators.directive';
6 |
7 | import * as _ from "lodash";
8 |
9 | @Component({
10 | selector: 'topHit-metric',
11 | templateUrl: './topHitMetric.component.html',
12 | styleUrls: ['./topHitMetric.component.scss']
13 | })
14 |
15 | export class TopHitMetricComponent {
16 | @Output() dataChange = new EventEmitter();
17 |
18 | private _selectedFieldData: any = {
19 | field: '',
20 | isTextField: false
21 | };
22 | @Input() set selectedFieldData(selectedFieldData: any) {
23 | this._selectedFieldData = selectedFieldData;
24 | this._aggsToDisplay = this.topHitAggregations.filter((agg) => this.isValidAgg(agg));
25 | if(this._aggsToDisplay.length===1)
26 | this.selectedTopHitAgg = this._aggsToDisplay[0];
27 | };
28 |
29 | private _fields: string[] = [];
30 | @Input() set fields(fields: string[]) {
31 | console.log('TOP HIT - SET - fields:', fields);
32 | if(!_.isEqual(fields,this._fields)){
33 | this.selectedSortField = fields[0];
34 | if(this._lodaded) this.dataChangeEvent();
35 | }
36 | this._fields = fields;
37 | };
38 |
39 | private _savedData: any = null;
40 | @Input() set savedData(savedData: any) {
41 | console.log('TOP HIT - SET savedData:', savedData);
42 | this._savedData = savedData;
43 | if(savedData && savedData.type==='top_hits'){
44 | this.selectedTopHitAgg = savedData.params.aggregate;
45 | this.hitsSize = savedData.params.size;
46 | this.selectedSortField = savedData.params.sortField;
47 | this.selectedOrder = savedData.params.sortOrder;
48 | }
49 | };
50 |
51 | private _lodaded: boolean = false;
52 |
53 | form: FormGroup;
54 | formErrors = {
55 | 'topHits': ''
56 | };
57 | validationMessages = {
58 | 'topHits': {}
59 | };
60 |
61 | topHitAggregations: string[] = [
62 | 'Concatenate',
63 | 'Average',
64 | 'Max',
65 | 'Min',
66 | 'Sum'
67 | ];
68 | private _aggsToDisplay: string[] = this.topHitAggregations;
69 | selectedTopHitAgg: string = this._aggsToDisplay[0];
70 |
71 | hitsSize: number = 1;
72 |
73 | orders: string[] = ['desc', 'asc'];
74 | selectedOrder: string = this.orders[0];
75 |
76 | selectedSortField: string = (this._fields) ? this._fields[0] : '';
77 |
78 |
79 | constructor( private fb: FormBuilder ) {}
80 |
81 | ngOnInit(): void{
82 | console.log('TOP HIT METRIC - ngOnInit()');
83 | this._lodaded = true;
84 | this.buildForm();
85 | console.log('_savedData:', this._savedData);
86 | if(!this._savedData)
87 | this.dataChangeEvent();
88 | }
89 |
90 | dataChangeEvent(): void {
91 | console.log('TOP HIT - EMIT CHANGE');
92 | this.dataChange.emit();
93 | }
94 |
95 | buildForm(): void {
96 | this.form = this.fb.group({
97 | 'topHits': ['', []]
98 | });
99 |
100 | this.form.valueChanges
101 | .subscribe(data => this.onValueChanged(data));
102 |
103 | this.onValueChanged(); // (re)set validation messages now
104 | }
105 |
106 | onValueChanged(data?: any) {
107 | if (!this.form) { return; }
108 | const form = this.form;
109 |
110 | for (const field in this.formErrors) {
111 | // clear previous error message (if any)
112 | this.formErrors[field] = '';
113 | const control = form.get(field);
114 |
115 | if (control && control.dirty && !control.valid) {
116 | const messages = this.validationMessages[field];
117 | for (const key in control.errors) {
118 | this.formErrors[field] += messages[key] + ' ';
119 | }
120 | }
121 | }
122 | }
123 |
124 | isValidAgg(agg: string){
125 | if(!this._selectedFieldData.isTextField || agg==='Concatenate')
126 | return true;
127 |
128 | return false;
129 | }
130 |
131 | debug(): void{
132 | console.log('selectedFieldData:', this._selectedFieldData);
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/metric.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
18 |
19 |
20 | Aggregation:
21 |
30 |
31 |
32 |
0 && isNumFieldAgg()" class="metric-opt">
33 | Field:
34 |
43 |
44 |
45 |
51 |
52 |
58 |
59 |
60 |
65 |
66 |
67 |
68 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/metric.component.scss:
--------------------------------------------------------------------------------
1 | div.metric {
2 |
3 | div.metric-header {
4 | display: flex;
5 | align-items: center;
6 |
7 | div {
8 | flex: 1;
9 | padding: 1rem;
10 |
11 | span.fa-trash-o {
12 | float: right;
13 | color: red;
14 | }
15 | }
16 |
17 | div.display-info {
18 | flex: 5;
19 | }
20 |
21 | div.display-info:hover {
22 | cursor: pointer;
23 | background-color: #e8e8e8;
24 | }
25 |
26 | div.remove {
27 | flex: 1;
28 | display: flex;
29 | align-items: center;
30 | flex-direction: column;
31 | }
32 |
33 | div.remove:hover {
34 | cursor: pointer;
35 | background-color: #ffe6e6;
36 | }
37 | }
38 |
39 | div.metric-body {
40 | padding: 0rem 1rem 1rem 1rem;
41 |
42 | div.metric-opt {
43 | display: flex;
44 | flex-direction: column;
45 | margin: 0.5rem 0 0.5rem 0;
46 |
47 | span {
48 | font-weight: bold;
49 | font-size: 0.75rem;
50 | padding-bottom: 0.25rem;
51 | }
52 | }
53 |
54 | select {
55 | font-size: 1rem;
56 | border-radius: .25rem;
57 | height: 1.75rem;
58 | color: rgb(0, 112, 210);
59 | white-space: normal;
60 | -webkit-user-select: none;
61 | background-color: white;
62 | padding-left: 0.5rem;
63 | cursor: pointer;
64 | border-color: #d4d4d4;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/metric.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, OnChanges, SimpleChange, EventEmitter, ViewChild } from '@angular/core';
2 |
3 | import { MetricsService } from './metrics.service';
4 | import { PercentilesMetricComponent } from './aggregations/percentilesMetric.component';
5 | import { PercentileRanksMetricComponent } from './aggregations/percentileRanksMetric.component';
6 | import { TopHitMetricComponent } from './aggregations/topHitMetric.component';
7 |
8 | import { AggregationData } from '../../object-classes/aggregationData';
9 |
10 | import * as _ from "lodash";
11 |
12 | @Component({
13 | selector: 'metric',
14 | templateUrl: './metric.component.html',
15 | styleUrls: ['./metric.component.scss'],
16 | providers: [ MetricsService ]
17 | })
18 |
19 | export class MetricComponent {
20 | @ViewChild(PercentilesMetricComponent)
21 | private percentilesMetricComponent: PercentilesMetricComponent;
22 | @ViewChild(PercentileRanksMetricComponent)
23 | private percentileRanksMetricComponent: PercentileRanksMetricComponent;
24 | @ViewChild(TopHitMetricComponent)
25 | private topHitMetricComponent: TopHitMetricComponent;
26 |
27 | @Output() dataChange = new EventEmitter();
28 | @Output() remove = new EventEmitter();
29 |
30 | @Input() index: string;
31 | @Input() widgetMode: boolean = false;
32 |
33 | private _numFields: string[] = [];
34 | @Input() set numFields(numFields: string[]) {
35 | console.log('numFields:', numFields);
36 | this._numFields = numFields;
37 | if(numFields && numFields.length>0)
38 | this.selectedField = numFields[0];
39 | this.dataChangeEvent();
40 | };
41 | get numFields(): string[] {
42 | return this._numFields;
43 | };
44 |
45 | private _textFields: string[] = [];
46 | @Input() set textFields(textFields: string[]) {
47 | console.log('textFields:', textFields);
48 | this._textFields = textFields;
49 | this.dataChangeEvent();
50 | };
51 | get textFields(): string[] {
52 | return this._textFields;
53 | };
54 |
55 | private _savedData: any = null;
56 | @Input() set savedData(savedData: any) {
57 | console.log('METRIC - SET - savedData');
58 | this._savedData = savedData;
59 | if(savedData)
60 | this._loadSavedMetric(savedData);
61 | };
62 | get savedData(): any {
63 | return this._savedData;
64 | };
65 |
66 | results: number[] = [];
67 |
68 | aggregationsArr: any[] = [
69 | { label: 'Count', value: 'count'},
70 | { label: 'Average', value: 'avg'},
71 | { label: 'Sum', value: 'sum'},
72 | { label: 'Min', value: 'min'},
73 | { label: 'Max', value: 'max'},
74 | { label: 'Median', value: 'median'},
75 | { label: 'Standard Deviation', value: 'extended_stats'},
76 | { label: 'Unique Count', value: 'cardinality'},
77 | { label: 'Percentiles', value: 'percentiles'},
78 | { label: 'Percentile Ranks', value: 'percentile_ranks'},
79 | { label: 'Top Hit', value: 'top_hits'}
80 | ];
81 | selectedAggregation: string = this.aggregationsArr[0].value;
82 | numFieldAgg: string[] = [
83 | 'avg', 'sum', 'min', 'max', 'median', 'extended_stats',
84 | 'cardinality', 'percentiles', 'percentile_ranks', 'top_hits'
85 | ];
86 | selectedField: string = '';
87 |
88 | private _displayed = false;
89 |
90 | constructor( public metricsService: MetricsService ) { }
91 |
92 | ngOnInit(): void {
93 | console.log('METRIC - ngOnInit()');
94 | }
95 |
96 | triggerRemoveEvent(): void {
97 | this.remove.emit();
98 | }
99 |
100 | dataChangeEvent(): void {
101 | console.log('METRIC - dataChangeEvent()');
102 | let aggregationData = this.getAggregationData();
103 | console.log('aggregationData:', aggregationData);
104 | if(aggregationData.params){
105 | this.dataChange.emit(aggregationData);
106 | }
107 | }
108 |
109 | getAggregationData(): AggregationData {
110 | var aggregationData = new AggregationData();
111 | aggregationData.enabled = true;
112 | aggregationData.type = this.selectedAggregation;
113 | aggregationData.schema = 'metric';
114 | aggregationData.params = this.getAggParams();
115 |
116 | return aggregationData;
117 | }
118 |
119 | private _loadSavedMetric(agg: AggregationData): void {
120 | console.log('METRIC - load():', agg);
121 | this.selectedAggregation = agg.type;
122 | this.selectedField = (agg.params.field) ? agg.params.field : this._numFields[0];
123 | }
124 |
125 | isNumFieldAgg(): Boolean{
126 | //console.log(this.selectedAggregation);
127 | return (this.numFieldAgg.indexOf(this.selectedAggregation)>=0);
128 | }
129 |
130 | getAggParams(): any {
131 | switch (this.selectedAggregation){
132 | case 'count':
133 | return {};
134 | case 'avg':
135 | case 'sum':
136 | case 'min':
137 | case 'max':
138 | case 'median':
139 | case 'extended_stats':
140 | case 'cardinality':
141 | return {
142 | field: this.selectedField
143 | };
144 | case 'percentiles': {
145 | let cmp = this.percentilesMetricComponent;
146 | return {
147 | field: this.selectedField,
148 | percents: (cmp) ? cmp.percentileValues : []
149 | };
150 | }case 'percentile_ranks': {
151 | let cmp = this.percentileRanksMetricComponent;
152 | return {
153 | field: this.selectedField,
154 | values: (cmp) ? cmp.percentileRankValues : []
155 | };
156 | }case 'top_hits': {
157 | let cmp = this.topHitMetricComponent;
158 | return {
159 | field: this.selectedField,
160 | aggregate: (cmp) ? cmp.selectedTopHitAgg: 'Concatenate',
161 | size: (cmp) ? cmp.hitsSize: '1',
162 | sortField: (cmp) ? cmp.selectedSortField: this._numFields[0],
163 | sortOrder: (cmp) ? cmp.selectedOrder: 'desc'
164 | };
165 | }default:
166 | return null;
167 | }
168 | }
169 |
170 | getTopHitsFieldData(): any {
171 | return {
172 | field: this.selectedField,
173 | isTextField: (this._textFields.indexOf(this.selectedField)>-1)
174 | }
175 | }
176 |
177 | getFields(): any {
178 | if(this.selectedAggregation==='top_hits')
179 | return this.getAllFields();
180 |
181 | return this._numFields;
182 | }
183 |
184 | getAllFields(): any {
185 | return _.concat(this._numFields, this._textFields);
186 | }
187 |
188 | debug(): void {
189 | console.log('METRIC - selectedField:', this.selectedField);
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/metrics.component.html:
--------------------------------------------------------------------------------
1 |
78 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/metrics/metrics.component.scss:
--------------------------------------------------------------------------------
1 | div.metrics-vis.widget {
2 | height: 100%;
3 | }
4 |
5 | div.metrics-vis{
6 | display: flex;
7 | border-bottom: 1px solid #d8d8d8;
8 | //height: 100%;
9 |
10 | div.scrollable {
11 | overflow-y: scroll;
12 | }
13 |
14 | div#metricsConfig {
15 | flex: 1;
16 | min-width: 115px;
17 |
18 | div#configFunctions {
19 | display: flex;
20 | align-items: center;
21 | background-color: #dddddd;
22 |
23 | span.function-icon {
24 | cursor: pointer;
25 | background-color: #dddddd;
26 | color: #3c75ca;
27 | padding: 0.75rem;
28 | }
29 |
30 | span.function-icon:hover {
31 | background-color: #b3b3b3;
32 | }
33 |
34 | input {
35 | height: 1.25rem;
36 | width: 100%;
37 | //border-radius: 0.25rem;
38 | font-size: 1rem;
39 | border: 0px;
40 | padding-left: 0.5rem;
41 | padding-right: 0.5rem;
42 | margin-left: 0.5rem;
43 | margin-right: 0.5rem;
44 | border-radius: 0.25rem;
45 | }
46 | }
47 |
48 | div#metricsContainer {
49 |
50 | div.metrics-header {
51 | display: flex;
52 |
53 | div.title {
54 | flex: 5;
55 | font-family: "Trebuchet MS", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Tahoma, sans-serif;
56 | font-size: 1.2rem;
57 | padding: 1rem;
58 | }
59 |
60 | div.metrics-actions {
61 | display: flex;
62 | flex-direction: row-reverse;
63 | flex: 1;
64 |
65 | div {
66 | padding: 1rem;
67 | border-radius: 0.25rem;
68 | cursor: pointer;
69 | }
70 |
71 | div.add-metric:hover {
72 | background-color: #ccdffb;
73 | }
74 |
75 | div.remove-all {
76 | color: red;
77 | }
78 |
79 | div.remove-all:hover {
80 | background-color: #ffe6e6;
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
87 | div.results-container {
88 | flex: 3;
89 | overflow-y: scroll;
90 | display: flex;
91 | flex-wrap: wrap;
92 |
93 | div.result-container {
94 | flex: 1;
95 | display: flex;
96 | flex-direction: column;
97 | align-items: center;
98 | justify-content: center;
99 | padding: 2rem;
100 | white-space: nowrap;
101 |
102 | span.result {
103 | font-size: 5rem;
104 | font-weight: bold;
105 | }
106 |
107 | span.result-label {}
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/pie-chart/pie-chart.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { Elasticsearch } from '../../elasticsearch';
4 | import { MetricsService } from '../metrics/metrics.service';
5 |
6 | import { AggregationData } from '../../object-classes/aggregationData';
7 | import { VisualizationObj } from '../../object-classes/visualizationObj';
8 |
9 | import { VisualizationTools } from "../../shared/visualization-tools";
10 |
11 | import * as _ from "lodash";
12 | declare let bodybuilder: any;
13 |
14 | @Injectable()
15 | export class PieChartService {
16 |
17 | constructor(
18 | private _elasticCli: Elasticsearch,
19 | private _metricsService: MetricsService
20 | ) { }
21 |
22 | savePieChart(visualizationObj: VisualizationObj): void {
23 | this._elasticCli.saveVisualization(visualizationObj);
24 | }
25 |
26 | getResults(index: string, metric: AggregationData, buckets: AggregationData[]): PromiseLike {
27 | let body = this._getRequestBody(buckets, metric);
28 | return this._elasticCli.request(index, body).then(response => {
29 | console.log('PIE CHART SERVICE - response:', response);
30 | return this._getFormattedResults(response, this._getAggByIdMap(_.concat([metric], buckets)), metric)
31 | });
32 | }
33 |
34 | private _getFormattedResults(response: any, aggsById: Map, metric: AggregationData): any {
35 | let aggregations = response.aggregations;
36 | if(!aggregations) return null;
37 | let results = [];
38 | for(let bucketId in aggregations){
39 | results = this._getBucketsResults(
40 | bucketId,
41 | aggregations[bucketId],
42 | metric,
43 | aggsById,
44 | 'root'
45 | );
46 | }
47 | console.log('PIE CHART SERVICE - results:', results);
48 | let resultsMap = this._getResultsMap(results);
49 | console.log('PIE CHART SERVICE - resultsMap:', resultsMap);
50 | return {
51 | rMap: resultsMap,
52 | rArray: results
53 | };
54 | }
55 |
56 | private _getResultsMap(results: any[]): Map {
57 | let resultsMap = new Map();
58 | for(let i=0; i,
72 | parentResultId: string
73 | ): any{
74 | let currentBucket = aggsById.get(bucketId);
75 | let results = [];
76 | for(let i in bucket.buckets){
77 | let bucketObj = bucket.buckets[i];
78 | let metricResult = this._getMetricResult(bucketObj, metric);
79 | metricResult = (metricResult.length>0) ? metricResult[0] : null;
80 | console.log('PIE CHART SERVICE - metricResult:', metricResult);
81 | let bucketValue = this._getBucketValue(currentBucket.type, bucketObj);
82 | console.log('PIE CHART SERVICE - bucketValue:', bucketValue);
83 | let id = VisualizationTools.guidGenerator();
84 | results.push({
85 | id: id,
86 | bucket: aggsById.get(bucketId),
87 | metricResult: metricResult,
88 | bucketValue: bucketValue,
89 | percent: null,
90 | parentResultId: parentResultId
91 | });
92 | let nestedResults = this._getNestedBucketResults(
93 | bucketId,
94 | bucketObj,
95 | metric,
96 | aggsById,
97 | id
98 | );
99 | results = (nestedResults) ? _.concat(results, nestedResults) : results;
100 | }
101 | return results;
102 | }
103 |
104 | private _getNestedBucketResults(
105 | bucketId: string,
106 | bucketObj: any,
107 | metric: AggregationData,
108 | aggsById: Map,
109 | parentResultId: string
110 | ): any{
111 | for(let key in bucketObj){
112 | if(this._isBucket(key))
113 | return this._getBucketsResults(key, bucketObj[key], metric, aggsById, parentResultId);
114 | }
115 | return null;
116 | }
117 |
118 | private _getMetricResult(bucket: any, metric: AggregationData): any {
119 | return this._metricsService.getAggResult(bucket, metric);
120 | }
121 |
122 | private _isBucket(aggId: string): boolean {
123 | return aggId.split('_')[0]==='bucket';
124 | }
125 |
126 | private _isMetric(aggId: string): boolean {
127 | return aggId.split('_')[0]==='metric';
128 | }
129 |
130 | private _getBucketValue(bucketType: string, bucket: any){
131 | switch(bucketType){
132 | case 'range':
133 | return bucket.from + ' to ' + bucket.to;
134 | case 'histogram':
135 | return bucket.key;
136 | default:
137 | return null;
138 | }
139 | }
140 |
141 | private _getAggByIdMap(aggs: AggregationData[]): Map {
142 | let aggByIdMap = new Map();
143 | for(let i=0; i=0; i--){
154 | console.log('PIE CHART SERVICE - bucket:', buckets[i]);
155 | console.log('PIE CHART SERVICE - aggType:', this._elasticCli.getAggType(buckets[i]));
156 | console.log('PIE CHART SERVICE - aggParams:', this._elasticCli.getAggParams(buckets[i]));
157 | let nestedBody = body.aggregation(
158 | this._elasticCli.getAggType(metric),
159 | null,
160 | metric.id,
161 | this._elasticCli.getAggParams(metric)
162 | );
163 | console.log('PIE CHART SERVICE - nestedBody:', body.build());
164 | body = bodybuilder().aggregation(
165 | this._elasticCli.getAggType(buckets[i]),
166 | null,
167 | buckets[i].id,
168 | this._elasticCli.getAggParams(buckets[i]),
169 | (a) => nestedBody
170 | );
171 | }
172 | console.log('PIE CHART SERVICE - body:', body.build());
173 | return body;
174 | }
175 |
176 | private _getSortedAggs(buckets: AggregationData[], metrics: AggregationData[]): AggregationData[] {
177 | return null;
178 | }
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/pie-chart/pieChart.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/pie-chart/pieChart.component.scss:
--------------------------------------------------------------------------------
1 | div.vis-container {
2 | display: flex;
3 | height: 100%;
4 |
5 | div#chart-config {
6 | flex: 1;
7 | min-width: 115px;
8 | /*background-color: #f1f6ff;
9 | box-shadow: -5px 0px 10px 0px rgba(0, 0, 0, 0.14);*/
10 |
11 | div#metricsAndBuckets {
12 | overflow-y: scroll;
13 | }
14 |
15 | div#configFunctions {
16 | display: flex;
17 | align-items: center;
18 | background-color: #dddddd;
19 |
20 | span.function-icon {
21 | cursor: pointer;
22 | background-color: #dddddd;
23 | color: #3c75ca;
24 | //border-radius: 0.25rem;
25 | padding: 0.75rem;
26 | }
27 |
28 | span.function-icon:hover {
29 | background-color: #b3b3b3;
30 | }
31 |
32 | /*div#calculateButton {
33 | flex: 1;
34 | //padding: 0.25rem;
35 | }*/
36 |
37 | input {
38 | height: 1.25rem;
39 | width: 100%;
40 | //border-radius: 0.25rem;
41 | font-size: 1rem;
42 | border: 0px;
43 | padding-left: 0.5rem;
44 | padding-right: 0.5rem;
45 | margin-left: 0.5rem;
46 | margin-right: 0.5rem;
47 | border-radius: 0.25rem;
48 | }
49 |
50 | /*div#saveForm {
51 | flex: 5;
52 | //padding: 0.25rem;
53 |
54 | input {
55 | height: 1.25rem;
56 | //border-radius: 0.25rem;
57 | font-size: 1rem;
58 | border: 0px;
59 | }
60 | }*/
61 | }
62 | }
63 |
64 | div#chart-container {
65 | flex: 3;
66 | position: relative;
67 | min-width: 0px;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/visualizations.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Saved Visualizations
5 |
6 |
7 |
8 | -
9 |
10 |
11 | {{visualization._source.title}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Visualization Options - {{_selectedIndex}} - {{_selectedVisualization}}
25 |
26 |
27 |
28 |
29 | Index:
30 |
40 |
41 |
42 |
43 | Visualization:
44 |
53 |
54 |
55 |
56 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/visualizations.component.scss:
--------------------------------------------------------------------------------
1 | div.main {
2 | background-color: white;
3 | height: 100%;
4 |
5 | div.saved-vis {
6 | ul {
7 | margin: 0px;
8 | padding: 0px;
9 | list-style-type: none;
10 |
11 | li {
12 | //padding: 0.25rem;
13 | //padding-right: 1rem;
14 | //padding-left: 1rem;
15 | border-bottom: 1px solid #efefef;
16 | color: #676767;
17 | }
18 |
19 | li:hover {
20 | background-color: #ecf5ff;
21 | cursor: pointer;
22 | }
23 | }
24 | }
25 |
26 | div#visOptions {
27 | display: flex;
28 | padding: 1rem;
29 |
30 | div#indexOpt {
31 | flex: 1;
32 | display: flex;
33 | align-items: center;
34 |
35 | span {
36 | padding-right: 0.5rem;
37 | }
38 | }
39 |
40 | div#visOpt {
41 | flex: 1;
42 | display: flex;
43 | align-items: center;
44 |
45 | span {
46 | padding-right: 0.5rem;
47 | }
48 | }
49 |
50 | select {
51 | font-size: 1rem;
52 | border-radius: .25rem;
53 | height: 1.75rem;
54 | color: rgb(0, 112, 210);
55 | white-space: normal;
56 | -webkit-user-select: none;
57 | background-color: white;
58 | padding-left: 0.5rem;
59 | cursor: pointer;
60 | border-color: #d4d4d4;
61 | }
62 | }
63 |
64 | div.section-title {
65 | font-family: "Trebuchet MS", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Tahoma, sans-serif;
66 | font-size: 1.2rem;
67 | padding: 1rem;
68 | background-color: #ddd;
69 | border-bottom: 1px solid #fbfbfb;
70 | cursor: pointer;
71 | }
72 |
73 | div.section-title:hover {
74 | background-color: #b7b7b7;
75 | }
76 |
77 | div.section-content {
78 | background-color: #fbfbfb;
79 |
80 | .option-container {
81 | display: flex;
82 | //justify-content: space-between;
83 | //align-items: center;
84 |
85 | .title-container {
86 | flex: 20;
87 | padding: 0.5rem;
88 | padding-left: 1rem;
89 | }
90 |
91 | .delete-icon-container {
92 | padding: 0.5rem;
93 | cursor: pointer;
94 | color: red;
95 | border-radius: 0.25rem;
96 | flex: 1;
97 | display: flex;
98 | justify-content: center;
99 | }
100 |
101 | .delete-icon-container:hover {
102 | background-color: #ffd3d3;
103 | }
104 | }
105 | }
106 |
107 | div.panel {
108 | display: block;
109 | }
110 |
111 | div.panel:host {
112 | display: block;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/dashboard-interface/src/app/visualizations/visualizations.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Subject } from 'rxjs/Subject';
3 |
4 | import { AggregationData } from '../object-classes/aggregationData';
5 |
6 |
7 | /*
8 | The reason why numFieldsSent and textFieldsSent observables are necessary
9 | is becasuse the angular 2 livecycle hook order is problematic with fields
10 | update syncrhonization on visualizations children.
11 | */
12 |
13 | @Injectable()
14 | export class VisualizationsService {
15 |
16 | // Observable sources
17 | private numFieldsSource = new Subject();
18 | private textFieldsSource = new Subject();
19 |
20 | // Observable streams
21 | numFieldsSent$ = this.numFieldsSource.asObservable();
22 | textFieldsSent$ = this.textFieldsSource.asObservable();
23 |
24 | // Service fields commands
25 | sendNumFields(numFields: string[]) {
26 | console.log('VISUALIZATIONS SERVICE - SEND - sendNumFields:', numFields);
27 | this.numFieldsSource.next(numFields);
28 | }
29 |
30 | sendTextFields(textFields: string[]) {
31 | console.log('VISUALIZATIONS SERVICE - SEND - sendTextFiedls:', textFields);
32 | this.textFieldsSource.next(textFields);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/dashboard-interface/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/dashboard-interface/src/assets/.gitkeep
--------------------------------------------------------------------------------
/dashboard-interface/src/assets/img/sakura.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/dashboard-interface/src/assets/img/sakura.png
--------------------------------------------------------------------------------
/dashboard-interface/src/assets/img/sakura.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dashboard-interface/src/assets/img/sakura2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/dashboard-interface/src/assets/img/sakura2.png
--------------------------------------------------------------------------------
/dashboard-interface/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/dashboard-interface/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false
8 | };
9 |
--------------------------------------------------------------------------------
/dashboard-interface/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/dashboard-interface/src/favicon.ico
--------------------------------------------------------------------------------
/dashboard-interface/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DashboardInterface
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Loading...
16 |
17 |
18 |
--------------------------------------------------------------------------------
/dashboard-interface/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule);
12 |
--------------------------------------------------------------------------------
/dashboard-interface/src/polyfills.ts:
--------------------------------------------------------------------------------
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 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/set';
35 |
36 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
37 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
38 |
39 | /** IE10 and IE11 requires the following to support `@angular/animation`. */
40 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
41 |
42 |
43 | /** Evergreen browsers require these. **/
44 | import 'core-js/es6/reflect';
45 | import 'core-js/es7/reflect';
46 |
47 |
48 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone'; // Included with Angular CLI.
57 |
58 |
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
64 | /**
65 | * Date, currency, decimal and percent pipes.
66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
67 | */
68 | // import 'intl'; // Run `npm install --save intl`.
69 |
--------------------------------------------------------------------------------
/dashboard-interface/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @import "~@angular/material/prebuilt-themes/indigo-pink.css";
3 |
4 | html,
5 | body {
6 | height: 100%;
7 | padding: 0;
8 | margin: 0;
9 | display: flex; /*enables flex content for its children*/
10 | box-sizing: border-box;
11 | flex-direction: column;
12 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
13 | }
14 |
15 | app-root {
16 | height: 100%;
17 | overflow: hidden;
18 | }
19 |
--------------------------------------------------------------------------------
/dashboard-interface/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/long-stack-trace-zone';
4 | import 'zone.js/dist/proxy.js';
5 | import 'zone.js/dist/sync-test';
6 | import 'zone.js/dist/jasmine-patch';
7 | import 'zone.js/dist/async-test';
8 | import 'zone.js/dist/fake-async-test';
9 | import { getTestBed } from '@angular/core/testing';
10 | import {
11 | BrowserDynamicTestingModule,
12 | platformBrowserDynamicTesting
13 | } from '@angular/platform-browser-dynamic/testing';
14 |
15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
16 | declare var __karma__: any;
17 | declare var require: any;
18 |
19 | // Prevent Karma from running prematurely.
20 | __karma__.loaded = function () {};
21 |
22 | // First, initialize the Angular testing environment.
23 | getTestBed().initTestEnvironment(
24 | BrowserDynamicTestingModule,
25 | platformBrowserDynamicTesting()
26 | );
27 | // Then we find all the tests.
28 | const context = require.context('./', true, /\.spec\.ts$/);
29 | // And load the modules.
30 | context.keys().map(context);
31 | // Finally, start Karma to run the tests.
32 | __karma__.start();
33 |
--------------------------------------------------------------------------------
/dashboard-interface/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "module": "es2015",
6 | "baseUrl": "",
7 | "types": []
8 | },
9 | "exclude": [
10 | "test.ts",
11 | "**/*.spec.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/dashboard-interface/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/spec",
5 | "module": "commonjs",
6 | "target": "es5",
7 | "baseUrl": "",
8 | "types": [
9 | "jasmine",
10 | "node"
11 | ]
12 | },
13 | "files": [
14 | "test.ts"
15 | ],
16 | "include": [
17 | "**/*.spec.ts",
18 | "**/*.d.ts"
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/dashboard-interface/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | /* SystemJS module definition */
2 | declare var module: NodeModule;
3 | interface NodeModule {
4 | id: string;
5 | }
6 |
--------------------------------------------------------------------------------
/dashboard-interface/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "baseUrl": "src",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "moduleResolution": "node",
9 | "emitDecoratorMetadata": true,
10 | "experimentalDecorators": true,
11 | "allowSyntheticDefaultImports": true,
12 | "target": "es5",
13 | "typeRoots": [
14 | "node_modules/@types"
15 | ],
16 | "lib": [
17 | "es2016",
18 | "dom"
19 | ]
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/dashboard-interface/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "callable-types": true,
7 | "class-name": true,
8 | "comment-format": [
9 | true,
10 | "check-space"
11 | ],
12 | "curly": true,
13 | "eofline": true,
14 | "forin": true,
15 | "import-blacklist": [true, "rxjs"],
16 | "import-spacing": true,
17 | "indent": [
18 | true,
19 | "spaces"
20 | ],
21 | "interface-over-type-literal": true,
22 | "label-position": true,
23 | "max-line-length": [
24 | true,
25 | 140
26 | ],
27 | "member-access": false,
28 | "member-ordering": [
29 | true,
30 | "static-before-instance",
31 | "variables-before-functions"
32 | ],
33 | "no-arg": true,
34 | "no-bitwise": true,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-construct": true,
44 | "no-debugger": true,
45 | "no-duplicate-variable": true,
46 | "no-empty": false,
47 | "no-empty-interface": true,
48 | "no-eval": true,
49 | "no-inferrable-types": [true, "ignore-params"],
50 | "no-shadowed-variable": true,
51 | "no-string-literal": false,
52 | "no-string-throw": true,
53 | "no-switch-case-fall-through": true,
54 | "no-trailing-whitespace": true,
55 | "no-unused-expression": true,
56 | "no-use-before-declare": true,
57 | "no-var-keyword": true,
58 | "object-literal-sort-keys": false,
59 | "one-line": [
60 | true,
61 | "check-open-brace",
62 | "check-catch",
63 | "check-else",
64 | "check-whitespace"
65 | ],
66 | "prefer-const": true,
67 | "quotemark": [
68 | true,
69 | "single"
70 | ],
71 | "radix": true,
72 | "semicolon": [
73 | "always"
74 | ],
75 | "triple-equals": [
76 | true,
77 | "allow-null-check"
78 | ],
79 | "typedef-whitespace": [
80 | true,
81 | {
82 | "call-signature": "nospace",
83 | "index-signature": "nospace",
84 | "parameter": "nospace",
85 | "property-declaration": "nospace",
86 | "variable-declaration": "nospace"
87 | }
88 | ],
89 | "typeof-compare": true,
90 | "unified-signatures": true,
91 | "variable-name": false,
92 | "whitespace": [
93 | true,
94 | "check-branch",
95 | "check-decl",
96 | "check-operator",
97 | "check-separator",
98 | "check-type"
99 | ],
100 |
101 | "directive-selector": [true, "attribute", "app", "camelCase"],
102 | "component-selector": [true, "element", "app", "kebab-case"],
103 | "use-input-property-decorator": true,
104 | "use-output-property-decorator": true,
105 | "use-host-property-decorator": true,
106 | "no-input-rename": true,
107 | "no-output-rename": true,
108 | "use-life-cycle-interface": true,
109 | "use-pipe-transform-interface": true,
110 | "component-class-suffix": true,
111 | "directive-class-suffix": true,
112 | "no-access-missing-member": true,
113 | "templates-use-public": true,
114 | "invoke-injectable": true
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/plantilla-memoria/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/.DS_Store
--------------------------------------------------------------------------------
/plantilla-memoria/Makefile:
--------------------------------------------------------------------------------
1 | all: memoria.pdf
2 |
3 | memoria.pdf: memoria.tex
4 | pdflatex memoria.tex; bibtex memoria; pdflatex memoria.tex; pdflatex memoria.tex
5 |
6 | clean:
7 | rm -f memoria.dvi memoria.ps *.snm *.out *.nav *.log *.aux *.toc *.vrb *.pdf *~ *.lof *.blg *.bbl
8 |
--------------------------------------------------------------------------------
/plantilla-memoria/README.md:
--------------------------------------------------------------------------------
1 | # plantilla-memoria
2 | Plantilla en LaTeX para la elaboración de una memoria de Trabajo Fin de Grado/Máster (TFG/TFM)
3 |
4 | ## Instrucciones de inicio
5 |
6 | Para hacer uso de esta plantilla, lo mejor es que te crees un fork de este repositorio, de manera que obtengas una copia del repositorio propia, con permisos para poder subir tus modificaciones a GitHub.
7 |
8 | Una buena práctica es, una vez realizado el fork, cambiar el nombre de tu repositorio a MemoriaTFG-TuNombreYApellidos, de mamera que sea fácilmente identificable para el resto.
9 |
10 | ## Comentarios y realimentación
11 |
12 | Esta plantilla no está terminada, por lo que se puede considerar trabajo en curso. Si tienes algun comentario o sugerencia, estaré encantado de recibirlo. Agradezco especialmente pull-requests.
13 |
14 | Para otras cuestiones, mándame un correo a grex (arroba) gsyc.urjc.es.
15 |
--------------------------------------------------------------------------------
/plantilla-memoria/img/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/.DS_Store
--------------------------------------------------------------------------------
/plantilla-memoria/img/Scrum_Framework.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/Scrum_Framework.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/angular-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/angular-architecture.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/arquitectura.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/arquitectura.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/bar-chart-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/bar-chart-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/bar-chart-lengend-filter-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/bar-chart-lengend-filter-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/center-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/center-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/chartjs-result-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/chartjs-result-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/dashboard-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/dashboard-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/dashboards-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/dashboards-diagram.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/dashboards-initial-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/dashboards-initial-view.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/data-table-histogram-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/data-table-histogram-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/data-table-initial-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/data-table-initial-view.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/data-table-multiaggregation-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/data-table-multiaggregation-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/data-table-range-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/data-table-range-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/final-satge-sprint1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/final-satge-sprint1.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/final-user-interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/final-user-interface.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/flex-end-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/flex-end-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/foro1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/foro1.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/jquery-result-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/jquery-result-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/kibana-dashboard-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/kibana-dashboard-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/kibana-nav-bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/kibana-nav-bar.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/kibana-visualization-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/kibana-visualization-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/logo_vect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/logo_vect.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-average-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-average-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-count-calcuation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-count-calcuation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-max-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-max-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-median-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-median-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-min-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-min-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-percentiles-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-percentiles-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-ranks-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-ranks-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-std-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-std-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-sum-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-sum-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-top-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-top-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-unique-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-unique-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/metric-visualization-initial-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/metric-visualization-initial-view.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/no-wrap-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/no-wrap-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/parent-child-via-service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/parent-child-via-service.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/pie-chart-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/pie-chart-calculation.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/pie-chart-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/pie-chart-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/saved-visualizations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/saved-visualizations.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/sprint1_architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/sprint1_architecture.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/sprint2_architecture_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/sprint2_architecture_1.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/sprint2_architecture_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/sprint2_architecture_2.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/user_interface_mockup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/user_interface_mockup.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/visualization-options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/visualization-options.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/visualizations-section.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/visualizations-section.png
--------------------------------------------------------------------------------
/plantilla-memoria/img/wrap-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/img/wrap-example.png
--------------------------------------------------------------------------------
/plantilla-memoria/memoria.bib:
--------------------------------------------------------------------------------
1 | % Bibliografía
2 |
3 | % Este fichero contiene la bibliografía de la memoria
4 | % Está en un formato que se conoce como BibTex.
5 | % Hay muchos sitios web que exportan referencias en formato BibTeX.
6 | % Prueba a buscar en http://scholar.google.com por referencias
7 | % y verás que lo puedes hacer de manera sencilla.
8 | % Más información:
9 | % http://texblog.org/2014/04/22/using-google-scholar-to-download-bibtex-citations/
10 |
11 | % Existen varias posibilidades para referenciar diferentes tipos de documentos,
12 | % ya que los datos necesarios varían. Así, existen formatos de entrada para
13 | % * libros (book)
14 | % * artículos en revistas de investigación (article)
15 | % * capítulos de libro (incollection)
16 | % * informes técnicos (techreport)
17 | % * otros (misc)
18 | %
19 | % Las páginas web deberían ir como misc.
20 |
21 | % Una última cosa: no referencias nunca la WikiPedia
22 | % La WikiPedia, como buena enciclopedia, no es fuente primaria.
23 | % Si acaso, busca por citas en la WikiPedia (que sí ha de referenciar fuentes
24 | % primarias) y haz referencia a las mismas.
25 |
26 | @Book{elasticsearch_book,
27 | author = {Clinton Gormley & Zachary Tong},
28 | title = {Elasticsearch - The Definitive Guide},
29 | publisher = {O'Reilly},
30 | year = 2015
31 | }
32 |
33 | @Misc{elasticsearch_doc,
34 | author = {Elasticsearch},
35 | title = {Elastic Stack and Product Documentation},
36 | note = {\\ https://www.elastic.co/guide/index.html}
37 | }
38 |
39 | @Book{kibana_book,
40 | author = {Bahaaldine Azarmi},
41 | title = {Learning Kibana 5.0},
42 | publisher = {Packt},
43 | year = 2017
44 | }
45 |
46 | @Misc{kibana_doc,
47 | author = {Kibana},
48 | title = {Kibana User Guide},
49 | note = {\\ https://www.elastic.co/guide/en/kibana/5.5/index.html}
50 | }
51 |
52 | @Book{javascript_book,
53 | author = {David Flanagan},
54 | title = {Javascript - The Definitive Guide},
55 | publisher = {O'Reilly},
56 | year = 2006
57 | }
58 |
59 | @Misc{javascript_doc,
60 | author = {Javascript},
61 | title = {MDN Web Docs},
62 | note = {\\ https://developer.mozilla.org/bm/docs/Web/JavaScript}
63 | }
64 |
65 | @Book{typescript_book,
66 | author = {Steve Fenton},
67 | title = {Pro Typescript},
68 | publisher = {Apress},
69 | year = 2017
70 | }
71 |
72 | @Misc{typescript_doc,
73 | author = {Typescript},
74 | title = {Typescript Documentation},
75 | note = {\\ https://www.typescriptlang.org/docs/home.html}
76 | }
77 |
78 | @Misc{chartjs_doc,
79 | author = {ChartJS},
80 | title = {ChartJS Documentation},
81 | note = {\\ http://www.chartjs.org/docs/latest/}
82 | }
83 |
84 | @Misc{bodybuilder_doc,
85 | author = {Bodybuilder},
86 | title = {Bodybuilder Documentation},
87 | note = {\\ http://bodybuilder.js.org/docs/}
88 | }
89 |
90 | @Misc{flexbox_doc,
91 | author = {CSS Reference},
92 | title = {Flexbox in CSS},
93 | note = {\\ http://cssreference.io/flexbox/}
94 | }
95 |
--------------------------------------------------------------------------------
/plantilla-memoria/memoria.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/memoria.pdf
--------------------------------------------------------------------------------
/plantilla-memoria/template.tex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/plantilla-memoria/template.tex
--------------------------------------------------------------------------------
/web/font-awesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/font-awesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/web/font-awesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/font-awesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/web/font-awesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/font-awesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/web/font-awesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/font-awesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/web/font-awesome/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/font-awesome/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/web/font-awesome/less/animated.less:
--------------------------------------------------------------------------------
1 | // Animated Icons
2 | // --------------------------
3 |
4 | .@{fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .@{fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/web/font-awesome/less/bordered-pulled.less:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em @fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .@{fa-css-prefix}-pull-left { float: left; }
11 | .@{fa-css-prefix}-pull-right { float: right; }
12 |
13 | .@{fa-css-prefix} {
14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .@{fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/web/font-awesome/less/core.less:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .@{fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/web/font-awesome/less/fixed-width.less:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .@{fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/web/font-awesome/less/font-awesome.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables.less";
7 | @import "mixins.less";
8 | @import "path.less";
9 | @import "core.less";
10 | @import "larger.less";
11 | @import "fixed-width.less";
12 | @import "list.less";
13 | @import "bordered-pulled.less";
14 | @import "animated.less";
15 | @import "rotated-flipped.less";
16 | @import "stacked.less";
17 | @import "icons.less";
18 | @import "screen-reader.less";
19 |
--------------------------------------------------------------------------------
/web/font-awesome/less/larger.less:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .@{fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .@{fa-css-prefix}-2x { font-size: 2em; }
11 | .@{fa-css-prefix}-3x { font-size: 3em; }
12 | .@{fa-css-prefix}-4x { font-size: 4em; }
13 | .@{fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/web/font-awesome/less/list.less:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: @fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .@{fa-css-prefix}-li {
11 | position: absolute;
12 | left: -@fa-li-width;
13 | width: @fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.@{fa-css-prefix}-lg {
17 | left: (-@fa-li-width + (4em / 14));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/web/font-awesome/less/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | .fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
14 | .fa-icon-rotate(@degrees, @rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
16 | -webkit-transform: rotate(@degrees);
17 | -ms-transform: rotate(@degrees);
18 | transform: rotate(@degrees);
19 | }
20 |
21 | .fa-icon-flip(@horiz, @vert, @rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
23 | -webkit-transform: scale(@horiz, @vert);
24 | -ms-transform: scale(@horiz, @vert);
25 | transform: scale(@horiz, @vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | .sr-only() {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | .sr-only-focusable() {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/web/font-awesome/less/path.less:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/web/font-awesome/less/rotated-flipped.less:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
7 |
8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .@{fa-css-prefix}-rotate-90,
15 | :root .@{fa-css-prefix}-rotate-180,
16 | :root .@{fa-css-prefix}-rotate-270,
17 | :root .@{fa-css-prefix}-flip-horizontal,
18 | :root .@{fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/web/font-awesome/less/screen-reader.less:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { .sr-only(); }
5 | .sr-only-focusable { .sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/web/font-awesome/less/spinning.less:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .@{fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | @-webkit-keyframes fa-spin {
10 | 0% {
11 | -webkit-transform: rotate(0deg);
12 | transform: rotate(0deg);
13 | }
14 | 100% {
15 | -webkit-transform: rotate(359deg);
16 | transform: rotate(359deg);
17 | }
18 | }
19 |
20 | @keyframes fa-spin {
21 | 0% {
22 | -webkit-transform: rotate(0deg);
23 | transform: rotate(0deg);
24 | }
25 | 100% {
26 | -webkit-transform: rotate(359deg);
27 | transform: rotate(359deg);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/web/font-awesome/less/stacked.less:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; }
21 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_animated.scss:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .#{$fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_bordered-pulled.scss:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em $fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .#{$fa-css-prefix}-pull-left { float: left; }
11 | .#{$fa-css-prefix}-pull-right { float: right; }
12 |
13 | .#{$fa-css-prefix} {
14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .#{$fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_fixed-width.scss:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .#{$fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_larger.scss:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .#{$fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .#{$fa-css-prefix}-2x { font-size: 2em; }
11 | .#{$fa-css-prefix}-3x { font-size: 3em; }
12 | .#{$fa-css-prefix}-4x { font-size: 4em; }
13 | .#{$fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_list.scss:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: $fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .#{$fa-css-prefix}-li {
11 | position: absolute;
12 | left: -$fa-li-width;
13 | width: $fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.#{$fa-css-prefix}-lg {
17 | left: -$fa-li-width + (4em / 14);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | @mixin fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
14 | @mixin fa-icon-rotate($degrees, $rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
16 | -webkit-transform: rotate($degrees);
17 | -ms-transform: rotate($degrees);
18 | transform: rotate($degrees);
19 | }
20 |
21 | @mixin fa-icon-flip($horiz, $vert, $rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
23 | -webkit-transform: scale($horiz, $vert);
24 | -ms-transform: scale($horiz, $vert);
25 | transform: scale($horiz, $vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | @mixin sr-only {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | @mixin sr-only-focusable {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_path.scss:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_rotated-flipped.scss:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); }
5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
7 |
8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .#{$fa-css-prefix}-rotate-90,
15 | :root .#{$fa-css-prefix}-rotate-180,
16 | :root .#{$fa-css-prefix}-rotate-270,
17 | :root .#{$fa-css-prefix}-flip-horizontal,
18 | :root .#{$fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_screen-reader.scss:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { @include sr-only(); }
5 | .sr-only-focusable { @include sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_spinning.scss:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | @-webkit-keyframes fa-spin {
10 | 0% {
11 | -webkit-transform: rotate(0deg);
12 | transform: rotate(0deg);
13 | }
14 | 100% {
15 | -webkit-transform: rotate(359deg);
16 | transform: rotate(359deg);
17 | }
18 | }
19 |
20 | @keyframes fa-spin {
21 | 0% {
22 | -webkit-transform: rotate(0deg);
23 | transform: rotate(0deg);
24 | }
25 | 100% {
26 | -webkit-transform: rotate(359deg);
27 | transform: rotate(359deg);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/_stacked.scss:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; }
21 |
--------------------------------------------------------------------------------
/web/font-awesome/scss/font-awesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables";
7 | @import "mixins";
8 | @import "path";
9 | @import "core";
10 | @import "larger";
11 | @import "fixed-width";
12 | @import "list";
13 | @import "bordered-pulled";
14 | @import "animated";
15 | @import "rotated-flipped";
16 | @import "stacked";
17 | @import "icons";
18 | @import "screen-reader";
19 |
--------------------------------------------------------------------------------
/web/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/web/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/web/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/web/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/web/img/bar-chart-lengend-filter-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/img/bar-chart-lengend-filter-example.png
--------------------------------------------------------------------------------
/web/img/dashboard-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/img/dashboard-example.png
--------------------------------------------------------------------------------
/web/img/data-table-multiaggregation-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/img/data-table-multiaggregation-calculation.png
--------------------------------------------------------------------------------
/web/img/fondo_principal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/img/fondo_principal.jpg
--------------------------------------------------------------------------------
/web/img/ismael.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/img/ismael.jpeg
--------------------------------------------------------------------------------
/web/img/metric-ranks-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/img/metric-ranks-calculation.png
--------------------------------------------------------------------------------
/web/img/pie-chart-calculation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/islimane/Angular-ElasticSearch-Dashboard_Interface/ae6fc4a88915bbb3695a5400def2b347c19d281f/web/img/pie-chart-calculation.png
--------------------------------------------------------------------------------
/web/js/grayscale.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Start Bootstrap - Grayscale Bootstrap Theme (http://startbootstrap.com)
3 | * Code licensed under the Apache License v2.0.
4 | * For details, see http://www.apache.org/licenses/LICENSE-2.0.
5 | */
6 |
7 | // jQuery to collapse the navbar on scroll
8 | $(window).scroll(function() {
9 | if ($(".navbar").offset().top > 50) {
10 | $(".navbar-fixed-top").addClass("top-nav-collapse");
11 | } else {
12 | $(".navbar-fixed-top").removeClass("top-nav-collapse");
13 | }
14 | });
15 |
16 | // jQuery for page scrolling feature - requires jQuery Easing plugin
17 | $(function() {
18 | $('a.page-scroll').bind('click', function(event) {
19 | var $anchor = $(this);
20 | $('html, body').stop().animate({
21 | scrollTop: $($anchor.attr('href')).offset().top
22 | }, 1500, 'easeInOutExpo');
23 | event.preventDefault();
24 | });
25 | });
26 |
27 | // Closes the Responsive Menu on Menu Item Click
28 | $('.navbar-collapse ul li a').click(function() {
29 | $('.navbar-toggle:visible').click();
30 | });
31 |
32 | // Google Maps Scripts
33 | // When the window has finished loading create our google map below
34 | google.maps.event.addDomListener(window, 'load', init);
35 |
36 | function init() {
37 | // Basic options for a simple Google Map
38 | // For more options see: https://developers.google.com/maps/documentation/javascript/reference#MapOptions
39 | var mapOptions = {
40 | // How zoomed in you want the map to start at (always required)
41 | zoom: 15,
42 |
43 | // The latitude and longitude to center the map (always required)
44 | center: new google.maps.LatLng(40.6700, -73.9400), // New York
45 |
46 | // Disables the default Google Maps UI components
47 | disableDefaultUI: true,
48 | scrollwheel: false,
49 | draggable: false,
50 |
51 | // How you would like to style the map.
52 | // This is where you would paste any style found on Snazzy Maps.
53 | styles: [{
54 | "featureType": "water",
55 | "elementType": "geometry",
56 | "stylers": [{
57 | "color": "#000000"
58 | }, {
59 | "lightness": 17
60 | }]
61 | }, {
62 | "featureType": "landscape",
63 | "elementType": "geometry",
64 | "stylers": [{
65 | "color": "#000000"
66 | }, {
67 | "lightness": 20
68 | }]
69 | }, {
70 | "featureType": "road.highway",
71 | "elementType": "geometry.fill",
72 | "stylers": [{
73 | "color": "#000000"
74 | }, {
75 | "lightness": 17
76 | }]
77 | }, {
78 | "featureType": "road.highway",
79 | "elementType": "geometry.stroke",
80 | "stylers": [{
81 | "color": "#000000"
82 | }, {
83 | "lightness": 29
84 | }, {
85 | "weight": 0.2
86 | }]
87 | }, {
88 | "featureType": "road.arterial",
89 | "elementType": "geometry",
90 | "stylers": [{
91 | "color": "#000000"
92 | }, {
93 | "lightness": 18
94 | }]
95 | }, {
96 | "featureType": "road.local",
97 | "elementType": "geometry",
98 | "stylers": [{
99 | "color": "#000000"
100 | }, {
101 | "lightness": 16
102 | }]
103 | }, {
104 | "featureType": "poi",
105 | "elementType": "geometry",
106 | "stylers": [{
107 | "color": "#000000"
108 | }, {
109 | "lightness": 21
110 | }]
111 | }, {
112 | "elementType": "labels.text.stroke",
113 | "stylers": [{
114 | "visibility": "on"
115 | }, {
116 | "color": "#000000"
117 | }, {
118 | "lightness": 16
119 | }]
120 | }, {
121 | "elementType": "labels.text.fill",
122 | "stylers": [{
123 | "saturation": 36
124 | }, {
125 | "color": "#000000"
126 | }, {
127 | "lightness": 40
128 | }]
129 | }, {
130 | "elementType": "labels.icon",
131 | "stylers": [{
132 | "visibility": "off"
133 | }]
134 | }, {
135 | "featureType": "transit",
136 | "elementType": "geometry",
137 | "stylers": [{
138 | "color": "#000000"
139 | }, {
140 | "lightness": 19
141 | }]
142 | }, {
143 | "featureType": "administrative",
144 | "elementType": "geometry.fill",
145 | "stylers": [{
146 | "color": "#000000"
147 | }, {
148 | "lightness": 20
149 | }]
150 | }, {
151 | "featureType": "administrative",
152 | "elementType": "geometry.stroke",
153 | "stylers": [{
154 | "color": "#000000"
155 | }, {
156 | "lightness": 17
157 | }, {
158 | "weight": 1.2
159 | }]
160 | }]
161 | };
162 |
163 | // Get the HTML DOM element that will contain your map
164 | // We are using a div with id="map" seen below in the
165 | var mapElement = document.getElementById('map');
166 |
167 | // Create the Google Map using out element and options defined above
168 | var map = new google.maps.Map(mapElement, mapOptions);
169 |
170 | // Custom Map Marker Icon - Customize the map-marker.png file to customize your icon
171 | var image = 'img/map-marker.png';
172 | var myLatLng = new google.maps.LatLng(40.6700, -73.9400);
173 | var beachMarker = new google.maps.Marker({
174 | position: myLatLng,
175 | map: map,
176 | icon: image
177 | });
178 | }
179 |
--------------------------------------------------------------------------------
/web/js/jquery.easing.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
3 | *
4 | * Uses the built in easing capabilities added In jQuery 1.1
5 | * to offer multiple easing options
6 | *
7 | * TERMS OF USE - EASING EQUATIONS
8 | *
9 | * Open source under the BSD License.
10 | *
11 | * Copyright © 2001 Robert Penner
12 | * All rights reserved.
13 | *
14 | * TERMS OF USE - jQuery Easing
15 | *
16 | * Open source under the BSD License.
17 | *
18 | * Copyright © 2008 George McGinley Smith
19 | * All rights reserved.
20 | *
21 | * Redistribution and use in source and binary forms, with or without modification,
22 | * are permitted provided that the following conditions are met:
23 | *
24 | * Redistributions of source code must retain the above copyright notice, this list of
25 | * conditions and the following disclaimer.
26 | * Redistributions in binary form must reproduce the above copyright notice, this list
27 | * of conditions and the following disclaimer in the documentation and/or other materials
28 | * provided with the distribution.
29 | *
30 | * Neither the name of the author nor the names of contributors may be used to endorse
31 | * or promote products derived from this software without specific prior written permission.
32 | *
33 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
34 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
35 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
36 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
37 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
38 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
39 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 | * OF THE POSSIBILITY OF SUCH DAMAGE.
42 | *
43 | */
44 | jQuery.easing.jswing=jQuery.easing.swing;jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(e,f,a,h,g){return jQuery.easing[jQuery.easing.def](e,f,a,h,g)},easeInQuad:function(e,f,a,h,g){return h*(f/=g)*f+a},easeOutQuad:function(e,f,a,h,g){return -h*(f/=g)*(f-2)+a},easeInOutQuad:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f+a}return -h/2*((--f)*(f-2)-1)+a},easeInCubic:function(e,f,a,h,g){return h*(f/=g)*f*f+a},easeOutCubic:function(e,f,a,h,g){return h*((f=f/g-1)*f*f+1)+a},easeInOutCubic:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f+a}return h/2*((f-=2)*f*f+2)+a},easeInQuart:function(e,f,a,h,g){return h*(f/=g)*f*f*f+a},easeOutQuart:function(e,f,a,h,g){return -h*((f=f/g-1)*f*f*f-1)+a},easeInOutQuart:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f+a}return -h/2*((f-=2)*f*f*f-2)+a},easeInQuint:function(e,f,a,h,g){return h*(f/=g)*f*f*f*f+a},easeOutQuint:function(e,f,a,h,g){return h*((f=f/g-1)*f*f*f*f+1)+a},easeInOutQuint:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f*f+a}return h/2*((f-=2)*f*f*f*f+2)+a},easeInSine:function(e,f,a,h,g){return -h*Math.cos(f/g*(Math.PI/2))+h+a},easeOutSine:function(e,f,a,h,g){return h*Math.sin(f/g*(Math.PI/2))+a},easeInOutSine:function(e,f,a,h,g){return -h/2*(Math.cos(Math.PI*f/g)-1)+a},easeInExpo:function(e,f,a,h,g){return(f==0)?a:h*Math.pow(2,10*(f/g-1))+a},easeOutExpo:function(e,f,a,h,g){return(f==g)?a+h:h*(-Math.pow(2,-10*f/g)+1)+a},easeInOutExpo:function(e,f,a,h,g){if(f==0){return a}if(f==g){return a+h}if((f/=g/2)<1){return h/2*Math.pow(2,10*(f-1))+a}return h/2*(-Math.pow(2,-10*--f)+2)+a},easeInCirc:function(e,f,a,h,g){return -h*(Math.sqrt(1-(f/=g)*f)-1)+a},easeOutCirc:function(e,f,a,h,g){return h*Math.sqrt(1-(f=f/g-1)*f)+a},easeInOutCirc:function(e,f,a,h,g){if((f/=g/2)<1){return -h/2*(Math.sqrt(1-f*f)-1)+a}return h/2*(Math.sqrt(1-(f-=2)*f)+1)+a},easeInElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g