periscope-ui
Version:
Perscope default set of widget/dashboard implementations
727 lines (609 loc) • 19.4 kB
JavaScript
import * as _ from 'lodash';
import $ from 'jquery';
import {useView,Container,Decorators,bindable,computedFrom,bindingMode} from 'aurelia-framework';
import {DashboardBase,PermissionsCustomAttribute,StringHelper,IntellisenceManager,GrammarTree,SearchBox,ExpressionParser,Datasource,SwaggerSchemaProvider,DataSourceConfigurator,DrillDownBehaviorConfiguration} from 'periscope-framework';
import {ValidationEngine,Validator} from 'aurelia-validatejs';
export class BootstrapDashboard extends DashboardBase {
constructor(name) {
super(name);
this.widgetBaseHeight = 70;
this.layoutStructure = [];
this.currentUrl = "";
}
replaceWidget(oldWidget, newWidget, callback){
super.replaceWidget(oldWidget, newWidget, callback);
this.layoutStructure = this.createLayoutStructure(this.layout);
}
restoreWidget(currentWidget){
super.restoreWidget(currentWidget);
this.layoutStructure = this.createLayoutStructure(this.layout);
}
addWidget(widget, dimensions){
super.addWidget(widget, dimensions);
this.layoutStructure =this.createLayoutStructure(this.layout);
}
removeWidget(widget){
super.removeWidget(widget);
this.layoutStructure = this.createLayoutStructure(this.layout);
}
resizeWidget(widget, dimensions){
super.resizeWidget(widget, dimensions);
this.layoutStructure = this.createLayoutStructure(this.layout);
}
attached(){
//this.layoutStructure = this.createLayoutStructure(this.layout);
}
createLayoutStructure(layout){
// sort widgets by row
var sortedWidgets = _.sortBy(layout, function(w) { return w.row; });
var result = [];
_.forOwn(_.groupBy(sortedWidgets, 'row'), (v, k)=>{
// sort widgets by col
var sortedByCol = _.sortBy(v, function(w) { return w.col; });
result.push({
row: k,
widgets: sortedByCol
});
});
return result;
}
getColWidth(layoutWidget){
if (layoutWidget.sizeX==="*") {
var totalX = _.sumBy(this.layout, x => {
if ((typeof(x.sizeX)==='number')&&(x.row==layoutWidget.row))
return x.sizeX;
});
var x = 12 - (totalX - (Math.floor(totalX / 12)*12));
return "col-md-" + (x!=0?x:12);
}
return "col-md-" + (layoutWidget.sizeX);
}
getColHeight(layoutWidget){
var result = "";
if (layoutWidget.sizeY==="*") { // stretch down to the screen bottom
// sum all elemets with predefined height
var totalHeight = _.sumBy(this.layout, x => {
if ((typeof(x.sizeY)==='number')&&(layoutWidget.row!==x.row))
return x.sizeY * this.widgetBaseHeight;
});
result = ($('#dashboard')[0].clientHeight - totalHeight);
}
else{
if (layoutWidget.sizeY>0)
result = layoutWidget.sizeY * this.widgetBaseHeight;
}
this.setWidgetHeight(layoutWidget, result);
return "height: " + result + "px;";
}
setWidgetHeight(layoutWidget, containerHeight){
if (layoutWidget.widget.showHeader)
layoutWidget.widget.minHeight = containerHeight-71;
else
layoutWidget.widget.minHeight = containerHeight-31;
}
openPopup() {
$(this.popWidgetHost).modal('show');
}
share(){
this.currentUrl = super.getRoute();
$(this.popupShare).modal('show');
//$(this.shareUrlInput).select();
}
}
import {DetailedView, Query} from 'periscope-framework'
export class DefaultDetailedView extends DetailedView {
constructor(settings) {
super(settings);
}
get data(){
return this._data;
}
set data(value){
this._data = value;
}
get viewFields() {
var result = []
if (!this.data)
return result;
if (this.fields) {
result = _.map(this.fields, c=>{
return {
name: c.title ? c.title : c.field,
value: this.data[c.field]
}
})
}
else {
_.forOwn(this.data, (v, k)=>{
result.push({
name: k,
value: v
});
})
}
return result;
}
refresh(){
let q = new Query();
q.take = 1;
q.skip = 0;
q.filter = this.dataFilter;
this.dataSource.getData(q).then(dH=>{
if (dH.data.length>0)
this.data = dH.data[0];
})
}
}
export class DefaultSearchBox extends SearchBox {
constructor(settings){
super(settings);
this._isValid = true;
this._caretPosition = 0;
this._separators = [" ",","];
this._specialSymbols= ["'","(",")","\""];
this._timer;
this._suggestionsListSettings = {
title:'',
suggestions:[],
focusedSuggestion: -1,
displaySuggestions: false,
lastWord: ''
}
}
get parser (){
return this._parser;
}
set parser(value){
this._parser = value;
}
get expressionManager (){
return this._expressionManager;
}
set expressionManager(value){
this._expressionManager = value;
}
get selectedSuggestion (){
return this._selectedSuggestion;
}
set selectedSuggestion (value){
if (this._selectedSuggestion != value) {
this._selectedSuggestion = value;
this.select(this._selectedSuggestion)
}
}
get suggestionsListSettings(){
return this._suggestionsListSettings;
}
set suggestionsListSettings(value){
this._suggestionsListSettings = value;
}
get isValid() {
if ((this.searchString==='')||(!this.parser))
return true;
return this.parser.validate(this.searchString);
}
refresh(){
super.refresh();
var self = this;
this.dataSource.transport.readService.getSchema().then(schema=>{
let allFields = _.map(schema.fields,"field");
//let grammar = new GrammarExpression(schema.fields);
let grammar = new GrammarTree(schema.fields);
self.parser = new ExpressionParser(grammar.getGrammar());
self.expressionManager = new IntellisenceManager(self.parser, self.dataSource, allFields);
self.restoreState();
if (self.state)
self.suggestionsListSettings.displaySuggestions = false;
});
}
get searchString(){
return this._searchString;
}
set searchString(value){
if (this._searchString != value) {
this._searchString = value;
this.populateSuggestions(value);
if (this.isValid) {
this.notifySearchCriteriaChanged();
}
}
}
get caretPosition(){
return this._caretPosition;
}
set caretPosition(value){
//$(this.searchBox)[0].selectionStart = value;
//$(this.searchBox)[0].selectionEnd = value;
if (value != this._caretPosition) {
var self = this;
self._caretPosition = value;
$(self.searchBox)[0].focus();
window.setTimeout(()=> {
$(self.searchBox)[0].setSelectionRange(value, value);
}, 400);
}
}
attached(){
var self = this;
$(this.searchBox)[0].addEventListener("keydown", function (e) {
if (e.keyCode==40) {
self.suggestionsListSettings.focusedSuggestion = 0;
e.preventDefault();
e.stopPropagation();
}
else {
self.suggestionsListSettings.focusedSuggestion = -1;
self._caretPosition = this.selectionEnd + 1;
}
if ((e.keyCode == 27)||(e.keyCode == 13)){ //escape
self.suggestionsListSettings.displaySuggestions = false;
}
}, true);
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
}
populateSuggestions(searchStr){
searchStr = searchStr.substring(0, this.caretPosition);
var lastWord = this.getLastWord(searchStr)
this.suggestionsListSettings.title = '';
this.expressionManager.populate(searchStr, lastWord).then(data=>{
this.suggestionsListSettings.suggestions = data;
this.suggestionsListSettings.lastWord = lastWord;
this.suggestionsListSettings.displaySuggestions = this.suggestionsListSettings.suggestions.length > 0;
});
}
select(suggestion){
var searchStr = this.searchString;
var position = this.caretPosition;
while ((position<searchStr.length)&&(searchStr[position]!=" ")){
position++;
}
var strLeft = searchStr.substring(0, position);
var strRight = position < searchStr.length? searchStr.substring(position, searchStr.length) : '';
var wordToReplace = this.getLastWord(searchStr);
strLeft = strLeft.substring(0,strLeft.lastIndexOf(wordToReplace));
var value = suggestion.value;
if ((suggestion.type==='string')||(suggestion.type==='array_string'))
value = "'" + value + "'";
if (suggestion.type==='array_string') {
// seatch for opening brace
var openBraceExsits = false;
for (let i=strLeft.trim().length;i>=0;i--){
if (strLeft[i]==="(") {
openBraceExsits = true;
break;
}
if (strLeft[i]===")")
break;
}
if (!openBraceExsits)
value = "(" + value;
else {
var lastChar = strLeft.trim().charAt(strLeft.trim().length - 1);
if ((lastChar !== '(') && (lastChar !== ','))
value = "," + value;
}
}
if ((suggestion.type==='operator')&&(suggestion.value==='in'))
value += " (";
else
value += " ";
this.caretPosition = (strLeft + value).length;
this.searchString = strLeft + value + strRight;
}
getLastWord(searchStr){
var str = StringHelper.getPreviousWord(searchStr,this.caretPosition,this._separators);
for (let s of this._specialSymbols)
str = StringHelper.replaceAll(str, "\\" + s,"");
return str.trim();
}
notifySearchCriteriaChanged() {
this.saveState();
var self = this;
window.clearTimeout(self._timer);
self._timer = window.setTimeout(function () {
if (self.isValid) {
let astTree;
if (self.searchString!=='')
astTree = self.parser.parse(self.searchString)
self.dataFilterChanged.raise(astTree);
}
}, 500);
}
}
import Swagger from "swagger-client"
export class SwaggerDataSourceConfigurator extends DataSourceConfigurator {
constructor(settings){
super(settings);
this.definitionUrl = settings.definitionsUrl.trim();
this._initSwaggerClient(this.definitionUrl);
}
get client(){
return this._client;
}
set client (value){
this._client = value;
}
get definitionUrl(){
return this._definitionUrl;
}
set definitionUrl(value){
this._definitionUrl = value;
}
get apis(){
if (this.client)
return _.map(this.client.apisArray,'name');
else
return [];
}
get methods(){
if (this.client && this.api){
let m = []
_.forOwn(this.client.apis[this.api].apis, a=>{
if (a.method.toLowerCase() === "get")
m.push(a.nickname);
})
return m;
}
else
return [];
}
get parameters(){
if (this.client && this.method && this.api){
return this.client.apis[this.api].apis[this.method].parameters;
}
else
return [];
}
set parameters(value){
this._parameters = value;
}
get api(){
return this._api;
}
set api(value){
this._api = value;
}
get method(){
return this._method;
}
set method(value){
this._method = value;
}
submit(){
if (!this.dataSourceToConfigurate)
throw "dataSourceToConfigurate is not provided";
let ds = this.dataSourceToConfigurate;
let url = this.client.scheme + "://" + this.client.host + this.client.basePath + this.client.apis[this.api].apis[this.method].path;
let queryParams = _.map(_.filter(this.parameters, x=>{ return (x.value && x.in == "query")} ), p=>{
if (p.value)
return p.name + "=" + p.value
});
let definitionModelName;
let responseDef = this.client[this.api].apis[this.method].successResponse["200"].definition;
if (responseDef.type === "array") {
if (responseDef.items.$ref.indexOf('#/definitions/') === 0) {
if (this.client.definitions[responseDef.items.$ref.substring('#/definitions/'.length)])
definitionModelName = this.client.definitions[responseDef.items.$ref.substring('#/definitions/'.length)].name;
}
}
else if (responseDef.name){
definitionModelName = responseDef.name;
}
_.forEach(_.filter(this.parameters, x=>{ return (x.value && x.in == "path")}), pathParam=>{
url = url.replace("{" + pathParam.name + "}", pathParam.value);
})
if (queryParams.length>0)
url = url + "?" + queryParams.join("&");
ds.transport.readService.configure({
url: url,
schemaProvider: new SwaggerSchemaProvider(this.definitionUrl, this.api, this.method, definitionModelName)
});
this.dataSourceChanged.raise(ds);
}
_initSwaggerClient(url){
return new Swagger({
url: url,
usePromise: true}).then(client => {
this.client = client;
})
}
}
export class GridMenu {
constructor(widget){
this.widget = widget;
this.drillDownModel = new DrillDownModel();
this.drillDownBehavior = this.getDrillDownBehavior();
this.availableParams = [];
if (this.drillDownBehavior){
this.drillDownModel.query = this.drillDownBehavior.queryPattern;
this.drillDownModel.url = this.drillDownBehavior.dataServiceUrl;
this.drillDownModel.username = this.drillDownBehavior.username;
this.drillDownModel.password = this.drillDownBehavior.password;
}
this.widget.dataSource.transport.readService.getSchema().then(schema=> {
this.availableParams = _.map(schema.fields, f=> {
return "@" + f.field;
});
});
this.validator = new Validator(this.drillDownModel)
.ensure('url')
.url()
.required()
.ensure('query')
.required();
this.reporter = ValidationEngine.getValidationReporter(this.drillDownModel);
this.subscriber = this.reporter.subscribe(result => {
this.renderErrors(result);
});
}
errors = [];
drillDownModel;
drillDownBehavior;
widget;
validator;
get showDrillDownButton(){
let result = false;
if (!this.drillDownBehavior)
return result;
_.forEach(this.widget.dashboard.behaviors,behavior=>{
if ((behavior)&&(behavior.constructor)&&(behavior.constructor.name === "DrillDownHandleBehavior")){
result = true;
}
})
return result;
}
hasErrors() {
return !!this.errors.length;
}
renderErrors(result) {
this.errors.splice(0, this.errors.length);
result.forEach(error => {
this.errors.push(error)
});
}
closePopup(){
$(this.popupDrilldown).modal('hide');
}
openPopup(){
$("body").append($(this.popupDrilldown));
$(this.popupDrilldown).modal('show');
}
save(){
this.validator.validate();
if (!this.hasErrors()) {
let configuration = new DrillDownBehaviorConfiguration()
configuration.queryPattern = this.drillDownModel.query;
configuration.dataServiceUrl = this.drillDownModel.url;
configuration.password = this.drillDownModel.password;
configuration.username = this.drillDownModel.username;
this.drillDownBehavior.configure(configuration);
this.closePopup();
}
}
getDrillDownBehavior(){
let result;
_.forEach(this.widget.behaviors, behavior=>{
if ((behavior)&&(behavior.constructor)&&(behavior.constructor.name === "DrillDownBehavior")){
result = behavior;
}
});
return result;
}
}
export class DrillDownModel {
url;
username;
password;
query;
}
export class List {
items = null;
title = "";
highlightText = "";
visible;
selectedItem;
focusedItemIndex;
constrictor(){
}
//itemsChanged(newValue, oldValue)
attached(params){
var self = this;
$("body").on( "click", function(args) {
if (($(args.target).parents(".list-view").length>0)||($(args.target).hasClass("list-view"))) //do not close when user clicks on the list-view
return;
self.visible = false;
});
if ($('.list-container').length===0)
return;
$('.list-container')[0].addEventListener("keydown", function (e) {
// Listen for the up, down arrow keys, otherwise, end here
/*if ([13, 38, 40].indexOf(e.keyCode) == -1) {
return;
}*/
// Store the reference to our top level link
var container = $(this);
if (container.find('li').length===0)
return;
switch (e.keyCode) {
case 38: /// up arrow
if (container.find('li').filter('.focused-item').length===0) {
self.focusedItemIndex = container.find('li').length-1;
}
else{
let previousIndex = self.focusedItemIndex - 1;
if (previousIndex < 0)
previousIndex = container.find('li').length-1;
self.focusedItemIndex = previousIndex;
}
break;
case 40: // down arrow
if (container.find('li').filter('.focused-item').length===0) {
self.focusedItemIndex = 0;
}
else{
let nextIndex = self.focusedItemIndex + 1;
if (nextIndex >= container.find('li').length)
nextIndex = 0;
self.focusedItemIndex = nextIndex;
}
break;
case 13: // enter
if (self.focusedItemIndex>=0) {
self.select(self.focusedItemIndex);
}
break;
case 27: //escape
self.visible = false;
break;
}
e.preventDefault();
e.stopPropagation();
});
}
format(itemText){
if ((this.highlightText!=='')&&(itemText)&&(itemText.toLowerCase().indexOf(this.highlightText.toLowerCase())>=0)) {
var regex = new RegExp(this.highlightText, 'i');
return itemText.replace(regex, '<b>$&</b>');
}
return itemText
}
select (itemIndex){
this.selectedItem = this.items[itemIndex];
this.focusedItemIndex = -1;
}
focusedItemIndexChanged(newValue, oldValue) {
if (this.focusedItemIndex!=undefined) {
if (this.focusedItemIndex >= 0)
this.setFocus(this.focusedItemIndex);
else
this.clearFocus();
}
}
setFocus(itemIndex) {
var container = $(this.listViewContainer);
if (container.find('li').length===0)
return;
container.find('li').filter('.focused-item').removeClass("focused-item");
$(container.find('li')[itemIndex]).addClass("focused-item");
$(container.find('li')[itemIndex]).find('button').first().focus();
}
clearFocus() {
var container = $(this.listViewContainer);
if (container.find('li').filter('.focused-item').length===0)
return;
container.find('li').filter('.focused-item').first().find('button').first().blur();
container.find('li').filter('.focused-item').removeClass("focused-item");
}
}
export class WidgetMenu {
widget = {};
content;
widgetChanged(oldVal, newVal) {
if (Object.getPrototypeOf(this.widget.constructor).name==="Grid")
this.content = new GridMenu(this.widget);
}
}