diff --git a/beat/web/reports/migrations/0004_auto_20170410_1121.py b/beat/web/reports/migrations/0004_auto_20170410_1121.py new file mode 100644 index 0000000000000000000000000000000000000000..aae102538b57fe7639effcecd329e7809d7b2515 --- /dev/null +++ b/beat/web/reports/migrations/0004_auto_20170410_1121.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.5 on 2017-04-10 11:21 +from __future__ import unicode_literals + +from django.db import migrations +import json +import re + +def parse_table(table, precision): + conv_table = { + 'fields': ['Experiment'], + 'precision': precision + } + + for row in table: + name = row['name'] + name = re.sub(r'\[.*\]$', '', name) + + if name == 'experiment': + continue + + if name == 'experiment.execution_time' or name == 'execution_time': + name = 'total_execution_time' + elif re.match(r'^execution_time\.', name): + name = re.sub(r'execution_time', 'linear_execution_time', name) + + if name.startswith('experiment.'): + name = re.sub(r'experiment\.', '', name) + + if '.' in name: + segs = name.split('.') + name = segs[1] + '.' + segs[0] + conv_table['fields'].append(name) + + return conv_table + +def parse_plot(plot): + conv_plot = { + 'name': plot['data']['output'][0], + 'type': plot['required_plotter'][0] + } + return conv_plot + +def experiment_fullname(exp): + return '%s/%s/%s/%s/%s' % (exp.author.username, exp.toolchain.author.username, exp.toolchain.name, exp.toolchain.version, exp.name) + +def analyzer_fullname(report): + return '%s/%s/%s' % (report.analyzer.author.username, report.analyzer.name, report.analyzer.version) + +def move_content_to_groups_format(apps, schema_editor): + Report = apps.get_model('reports', 'Report') + + for report in Report.objects.all(): + report_content = json.loads(report.content) + # convert to groups format + if 'groups' not in report_content: + exps = report.experiments.all() + # groups: { + # group1 : { + # experiments: [], + # reportItems: [], + # analyzer: '', + # aliases: {}, + # idx: 1 + # }, + # ... + # } + obj = {} + groups = {} + group1 = { + 'experiments': [ experiment_fullname(e) for e in exps ], + 'reportItems': [], + 'analyzer': analyzer_fullname(report) if report.analyzer else '', + 'aliases': {}, + 'idx': 1 + } + for e in exps: + group1['aliases'][experiment_fullname(e)] = e.name + + count_tables = 0 + count_plots = 0 + for item_name in report_content: + if item_name == 'floating_point_precision' or item_name == 'alias_experiments': + continue + + item = report_content[item_name] + item_type = 'table' if item_name.startswith('table') else 'plot' + fpp = report_content['floating_point_precision'] if 'floating_point_precision' in report_content else 10 + + converted_content = parse_table(item, fpp) if item_type == 'table' else parse_plot(item) + + converted_id = '' + if item_type == 'table': + converted_id = 'table_' + str(count_tables) + count_tables += 1 + else: + converted_id = 'plot_' + str(count_plots) + count_plots += 1 + + converted_item = { + 'id': converted_id, + 'content': converted_content + } + + group1['reportItems'].append(converted_item) + + groups['group1'] = group1 + obj['groups'] = groups + report.content = json.dumps(obj) + report.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('reports', '0003_report_last_edited_date'), + ] + + operations = [ + migrations.RunPython(move_content_to_groups_format) + ] diff --git a/beat/web/reports/static/reports/app/controllers/groupsController.js b/beat/web/reports/static/reports/app/controllers/groupsController.js index 7a0c4bdd0e71ce9cd511512a8809adaced430b0e..e7432840f60395a92caea6fe40a4c80c753b2a7d 100644 --- a/beat/web/reports/static/reports/app/controllers/groupsController.js +++ b/beat/web/reports/static/reports/app/controllers/groupsController.js @@ -23,9 +23,9 @@ /* * GroupsController * provides access to the groups data to Django templates, - * mostly used for handling the removal of experiments from the report + * used for handling the removal of experiments from the report */ -angular.module('reportApp').controller('GroupsController', ['$scope', '$http', 'GroupsService', 'UrlService', function ($scope, $http, GroupsService, UrlService){ +angular.module('reportApp').controller('GroupsController', ['$http', 'UrlService', function ($http, UrlService){ let vm = this; vm.expNamesToRemove = []; diff --git a/beat/web/reports/static/reports/app/controllers/reportController.js b/beat/web/reports/static/reports/app/controllers/reportController.js index bd6a268937dca172534f8827a572649cc877a0ec..2c4700588265357f3fc37a4666a76d2c0445e3c3 100644 --- a/beat/web/reports/static/reports/app/controllers/reportController.js +++ b/beat/web/reports/static/reports/app/controllers/reportController.js @@ -19,10 +19,15 @@ * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. */ -//This controller retrieves data from the reportFactory/experimentFactory through the REST API and associates it with the $scope -//The $scope is ultimately bound to the report view -angular.module('reportApp').controller('reportController',['$scope', 'reportFactory', 'experimentFactory', 'plotterFactory', 'dataFactory', '$q', 'GroupsService', 'ExperimentsService', function ($scope, reportFactory, experimentFactory, plotterFactory, dataFactory, $q, GroupsService, ExperimentsService){ - $scope.q = $q; + +/* reportController + * + * This controller retrieves data from the reportFactory/experimentFactory through the REST API and associates it with the $scope. + * The $scope is ultimately bound to the report view. + * + * This controller is "deprecated" - it needs to be completely removed, and should not be expanded/built upon. + */ +angular.module('reportApp').controller('reportController',['$scope', 'reportFactory', 'ReportService', function ($scope, reportFactory, ReportService){ $scope.user; $scope.report_id; $scope.url_prefix; @@ -35,375 +40,14 @@ angular.module('reportApp').controller('reportController',['$scope', 'reportFact $scope.table_item_content = []; $scope.selectedObject = {}; - $scope.tables_details = {}; - $scope.plots_details = {}; - $scope.report_experiments_blocks = {}; - $scope.report_experiments_blocks_merged_blocks = []; - $scope.report_experiments_blocks_computation_times = {}; - - $scope.report_experiments_alias = {}; - $scope.report_experiments_alias_from_content = {}; - $scope.floating_point_precision = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - $scope.floating_point_precision.selected = 10; - $scope.report_algorithm_parameters = {}; - $scope.report_algorithm_parameters_experiment = {}; - $scope.sorted_tables = []; //tables that were sorted - $scope.sorted_experiments_keys_tables = {}; - $scope.sorted_experiments_alias_keys_tables = {}; - $scope.sorted_experiments_keys_reverse = {}; - $scope.sorted_experiments_keys_tables_sortkey = {}; - - $scope.init = function(user, report_id, url_prefix, data_itemcontent_file, data_table_itemcontent_file){ + $scope.init = function(user, report_id, url_prefix){ $scope.user = user; $scope.report_id = report_id; $scope.url_prefix = url_prefix; - getReportData($scope.user, $scope.report_id); - $scope.item_content = dataFactory.getData(data_itemcontent_file); - $scope.table_item_content = dataFactory.getData(data_table_itemcontent_file); }; - $scope.initWithReportNumber = function(report_number, url_prefix, data_itemcontent_file, data_table_itemcontent_file){ + $scope.initWithReportNumber = function(report_number, url_prefix){ $scope.report_number = report_number; $scope.url_prefix = url_prefix; - getReportDataFromNumber($scope.report_number); - $scope.item_content = dataFactory.getData(data_itemcontent_file); - $scope.table_item_content = dataFactory.getData(data_table_itemcontent_file); }; - - // saves a data object to an different object by iterating through - // the data obj's entries and assigning them one-by-one. - // Why? JS is pass-by-value, but complex datatypes (Objects, arrays, funcs) are pointers. - // Angular depends on these pointers in two-way bindings of complex datatypes. - // If one assigns a different obj, the two-way binding is lost! - function mutateSave(saveObj, dataObj){ - let t = typeof(dataObj); - - if (t === 'object' && saveObj) { - Object.entries(dataObj) - .forEach(([key, val]) => { - saveObj[key] = val; - }); - } else if (t === 'array' && typeof(saveObj) === 'array') { - saveObj.length = 0; - dataObj.forEach(e => saveObj.push(e)); - } - } - - // saves the report data from the API to the $scope - function saveReportData(reportData){ - mutateSave($scope.report, reportData); - - $scope.report.url_prefix = $scope.url_prefix; - - if($scope.report.content.alias_experiments != undefined){ - mutateSave($scope.report_experiments_alias, $scope.report.content.alias_experiments); - } - - // save groups data to the model - GroupsService.loadGroups($scope.report.content.groups); - const isEditable = $scope.report.is_owner && $scope.report.status === 'editable'; - GroupsService.setEditable(isEditable); - } - - function getReportData(user, report_id){ - reportFactory.getReportInformation(user, report_id, $scope.url_prefix) - .success(function (reportData){ - saveReportData(reportData); - let promises = []; - - function lastTask(){ - getPlotters(); - } - - let experiments = $scope.report.experiments; - if(experiments != undefined){ - promises.push(getExperimentDataForAuthor(experiments)); - $scope.q.all(promises).then(lastTask); - } - }) - .error(function (error){ - $scope.status = 'Unable to load report data: ' + error.message; - }); - - $('#tabs_progress').hide(); - } - - function getReportDataFromNumber(report_number, $q){ - reportFactory.getReportInformationFromNumber(report_number, $scope.url_prefix) - .success(function (reportData){ - saveReportData(reportData); - let promises = []; - - function lastTask(){ - getPlotters(); - } - - let experiments = $scope.report.experiments; - if(experiments != undefined){ - promises.push(getExperimentDataReportNumber(report_number)); - $scope.q.all(promises).then(lastTask); - } - }) - .error(function (error){ - $scope.status = 'Unable to load report data: ' + error.message; - }); - - $('#tabs_progress').hide(); - } - - function getExperimentDataReportNumber(report_number){ - ExperimentsService.loadExperiments($scope.url_prefix, report_number); - experimentFactory.getAllExperimentResults($scope.url_prefix, report_number) - .then(function (experiments){ - mutateSave($scope.report_experiments, experiments); - - $scope.report.all_experiments = experiments; - let experiment_aliases = Object.keys(experiments); - for(let i = 0; i < experiment_aliases.length; i++){ - let experiment_alias = experiment_aliases[i]; - - if($scope.report.content.alias_experiments != undefined){ - if($scope.report.content.alias_experiments[experiment_alias] != undefined){ - setExperimentAliasFromContent(experiment_alias, $scope.report.content.alias_experiments[experiment_alias]); - } - else{ - setExperimentAlias(experiment_alias); - } - } - else{ - setExperimentAlias(experiment_alias); - } - intersectBlocks(experiment_alias); - algorithmParameters(experiment_alias); - } - //sort experiments in case it's sorted - if(!(jQuery.isEmptyObject($scope.report.content.sorted_tables_experiments)) && - !(jQuery.isEmptyObject($scope.report.content.sorted_tables_alias_experiments)) && - !(jQuery.isEmptyObject($scope.report.content.sorted_tables_keys_reverse)) && - !(jQuery.isEmptyObject($scope.report.content.sorted_tables_sortkey))){ - $scope.sorted_experiments_keys_tables = $scope.report.content.sorted_tables_experiments; - if($scope.report.status == "locked"){ - //special case for locked reports - $scope.sorted_experiments_keys_tables = $scope.report.content.sorted_tables_alias_experiments; - } - $scope.sorted_experiments_alias_keys_tables = $scope.report.content.sorted_tables_alias_experiments; - $scope.sorted_experiments_keys_reverse = $scope.report.content.sorted_tables_keys_reverse; - $scope.sorted_experiments_keys_tables_sortkey = $scope.report.content.sorted_tables_sortkey; - } - for(let i = 0; i < Object.keys($scope.sorted_experiments_keys_tables_sortkey).length; i++){ - $scope.sorted_tables.push(Object.keys($scope.sorted_experiments_keys_tables_sortkey)[i]); - } - }); - } - - function getExperimentDataForAuthor(all_experiments){ - ExperimentsService.loadExperiments($scope.user, $scope.report_id, $scope.url_prefix); - experimentFactory.getAllExperimentResultsForAuthor($scope.user, $scope.report_id, $scope.url_prefix) - .then(function (experiments){ - mutateSave($scope.report_experiments, experiments); - - $scope.report.all_experiments = experiments; - let experiment_aliases = Object.keys(experiments); - for(let i = 0; i < experiment_aliases.length; i++){ - let experiment_alias = experiment_aliases[i]; - - if($scope.report.content.alias_experiments != undefined){ - if($scope.report.content.alias_experiments[experiment_alias] != undefined){ - setExperimentAliasFromContent(experiment_alias, $scope.report.content.alias_experiments[experiment_alias]); - } - else{ - setExperimentAlias(experiment_alias); - } - } - else{ - setExperimentAlias(experiment_alias); - } - intersectBlocks(experiment_alias); - algorithmParameters(experiment_alias); - } - - //sort experiments in case it's sorted - if(!(jQuery.isEmptyObject($scope.report.content.sorted_tables_experiments)) && - !(jQuery.isEmptyObject($scope.report.content.sorted_tables_alias_experiments)) && - !(jQuery.isEmptyObject($scope.report.content.sorted_tables_keys_reverse)) && - !(jQuery.isEmptyObject($scope.report.content.sorted_tables_sortkey))){ - $scope.sorted_experiments_keys_tables = $scope.report.content.sorted_tables_experiments; - if($scope.report.status == "locked"){ - //special case for locked reports - $scope.sorted_experiments_keys_tables = $scope.report.content.sorted_tables_alias_experiments; - } - $scope.sorted_experiments_alias_keys_tables = $scope.report.content.sorted_tables_alias_experiments; - $scope.sorted_experiments_keys_reverse = $scope.report.content.sorted_tables_keys_reverse; - $scope.sorted_experiments_keys_tables_sortkey = $scope.report.content.sorted_tables_sortkey; - } - for(let i = 0; i < Object.keys($scope.sorted_experiments_keys_tables_sortkey).length; i++){ - $scope.sorted_tables.push(Object.keys($scope.sorted_experiments_keys_tables_sortkey)[i]); - } - - }); - } - - function getExperimentData(experiment_id){ - experimentFactory.getExperimentInformation($scope.url_prefix, experiment_id) - .then(function (experimentData){ - let experiments = $scope.report_experiments; - experiments[experiment_id] = experimentData; - mutateSave($scope.report_experiments, experiments); - $scope.report.all_experiments = experiments; - - if($scope.report.content.alias_experiments != undefined){ - if($scope.report.content.alias_experiments[experiment_id] != undefined){ - setExperimentAliasFromContent(experiment_id, $scope.report.content.alias_experiments[experiment_id]); - } - else{ - setExperimentAlias(experiment_id); - } - } - else{ - setExperimentAlias(experiment_id); - } - - intersectBlocks(experiment_id); - algorithmParameters(experiment_id); - }); - } - - function getPlotters(){ - plotterFactory.getPlotters($scope.url_prefix) - .success(function (plottersData){ - $scope.report.plotters = plottersData; - getPlotterParameterData(); - }) - .error(function (error){ - $scope.status = 'Unable to load plotters data - ' + ' : ' + error.message; - }); - } - - function getDefaultPlotters(){ - plotterFactory.getDefaultPlotters($scope.url_prefix) - .success(function (defaultPlottersData){ - $scope.report.defaultplotters = defaultPlottersData; - checkContent(); - }) - .error(function (error){ - $scope.status = 'Unable to load default plotters parameter data - ' + ' : ' + error.message; - }); - } - - function getPlotterParameterData(){ - plotterFactory.getPlotterParameter($scope.url_prefix) - .success(function (plotterParameterData){ - $scope.report.plotterparameter = plotterParameterData; - //$scope.report.plotterparameter.push({"name":"Default"}); - getDefaultPlotters(); - }) - .error(function (error){ - $scope.status = 'Unable to load plotter parameter data - ' + ' : ' + error.message; - }); - } - - function checkContent(){ - if($scope.report.content != undefined){ - - let orderkeys = []; - angular.forEach($scope.report.content, function(value, key){ - orderkeys.push(key); - }); - - orderkeys.sort(function(a,b){ - a = a.split("_"); - b = b.split("_"); - a_num = parseInt(a[a.length-1]) || -1; - b_num = parseInt(b[b.length-1]) || -1; - - return a_num - b_num; - }); - $scope.report.orderedcontent = orderkeys; - - if($scope.report.content.floating_point_precision != undefined){ - $scope.floating_point_precision.selected = $scope.report.content.floating_point_precision; - } - - for(let i = 0; i < $scope.report.orderedcontent.length; i++){ - let id_content = $scope.report.orderedcontent[i]; - addElementToReport(id_content); - } - } - } - - function addElementToReport(id_content){ - let type = id_content.split("_")[0]; - $scope.$broadcast("addSavedElement", id_content, type); - } - - function intersectBlocks(experiment_id){ - $scope.report_experiments_blocks[experiment_id] = Object.keys($scope.report_experiments[experiment_id].blocks_status); - let values = $.map($scope.report_experiments_blocks[experiment_id], function(value, key) { return value; }); - $scope.report_experiments_blocks_merged_blocks.push(values); - } - - function algorithmParameters(experiment_id){ - //go through globals - angular.forEach($scope.report_experiments[experiment_id].declaration.globals, function(value_algorithm, key_algorithm){ - //only get algorithms - if(key_algorithm.indexOf("/") != -1){ - $scope.report_algorithm_parameters[key_algorithm] = value_algorithm; - let experiment_algorithm_parameter = {}; - - if($scope.report_algorithm_parameters_experiment[experiment_id] == undefined){ - $scope.report_algorithm_parameters_experiment[experiment_id] = {}; - } - - if($scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm] == undefined){ - $scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm] = {}; - } - - //go through each blocks of the experiment and save parameters for given algorithm - angular.forEach($scope.report_experiments[experiment_id].declaration.blocks, function(value_block, key_block){ - //check blocks that matches globals - if($scope.report_experiments[experiment_id].declaration.blocks[key_block]['algorithm'] == key_algorithm){ - if($scope.report_experiments[experiment_id].declaration.blocks[key_block]['parameters'] != undefined){ - //override globals parameters value if block contains 'parameters' key - angular.forEach($scope.report_experiments[experiment_id].declaration.blocks[key_block]['parameters'], function(value_block_parameter, key_block_parameter){ - if($scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter] == undefined){ - $scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter] = []; - } - $scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter].push(value_block_parameter); - - $scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter] = unique($scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter]); - }); - } - else{ - //get globals parameters value if block doesn't contain 'parameters' key - angular.forEach($scope.report_experiments[experiment_id].declaration.globals[key_algorithm], function(value_block_parameter, key_block_parameter){ - if($scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter] == undefined){ - $scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter] = []; - } - $scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter].push(value_block_parameter); - $scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter] = unique($scope.report_algorithm_parameters_experiment[experiment_id][key_algorithm][key_block_parameter]); - }); - } - } - }); - } - }); - } - - function setExperimentAlias(experiment_id){ - $scope.report_experiments_alias[experiment_id] = experiment_id.split("/").pop(); - $scope.report_experiments_alias_from_content[experiment_id] = experiment_id.split("/").pop(); - } - - function setExperimentAliasFromContent(experiment_id, experiment_alias){ - $scope.report_experiments_alias[experiment_id] = experiment_alias; - $scope.report_experiments_alias_from_content[experiment_id] = experiment_alias; - } - - function unique(list){ - let result = []; - $.each(list, function(i, e) { - if ($.inArray(e, result) == -1) result.push(e); - }); - return result; - } }]); diff --git a/beat/web/reports/static/reports/app/data/itemcontent.json b/beat/web/reports/static/reports/app/data/itemcontent.json deleted file mode 100644 index 297831665fdde6e7bf49f9756e1f9e6c697617a8..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/data/itemcontent.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "identifier": "table", - "name": "Table", - "description": "Compare elements in a table" - }, - { - "identifier": "plot", - "name": "Figure", - "description": "Compare graphical elements (ROC, bar plots, etc.)" - } -] diff --git a/beat/web/reports/static/reports/app/data/table_itemcontent.json b/beat/web/reports/static/reports/app/data/table_itemcontent.json deleted file mode 100644 index 13e37560096b4947b4c0a316a0bb9f71a7698260..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/data/table_itemcontent.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "identifier": "tableresults", - "name": "Results", - "description": "Only compare experiments results" - } -] diff --git a/beat/web/reports/static/reports/app/directives/addReportItem.js b/beat/web/reports/static/reports/app/directives/addReportItem.js deleted file mode 100644 index 4e57c6a54b4c1d4bb51618ae2fc87b5ff10e7ec7..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/addReportItem.js +++ /dev/null @@ -1,778 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ -//Directive for opening smart_selector list on "Add a report item" button click that displays options - -angular.module('reportApp').directive("addreportitem", function($compile){ - return function(scope, element, attrs){ - scope.$on("addSavedElement", function(event, id_content, type){ - let num_tables_in_content = 0; - let num_figures_in_content = 0; - for(let i = 0; i < Object.keys(scope.report.content).length; i++){ - if(Object.keys(scope.report.content)[i].indexOf("table_") == 0){ - num_tables_in_content++; - } - else if(Object.keys(scope.report.content)[i].indexOf("chart_") == 0){ - num_figures_in_content++; - } - } - - if(type == "table"){ - let table_id = id_content; - let table_details = undefined; - - //take the one with more elements - if(Object.keys(scope.tables_details).length > num_tables_in_content){ - table_details = scope.tables_details[id_content]; - } - else{ - table_details = scope.report.content[id_content]; - } - - let name_to_remove = "experiment"; - for(let i = 0; i < table_details.length; i++){ - if(table_details[i].name == "experiment"){ - table_details.splice(i,1); - break; - } - } - - scope.tables_details[table_id] = table_details; - - let accessnumber = "no_number"; - if(scope.report.number == scope.report_number){ - accessnumber = "number"; - } - let html_div_code = '<div class="panel panel-default" id="' + table_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + table_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-table"> Table</i></a></h4></div><div id="collapse-' + table_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div class="panel-body" table-dynamic monster=' + scope.num_report_items + " tableid=" + table_id + " reportstatus=" + scope.report.status + " accessnumber=" + accessnumber + " urlprefix=" + scope.url_prefix + '></div></div></div>'; - - angular.element(document.getElementById('space-for-report-items')).append($compile(html_div_code)(scope)); - if(parseInt(table_id.split("_").pop(-1)) >= scope.max_num){ - scope.max_num = parseInt(table_id.split("_").pop(-1)); - scope.num_report_items = scope.max_num; - } - - scope.num_report_items++; - - - } - else if(type == "chart"){ - - let content_detail = {}; - let chart_id = id_content; - - let plot_details = undefined; - - //take the one with more elements - if(Object.keys(scope.plots_details).length > num_figures_in_content){ - plot_details = scope.plots_details[chart_id]; - } - else{ - plot_details = scope.report.content[chart_id]; - } - - - - content_detail["name"] = plot_details.data.output[0]; - //content_detail["description"] = scope.report.content[chart_id].data.plotter; - if(plot_details.data.plotter != undefined){ - content_detail["selected_plotter"] = plot_details.data.plotter; - } - if(plot_details.selected_template != undefined){ - content_detail["selected_template"] = plot_details.selected_template; - } - if(plot_details.data.merged != undefined){ - content_detail["merged"] = plot_details.data.merged; - } - if(plot_details.merged != undefined){ - content_detail["merged"] = plot_details.merged; - } - - let html_div_code = '<div class="panel panel-default" id="' + chart_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + chart_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-area-chart"> ' + content_detail.name + '</i></a></h4></div><div id="collapse-' + chart_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div id="'+chart_id+'" class="panel-body chart {$ report.status $}"></div></div></div>'; - generate_element(scope, "plot", html_div_code); - let element = document.getElementById(chart_id); - let label_element = $(document.createElement('div')); - label_element.addClass('row'); - - let accessnumber = "no_number"; - if(scope.report.number == scope.report_number){ - accessnumber = "number"; - } - - let prepend_buttons = '<div class="col-sm-12"><div class="action-buttons report-buttons pull-left">'; - let append_buttons = '</div></div>'; - - let a_export = '<div class="btn-group"><button type="button" class="btn btn-primary btn-sm dropdown-toggle item_export ' + scope.report.status + ' ' + accessnumber + '" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-download fa-lg"></i> Export Figure <span class="caret"></span></button><ul class="dropdown-menu"><li id="PNG" buttonexportitem><a>PNG</a></li><li id="JPEG" buttonexportitem><a>JPEG</a></li><li id="PDF" buttonexportitem><a>PDF</a></li></ul></div>'; - if(scope.report.status == "editable" && scope.report.number != scope.report_number) { - let a_element = '<button class="btn btn-danger btn-sm item_delete ' + scope.report.status + ' ' + accessnumber + '" buttondeleteitem><i class="fa fa-times fa-lg"></i> Delete</button>'; - label_element.html(prepend_buttons + a_element + a_export + append_buttons); - } - else { - label_element.html(prepend_buttons + a_export + append_buttons); - } - ; - $(element).find('.panel-body').append(label_element); - angular.element(document.getElementById('space-for-report-items')).append($compile(element)(scope)); - //let html_dropdown = "<chartdropdown id='selector_" + chart_id +"'></chartdropdown>"; - //angular.element(document.getElementById(chart_id)).append($compile(html_dropdown)(scope)); - - _retrieve_chart(scope, content_detail, element); - - if(parseInt(chart_id.split("_").pop(-1)) >= scope.max_num){ - scope.max_num = parseInt(chart_id.split("_").pop(-1)); - scope.num_report_items = scope.max_num; - } - - scope.num_report_items++; - - } - - } - ); - - scope.$on("redrawGraphElement", function(event, id_content, type){ - let content_detail = {}; - let chart_id = id_content; - content_detail["name"] = scope.report.content[chart_id].data.output[0]; - //content_detail["description"] = scope.report.content[chart_id].data.plotter; - if(scope.report.content[chart_id].data.plotter != undefined){ - content_detail["selected_plotter"] = scope.report.content[chart_id].data.plotter; - } - if(scope.report.content[chart_id].data.parameter != undefined){ - content_detail["selected_template"] = scope.report.content[chart_id].data.parameter; - } - if(scope.report.content[chart_id].data.merged != undefined){ - content_detail["merged"] = scope.report.content[chart_id].data.merged; - } - - let html_div_code = '<div class="panel panel-default" id="' + chart_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + chart_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-area-chart"> ' + content_detail.name + '</i></a></h4></div><div id="collapse-' + chart_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div id="'+chart_id+'" class="panel-body chart"></div></div></div>'; - generate_element(scope, "plot", html_div_code); - let element = document.getElementById(chart_id); - let label_element = $(document.createElement('div')); - label_element.addClass('row'); - - let accessnumber = "no_number"; - if(scope.report.number == scope.report_number){ - accessnumber = "number"; - } - - let prepend_buttons = '<div class="col-sm-12"><div class="action-buttons report-buttons pull-left">'; - let append_buttons = '</div></div>'; - - let a_export = '<div class="btn-group"><button type="button" class="btn btn-primary btn-sm dropdown-toggle item_export ' + scope.report.status + ' ' + accessnumber + '" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-download fa-lg"></i> Export Figure <span class="caret"></span></button><ul class="dropdown-menu"><li id="PNG" buttonexportitem><a>PNG</a></li><li id="JPEG" buttonexportitem><a>JPEG</a></li><li id="PDF" buttonexportitem><a>PDF</a></li></ul></div>'; - if(scope.report.status == "editable" && scope.report.number != scope.report_number) { - let a_element = '<button class="btn btn-danger btn-sm item_delete ' + scope.report.status + ' ' + accessnumber + '" buttondeleteitem><i class="fa fa-times fa-lg"></i> Delete</button>'; - label_element.html(prepend_buttons + a_element + a_export + append_buttons); - } - else { - label_element.html(prepend_buttons + a_export + append_buttons); - } - ; - $(element).find('.panel-body').append(label_element); - angular.element(document.getElementById('space-for-report-items')).append($compile(element)(scope)); - //let html_dropdown = "<chartdropdown id='selector_" + chart_id +"'></chartdropdown>"; - //angular.element(document.getElementById(chart_id)).html($compile(html_dropdown)(scope)); - - _retrieve_chart(scope, content_detail, element); - - }); - - //add new report item - element.bind("click", function(){ - let left = $('.add_item').offset().left - $('.add_item').width() + 400; - let top = $('.add_item').offset().top; - smart_selector.display(scope.item_content.content, left, top); - - let allblocks = []; - for(let i = 0; i < scope.report_experiments_blocks_merged_blocks.length; i++){ - allblocks.push(scope.report_experiments_blocks_merged_blocks[i]); - } - scope.report.common_blocks = arraysInCommon(allblocks); - }); - - //handles first selector selection (table/plot) - if(smart_selector != undefined){ - smart_selector.onEntrySelected = function(item_selected){ - - let left = $('.add_item').offset().left - $('.add_item').width() + 400; - let top = $('.add_item').offset().top; - - let next_items_for_selector = prepareContent(scope, smart_selector.entries[smart_selector.selected_entry].identifier); - smart_selector_detail.display(next_items_for_selector, left, top); - }; - } - - //handles next selector detail selection - if(smart_selector_detail != undefined){ - smart_selector_detail.onEntrySelected = function(item_selected){ - let left = $('.add_item').offset().left - $('.add_item').width() + 400; - let top = $('.add_item').offset().top; - - - let result_next_items = nextDetailContent(scope, smart_selector.entries[smart_selector.selected_entry].identifier, smart_selector_detail.entries[smart_selector_detail.selected_entry]); - - if(!result_next_items[0]){ - multiple_selector.display(result_next_items[1], left, top); - } - }; - } - - //handles first creation of table based on options - if(multiple_selector != undefined){ - multiple_selector.onEntrySelected = function(item_selected, data){ - for(let i = 0; i < multiple_selector.entries.length; i++){ - if(multiple_selector.entries[i].name == item_selected){ - multiple_selector.entries[i].selected = true; - } - } - }; - - multiple_selector.onEntryDeselected = function(item_selected, data){ - for(let i = 0; i < multiple_selector.entries.length; i++){ - if(multiple_selector.entries[i].name == item_selected){ - multiple_selector.entries[i].selected = false; - } - } - }; - - multiple_selector.onClose = function(){ - //check if at least one item is selected - let checkOneSelected = false; - angular.forEach(multiple_selector.entries, function(value, key){ - if(value.selected) - checkOneSelected = true; - }); - - if(checkOneSelected){ - let table_id = 'table' + '_' + scope.num_report_items; - - scope.tables_details[table_id] = multiple_selector.entries; - - let html_div_code = '<div class="panel panel-default" id="' + table_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + table_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-table"> Table</i></a></h4></div><div id="collapse-' + table_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div class="panel-body" table-dynamic monster=' + scope.num_report_items + " tableid=" + table_id + " reportstatus=" + scope.report.status + " urlprefix=" + scope.url_prefix + '></div></div></div>'; - - angular.element(document.getElementById('space-for-report-items')).append($compile(html_div_code)(scope)); - - scope.report.orderedcontent.push(table_id); - scope.num_report_items++; - } - }; - } - - //handles single table updates via settings option - if(multiple_selector_updater != undefined){ - multiple_selector_updater.onEntrySelected = function(item_selected, data){ - for(let i = 0; i < multiple_selector_updater.entries.length; i++){ - if(multiple_selector_updater.entries[i].name == item_selected){ - multiple_selector_updater.entries[i].selected = true; - } - } - }; - - multiple_selector_updater.onEntryDeselected = function(item_selected, data){ - for(let i = 0; i < multiple_selector_updater.entries.length; i++){ - if(multiple_selector_updater.entries[i].name == item_selected){ - multiple_selector_updater.entries[i].selected = false; - } - } - }; - - multiple_selector_updater.onClose = function(){ - - //check if at least one item is selected - let checkOneSelected = false; - angular.forEach(multiple_selector_updater.entries, function(value, key){ - if(value.selected) - checkOneSelected = true; - }); - - if(checkOneSelected){ - let element = document.getElementById(multiple_selector_updater.current_table); - - $(element).attr('id', null); - $compile(element)(scope); - $(element).attr('id', multiple_selector_updater.current_table); - } - }; - - }; - - //Prepare the content for selector initialization - function prepareContent(scope, content_identifier){ - let next_content_items = []; - - switch(content_identifier){ - case 'table': - next_content_items = scope.table_item_content.content; - break; - case 'plot': - angular.forEach(scope.report_experiments, function(value, key){ - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer){ - if(value_analyzer.algorithm == scope.report.analyzer){ - scope.report_experiments[key].analyzer_block = key_analyzer; - } - }); - - let plottable_result = []; - angular.forEach(value.results[scope.report_experiments[key].analyzer_block], function(value_result_item, key_result_item){ - if(value_result_item.type.startsWith("plot/")){ - plottable_result.push(key_result_item); - } - - }); - - scope.report_experiments[key].plottable_blocks = plottable_result; - - }); - - //Results block are the same for all experiments from same analyzer. - //So just grab information from one of them for smart_selector items - let single_experiment = scope.report.experiments[0]; - - //create smart_selector items - angular.forEach(scope.report_experiments[single_experiment].plottable_blocks, function(value_plottable, key_plottable){ - let plot_type = scope.report_experiments[single_experiment].results[scope.report_experiments[single_experiment].analyzer_block][value_plottable].type; - let item_dict = {}; - item_dict["identifier"] = value_plottable; - item_dict["name"] = value_plottable; - item_dict["description"] = plot_type; - - next_content_items.push(item_dict); - }); - break; - } - - return next_content_items; - } - - //Get the detailed content for next selector - function nextDetailContent(scope, content_identifier, sub_content){ - let is_end = false; - let next_items = []; - let return_contents = []; - switch(content_identifier){ - case 'table': - is_end = false; - angular.forEach(scope.report_experiments, function(value, key){ - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer){ - if(value_analyzer.algorithm == scope.report.analyzer){ - scope.report_experiments[key].analyzer_block = key_analyzer; - } - }); - - let table_result = []; - angular.forEach(value.results[scope.report_experiments[key].analyzer_block], function(value_result_item, key_result_item){ - if(!(value_result_item.type.startsWith("plot/"))){ - table_result.push(key_result_item); - } - - }); - - scope.report_experiments[key].table_result_blocks = table_result; - - }); - - //Results block are the same for all experiments from same analyzer. - //So just grab information from one of them for smart_selector items - let single_experiment = scope.report.experiments[0]; - - //create smart_selector items - angular.forEach(scope.report_experiments[single_experiment].table_result_blocks, function(value_table_result, key_table_result){ - - let table_item_data = scope.report_experiments[single_experiment].results[scope.report_experiments[single_experiment].analyzer_block][value_table_result]; - let item_dict = {}; - item_dict["identifier"] = value_table_result; - item_dict["name"] = value_table_result; - item_dict["description"] = table_item_data.type; - if(table_item_data.primary) - item_dict["selected"] = true; - else - item_dict["selected"] = false; - item_dict["data"] = table_item_data; - - next_items.push(item_dict); - }); - - //adding execution time entry information for common blocks - angular.forEach(scope.report.common_blocks, function(value_table_result, key_table_result){ - let item_dict = {}; - item_dict["identifier"] = "execution_time." + value_table_result; - item_dict["name"] = "execution_time." + value_table_result; - item_dict["selected"] = false; - next_items.push(item_dict); - - }); - - //adding total execution time entry information for experiment - let item_dict = {}; - item_dict["identifier"] = "experiment.execution_time"; - item_dict["name"] = "experiment.execution_time"; - item_dict["selected"] = false; - next_items.push(item_dict); - - //adding globals algorithms parameters - angular.forEach(scope.report_algorithm_parameters, function(value_algorithm_parameters, key_algorithm_parameters){ - for(let i = 0; i < Object.keys(value_algorithm_parameters).length; i++){ - let item_dict = {}; - item_dict["identifier"] = "algorithm_parameter." + key_algorithm_parameters + "__" +Object.keys(value_algorithm_parameters)[i]; - item_dict["name"] = "algorithm_parameter." + key_algorithm_parameters + "__" +Object.keys(value_algorithm_parameters)[i]; - item_dict["selected"] = false; - next_items.push(item_dict); - } - - }); - - break; - case 'plot': - is_end = true; - let chart_id = 'chart_' + sub_content.identifier + '_graph' + '_' + scope.num_report_items; - let html_div_code = '<div class="panel panel-default" id="' + chart_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + chart_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-area-chart"> ' + sub_content.name + '</i></a></h4></div><div id="collapse-' + chart_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div id="'+chart_id+'" class="panel-body chart {$ report.status $}"></div></div></div>'; - generate_element(scope, content_identifier, html_div_code); - let element = document.getElementById(chart_id); - let label_element = $(document.createElement('div')); - label_element.addClass('row'); - - let accessnumber = "no_number"; - if(scope.report.number == scope.report_number){ - accessnumber = "number"; - } - - let prepend_buttons = '<div class="col-sm-12"><div class="action-buttons report-buttons pull-left">'; - let append_buttons = '</div></div>'; - - let a_export = '<div class="btn-group"><button type="button" class="btn btn-primary btn-sm dropdown-toggle item_export ' + scope.report.status + ' ' + accessnumber + '" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-download fa-lg"></i> Export Figure <span class="caret"></span></button><ul class="dropdown-menu"><li id="PNG" buttonexportitem><a>PNG</a></li><li id="JPEG" buttonexportitem><a>JPEG</a></li><li id="PDF" buttonexportitem><a>PDF</a></li></ul></div>'; - if(scope.report.status == "editable" && scope.report.number != scope.report_number) { - let a_element = '<button class="btn btn-danger btn-sm item_delete ' + scope.report.status + ' ' + accessnumber + '" buttondeleteitem><i class="fa fa-times fa-lg"></i> Delete</button>'; - label_element.html(prepend_buttons + a_element + a_export + append_buttons); - } - else { - label_element.html(prepend_buttons + a_export + append_buttons); - } - $(element).find('.panel-body').append(label_element); - - angular.element(document.getElementById('space-for-report-items')).append($compile(element)(scope)); - - _retrieve_chart(scope, sub_content, element); - scope.report.orderedcontent.push(chart_id); - break; - } - - return_contents = [is_end, next_items]; - - return return_contents; - - } - - //Generate and compile DOM element - function generate_element(scope, content_identifier, html_div_code){ - switch(content_identifier){ - case 'table': - angular.element(document.getElementById('space-for-report-items')).append($compile(html_div_code)(scope)); - scope.num_report_items++; - break; - case 'plot': - angular.element(document.getElementById('space-for-report-items')).append($compile(html_div_code)(scope)); - scope.num_report_items++; - break; - } - - } - - //Retrieve chart from api and display on proper item - function _get_chart(scope, sub_content, content_type, chart_id){ - let required_plotter = []; - let set_plotter = ''; - if(sub_content.selected_plotter != undefined){ - //required_plotter.push(sub_content.selected_plotter); - set_plotter = sub_content.selected_plotter; - let requested_dataformat = ''; - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].name == sub_content.selected_plotter){ - requested_dataformat = scope.report.plotters[i].dataformat; - break; - } - } - - //Get default plotter for required dataformat - for (let i = 0; i < scope.report.defaultplotters.length; i++){ - if(scope.report.defaultplotters[i].dataformat == requested_dataformat){ - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].dataformat == requested_dataformat && scope.report.plotters[i].name != sub_content.defaultplotter.plotter){ - required_plotter.push(scope.report.plotters[i].name); - } - } - } - else{ - //Get default plotter for required dataformat - for (let i = 0; i < scope.report.defaultplotters.length; i++){ - if(scope.report.defaultplotters[i].dataformat == sub_content.description){ - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - set_plotter = sub_content.defaultplotter.plotter; - - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].dataformat == sub_content.description && scope.report.plotters[i].name != sub_content.defaultplotter.plotter){ - required_plotter.push(scope.report.plotters[i].name); - } - } - } - - let plotterparameter = []; - //Get other plotterparameter - for (let i = 0; i < scope.report.plotterparameter.length; i++){ - plotterparameter.push(scope.report.plotterparameter[i].name); - } - - let chart_name = sub_content.name; - - let legend_experiments = ''; - let alias_experiments = []; - for(let i = 0; i < scope.report.experiments.length; i++){ - if(i == 0) - legend_experiments = scope.report_experiments_alias[scope.report.experiments[i]]; - else - legend_experiments = legend_experiments+ "&" +scope.report_experiments_alias[scope.report.experiments[i]]; - - alias_experiments.push(scope.report_experiments_alias[scope.report.experiments[i]]); - } - - let request_data = { - experiment: alias_experiments, - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - legend: legend_experiments, - report_number: scope.report.number, - //height: 300, - //width: 400, - }; - - base_url = scope.report.url_prefix; - - let plot_detail = {}; - plot_detail["required_plotter"] = required_plotter; - plot_detail["data"] = { - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - }; - - if(sub_content.selected_template != undefined){// && sub_content.selected_template != "Default") - plot_detail["selected_template"] = sub_content.selected_template; - request_data.parameter = plot_detail["selected_template"]; - } - else{ - plot_detail["selected_template"] = sub_content.defaultplotter.parameter; - request_data.parameter = plot_detail["selected_template"]; - } - - if(sub_content.merged != undefined){// && sub_content.selected_template != "Default") - plot_detail["merged"] = sub_content.merged; - request_data.merged = plot_detail["merged"]; - } - else{ - plot_detail["merged"] = true; - request_data.merged = plot_detail["merged"]; - } - - beat.experiments.utils.getPlotData(base_url, - request_data, required_plotter, plotterparameter, content_type, - function(r_image_data, selected_content_type) { - download(r_image_data, chart_id + "." + content_type.toLowerCase(), selected_content_type); - } - ); - } - - - //Retrieve chart from api and display on proper item - function _retrieve_chart(scope, sub_content, container){ - let required_plotter = []; - let set_plotter = ''; - if(sub_content.selected_plotter != undefined){ - //required_plotter.push(sub_content.selected_plotter); - set_plotter = sub_content.selected_plotter; - let requested_dataformat = ''; - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].name == sub_content.selected_plotter){ - requested_dataformat = scope.report.plotters[i].dataformat; - break; - } - } - - //Get default plotter for required dataformat - for (let i = 0; i < scope.report.defaultplotters.length; i++){ - if(scope.report.defaultplotters[i].dataformat == requested_dataformat){ - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].dataformat == requested_dataformat && scope.report.plotters[i].name != sub_content.defaultplotter.plotter){ - required_plotter.push(scope.report.plotters[i].name); - } - } - } - else{ - //Get default plotter for required dataformat - for (let i = 0; i < scope.report.defaultplotters.length; i++){ - if(scope.report.defaultplotters[i].dataformat == sub_content.description){ - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - set_plotter = sub_content.defaultplotter.plotter; - - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].dataformat == sub_content.description && scope.report.plotters[i].name != sub_content.defaultplotter.plotter){ - required_plotter.push(scope.report.plotters[i].name); - } - } - } - - let plotterparameter = []; - //Get other plotterparameter - for (let i = 0; i < scope.report.plotterparameter.length; i++){ - plotterparameter.push(scope.report.plotterparameter[i].name); - } - - let chart_name = sub_content.name; - - let legend_experiments = ''; - let alias_experiments = []; - - for(let i = 0; i < scope.report.experiments.length; i++){ - if(i == 0) - legend_experiments = scope.report_experiments_alias[scope.report.experiments[i]]; - else - legend_experiments = legend_experiments+ "&" +scope.report_experiments_alias[scope.report.experiments[i]]; - - if(Object.keys(scope.$parent.report_experiments_alias_from_content).length === 0) - alias_experiments.push(scope.report_experiments_alias[scope.report.experiments[i]]); - else - alias_experiments.push(scope.report_experiments_alias_from_content[scope.report.experiments[i]]); - } - - let request_data = { - experiment: alias_experiments, - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - legend: legend_experiments, - report_number: scope.report.number, - //height: 300, - //width: 400, - }; - - base_url = scope.report.url_prefix; - //scope.plots_details[container.id]; - - let plot_detail = {}; - plot_detail["required_plotter"] = required_plotter; - plot_detail["data"] = { - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - }; - - - if(sub_content.selected_template != undefined){// && sub_content.selected_template != "Default") - plot_detail["selected_template"] = sub_content.selected_template; - request_data.parameter = plot_detail["selected_template"]; - } - else{ - plot_detail["selected_template"] = sub_content.defaultplotter.parameter; - request_data.parameter = plot_detail["selected_template"]; - } - - if(sub_content.merged != undefined){// && sub_content.selected_template != "Default") - plot_detail["merged"] = sub_content.merged; - request_data.merged = plot_detail["merged"]; - } - else{ - plot_detail["merged"] = true; - request_data.merged = plot_detail["merged"]; - } - - scope.plots_details[container.id]= plot_detail; - - if(scope.report.status == "editable" && scope.report.number != scope.report_number){ - beat.experiments.utils.displayPlot(base_url, $(container).find('.panel-body')[0], - request_data, required_plotter, plotterparameter, false, - - function(r_plotter, r_plotterparameter, r_merged) { - scope.plots_details[container.id]["data"]["plotter"] = r_plotter; - scope.plots_details[container.id]["selected_template"] = r_plotterparameter; - scope.plots_details[container.id]["merged"] = r_merged; - } - ); - } - else{ - beat.experiments.utils.displayPlot(base_url, $(container).find('.panel-body')[0], - request_data, [], [], false, - - function(r_plotter, r_plotterparameter, r_merged) { - } - ); - } - } - - function arraysInCommon(arrays){ - let i, common, - L= arrays.length, min= Infinity; - while(L){ - if(arrays[--L].length<min){ - min= arrays[L].length; - i= L; - } - } - common= arrays.splice(i, 1)[0]; - return common.filter(function(itm, indx){ - if(common.indexOf(itm)== indx){ - return arrays.every(function(arr){ - return arr.indexOf(itm)!= -1; - }); - } - }); - } - - }; -}); - diff --git a/beat/web/reports/static/reports/app/directives/aliasExperiment.js b/beat/web/reports/static/reports/app/directives/aliasExperiment.js deleted file mode 100644 index 5fda415e6ed13ff121bcace03aa0ddcdf93ff61a..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/aliasExperiment.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to handle table settings click -angular.module('reportApp').directive("aliasexperiment", function($compile){ - return { - link:function(scope, element, attrs){ - let alias_name = scope.$parent.$parent.$parent.$parent.report_experiments_alias[scope.name]; - createAlias(scope.name, alias_name); - - element.bind("click", function(){ - let input_element = document.getElementById("input_"+scope.name); - let icon_element = document.getElementById("icon_"+scope.name); - let button_element = document.getElementById("button_alias_"+scope.name); - if(! $(input_element).hasClass("input-disabled")){ - if ($(input_element).val()){ - $(input_element).addClass("input-disabled"); - $(input_element).attr("disabled", true); - $(icon_element).removeClass("fa-unlock"); - $(icon_element).addClass("fa-lock"); - $(button_element).addClass("setalias"); - let experiment_name = attrs.id.split("button_alias_")[1]; - let alias_name = $(input_element).val(); - $(input_element).val(alias_name); - createAlias(experiment_name, alias_name); - } - else{ - alert("Alias for experiment" + scope.name + " can't be empty!"); - } - } - else{ - $(input_element).removeClass("input-disabled"); - $(input_element).attr("disabled", false); - $(icon_element).removeClass("fa-lock"); - $(icon_element).addClass("fa-unlock"); - $(button_element).removeClass("setalias"); - - } - }); - - function createAlias(experiment_name, alias_name){ - scope.report_experiments_alias[experiment_name] = alias_name; - scope.$parent.$parent.$parent.$parent.report_experiments_alias[experiment_name] = alias_name; - - if(!scope.$$phase){ - //$digest or $apply - let parent_scope = scope.$parent.$parent.$parent.$parent; - let table_details = parent_scope.tables_details; - - for(let i = 0; i < parent_scope.report.orderedcontent.length; i++){ - let element = document.getElementById(parent_scope.report.orderedcontent[i]); - - $(element).remove(); - - let id_content = parent_scope.report.orderedcontent[i]; - let type = id_content.split("_")[0]; - parent_scope.$parent.$broadcast("addSavedElement", id_content, type); - } - } - } - } - }; -}); - diff --git a/beat/web/reports/static/reports/app/directives/buttonDeleteItem.js b/beat/web/reports/static/reports/app/directives/buttonDeleteItem.js deleted file mode 100644 index d23011aea97b6a475a17b23b54f77e60887b008d..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/buttonDeleteItem.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to handle table settings click -angular.module('reportApp').directive("buttondeleteitem", function(){ - return { - link:function(scope, element, attrs){ - element.bind("click", function(){ - let elementToRemove = element.context.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement; - beat.ui.report.remove_item('report_remove_item', elementToRemove, scope); - }); - } - }; -}); - diff --git a/beat/web/reports/static/reports/app/directives/buttonExportItem.js b/beat/web/reports/static/reports/app/directives/buttonExportItem.js deleted file mode 100644 index 5fdd72eae6acfb0c1d76d417690bfbb548265bdd..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/buttonExportItem.js +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to export graph/tables on click -angular.module('reportApp').directive("buttonexportitem", function(){ - return { - link:function(scope, element, attrs){ - element.bind("click", function(){ - let the_element = element.context.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement; - if(the_element.id.indexOf("chart_") == 0){ - let content_detail = {}; - let chart_id = the_element.id; - - content_detail["name"] = scope.plots_details[chart_id].data.output[0]; - - if(scope.plots_details[chart_id].data.plotter != undefined){ - content_detail["selected_plotter"] = scope.plots_details[chart_id].data.plotter; - } - if(scope.plots_details[chart_id].data.parameter != undefined){ - content_detail["selected_template"] = scope.plots_details[chart_id].data.parameter; - } - if(scope.plots_details[chart_id].data.merged != undefined){ - content_detail["merged"] = scope.plots_details[chart_id].data.merged; - } - - let accessnumber = "no_number"; - if(scope.report.number == scope.report_number){ - accessnumber = "number"; - } - _get_chart(scope, content_detail, element[0].id, chart_id); - } - else if(the_element.id.indexOf("table_") == 0){ - let separator = ","; - let csv_text = export_table_as_csv(scope, the_element.id, separator); - let output_filename = the_element.id + ".csv"; - download(csv_text, output_filename, "text/plain"); - } - }); - } - }; - - function export_table_as_csv(scope, table_id, separator){ - let report_experiments = scope.$parent.report_experiments; - let report_experiments_alias = scope.$parent.report_experiments_alias; - let floating_point_precision = scope.$parent.floating_point_precision; - let report = scope.report; - let final_table = []; - let table_headers = []; - angular.forEach(scope.tables_details[table_id], function(table_value, table_key){ - if(table_value.selected){ - table_headers.push(table_value.name); - } - }); - - final_table.push(table_headers); - - angular.forEach(report_experiments, function(experiment_value, experiment_key){ - let table_items = []; - - angular.forEach(table_headers, function(table_value, table_key){ - let experiment_name = experiment_key; - let analyzer_block = report_experiments[experiment_name].analyzer_block; - let report_algorithm_parameters_experiment = scope.$parent.report_algorithm_parameters_experiment; - - if(table_value != "experiment"){ - if(analyzer_block == undefined){ - angular.forEach(report_experiments, function(value, key){ - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer){ - if(value_analyzer.algorithm == report.analyzer && (key_analyzer in report_experiments[experiment_name].declaration.analyzers)){ - report_experiments[experiment_name].analyzer_block = key_analyzer; - analyzer_block = report_experiments[experiment_name].analyzer_block; - } - }); - }); - } - - if(table_value.indexOf("execution_time.") == 0){ - //execution time information - let block_name = table_value.split("execution_time.")[1].split("[s]")[0]; - if(Object.keys(report_experiments[experiment_name].execution_info).length === 0){ - table_items.push("-"); - } - else{ - if(report_experiments[experiment_name].execution_info[block_name] == undefined){ - table_items.push("-"); - } - else{ - table_items.push((report_experiments[experiment_name].execution_info[block_name].linear_execution_time).toFixed(floating_point_precision.selected)); - } - } - } - else if(table_value.indexOf("experiment.") == 0){ - //total execution time information - let block_name = table_value.split("execution_time.")[1]; - let total_time = 0; - if(Object.keys(report_experiments[experiment_name].execution_info).length === 0){ - total_time = "-"; - } - else{ - angular.forEach(report_experiments[experiment_name].execution_info, function(value, key){ - total_time += value.linear_execution_time; - }); - } - - table_items.push(total_time.toFixed(floating_point_precision.selected)); - } - else if(table_value.indexOf("algorithm_parameter.") == 0){ - //total execution time information - let block_name = table_value.split("algorithm_parameter.")[1]; - let algorithm_name = block_name.split("__")[0]; - let parameter_name = block_name.split("__")[1]; - if(report_algorithm_parameters_experiment[experiment_name][algorithm_name] != undefined){ - let value = ""; - for(let i = 0; i < report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name].length; i++){ - if(i > 0 && i < report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name].length -1 ){ - value += ","; - } - value = report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name][i]; - } - - table_items.push(value); - } - else{ - table_items.push("-"); - } - } - else{ - //results information - table_items.push((report_experiments[experiment_name].results[analyzer_block][table_value].value).toFixed(floating_point_precision.selected)); - } - } - else{ - let experiment_alias = report_experiments_alias[experiment_name]; - table_items.push(experiment_alias); - } - - }); - - final_table.push(table_items); - - }); - - let csv_text = ""; - for(let i = 0; i < final_table.length; i++){ - if(i != 0){ - csv_text += "\n"; - } - - for(let j = 0; j < final_table[i].length; j++){ - if( j != 0){ - csv_text += separator; - } - csv_text += final_table[i][j]; - } - } - - let pre_base64_text = "data:text/plain;base64,"; - let base_64_csv_text = pre_base64_text + Base64.encode(csv_text); - return base_64_csv_text; - } - - //Retrieve chart from api and display on proper item - function _get_chart(scope, sub_content, content_type, chart_id){ - let required_plotter = []; - let set_plotter = ''; - if(sub_content.selected_plotter != undefined){ - //required_plotter.push(sub_content.selected_plotter); - set_plotter = sub_content.selected_plotter; - let requested_dataformat = ''; - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].name == sub_content.selected_plotter){ - requested_dataformat = scope.report.plotters[i].dataformat; - break; - } - } - - //Get default plotter for required dataformat - for (let i = 0; i < scope.report.defaultplotters.length; i++){ - if(scope.report.defaultplotters[i].dataformat == requested_dataformat){ - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].dataformat == requested_dataformat && scope.report.plotters[i].name != sub_content.defaultplotter.plotter){ - required_plotter.push(scope.report.plotters[i].name); - } - } - } - else{ - //Get default plotter for required dataformat - for (let i = 0; i < scope.report.defaultplotters.length; i++){ - if(scope.report.defaultplotters[i].dataformat == sub_content.description){ - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - set_plotter = sub_content.defaultplotter.plotter; - - //Get other plotters for required dataformat - for (let i = 0; i < scope.report.plotters.length; i++){ - if(scope.report.plotters[i].dataformat == sub_content.description && scope.report.plotters[i].name != sub_content.defaultplotter.plotter){ - required_plotter.push(scope.report.plotters[i].name); - } - } - } - - let plotterparameter = []; - //Get other plotterparameter - for (let i = 0; i < scope.report.plotterparameter.length; i++){ - plotterparameter.push(scope.report.plotterparameter[i].name); - } - - let chart_name = sub_content.name; - - let legend_experiments = ''; - for(let i = 0; i < scope.report.experiments.length; i++){ - if(i == 0) - legend_experiments = scope.report_experiments_alias[scope.report.experiments[i]]; - else - legend_experiments = legend_experiments+ "&" +scope.report_experiments_alias[scope.report.experiments[i]]; - } - - let request_data = { - experiment: scope.report.experiments, - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - legend: legend_experiments, - //height: 300, - //width: 400, - }; - - base_url = scope.report.url_prefix; - - let plot_detail = {}; - plot_detail["required_plotter"] = required_plotter; - plot_detail["data"] = request_data; - if(sub_content.selected_template != undefined){// && sub_content.selected_template != "Default") - plot_detail["selected_template"] = sub_content.selected_template; - request_data.parameter = plot_detail["selected_template"]; - } - else{ - plot_detail["selected_template"] = sub_content.defaultplotter.parameter; - request_data.parameter = plot_detail["selected_template"]; - } - - if(sub_content.merged != undefined){// && sub_content.selected_template != "Default") - plot_detail["merged"] = sub_content.merged; - request_data.merged = plot_detail["merged"]; - } - else{ - plot_detail["merged"] = true; - request_data.merged = plot_detail["merged"]; - } - - beat.experiments.utils.getPlotData(base_url, - request_data, required_plotter, plotterparameter, content_type, - function(r_image_data, selected_content_type) { - download(r_image_data, chart_id + "." + content_type.toLowerCase(), selected_content_type); - } - ); - } - - -}); - diff --git a/beat/web/reports/static/reports/app/directives/buttonSettings.js b/beat/web/reports/static/reports/app/directives/buttonSettings.js deleted file mode 100644 index 06062c6b2638708e92543d4dbcea787e5c06d640..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/buttonSettings.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to handle table settings click -angular.module('reportApp').directive("buttonsettings", function(){ - return { - link:function(scope, element, attrs){ - element.bind("click", function(){ - let name_to_remove = "experiment"; - let tables_details = scope.$parent.tables_details[scope.dattrs.tableid]; - for(let i = 0; i < tables_details.length; i++){ - if(tables_details[i].name == "experiment"){ - tables_details.splice(i,1); - break; - } - } - multiple_selector_updater.current_table = scope.dattrs.tableid; - multiple_selector_updater.display(tables_details); - }); - } - }; -}); - diff --git a/beat/web/reports/static/reports/app/directives/edit/addGroupMenu.js b/beat/web/reports/static/reports/app/directives/edit/addGroupMenu.js index 40dcee254cf0f470b02e624a51f3fd740d1b6dad..dcefe7f83a0fedd4b9110c930596efdfe8f8e5bf 100644 --- a/beat/web/reports/static/reports/app/directives/edit/addGroupMenu.js +++ b/beat/web/reports/static/reports/app/directives/edit/addGroupMenu.js @@ -23,7 +23,7 @@ /* * groupAddGroupMenu * Desc: - * represents the menu for creating groups + * the menu & validating for creating a new group */ angular.module('reportApp') .directive("groupAddGroupMenu", ['GroupsService', function(GroupsService){ @@ -32,12 +32,16 @@ angular.module('reportApp') }, link: function(scope){ scope.newGroupName = { val: '' }; + // validates the user input scope.hasError = (val) => { // if val is undefined, empty, or a dup, its an err const isErr = !val || val.length === 0 || GroupsService.groups.find(g => g.name === val); // cast to boolean return !!isErr; }; + + // creates a new group if the new group name is valid + // wipes the input on successful creation scope.createGroup = () => { if(scope.hasError(scope.newGroupName.val)){ return; diff --git a/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js b/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js index d19b96086f035070a8b8fdace3f78b5472b7d4c5..d4ee0c8a1db1d38f35a7c836dce4861702a4c4cc 100644 --- a/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js +++ b/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js @@ -23,7 +23,7 @@ /* * groupAddItemsMenu * Desc: - * represents the menu for adding report items to a group + * the button group for adding report items (plot, table, text) to a group */ angular.module('reportApp') .directive("groupAddItemsMenu", ['ExperimentsService', 'GroupsService', function(ExperimentsService, GroupsService){ @@ -32,18 +32,22 @@ angular.module('reportApp') group: '=' }, link: function(scope){ - scope.isEditable = GroupsService.isEditable; + // finds the id for the next report item of + // the given type + // by looking at the existing items const getNextItemId = (type) => { let count = Object.values(scope.group.reportItems) .filter(v => v.id.includes(type)) .length ; + let nextId = `${type}_${count}`; return nextId; }; scope.plottables = ExperimentsService.plottables; + // helper func for adding a table scope.addNewTable = () => { const id = getNextItemId('table'); @@ -63,31 +67,47 @@ angular.module('reportApp') const defaultFields = Array.from(defaultFieldsSet); console.log(defaultFields); - scope.group.addReportItem(id, { + // tables have an arr of selected fields + // and a float precision + let content = { fields: defaultFields, precision: 10 - }); + }; + + scope.group.addReportItem(id, content); }; - scope.addNewPlot = (content) => { + // helper func for adding a plot + scope.addNewPlot = (plot) => { let id = getNextItemId('plot'); + + // plots have a given name (by analyzer) + // and a plot type + let content = { + name: plot.label, + type: plot.type + }; + scope.group.addReportItem(id, content); }; + // helper func for adding a text block scope.addNewText = () => { let id = getNextItemId('text'); - scope.group.addReportItem(id, ''); + // text blocks just have raw RST + let content = ''; + scope.group.addReportItem(id, content); }; }, template: ` <div class="btn-group" role="group"> - <button ng-disabled='!isEditable' type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Add Plot <span class="caret"></span> </button> <ul class='dropdown-menu' ng-repeat='(expName, plots) in plottables' ng-if='expName === group.experiments[0]'> <li ng-repeat='plot in plots'> - <a href='#' ng-click='addNewPlot(plot.label)'>{{ plot.label }} <i>({{ plot.type }})</i></a> + <a href='#' ng-click='addNewPlot(plot)'>{{ plot.label }} <i>({{ plot.type }})</i></a> </li> </ul> </div> @@ -95,7 +115,7 @@ angular.module('reportApp') Add Table </button> <div class="btn-group" role="group"> - <button ng-disabled='!isEditable' + <button ng-click='addNewText()' type="button" class="btn btn-default" diff --git a/beat/web/reports/static/reports/app/directives/edit/itemContainer.js b/beat/web/reports/static/reports/app/directives/edit/itemContainer.js index 3aed999c49d25f8dd93bd3b9059a387d610ffb22..1361c99e7b35d4ce483cb519e395fbd603f01226 100644 --- a/beat/web/reports/static/reports/app/directives/edit/itemContainer.js +++ b/beat/web/reports/static/reports/app/directives/edit/itemContainer.js @@ -23,7 +23,9 @@ /* * groupItemContainer * Desc: - * container for an item in the group + * container for an item in the group. + * depending of the type of the item (found in the item's id) + * it creates a table, plot, or text item */ angular.module('reportApp') .directive("groupItemContainer", [function(){ @@ -34,6 +36,7 @@ angular.module('reportApp') }, link: function(scope){ scope.item = scope.reportItem; + // report-wide-unique prefix for the item to use scope.domId = `${scope.group.name}_${scope.id}`; }, template: ` diff --git a/beat/web/reports/static/reports/app/directives/edit/layout.js b/beat/web/reports/static/reports/app/directives/edit/layout.js index ad31140e5ff34616a979c639c035d1f54b553028..c2b40bfaeb64f523f420075467aa957335e025a9 100644 --- a/beat/web/reports/static/reports/app/directives/edit/layout.js +++ b/beat/web/reports/static/reports/app/directives/edit/layout.js @@ -23,23 +23,25 @@ /* * groupsLayout * Desc: - * controls the layout of the reports content, generating group panels - * using the GroupsService data. + * controls the layout of the reports content, + * generating group panels using the GroupsService data, + * and holding the menu for adding a group */ angular.module('reportApp').directive("groupsLayout", ['GroupsService', function(GroupsService){ return { - // isolate scope for modularity & less coupling scope: { }, link: function(scope, el, attr){ scope.groups = GroupsService.groups; scope.GroupsService = GroupsService; + + // drag handle CSS selector scope.sortableOptions = { handle: '.panel-heading > .panel-title > .action-buttons > .drag-handle' }; }, template: ` -<div ng-if='GroupsService.isEditable' group-add-group-menu class='panel'></div> +<div group-add-group-menu class='panel'></div> <div ui-sortable='sortableOptions' ng-model='GroupsService.groups' id='groupsLayout' class='panel-group'> <div diff --git a/beat/web/reports/static/reports/app/directives/edit/panelContent.js b/beat/web/reports/static/reports/app/directives/edit/panelContent.js index f714b2efbcc9b9b518a6a38a1972fbc6dc8cfab3..bfb1fecc1982d933b1429ba8c029c920515428b7 100644 --- a/beat/web/reports/static/reports/app/directives/edit/panelContent.js +++ b/beat/web/reports/static/reports/app/directives/edit/panelContent.js @@ -23,7 +23,11 @@ /* * groupPanelContent * Desc: - * lays out the content of a group in a panel + * presents the group to the user in logical blocks: + * - a panel holds content + * - panel header contains an (editable) group name label + * - panel header also contains the buttons to add report items + * - two sub-panels are added: the experiments list, and the items list */ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', function(GroupsService){ return { @@ -31,10 +35,9 @@ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', fun group: '=' }, link: function(scope){ - scope.isEditable = GroupsService.isEditable; scope.deleteGroup = GroupsService.deleteGroup; scope.editingGroupName = false; - scope.change = () => { + scope.toggleEditingGroupName = () => { scope.editingGroupName = !scope.editingGroupName; }; }, @@ -50,7 +53,7 @@ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', fun aria-expanded="true" aria-controls="collapse-{{group.name}}"> </a> - <span ng-if='!editingGroupName' ng-click='change()'> + <span ng-if='!editingGroupName' ng-click='toggleEditingGroupName()'> <span>{{ group.name }}</span> <span style='cursor: pointer;' class='glyphicon glyphicon-pencil'></span> </span> @@ -62,7 +65,7 @@ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', fun class='form-control' placeholder='Group name...' ng-model='group._name'/> - <span class='input-group-addon' ng-click='change()'> + <span class='input-group-addon' ng-click='toggleEditingGroupName()'> Save </span> </span> diff --git a/beat/web/reports/static/reports/app/directives/edit/panelExperiments.js b/beat/web/reports/static/reports/app/directives/edit/panelExperiments.js index 2a0d9d3544fa9c8f6ad22a50b904a84ca267a50c..8913dcbd29e4e27d68af0d84a0b214acaca7f3d0 100644 --- a/beat/web/reports/static/reports/app/directives/edit/panelExperiments.js +++ b/beat/web/reports/static/reports/app/directives/edit/panelExperiments.js @@ -23,7 +23,9 @@ /* * groupPanelExperiments * Desc: - * displays the experiments panel of the group + * displays the experiments panel of the group - + * a table of experiments in the group, their databases/protocols, and aliases. + * Also has a menu for adding (compatible) experiments to the group. */ angular.module('reportApp').directive("groupPanelExperiments", ['GroupsService', 'ExperimentsService', 'UrlService', function(GroupsService, ExperimentsService, UrlService){ return { @@ -31,9 +33,11 @@ angular.module('reportApp').directive("groupPanelExperiments", ['GroupsService', group: '=' }, link: function(scope){ - scope.isEditable = GroupsService.isEditable; scope.experiments = ExperimentsService.experiments; scope.dropdownId = `${scope.group.name}_exp_add_dropdown`; + + // find experiments that are not in the group but are + // compatible with the existing experiments (if any) scope.expsNotInGroup = () => { return ExperimentsService.experimentNames // exps not in group @@ -42,10 +46,14 @@ angular.module('reportApp').directive("groupPanelExperiments", ['GroupsService', .filter(e => scope.group.analyzer === '' || ExperimentsService.getAnalyzerFromExpName(e) === scope.group.analyzer) ; }; + + // collects an array of formatted databases & protocols of an experiment + // format is "<database name>@<protocol name>" scope.getExpDatabases = (expName) => { let dbs = scope.experiments[expName].declaration.datasets; return Array.from(new Set(Object.values(dbs).map(db => `${db.database}@${db.protocol}`))); }; + scope.getAnalyzerFromExpName = ExperimentsService.getAnalyzerFromExpName; scope.getExpUrl = UrlService.getExperimentUrl; scope.getBlockUrl = UrlService.getBlockUrl; @@ -66,7 +74,7 @@ angular.module('reportApp').directive("groupPanelExperiments", ['GroupsService', </a> <div class='btn-group'> <div class="dropdown"> - <button ng-disabled='!isEditable' class="btn btn-default dropdown-toggle" ng-class='{disabled: expsNotInGroup().length === 0}' type="button" id="{{ dropdownId }}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> + <button class="btn btn-default dropdown-toggle" ng-class='{disabled: expsNotInGroup().length === 0}' type="button" id="{{ dropdownId }}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> Add Experiment <span class="caret"></span> </button> @@ -114,11 +122,11 @@ angular.module('reportApp').directive("groupPanelExperiments", ['GroupsService', <td><a href='{{ getExpUrl(expName) }}'>{{ expName }}</a></td> <td> <span ng-repeat='db in getExpDatabases(expName)'> - <a href='{{ getDatabaseUrl(db) }}'>{{ db }}</a> + <a href='{{ getDatabaseUrl(db.split("@")[0]) }}'>{{ db }}</a> </span> </td> - <td><input ng-disabled='!isEditable' ng-model='group.aliases[expName]'></input></td> + <td><input ng-model='group.aliases[expName]'></input></td> </tr> </tbody> </table> diff --git a/beat/web/reports/static/reports/app/directives/edit/panelItems.js b/beat/web/reports/static/reports/app/directives/edit/panelItems.js index 0f446ed829bc8431ef67ed490887bbce9c2cd53c..0c73d467701c8372a7cd9881484d6426f211f8bd 100644 --- a/beat/web/reports/static/reports/app/directives/edit/panelItems.js +++ b/beat/web/reports/static/reports/app/directives/edit/panelItems.js @@ -23,7 +23,8 @@ /* * groupPanelItems * Desc: - * displays the panel of report items of the group + * displays the panel of report items of the group, + * using the item container adaptor */ angular.module('reportApp').directive("groupPanelItems", [function(){ return { @@ -31,6 +32,9 @@ angular.module('reportApp').directive("groupPanelItems", [function(){ group: '=' }, link: function(scope){ + // CSS selector for drag handles for the ui-sortable functionality + // TODO: this needs to be changed each time the HTML hierarchy changes. + // Make it hierarchy-independent scope.sortableOptions = { handle: '.panel-heading > .panel-title > .action-buttons > .drag-handle' }; diff --git a/beat/web/reports/static/reports/app/directives/edit/plotItem.js b/beat/web/reports/static/reports/app/directives/edit/plotItem.js index cdc7343f779c9264478e2406d473ce3a1b0fbfae..138d6b90fac8de0e6993aecfba801547915cb6e2 100644 --- a/beat/web/reports/static/reports/app/directives/edit/plotItem.js +++ b/beat/web/reports/static/reports/app/directives/edit/plotItem.js @@ -23,10 +23,10 @@ /* * groupPlotItem * Desc: - * displays a plot report item + * displays a plot report item (basically a container for the plots code to insert into) */ angular.module('reportApp') -.directive("groupPlotItem", ['ExperimentsService', function(ExperimentsService){ +.directive("groupPlotItem", ['ExperimentsService', 'PlotService', '$timeout', function(ExperimentsService, PlotService, $timeout){ return { scope: { group: '=', @@ -34,7 +34,37 @@ angular.module('reportApp') content: '=' }, link: function(scope){ + const group = scope.group; scope.domId = `${scope.group.name}_${scope.id}`; + + // container for the plots applet to insert into + scope.renderDivId = `${scope.domId}-render`; + + // wait until the container html element is rendered. + // angular will run these functions called with $timeout + // after everything has been rendered + $timeout(function() { + PlotService.addPlot(scope.group, scope.id, scope.renderDivId); + }); + + // if the group has exps added/removed, rerender the plot + scope.$watch( + // angular doesnt watch arrays properly (i.e. watching scope.group._experimentNames), + // as it doesnt register array changes. + // it also doesnt watch getters properly (i.e. watching scope.group.experiments), + // because it compares shallowly and getters commonly return a new obj each time. + // so, watch the getters length instead + () => scope.group.experiments.length, + (newExps, oldExps) => { + let el = document.querySelector(`#${scope.renderDivId}`); + // if the container is rendered and it already has had a render, + // redo the render + if(el && el.childNodes.length > 0){ + el.innerHTML = ''; + PlotService.addPlot(scope.group, scope.id, scope.renderDivId); + } + } + ); }, template: ` <div id="{{domId}}-heading" class="panel-heading" role="tab"> @@ -68,8 +98,7 @@ angular.module('reportApp') role="tabpanel" aria-labelledby="{{domId}}-heading"> <div class='panel-body'> - <p>{{ id }} content</p> - <strong class='text-danger'>Plot items in reports are not implemented yet.</strong> + <div id='{{ renderDivId }}'></div> </div> </div> ` diff --git a/beat/web/reports/static/reports/app/directives/edit/tableFieldSelector.js b/beat/web/reports/static/reports/app/directives/edit/tableFieldSelector.js index 3305cc2c59cb9a71b16e88f218847604bb5916d8..f3ac84adc688d70cdb29cbc589c353bde7444a1b 100644 --- a/beat/web/reports/static/reports/app/directives/edit/tableFieldSelector.js +++ b/beat/web/reports/static/reports/app/directives/edit/tableFieldSelector.js @@ -31,13 +31,16 @@ angular.module('reportApp') scope: { id: '=', group: '=', + // currently selected columns for the table colsSelected: '=', + // function to execute when the user clicks the submit button buttonAction: '&', + // title for the menu title: '@', + // text for the submit button buttonText: '@' }, link: function(scope){ - scope.isEditable = GroupsService.isEditable; // bootstrap's auto dropdown toggling is disabled for the table creation dropdown // add a click handler for the table creation dropdown submit button to toggle // manually @@ -47,34 +50,52 @@ angular.module('reportApp') }; scope.tableables = () => { + // start with the tableables generated in experimentsservice const tableables = ExperimentsService.tableables; const fieldArr = Object.entries(tableables) + // only look at fields that are from an experiment in the group .filter(([e, fields]) => scope.group.experiments.includes(e)) + // get the names of the fields .map(([e, fields]) => Object.keys(fields)) + // make one big array of all field names .reduce((arr, fArr) => [...arr, ...fArr], []) ; + // converting to and from a Set is a simple way of + // removing dups return Array.from(new Set(fieldArr)); }; + // has this fieldName already been processed? + // need to look at the already-processed field names scope.isUniqueTableable = (expName, fieldName) => { const tableables = ExperimentsService.tableables; const concatNames = (eName, fName) => `${eName}.${fName}`; + // see if this field is a repeat const isRepeat = Object.entries(tableables) .filter(([e, fields]) => { + // only look at tableables of exps that are in group let isInGroup = scope.group.experiments.includes(e); + // and have already been looked at let alreadyChecked = Object.keys(tableables).indexOf(e) < Object.keys(tableables).indexOf(expName); return isInGroup && alreadyChecked; }) + // get field names .map(([e, fields]) => Object.keys(fields)) + // flatten .reduce((arr, fArr) => [...arr, ...fArr], []) + // does this flattened array have this field name in it? .includes(fieldName) ; + // if it isnt a repeat, its unique! return !isRepeat; }; + // many tableable fields are fields from an analyzer, a block, or something else + // these fields have a field group name, a '.', and an actual field name + // find these group names and use them to subdivide the list of fields in the menu scope.tableablesGroups = () => { let groupNames = scope.tableables() .filter(f => f.includes('.')) @@ -83,8 +104,10 @@ angular.module('reportApp') return Array.from(new Set(groupNames)).sort((a, b) => groupNames.indexOf(a) - groupNames.indexOf(b)); }; + // finds the actual field name whether its in a field group or not scope.subfieldName = (field) => field.includes('.') ? field.split('.').slice(1).join('.') : field; + // toggle the selection of a field scope.toggleField = (fName) => { let idx = scope.colsSelected.indexOf(fName); if(idx > -1){ @@ -96,7 +119,7 @@ angular.module('reportApp') }; }, template: ` -<button ng-disabled='!isEditable' id='{{ id }}' type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> +<button id='{{ id }}' type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {{ title }} <span class="caret"></span> </button> diff --git a/beat/web/reports/static/reports/app/directives/edit/tableItem.js b/beat/web/reports/static/reports/app/directives/edit/tableItem.js index 69a4fa74ab732681416d5deae734124c7634d3e6..9fba43f28944e7eb73ef6d78ffa26a1077542509 100644 --- a/beat/web/reports/static/reports/app/directives/edit/tableItem.js +++ b/beat/web/reports/static/reports/app/directives/edit/tableItem.js @@ -23,7 +23,8 @@ /* * groupTableItem * Desc: - * displays a table report item + * displays a table report item and lets the user + * manage this table's selected cols and float precision */ angular.module('reportApp') .directive("groupTableItem", ['GroupsService', 'ExperimentsService', function(GroupsService, ExperimentsService){ @@ -35,80 +36,27 @@ angular.module('reportApp') }, link: function(scope){ // aliases - scope.isEditable = GroupsService.isEditable; scope.fields = scope.content.fields; // ids scope.domId = `${scope.group.name}_${scope.id}`; scope.colSelectorId = `${scope.domId}_columnSelector`; - // add 'expName' to the beginning of the fields to show in the table - // if it isnt already there - if(scope.fields.length === 0 || scope.fields[0] !== 'Experiment'){ - scope.fields.unshift('Experiment'); - } - // 1 - 10 + // probably the most concise way of generating 1-10 computationally + // also vastly more complex than writing [1,2,3,4,5,6,7,9,10] scope.floatingPointRange = [...(new Array(10)).keys()].map(i => i + 1); - // get possible table entries - scope.tableables = ExperimentsService.tableables || {}; - - // gets the field type (int, float, string, nothing) - scope.getFieldType = (field) => { - if(field === scope.fields[0]){ - return 'string'; - } - - let hasFieldObj = Object.values(scope.tableables) - .find(o => o[field]); - let fVal = hasFieldObj ? hasFieldObj[field] : {}; - let type; - if(fVal.type){ - type = fVal.type; - } else if(Number.isSafeInteger(fVal)){ - type = 'integer'; - } else if(Number.isFinite(fVal)){ - type = 'float'; - } else if(typeof fVal === 'string'){ - type = 'string'; - } else { - type = undefined; - } - - return type; - }; - // gets the field val for the given exp - scope.getFieldVal = (expName, field) => { - let fVal = scope.tableables[expName] ? - scope.tableables[expName][field] : undefined; - let val; - if(field === scope.fields[0]){ - val = scope.group.aliases[expName].length > 0 ? scope.group.aliases[expName] : expName; - } else if(!fVal){ - val = '-'; - } else { - let tmp; - if(fVal.value){ - tmp = fVal.value; - } else { - tmp = fVal; - } - - let type = scope.getFieldType(field); - if(type && type.startsWith('float')){ - val = tmp.toFixed(parseInt(scope.content.precision)); - } else { - val = tmp; - } - } - - return val; - }; - // init the chosen cols for the table with the saved cols scope.chosenCols = Array.from(scope.fields); + // save new cols choice + // due to how angular handles functions passed as props to an element, + // it must return a function that does the actual work. scope.saveChosenCols = () => () => { + // we want to keep the selected columns in order, + // so try to add new columns in their correct indices, + // and rm cols by mutating the array + const newCols = scope.chosenCols .filter(c => !scope.fields.includes(c)); @@ -120,48 +68,6 @@ angular.module('reportApp') newCols.forEach(nf => scope.fields.push(nf)); }; - // need to nest actual value in an obj to get angular - // to watch it correctly - scope.sortField = { val: 'Experiment', isReversed: false }; - // sort rows (one row per exp) - scope.sortFunc = (expName) => { - return scope.getFieldType(scope.sortField.val) ? - scope.getFieldVal(expName, scope.sortField.val) : expName; - }; - // sets the new sort field and direction - scope.setSortField = (field) => { - if(scope.sortField.val === field){ - scope.sortField.isReversed = !scope.sortField.isReversed; - } else { - scope.sortField.val = field; - scope.sortField.isReversed = false; - } - }; - - // a different view of the table - scope.getCSV = () => { - let fields = scope.fields; - let exps = scope.group.experiments - // clone arr - .map(e => `${e}`) - .sort((ea, eb) => (scope.sortField.isReversed ? -1 : 1) * (scope.sortFunc(ea) > scope.sortFunc(eb) ? -1 : 1)) - ; - - let str = ''; - - let fieldsStr = fields - .map(f => `${f}(${scope.getFieldType(f)})`) - .join(','); - - let expsStrs = exps - .map(e => fields.map(f => `${scope.getFieldVal(e, f)}`).join(',')) - .join('\n'); - - str = `${fieldsStr}\n${expsStrs}`; - - return str; - }; - // toggle val for viewing CSV scope.isViewingCSV = { val: false }; scope.toggleViewingCSV = () => { @@ -205,7 +111,7 @@ angular.module('reportApp') > </div> <div class='btn-group' role='group'> - <button ng-disabled='!isEditable' class='btn btn-default' id="{{domId}}-precision" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + <button class='btn btn-default' id="{{domId}}-precision" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Float Precision: {{ content.precision }} <span class="caret"></span> </button> @@ -223,38 +129,7 @@ angular.module('reportApp') class="panel-collapse collapse in" role="tabpanel" aria-labelledby="{{domId}}-heading"> - <div ng-if='isViewingCSV.val' class='panel-body'> - <pre>{{ getCSV() }}</pre> - </div> - <div ng-if='!isViewingCSV.val' class='panel-body' style='height: 100%; overflow-x: auto;'> - <table class="table table-striped table-hover"> - <thead> - <tr ui-sortable ng-model='fields'> - <th ng-repeat='field in fields'> - <span - ng-if="sortField.val == field" - class='glyphicon' - ng-class="{ - 'glyphicon-chevron-up': sortField.isReversed, - 'glyphicon-chevron-down': !sortField.isReversed - }" - > - </span> - <a role='button' ng-click='setSortField(field)'> - {{ field }} <i>({{ getFieldType(field) }})</i> - </a> - </th> - </tr> - </thead> - <tbody> - <tr ng-repeat="exp in group.experiments | orderBy:sortFunc:sortField.isReversed"> - <td ng-repeat='field in fields'> - {{ getFieldVal(exp, field) }} - </td> - </tr> - </tbody> - </table> - </div> + <div table-item group='group' content='content' is-viewing-csv='isViewingCSV'></div> </div> ` }; diff --git a/beat/web/reports/static/reports/app/directives/edit/textItem.js b/beat/web/reports/static/reports/app/directives/edit/textItem.js index d55618a86927b3700795e23730e64a7921cd12ad..c38e9aafd6b39b5c24d4e99e7ff776f67e739955 100644 --- a/beat/web/reports/static/reports/app/directives/edit/textItem.js +++ b/beat/web/reports/static/reports/app/directives/edit/textItem.js @@ -23,7 +23,11 @@ /* * groupTextItem * Desc: - * displays a text report item + * displays a text report item: + * - sends the raw RST to the server to be compiled, + * and displays the returned HTML + * - the user can edit the RST using codemirror + * - the compile is async and doesnt require refreshing the page */ angular.module('reportApp') .directive("groupTextItem", ['GroupsService', '$sce', 'UrlService', 'reportFactory', function(GroupsService, $sce, UrlService, reportFactory){ @@ -34,24 +38,18 @@ angular.module('reportApp') }, link: function(scope){ // aliases + // angular requires that compiling raw html be sanitized scope.trustAsHtml = $sce.trustAsHtml; - scope.isEditable = GroupsService.isEditable; scope.item = scope.reportItem; scope.domId = `${scope.group.name}_${scope.item.id}`; // codemirror options scope.uicmOptions = { mode: 'rst', - readOnly: !GroupsService.isEditable - }; - - // readonly codemirror options - scope.srccmOptions = { - mode: 'rst', - readOnly: true }; // handle compiling content + // holds the last response from the server scope.compiledContent = { val: '' }; scope.compileContent = () => { let url = UrlService.getCompileRstUrl(); @@ -59,18 +57,22 @@ angular.module('reportApp') return reportFactory.compileRST(url, content) .then(data => { + // when compiled, save the raw html scope.compiledContent.val = data.data.html_str; }); }; // handle edit/save/cancel buttons scope.isEditing = { val: false }; + // when editing, use a buffer to hold the raw text scope.unsavedContent = { val: `${scope.item.content}` }; + // save the buffer to the actual report item content scope.saveAction = () => { scope.item.content = scope.unsavedContent.val; scope.compileContent(); scope.isEditing.val = false; }; + // discard buffer and use report item content scope.cancelAction = () => { scope.unsavedContent.val = `${scope.item.content}`; scope.isEditing.val = false; diff --git a/beat/web/reports/static/reports/app/directives/edit/viewSerialized.js b/beat/web/reports/static/reports/app/directives/edit/viewSerialized.js deleted file mode 100644 index fa0821546d66f4be2fef1ad3a4e824194ac5c0ff..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/edit/viewSerialized.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * groupViewSerialized - * Desc: - * renders a 'serialized' view of the report item using their html func: - * - text: The HTML compiled on the server from the raw RST in the input - * - table: A CSV-style, raw & easily copyable text block - */ -angular.module('reportApp') -.directive("groupViewSerialized", ['$sce', function($sce){ - return { - scope: { - entity: '=', - serializeFuncObj: '=' - }, - link: function(scope, el){ - scope.trustAsHtml = $sce.trustAsHtml; - }, - template: ` -<div class='well'> - <div ng-bind-html='trustAsHtml(serializeFuncObj.val())'></div> -</div> -` - }; -}]); diff --git a/beat/web/reports/static/reports/app/directives/item.js b/beat/web/reports/static/reports/app/directives/item.js deleted file mode 100644 index 5e383a4747a3baa19f02e7f2a1fadf18858e32b4..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/item.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Dynamic tables items -angular.module('reportApp').directive('item', function ($compile) { - function createTDElement(column) { - let table = angular.element('<table><tr><td class="tableitemspace" thecolumn="' + column + '"></td></tr></table>'); - return table.find('td'); - } - - function render(element, scope) { - let column, html, i; - let columns = scope.$parent.tables_details[scope.$parent.dattrs.tableid]; - - for (i = 0; i < columns.length ; i++) { - if(i == 0 && columns.length > 0){ - html = $compile(createTDElement("experiment"))(scope); - - } - column = columns[i]; - if (column.selected) { - - html = $compile(createTDElement(column.name))(scope); - element.append(html); - } - } - - - } - - return { - // restrict: 'A', - scope: { - exp_name: "=", - item: "=", - columns: "=" - }, - compile: function () { - return function (scope, element) { - render(element, scope); - }; - - } - }; - -}); - diff --git a/beat/web/reports/static/reports/app/directives/loadedContent.js b/beat/web/reports/static/reports/app/directives/loadedContent.js deleted file mode 100644 index fa47b3d859d6b8fe949f58339f0ce265375d61f6..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/loadedContent.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. -*/ - -//Directive that returns an element which adds buttons on click which adds items -angular.module('reportApp').directive('loadedcontent', function(){ - //return { - // link: function (scope, elem, attrs, ctrl) { - // angular.element(document).ready(function() { - // console.info(scope.report.content); - // - // }); - // //$(window).load(function() { - // // - // // console.info(scope.report.content); - // // - // // }); - // } - //} -}); - - diff --git a/beat/web/reports/static/reports/app/directives/lockReport.js b/beat/web/reports/static/reports/app/directives/lockReport.js index 31e0f9e67e903e86dda30c155c868f6c5fd1d652..9d02f4eebda3681be7489ab6b94357ee9901d2dc 100644 --- a/beat/web/reports/static/reports/app/directives/lockReport.js +++ b/beat/web/reports/static/reports/app/directives/lockReport.js @@ -25,13 +25,8 @@ angular.module('reportApp').directive("lockreport", function($compile){ return function(scope, element, attrs){ //add new report item element.bind("click", function(){ - lockReport(); - }); - - - function lockReport(){ beat.ui.report.lock_report('report_lock', scope); - } + }); }; }); diff --git a/beat/web/reports/static/reports/app/directives/myReportInfo.js b/beat/web/reports/static/reports/app/directives/myReportInfo.js deleted file mode 100644 index f8f0c4cb0b63d4a821c75b32aaa83b53749840a8..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/myReportInfo.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to generate the dynamic table loading partials -angular.module('reportApp').directive("myreportinfo", function(){ - return { - restrict: 'E', - scope: true, - replace: true, - Â Â Â Â //templateUrl: "/reports/partials/reportTable/", - Â Â Â Â templateUrl: function(scope, elem, attrs){ - let prefix = elem['urlprefix']; - Â Â Â Â let the_url = prefix + "/reports/partials/reportInfo/"; - return the_url; - }, - link: function(scope, elem, attrs){ - }, - controller: ['$scope', function ($scope) { - }], - }; -}); - diff --git a/beat/web/reports/static/reports/app/directives/publishReport.js b/beat/web/reports/static/reports/app/directives/publishReport.js index 4d03afae59d25b11f72ccdc2d70ba3d32c333d73..2595699e5dd5d1c0e88624a39f73e3c265d89d2e 100644 --- a/beat/web/reports/static/reports/app/directives/publishReport.js +++ b/beat/web/reports/static/reports/app/directives/publishReport.js @@ -25,11 +25,6 @@ angular.module('reportApp').directive("publishreport", function($compile){ return function(scope, element, attrs){ //add new report item element.bind("click", function(){ - publishReport(); - }); - - - function publishReport(){ scope.reportFactory.publishReportAlgorithms(scope.user, scope.report_id, scope.url_prefix) .success(function (reportData){ beat.ui.report.publish_report('report_publish', scope, reportData); @@ -44,9 +39,7 @@ angular.module('reportApp').directive("publishreport", function($compile){ $("#report_publish .errors .errorslist").append(scope.status); $("#button-report_publish-cancel").hide(); }); - - - } + }); }; }); diff --git a/beat/web/reports/static/reports/app/directives/removeExperiment.js b/beat/web/reports/static/reports/app/directives/removeExperiment.js deleted file mode 100644 index b6a55a0c84d36e72bc96d014a181cd28ac6d8941..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/removeExperiment.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive for opening smart_selector list on "Add a report item" button click that displays options -angular.module('reportApp').directive("removeexperiment", function($compile){ - return function(scope, element, attrs){ - //add new report item - element.bind("click", function(){ - removeExperiment(attrs.id); - }); - - - function removeExperiment(experiment_name){ - beat.ui.report.remove_experiment('report_remove_experiment', experiment_name, scope); - } - }; -}); - - diff --git a/beat/web/reports/static/reports/app/directives/reportItemView.js b/beat/web/reports/static/reports/app/directives/reportItemView.js deleted file mode 100644 index 68f67287153717e141d39bc1c87cd9e2c158df41..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/reportItemView.js +++ /dev/null @@ -1,2185 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. -*/ -//Directive that returns an element which adds buttons on click which adds items -var app = angular.module('reportApp'); - -app.directive('loadedcontent', function() -{ - //return { - // link: function (scope, elem, attrs, ctrl) { - // angular.element(document).ready(function() { - // console.info(scope.report.content); - // - // }); - // //$(window).load(function() { - // // - // // console.info(scope.report.content); - // // - // // }); - // } - //} -}); - -//Directive for opening smart_selector list on "Add a report item" button click that displays options -app.directive("removeexperiment", function($compile) -{ - return function(scope, element, attrs) - { - //add new report item - element.bind("click", function() - { - removeExperiment(attrs.id); - }); - - - function removeExperiment(experiment_name) - { - beat.ui.report.remove_experiment('report_remove_experiment', experiment_name, scope); - } - } -}); - -//Directive for opening smart_selector list on "Add a report item" button click that displays options -app.directive("savereportitems", function($compile) -{ - return function(scope, element, attrs) - { - //add new report item - element.bind("click", function() - { - //var savecontent = []; - var savecontent = {}; - if(scope.plots_details != undefined) - { - angular.forEach(scope.plots_details, function(value, key) - { - //savecontent.push(key, value); - savecontent[key] = value; - }); - } - if(scope.tables_details != undefined) - { - angular.forEach(scope.tables_details, function(value, key) - { - savecontent[key] = value; - //savecontent.push(key, value); - }); - - if(scope.floating_point_precision.selected != undefined) - { - savecontent["floating_point_precision"] = scope.floating_point_precision.selected; - } - } - if(scope.report_experiments_alias != undefined) - { - var alias_experiments = {}; - angular.forEach(scope.report_experiments_alias, function(value, key) - { - alias_experiments[key] = value; - }); - savecontent["alias_experiments"] = alias_experiments; - } - - if(!(jQuery.isEmptyObject(scope.sorted_experiments_keys_tables)) && !(jQuery.isEmptyObject(scope.sorted_experiments_keys_reverse)) && !(jQuery.isEmptyObject(scope.sorted_experiments_keys_tables_sortkey))) - { - savecontent["sorted_tables_experiments"] = scope.sorted_experiments_keys_tables; - savecontent["sorted_tables_alias_experiments"] = scope.sorted_experiments_alias_keys_tables; - savecontent["sorted_tables_keys_reverse"] = scope.sorted_experiments_keys_reverse; - savecontent["sorted_tables_sortkey"] = scope.sorted_experiments_keys_tables_sortkey; - } - //call set report content from factory - var mydict = {}; - mydict["experiments"] = scope.report.experiments; - mydict["content"] = savecontent; - - for(var i = 0; i < scope.report.experiments.length; i++) - { - scope.report_experiments_alias_from_content[scope.report.experiments[i]] = scope.report_experiments_alias[scope.report.experiments[i]]; - } - - updateReport(mydict); - }); - - - function updateReport(data) - { - scope.reportFactory.updateReport(scope.user, scope.report_id, data, scope.url_prefix) - .success(function (reportData) - { - //alert("The report "+ scope.report_id +" has been saved."); - - beat.ui.report.report_saved('report_saved', scope); - }) - .error(function (error) - { - scope.status = 'Unable to update report data: ' + error.message; - - }); - - } - } -}); - -//Directive for opening smart_selector list on "Add a report item" button click that displays options -app.directive("lockreport", function($compile) -{ - return function(scope, element, attrs) - { - //add new report item - element.bind("click", function() - { - lockReport(); - }); - - - function lockReport() - { - beat.ui.report.lock_report('report_lock', scope); - } - } -}); - -//Directive for opening smart_selector list on "Add a report item" button click that displays options -app.directive("publishreport", function($compile) -{ - return function(scope, element, attrs) - { - //add new report item - element.bind("click", function() - { - publishReport(); - }); - - - function publishReport() - { - scope.reportFactory.publishReportAlgorithms(scope.user, scope.report_id, scope.url_prefix) - .success(function (reportData) - { - beat.ui.report.publish_report('report_publish', scope, reportData); - }) - .error(function (error) - { - scope.status = 'Unable to publish report data: ' + error; - $(".explanation_text").hide(); - $("#report_publish .warnings").hide(); - $("#report_publish .errors").show(); - if(error.detail != undefined) - scope.status = 'Unable to publish report data: ' + error.detail; - $("#report_publish .errors .errorslist").append(scope.status); - $("#button-report_publish-cancel").hide(); - }); - - - } - } -}); - -//Directive for opening smart_selector list on "Add a report item" button click that displays options -app.directive("addreportitem", function($compile) -{ - return function(scope, element, attrs) - { - scope.$on("addSavedElement", function(event, id_content, type) - { - var num_tables_in_content = 0; - var num_figures_in_content = 0; - for(var i = 0; i < Object.keys(scope.report.content).length; i++) - { - if(Object.keys(scope.report.content)[i].indexOf("table_") == 0) - { - num_tables_in_content++; - } - else if(Object.keys(scope.report.content)[i].indexOf("chart_") == 0) - { - num_figures_in_content++; - } - } - - if(type == "table") - { - var table_id = id_content; - var table_details = undefined; - - //take the one with more elements - if(Object.keys(scope.tables_details).length > num_tables_in_content) - { - table_details = scope.tables_details[id_content]; - } - else - { - table_details = scope.report.content[id_content]; - } - - var name_to_remove = "experiment"; - for(var i = 0; i < table_details.length; i++) - { - if(table_details[i].name == "experiment") - { - table_details.splice(i,1); - break; - } - } - - scope.tables_details[table_id] = table_details; - - var accessnumber = "no_number"; - if(scope.report.number == scope.report_number) - { - accessnumber = "number"; - } - var html_div_code = '<div class="panel panel-default" id="' + table_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + table_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-table"> Table</i></a></h4></div><div id="collapse-' + table_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div class="panel-body" table-dynamic monster=' + scope.num_report_items + " tableid=" + table_id + " reportstatus=" + scope.report.status + " accessnumber=" + accessnumber + " urlprefix=" + scope.url_prefix + '></div></div></div>'; - - angular.element(document.getElementById('space-for-report-items')).append($compile(html_div_code)(scope)); - if(parseInt(table_id.split("_").pop(-1)) >= scope.max_num) - { - scope.max_num = parseInt(table_id.split("_").pop(-1)); - scope.num_report_items = scope.max_num; - } - - scope.num_report_items++; - - - } - else if(type == "chart") - { - - var content_detail = {}; - var chart_id = id_content; - - var plot_details = undefined; - - //take the one with more elements - if(Object.keys(scope.plots_details).length > num_figures_in_content) - { - plot_details = scope.plots_details[chart_id]; - } - else - { - plot_details = scope.report.content[chart_id]; - } - - - - content_detail["name"] = plot_details.data.output[0]; - //content_detail["description"] = scope.report.content[chart_id].data.plotter; - if(plot_details.data.plotter != undefined) - { - content_detail["selected_plotter"] = plot_details.data.plotter; - } - if(plot_details.selected_template != undefined) - { - content_detail["selected_template"] = plot_details.selected_template; - } - if(plot_details.data.merged != undefined) - { - content_detail["merged"] = plot_details.data.merged; - } - if(plot_details.merged != undefined) - { - content_detail["merged"] = plot_details.merged; - } - - var html_div_code = '<div class="panel panel-default" id="' + chart_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + chart_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-area-chart"> ' + content_detail.name + '</i></a></h4></div><div id="collapse-' + chart_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div id="'+chart_id+'" class="panel-body chart {$ report.status $}"></div></div></div>'; - generate_element(scope, "plot", html_div_code); - var element = document.getElementById(chart_id); - var label_element = $(document.createElement('div')); - label_element.addClass('row'); - - var accessnumber = "no_number"; - if(scope.report.number == scope.report_number) - { - accessnumber = "number"; - } - - var prepend_buttons = '<div class="col-sm-12"><div class="action-buttons report-buttons pull-left">'; - var append_buttons = '</div></div>'; - - var a_export = '<div class="btn-group"><button type="button" class="btn btn-primary btn-sm dropdown-toggle item_export ' + scope.report.status + ' ' + accessnumber + '" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-download fa-lg"></i> Export Figure <span class="caret"></span></button><ul class="dropdown-menu"><li id="PNG" buttonexportitem><a>PNG</a></li><li id="JPEG" buttonexportitem><a>JPEG</a></li><li id="PDF" buttonexportitem><a>PDF</a></li></ul></div>'; - if(scope.report.status == "editable" && scope.report.number != scope.report_number) { - var a_element = '<button class="btn btn-danger btn-sm item_delete ' + scope.report.status + ' ' + accessnumber + '" buttondeleteitem><i class="fa fa-times fa-lg"></i> Delete</button>'; - label_element.html(prepend_buttons + a_element + a_export + append_buttons); - } - else { - label_element.html(prepend_buttons + a_export + append_buttons); - } -; - $(element).find('.panel-body').append(label_element); - angular.element(document.getElementById('space-for-report-items')).append($compile(element)(scope)); - //var html_dropdown = "<chartdropdown id='selector_" + chart_id +"'></chartdropdown>"; - //angular.element(document.getElementById(chart_id)).append($compile(html_dropdown)(scope)); - - _retrieve_chart(scope, content_detail, element); - - if(parseInt(chart_id.split("_").pop(-1)) >= scope.max_num) - { - scope.max_num = parseInt(chart_id.split("_").pop(-1)); - scope.num_report_items = scope.max_num; - } - - scope.num_report_items++; - - } - - } - ); - - scope.$on("redrawGraphElement", function(event, id_content, type) - { - var content_detail = {}; - var chart_id = id_content; - content_detail["name"] = scope.report.content[chart_id].data.output[0]; - //content_detail["description"] = scope.report.content[chart_id].data.plotter; - if(scope.report.content[chart_id].data.plotter != undefined) - { - content_detail["selected_plotter"] = scope.report.content[chart_id].data.plotter; - } - if(scope.report.content[chart_id].data.parameter != undefined) - { - content_detail["selected_template"] = scope.report.content[chart_id].data.parameter; - } - if(scope.report.content[chart_id].data.merged != undefined) - { - content_detail["merged"] = scope.report.content[chart_id].data.merged; - } - - var html_div_code = '<div class="panel panel-default" id="' + chart_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + chart_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-area-chart"> ' + content_detail.name + '</i></a></h4></div><div id="collapse-' + chart_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div id="'+chart_id+'" class="panel-body chart"></div></div></div>'; - generate_element(scope, "plot", html_div_code); - var element = document.getElementById(chart_id); - var label_element = $(document.createElement('div')); - label_element.addClass('row'); - - var accessnumber = "no_number"; - if(scope.report.number == scope.report_number) - { - accessnumber = "number"; - } - - var prepend_buttons = '<div class="col-sm-12"><div class="action-buttons report-buttons pull-left">'; - var append_buttons = '</div></div>'; - - var a_export = '<div class="btn-group"><button type="button" class="btn btn-primary btn-sm dropdown-toggle item_export ' + scope.report.status + ' ' + accessnumber + '" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-download fa-lg"></i> Export Figure <span class="caret"></span></button><ul class="dropdown-menu"><li id="PNG" buttonexportitem><a>PNG</a></li><li id="JPEG" buttonexportitem><a>JPEG</a></li><li id="PDF" buttonexportitem><a>PDF</a></li></ul></div>'; - if(scope.report.status == "editable" && scope.report.number != scope.report_number) { - var a_element = '<button class="btn btn-danger btn-sm item_delete ' + scope.report.status + ' ' + accessnumber + '" buttondeleteitem><i class="fa fa-times fa-lg"></i> Delete</button>'; - label_element.html(prepend_buttons + a_element + a_export + append_buttons); - } - else { - label_element.html(prepend_buttons + a_export + append_buttons); - } -; - $(element).find('.panel-body').append(label_element); - angular.element(document.getElementById('space-for-report-items')).append($compile(element)(scope)); - //var html_dropdown = "<chartdropdown id='selector_" + chart_id +"'></chartdropdown>"; - //angular.element(document.getElementById(chart_id)).html($compile(html_dropdown)(scope)); - - _retrieve_chart(scope, content_detail, element); - - }); - - //add new report item - element.bind("click", function() - { - var left = $('.add_item').offset().left - $('.add_item').width() + 400; - var top = $('.add_item').offset().top; - smart_selector.display(scope.item_content.content, left, top); - - var allblocks = []; - for(var i = 0; i < scope.report_experiments_blocks_merged_blocks.length; i++) - { - allblocks.push(scope.report_experiments_blocks_merged_blocks[i]); - } - scope.report.common_blocks = arraysInCommon(allblocks); - }); - - //handles first selector selection (table/plot) - if(smart_selector != undefined) - { - smart_selector.onEntrySelected = function(item_selected) - { - - var left = $('.add_item').offset().left - $('.add_item').width() + 400; - var top = $('.add_item').offset().top; - - var next_items_for_selector = prepareContent(scope, smart_selector.entries[smart_selector.selected_entry].identifier); - smart_selector_detail.display(next_items_for_selector, left, top); - }; - } - - //handles next selector detail selection - if(smart_selector_detail != undefined) - { - smart_selector_detail.onEntrySelected = function(item_selected) - { - var left = $('.add_item').offset().left - $('.add_item').width() + 400; - var top = $('.add_item').offset().top; - - - var result_next_items = nextDetailContent(scope, smart_selector.entries[smart_selector.selected_entry].identifier, smart_selector_detail.entries[smart_selector_detail.selected_entry]); - - if(!result_next_items[0]) - { - multiple_selector.display(result_next_items[1], left, top); - } - }; - } - - //handles first creation of table based on options - if(multiple_selector != undefined) - { - multiple_selector.onEntrySelected = function(item_selected, data) - { - for(var i = 0; i < multiple_selector.entries.length; i++) - { - if(multiple_selector.entries[i].name == item_selected) - { - multiple_selector.entries[i].selected = true; - } - } - }; - - multiple_selector.onEntryDeselected = function(item_selected, data) - { - for(var i = 0; i < multiple_selector.entries.length; i++) - { - if(multiple_selector.entries[i].name == item_selected) - { - multiple_selector.entries[i].selected = false; - } - } - }; - - multiple_selector.onClose = function() - { - //check if at least one item is selected - var checkOneSelected = false; - angular.forEach(multiple_selector.entries, function(value, key) - { - if(value.selected) - checkOneSelected = true - }); - - if(checkOneSelected) - { - var table_id = 'table' + '_' + scope.num_report_items; - - scope.tables_details[table_id] = multiple_selector.entries; - - var html_div_code = '<div class="panel panel-default" id="' + table_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + table_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-table"> Table</i></a></h4></div><div id="collapse-' + table_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div class="panel-body" table-dynamic monster=' + scope.num_report_items + " tableid=" + table_id + " reportstatus=" + scope.report.status + " urlprefix=" + scope.url_prefix + '></div></div></div>'; - - angular.element(document.getElementById('space-for-report-items')).append($compile(html_div_code)(scope)); - - scope.report.orderedcontent.push(table_id); - scope.num_report_items++; - } - } - } - - //handles single table updates via settings option - if(multiple_selector_updater != undefined) - { - multiple_selector_updater.onEntrySelected = function(item_selected, data) - { - for(var i = 0; i < multiple_selector_updater.entries.length; i++) - { - if(multiple_selector_updater.entries[i].name == item_selected) - { - multiple_selector_updater.entries[i].selected = true; - } - } - }; - - multiple_selector_updater.onEntryDeselected = function(item_selected, data) - { - for(var i = 0; i < multiple_selector_updater.entries.length; i++) - { - if(multiple_selector_updater.entries[i].name == item_selected) - { - multiple_selector_updater.entries[i].selected = false; - } - } - }; - - multiple_selector_updater.onClose = function() - { - - //check if at least one item is selected - var checkOneSelected = false; - angular.forEach(multiple_selector_updater.entries, function(value, key) - { - if(value.selected) - checkOneSelected = true - }); - - if(checkOneSelected) - { - var element = document.getElementById(multiple_selector_updater.current_table); - - $(element).attr('id', null); - $compile(element)(scope); - $(element).attr('id', multiple_selector_updater.current_table); - } - } - - }; - - //Prepare the content for selector initialization - function prepareContent(scope, content_identifier) - { - var next_content_items = []; - - switch(content_identifier) - { - case 'table': - next_content_items = scope.table_item_content.content; - break; - case 'plot': - angular.forEach(scope.report_experiments, function(value, key) - { - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer) - { - if(value_analyzer.algorithm == scope.report.analyzer) - { - scope.report_experiments[key].analyzer_block = key_analyzer; - } - }); - - var plottable_result = []; - angular.forEach(value.results[scope.report_experiments[key].analyzer_block], function(value_result_item, key_result_item) - { - if(value_result_item.type.startsWith("plot/")) - { - plottable_result.push(key_result_item); - } - - }); - - scope.report_experiments[key].plottable_blocks = plottable_result; - - }); - - //Results block are the same for all experiments from same analyzer. - //So just grab information from one of them for smart_selector items - var single_experiment = scope.report.experiments[0]; - - //create smart_selector items - angular.forEach(scope.report_experiments[single_experiment].plottable_blocks, function(value_plottable, key_plottable) - { - var plot_type = scope.report_experiments[single_experiment].results[scope.report_experiments[single_experiment].analyzer_block][value_plottable].type; - var item_dict = {}; - item_dict["identifier"] = value_plottable; - item_dict["name"] = value_plottable; - item_dict["description"] = plot_type; - - next_content_items.push(item_dict); - }); - break; - } - - return next_content_items; - } - - //Get the detailed content for next selector - function nextDetailContent(scope, content_identifier, sub_content) - { - var is_end = false; - var next_items = []; - var return_contents = []; - switch(content_identifier) - { - case 'table': - is_end = false; - angular.forEach(scope.report_experiments, function(value, key) - { - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer) - { - if(value_analyzer.algorithm == scope.report.analyzer) - { - scope.report_experiments[key].analyzer_block = key_analyzer; - } - }); - - var table_result = []; - angular.forEach(value.results[scope.report_experiments[key].analyzer_block], function(value_result_item, key_result_item) - { - if(!(value_result_item.type.startsWith("plot/"))) - { - table_result.push(key_result_item); - } - - }); - - scope.report_experiments[key].table_result_blocks = table_result; - - }); - - //Results block are the same for all experiments from same analyzer. - //So just grab information from one of them for smart_selector items - var single_experiment = scope.report.experiments[0]; - - //create smart_selector items - angular.forEach(scope.report_experiments[single_experiment].table_result_blocks, function(value_table_result, key_table_result) - { - - var table_item_data = scope.report_experiments[single_experiment].results[scope.report_experiments[single_experiment].analyzer_block][value_table_result]; - var item_dict = {}; - item_dict["identifier"] = value_table_result; - item_dict["name"] = value_table_result; - item_dict["description"] = table_item_data.type; - if(table_item_data.primary) - item_dict["selected"] = true; - else - item_dict["selected"] = false; - item_dict["data"] = table_item_data; - - next_items.push(item_dict); - }); - - //adding execution time entry information for common blocks - angular.forEach(scope.report.common_blocks, function(value_table_result, key_table_result) - { - var item_dict = {}; - item_dict["identifier"] = "execution_time." + value_table_result; - item_dict["name"] = "execution_time." + value_table_result; - item_dict["selected"] = false; - next_items.push(item_dict); - - }); - - //adding total execution time entry information for experiment - var item_dict = {}; - item_dict["identifier"] = "experiment.execution_time"; - item_dict["name"] = "experiment.execution_time"; - item_dict["selected"] = false; - next_items.push(item_dict); - - //adding globals algorithms parameters - angular.forEach(scope.report_algorithm_parameters, function(value_algorithm_parameters, key_algorithm_parameters) - { - for(var i = 0; i < Object.keys(value_algorithm_parameters).length; i++) - { - var item_dict = {}; - item_dict["identifier"] = "algorithm_parameter." + key_algorithm_parameters + "__" +Object.keys(value_algorithm_parameters)[i]; - item_dict["name"] = "algorithm_parameter." + key_algorithm_parameters + "__" +Object.keys(value_algorithm_parameters)[i]; - item_dict["selected"] = false; - next_items.push(item_dict); - } - - }); - - break; - case 'plot': - is_end = true; - var chart_id = 'chart_' + sub_content.identifier + '_graph' + '_' + scope.num_report_items; - var html_div_code = '<div class="panel panel-default" id="' + chart_id + '"><div class="panel-heading" role="tab"><h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-' + chart_id + '" aria-expanded="true" aria-controls="collapse-info"><i class="fa fa-area-chart"> ' + sub_content.name + '</i></a></h4></div><div id="collapse-' + chart_id + '" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"><div id="'+chart_id+'" class="panel-body chart {$ report.status $}"></div></div></div>'; - generate_element(scope, content_identifier, html_div_code); - var element = document.getElementById(chart_id); - var label_element = $(document.createElement('div')); - label_element.addClass('row'); - - var accessnumber = "no_number"; - if(scope.report.number == scope.report_number) - { - accessnumber = "number"; - } - - var prepend_buttons = '<div class="col-sm-12"><div class="action-buttons report-buttons pull-left">'; - var append_buttons = '</div></div>'; - - var a_export = '<div class="btn-group"><button type="button" class="btn btn-primary btn-sm dropdown-toggle item_export ' + scope.report.status + ' ' + accessnumber + '" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-download fa-lg"></i> Export Figure <span class="caret"></span></button><ul class="dropdown-menu"><li id="PNG" buttonexportitem><a>PNG</a></li><li id="JPEG" buttonexportitem><a>JPEG</a></li><li id="PDF" buttonexportitem><a>PDF</a></li></ul></div>'; - if(scope.report.status == "editable" && scope.report.number != scope.report_number) { - var a_element = '<button class="btn btn-danger btn-sm item_delete ' + scope.report.status + ' ' + accessnumber + '" buttondeleteitem><i class="fa fa-times fa-lg"></i> Delete</button>'; - label_element.html(prepend_buttons + a_element + a_export + append_buttons); - } - else { - label_element.html(prepend_buttons + a_export + append_buttons); - } - $(element).find('.panel-body').append(label_element); - - angular.element(document.getElementById('space-for-report-items')).append($compile(element)(scope)); - - _retrieve_chart(scope, sub_content, element); - scope.report.orderedcontent.push(chart_id); - break; - } - - return_contents = [is_end, next_items]; - - return return_contents; - - } - - //Generate and compile DOM element - function generate_element(scope, content_identifier, html_div_code) - { - switch(content_identifier) - { - case 'table': - angular.element(document.getElementById('space-for-report-items')).append($compile(html_div_code)(scope)); - scope.num_report_items++; - break; - case 'plot': - angular.element(document.getElementById('space-for-report-items')).append($compile(html_div_code)(scope)); - scope.num_report_items++; - break; - } - - } - - //Retrieve chart from api and display on proper item - function _get_chart(scope, sub_content, content_type, chart_id) - { - var required_plotter = []; - var set_plotter = '' - if(sub_content.selected_plotter != undefined) - { - //required_plotter.push(sub_content.selected_plotter); - set_plotter = sub_content.selected_plotter; - var requested_dataformat = ''; - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].name == sub_content.selected_plotter) - { - requested_dataformat = scope.report.plotters[i].dataformat; - break; - } - } - - //Get default plotter for required dataformat - for (var i = 0; i < scope.report.defaultplotters.length; i++) - { - if(scope.report.defaultplotters[i].dataformat == requested_dataformat) - { - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].dataformat == requested_dataformat && scope.report.plotters[i].name != sub_content.defaultplotter.plotter) - { - required_plotter.push(scope.report.plotters[i].name); - } - } - } - else - { - //Get default plotter for required dataformat - for (var i = 0; i < scope.report.defaultplotters.length; i++) - { - if(scope.report.defaultplotters[i].dataformat == sub_content.description) - { - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - set_plotter = sub_content.defaultplotter.plotter; - - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].dataformat == sub_content.description && scope.report.plotters[i].name != sub_content.defaultplotter.plotter) - { - required_plotter.push(scope.report.plotters[i].name); - } - } - } - - var plotterparameter = []; - //get plotterparameters valid for requested plotter - var required_plotter_id = undefined; - for(var i = 0; i < scope.report.plotters.length; i++) - { - if(required_plotter[0] == scope.report.plotters[i].name) - { - required_plotter_id = scope.report.plotters[i].id - } - } - - //Get other plotterparameter - for (var i = 0; i < scope.report.plotterparameter.length; i++) - { - if(required_plotter_id == undefined) - { - plotterparameter.push(scope.report.plotterparameter[i].name); - } - else - { - if(scope.report.plotterparameter[i].plotter == required_plotter_id) - { - plotterparameter.push(scope.report.plotterparameter[i].name); - } - } - } - - var chart_name = sub_content.name; - - var legend_experiments = ''; - var alias_experiments = []; - for(var i = 0; i < scope.report.experiments.length; i++) - { - if(i == 0) - legend_experiments = scope.report_experiments_alias[scope.report.experiments[i]]; - else - legend_experiments = legend_experiments+ "&" +scope.report_experiments_alias[scope.report.experiments[i]]; - - alias_experiments.push(scope.report_experiments_alias[scope.report.experiments[i]]); - } - - var request_data = { - experiment: alias_experiments, - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - legend: legend_experiments, - report_number: scope.report.number, - //height: 300, - //width: 400, - }; - - base_url = scope.report.url_prefix; - - var plot_detail = {}; - plot_detail["required_plotter"] = required_plotter; - plot_detail["data"] = { - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - }; - - if(sub_content.selected_template != undefined)// && sub_content.selected_template != "Default") - { - plot_detail["selected_template"] = sub_content.selected_template; - request_data.parameter = plot_detail["selected_template"]; - } - else - { - plot_detail["selected_template"] = sub_content.defaultplotter.parameter; - request_data.parameter = plot_detail["selected_template"]; - } - - if(sub_content.merged != undefined)// && sub_content.selected_template != "Default") - { - plot_detail["merged"] = sub_content.merged; - request_data.merged = plot_detail["merged"]; - } - else - { - plot_detail["merged"] = true; - request_data.merged = plot_detail["merged"]; - } - - beat.experiments.utils.getPlotData(base_url, - request_data, required_plotter, plotterparameter, content_type, - function(r_image_data, selected_content_type) { - download(r_image_data, chart_id + "." + content_type.toLowerCase(), selected_content_type); - } - ); - } - - - //Retrieve chart from api and display on proper item - function _retrieve_chart(scope, sub_content, container) - { - var required_plotter = []; - var set_plotter = '' - if(sub_content.selected_plotter != undefined) - { - //required_plotter.push(sub_content.selected_plotter); - set_plotter = sub_content.selected_plotter; - var requested_dataformat = ''; - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].name == sub_content.selected_plotter) - { - requested_dataformat = scope.report.plotters[i].dataformat; - break; - } - } - - //Get default plotter for required dataformat - for (var i = 0; i < scope.report.defaultplotters.length; i++) - { - if(scope.report.defaultplotters[i].dataformat == requested_dataformat) - { - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].dataformat == requested_dataformat && scope.report.plotters[i].name != sub_content.defaultplotter.plotter) - { - required_plotter.push(scope.report.plotters[i].name); - } - } - } - else - { - //Get default plotter for required dataformat - for (var i = 0; i < scope.report.defaultplotters.length; i++) - { - if(scope.report.defaultplotters[i].dataformat == sub_content.description) - { - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - set_plotter = sub_content.defaultplotter.plotter; - - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].dataformat == sub_content.description && scope.report.plotters[i].name != sub_content.defaultplotter.plotter) - { - required_plotter.push(scope.report.plotters[i].name); - } - } - } - - var plotterparameter = []; - //get plotterparameters valid for requested plotter - var required_plotter_id = undefined; - for(var i = 0; i < scope.report.plotters.length; i++) - { - if(required_plotter[0] == scope.report.plotters[i].name) - { - required_plotter_id = scope.report.plotters[i].id - } - } - - //Get other plotterparameter - for (var i = 0; i < scope.report.plotterparameter.length; i++) - { - if(required_plotter_id == undefined) - { - plotterparameter.push(scope.report.plotterparameter[i].name); - } - else - { - if(scope.report.plotterparameter[i].plotter == required_plotter_id) - { - plotterparameter.push(scope.report.plotterparameter[i].name); - } - } - } - - var chart_name = sub_content.name; - - var legend_experiments = ''; - var alias_experiments = []; - - for(var i = 0; i < scope.report.experiments.length; i++) - { - if(i == 0) - legend_experiments = scope.report_experiments_alias[scope.report.experiments[i]]; - else - legend_experiments = legend_experiments+ "&" +scope.report_experiments_alias[scope.report.experiments[i]]; - - if(Object.keys(scope.$parent.report_experiments_alias_from_content).length === 0 || scope.report_experiments_alias_from_content[scope.report.experiments[i]] == undefined ) - alias_experiments.push(scope.report_experiments_alias[scope.report.experiments[i]]); - else - alias_experiments.push(scope.report_experiments_alias_from_content[scope.report.experiments[i]]); - } - - var request_data = { - experiment: alias_experiments, - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - legend: legend_experiments, - report_number: scope.report.number, - //height: 300, - //width: 400, - }; - - base_url = scope.report.url_prefix; - //scope.plots_details[container.id]; - - var plot_detail = {}; - plot_detail["required_plotter"] = required_plotter; - plot_detail["data"] = { - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - }; - - - if(sub_content.selected_template != undefined)// && sub_content.selected_template != "Default") - { - plot_detail["selected_template"] = sub_content.selected_template; - request_data.parameter = plot_detail["selected_template"]; - } - else - { - plot_detail["selected_template"] = sub_content.defaultplotter.parameter; - request_data.parameter = plot_detail["selected_template"]; - } - - if(sub_content.merged != undefined)// && sub_content.selected_template != "Default") - { - plot_detail["merged"] = sub_content.merged; - request_data.merged = plot_detail["merged"]; - } - else - { - plot_detail["merged"] = true; - request_data.merged = plot_detail["merged"]; - } - - scope.plots_details[container.id]= plot_detail; - - if(scope.report.status == "editable" && scope.report.number != scope.report_number) - { - beat.experiments.utils.displayPlot(base_url, $(container).find('.panel-body')[0], - request_data, required_plotter, plotterparameter, false, - - function(r_plotter, r_plotterparameter, r_merged) { - scope.plots_details[container.id]["data"]["plotter"] = r_plotter; - scope.plots_details[container.id]["selected_template"] = r_plotterparameter; - scope.plots_details[container.id]["merged"] = r_merged; - } - ); - } - else - { - beat.experiments.utils.displayPlot(base_url, $(container).find('.panel-body')[0], - request_data, [], [], false, - - function(r_plotter, r_plotterparameter, r_merged) { - } - ); - } - } - - function arraysInCommon(arrays) - { - var i, common, - L= arrays.length, min= Infinity; - while(L){ - if(arrays[--L].length<min){ - min= arrays[L].length; - i= L; - } - } - common= arrays.splice(i, 1)[0]; - return common.filter(function(itm, indx){ - if(common.indexOf(itm)== indx){ - return arrays.every(function(arr){ - return arr.indexOf(itm)!= -1; - }); - } - }); - } - - } -}); - - -//Dynamic tables items -app.directive('item', function ($compile) { - function createTDElement(column) { - var table = angular.element('<table><tr><td class="tableitemspace" thecolumn="' + column + '"></td></tr></table>'); - return table.find('td'); - } - - function render(element, scope) { - var column, html, i; - var columns = scope.$parent.tables_details[scope.$parent.dattrs.tableid]; - - for (i = 0; i < columns.length ; i++) { - if(i == 0 && columns.length > 0) - { - html = $compile(createTDElement("experiment"))(scope); - - } - column = columns[i]; - if (column.selected) { - - html = $compile(createTDElement(column.name))(scope); - element.append(html); - } - } - - - } - - return { - // restrict: 'A', - scope: { - exp_name: "=", - item: "=", - columns: "=" - }, - compile: function () { - return function (scope, element) { - render(element, scope); - } - - } - }; - -}); - -//Directive used to set proper item value in selected column -app.directive("thecolumn",['$compile', function ($compile) { - - return { - scope: { - thecolumn: "@" - }, - restrict: 'A', - template: '{{itemValue}}', - controller: ['$scope', function ($scope) { - - var the_parent = $scope.$parent.$parent.$parent.$parent; - var report_experiments = $scope.$parent.$parent.$parent.$parent.report_experiments; - var report_experiments_alias = $scope.$parent.$parent.$parent.$parent.report_experiments_alias; - var floating_point_precision = $scope.$parent.$parent.$parent.$parent.floating_point_precision; - var report = $scope.$parent.$parent.$parent.report; - var experiment_name = $scope.$parent.item; - - if(jQuery.isEmptyObject(report_experiments) || (report_experiments[experiment_name] == undefined)) - { - return - } - - var analyzer_block = report_experiments[experiment_name].analyzer_block; - var report_algorithm_parameters_experiment = $scope.$parent.$parent.$parent.$parent.report_algorithm_parameters_experiment; - - if($scope.thecolumn != "experiment") - { - if(analyzer_block == undefined) - { - angular.forEach(report_experiments, function(value, key) - { - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer) - { - if(value_analyzer.algorithm == report.analyzer && (key_analyzer in report_experiments[experiment_name].declaration.analyzers)) - { - report_experiments[experiment_name].analyzer_block = key_analyzer; - analyzer_block = report_experiments[experiment_name].analyzer_block; - } - }); - }); - } - - if($scope.thecolumn.indexOf("execution_time.") == 0) - { - //execution time information - var block_name = $scope.thecolumn.split("execution_time.")[1].split("[s]")[0]; - if(Object.keys(report_experiments[experiment_name].execution_info).length === 0) - { - $scope.itemValue = "-"; - } - else - { - if(report_experiments[experiment_name].execution_info[block_name] == undefined) - { - $scope.itemValue = "-"; - } - else - { - $scope.itemValue = (report_experiments[experiment_name].execution_info[block_name].linear_execution_time).toFixed(floating_point_precision.selected);; - } - } - } - else if($scope.thecolumn.indexOf("experiment.") == 0) - { - //total execution time information - var block_name = $scope.thecolumn.split("execution_time.")[1]; - var total_time = 0; - if(Object.keys(report_experiments[experiment_name].execution_info).length === 0) - { - total_time = "-"; - } - else - { - angular.forEach(report_experiments[experiment_name].execution_info, function(value, key) - { - total_time += value.linear_execution_time; - }); - } - - $scope.itemValue = total_time.toFixed(floating_point_precision.selected); - } - else if($scope.thecolumn.indexOf("algorithm_parameter.") == 0) - { - //total execution time information - var block_name = $scope.thecolumn.split("algorithm_parameter.")[1]; - var algorithm_name = block_name.split("__")[0]; - var parameter_name = block_name.split("__")[1]; - if(report_algorithm_parameters_experiment[experiment_name][algorithm_name] != undefined) - { - var value = ""; - if(report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name] != undefined) - { - for(var i = 0; i < report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name].length; i++) - { - if(i > 0 && i < report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name].length -1 ) - { - value += ","; - } - value = report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name][i]; - } - } - else if(report["all_experiments"][experiment_name]["declaration"]["globals"][algorithm_name][parameter_name] != undefined) - { - //get globals value - value = report["all_experiments"][experiment_name]["declaration"]["globals"][algorithm_name][parameter_name]; - } - else - { - //nothing is defined - value = "-"; - } - - $scope.itemValue = value; - } - else - { - $scope.itemValue = "-"; - } - } - else - { - //results information - $scope.itemValue = (report_experiments[experiment_name].results[analyzer_block][$scope.thecolumn].value).toFixed(floating_point_precision.selected); - } - } - else - { - var experiment_alias = report_experiments_alias[experiment_name]; - $scope.itemValue = experiment_alias; - } - }]//, - //link: function(scope, element, attrs) - //{ - // console.log(scope); - // var report_experiments_alias = scope.$parent.$parent.$parent.$parent.report_experiments_alias; - // var experiment_name = scope.$parent.item; - // var experiment_alias = report_experiments_alias[experiment_name]; - // scope.$watch(scope.$parent.$parent.$parent.$parent.report_experiments_alias,function(newValue, oldValue) - // { - // console.log("changed"); - // console.log(report_experiments_alias); - // console.log(oldValue); - // console.log(newValue); - // }); - // - //} - } -}]); - -//Directive used to generate the dynamic table loading partials -app.directive("tableDynamic", function(){ - - return { - restrict: 'A', - scope: true, - replace: true, - Â Â Â Â //templateUrl: "/reports/partials/reportTable/", - Â Â Â Â templateUrl: function(scope, elem, attrs) - { - var prefix = elem['urlprefix']; - Â Â Â Â var the_url = prefix + "/reports/partials/reportTable/"; - return the_url; - }, - link: function(scope, elem, attrs) - { - var prepend_item = {}; - prepend_item["name"] = "experiment"; - prepend_item["selected"] = true; - - scope.tables_details[attrs.tableid].unshift(prepend_item); - - angular.forEach(scope.tables_details, function(table_value, table_key) - { - for(var i = 0; i < table_value.length; i++) - { - if(table_value[i].name.indexOf("execution_time") > -1 && - table_value[i].name.indexOf("[s]") == -1) - { - table_value[i].name = table_value[i].name + "[s]"; - } - }; - }); - - scope.dattrs = attrs; - } - }; -}); - -//Directive used to generate the dynamic table loading partials -app.directive("myreportinfo", function(){ - - return { - restrict: 'E', - scope: true, - replace: true, - Â Â Â Â //templateUrl: "/reports/partials/reportTable/", - Â Â Â Â templateUrl: function(scope, elem, attrs) - { - var prefix = elem['urlprefix']; - Â Â Â Â var the_url = prefix + "/reports/partials/reportInfo/"; - return the_url; - }, - link: function(scope, elem, attrs) - { - }, - controller: ['$scope', function ($scope) { - }], - }; -}); - -//Directive used to handle table settings click -app.directive("buttonsettings", function() -{ - return { - link:function(scope, element, attrs) - { - element.bind("click", function() - { - var name_to_remove = "experiment"; - var tables_details = scope.$parent.tables_details[scope.dattrs.tableid]; - for(var i = 0; i < tables_details.length; i++) - { - if(tables_details[i].name == "experiment") - { - tables_details.splice(i,1); - break; - } - } - multiple_selector_updater.current_table = scope.dattrs.tableid; - multiple_selector_updater.display(tables_details); - }); - } - }; -}); - -//Directive used to handle table settings click -app.directive("sortdata", function($compile) -{ - return { - link:function(scope, element, attrs) - { - element.bind("click", function() - { - var the_parent = scope.$parent.$parent.$parent.$parent; - var analyzer_block = undefined; - var report_experiments = the_parent.report_experiments; - var report = the_parent.report; - var table_id = attrs.sorttblid; //get table id - the_parent.sorted_tables.push(table_id); - - if(the_parent.sorted_experiments_keys_reverse[table_id] == undefined) - { - the_parent.sorted_experiments_keys_reverse[table_id] = true; - } - else - { - the_parent.sorted_experiments_keys_reverse[table_id] = !the_parent.sorted_experiments_keys_reverse[table_id]; - } - - the_parent.sorted_experiments_keys_tables_sortkey[table_id] = attrs.sortth; //set the sortKey to the param passed - - if(the_parent.sorted_experiments_keys_tables_sortkey[table_id] != "experiment") - { - var local_sort_list = []; - - if(analyzer_block == undefined) - { - angular.forEach(report_experiments, function(value, key) - { - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer) - { - if(value_analyzer.algorithm == report.analyzer && (key_analyzer in report_experiments[key].declaration.analyzers)) - { - report_experiments[key].analyzer_block = key_analyzer; - analyzer_block = report_experiments[key].analyzer_block; - } - }); - }); - } - - if(the_parent.sorted_experiments_keys_tables_sortkey[table_id].indexOf("execution_time.") == 0) - { - //execution time information - var block_name = the_parent.sorted_experiments_keys_tables_sortkey[table_id].split("execution_time.")[1].split("[s]")[0]; - angular.forEach(report_experiments, function(value, key) - { - var local_sort_dict = {}; - local_sort_dict["experiment"] = key; - var itemValue = ""; - - if(Object.keys(report_experiments[key].execution_info).length === 0) - { - itemValue = "-"; - } - else - { - if(report_experiments[key].execution_info[block_name] == undefined) - { - itemValue = "-"; - } - else - { - itemValue = (report_experiments[key].execution_info[block_name].linear_execution_time); - } - } - - local_sort_dict["value"] = itemValue; - local_sort_list.push(local_sort_dict); - }); - } - else if(the_parent.sorted_experiments_keys_tables_sortkey[table_id].indexOf("experiment.") == 0) - { - //total execution time information - var block_name = the_parent.sorted_experiments_keys_tables_sortkey[table_id].split("execution_time.")[1]; - - angular.forEach(report_experiments, function(value, key) - { - var local_sort_dict = {}; - local_sort_dict["experiment"] = key; - var itemValue = ""; - var total_time = 0; - - if(Object.keys(report_experiments[key].execution_info).length === 0) - { - total_time = "-"; - } - else - { - angular.forEach(report_experiments[key].execution_info, function(value, key) - { - total_time += value.linear_execution_time; - }); - } - - itemValue = total_time; - - local_sort_dict["value"] = itemValue; - local_sort_list.push(local_sort_dict); - }); - } - else if(the_parent.sorted_experiments_keys_tables_sortkey[table_id].indexOf("algorithm_parameter.") == 0) - { - //total execution time information - var block_name = the_parent.sorted_experiments_keys_tables_sortkey[table_id].split("algorithm_parameter.")[1]; - var algorithm_name = block_name.split("__")[0]; - var parameter_name = block_name.split("__")[1]; - - angular.forEach(report_experiments, function(value, key) - { - - var local_sort_dict = {}; - local_sort_dict["experiment"] = key; - var itemValue = ""; - - if(the_parent.report_algorithm_parameters_experiment[key][algorithm_name] != undefined) - { - var value = ""; - if(the_parent.report_algorithm_parameters_experiment[key][algorithm_name][parameter_name] != undefined) - { - for(var i = 0; i < the_parent.report_algorithm_parameters_experiment[key][algorithm_name][parameter_name].length; i++) - { - if(i > 0 && i < the_parent.report_algorithm_parameters_experiment[key][algorithm_name][parameter_name].length -1 ) - { - value += ","; - } - value = the_parent.report_algorithm_parameters_experiment[key][algorithm_name][parameter_name][i]; - } - } - else if(the_parent.report["all_experiments"][key]["declaration"]["globals"][algorithm_name][parameter_name] != undefined) - { - //get globals value - value = the_parent.report["all_experiments"][key]["declaration"]["globals"][algorithm_name][parameter_name]; - } - else - { - //nothing is defined - value = "-"; - } - - itemValue = value; - } - else - { - itemValue = "-"; - } - - local_sort_dict["value"] = itemValue; - local_sort_list.push(local_sort_dict); - }); - } - else - { - //results information - angular.forEach(report_experiments, function(value, key) - { - var local_sort_dict = {}; - local_sort_dict["experiment"] = key; - local_sort_dict["value"] = report_experiments[key].results[analyzer_block][the_parent.sorted_experiments_keys_tables_sortkey[table_id]].value; - - local_sort_list.push(local_sort_dict); - - }); - - } - - if(the_parent.sorted_experiments_keys_reverse[table_id]) - { - local_sort_list.sort(function(a, b) - { - return a.value - b.value; - }); - } - else - { - local_sort_list.sort(function(a, b) - { - return b.value - a.value; - }); - } - - the_parent.sorted_experiments_keys_tables[table_id] = []; - the_parent.sorted_experiments_alias_keys_tables[table_id] = []; - for(var i = 0; i < local_sort_list.length; i++) - { - the_parent.sorted_experiments_keys_tables[table_id].push(local_sort_list[i]["experiment"]); - if(the_parent.report.status == "editable") - { - the_parent.sorted_experiments_alias_keys_tables[table_id].push(the_parent.report_experiments_alias[local_sort_list[i]["experiment"]]); - } - } - - } - else - { - var experiments_aliases = []; - for(var i = 0; i < the_parent.report.experiments.length; i++) - { - var experiment_name = the_parent.report.experiments[i]; - var experiment_alias = the_parent.report_experiments_alias[experiment_name]; - experiments_aliases.push(experiment_alias); - } - - if(the_parent.sorted_experiments_keys_reverse[table_id]) - { - experiments_aliases.sort(function(a, b) - { - return a.value - b.value; - }); - } - else - { - experiments_aliases.reverse(function(a, b) - { - return b.value - a.value; - }); - } - - the_parent.sorted_experiments_keys_tables[table_id] = []; - the_parent.sorted_experiments_alias_keys_tables[table_id] = []; - for(var i = 0; i < experiments_aliases.length; i++) - { - for(var the_experiment_key in the_parent.report_experiments_alias) - { - if(the_parent.report_experiments_alias[the_experiment_key] == experiments_aliases[i]) - { - the_parent.sorted_experiments_keys_tables[table_id].push(the_experiment_key); - if(the_parent.report.status == "editable") - { - the_parent.sorted_experiments_alias_keys_tables[table_id].push(the_parent.report_experiments_alias[the_experiment_key]); - } - } - - } - } - } - - var name_to_remove = "experiment"; - var tables_details = the_parent.tables_details[table_id]; - for(var i = 0; i < tables_details.length; i++) - { - if(tables_details[i].name == "experiment") - { - tables_details.splice(i,1); - break; - } - } - - var element = document.getElementById(table_id); - - $(element).attr('id', null); - $compile(element)(scope.$parent.$parent); - $(element).attr('id', table_id); - }); - } - }; -}); - -//Directive used to handle table settings click -app.directive("tableprecision", function($compile) -{ - return { - link:function(scope, element, attrs) - { - element.bind("change", function() - { - fixFloatingPoint(scope.$parent.$parent.floating_point_precision.selected); - }); - - function fixFloatingPoint(selected_precision) - { - if(!scope.$$phase) - { - //$digest or $apply - var parent_scope = scope.$parent; - var table_details = parent_scope.tables_details; - - for(var i = 0; i < parent_scope.report.orderedcontent.length; i++) - { - var element = document.getElementById(parent_scope.report.orderedcontent[i]); - - $(element).remove(); - - var id_content = parent_scope.report.orderedcontent[i]; - var type = id_content.split("_")[0]; - parent_scope.$parent.$parent.$broadcast("addSavedElement", id_content, type); - } - } - } - } - }; -}); - -//Directive used to handle table settings click -app.directive("buttondeleteitem", function() -{ - return { - link:function(scope, element, attrs) - { - element.bind("click", function() - { - var elementToRemove = element.context.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement; - beat.ui.report.remove_item('report_remove_item', elementToRemove, scope); - }); - } - }; -}); - -//Directive used to export graph/tables on click -app.directive("buttonexportitem", function() -{ - return { - link:function(scope, element, attrs) - { - element.bind("click", function() - { - var the_element = element.context.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement; - if(the_element.id.indexOf("chart_") == 0) - { - var content_detail = {}; - var chart_id = the_element.id; - - content_detail["name"] = scope.plots_details[chart_id].data.output[0]; - - if(scope.plots_details[chart_id].data.plotter != undefined) - { - content_detail["selected_plotter"] = scope.plots_details[chart_id].data.plotter; - } - if(scope.plots_details[chart_id].data.parameter != undefined) - { - content_detail["selected_template"] = scope.plots_details[chart_id].data.parameter; - } - else if(scope.plots_details[chart_id]["selected_template"] != undefined) - { - content_detail["selected_template"] = scope.plots_details[chart_id]["selected_template"]; - } - if(scope.plots_details[chart_id].data.merged != undefined) - { - content_detail["merged"] = scope.plots_details[chart_id].data.merged; - } - - var accessnumber = "no_number"; - if(scope.report.number == scope.report_number) - { - accessnumber = "number"; - } - _get_chart(scope, content_detail, element[0].id, chart_id); - } - else if(the_element.id.indexOf("table_") == 0) - { - var separator = ","; - var csv_text = export_table_as_csv(scope, the_element.id, separator); - var output_filename = the_element.id + ".csv"; - download(csv_text, output_filename, "text/plain"); - } - }); - } - }; - - function export_table_as_csv(scope, table_id, separator) - { - var report_experiments = scope.$parent.report_experiments; - var report_experiments_alias = scope.$parent.report_experiments_alias; - var floating_point_precision = scope.$parent.floating_point_precision; - var report = scope.report; - var final_table = []; - var table_headers = []; - angular.forEach(scope.tables_details[table_id], function(table_value, table_key) - { - if(table_value.selected) - { - table_headers.push(table_value.name); - } - }); - - final_table.push(table_headers); - - angular.forEach(report_experiments, function(experiment_value, experiment_key) - { - var table_items = []; - - angular.forEach(table_headers, function(table_value, table_key) - { - var experiment_name = experiment_key; - var analyzer_block = report_experiments[experiment_name].analyzer_block; - var report_algorithm_parameters_experiment = scope.$parent.report_algorithm_parameters_experiment; - - if(table_value != "experiment") - { - if(analyzer_block == undefined) - { - angular.forEach(report_experiments, function(value, key) - { - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer) - { - if(value_analyzer.algorithm == report.analyzer && (key_analyzer in report_experiments[experiment_name].declaration.analyzers)) - { - report_experiments[experiment_name].analyzer_block = key_analyzer; - analyzer_block = report_experiments[experiment_name].analyzer_block; - } - }); - }); - } - - if(table_value.indexOf("execution_time.") == 0) - { - //execution time information - var block_name = table_value.split("execution_time.")[1].split("[s]")[0]; - if(Object.keys(report_experiments[experiment_name].execution_info).length === 0) - { - table_items.push("-"); - } - else - { - if(report_experiments[experiment_name].execution_info[block_name] == undefined) - { - table_items.push("-"); - } - else - { - table_items.push((report_experiments[experiment_name].execution_info[block_name].linear_execution_time).toFixed(floating_point_precision.selected)); - } - } - } - else if(table_value.indexOf("experiment.") == 0) - { - //total execution time information - var block_name = table_value.split("execution_time.")[1]; - var total_time = 0; - if(Object.keys(report_experiments[experiment_name].execution_info).length === 0) - { - total_time = "-"; - } - else - { - angular.forEach(report_experiments[experiment_name].execution_info, function(value, key) - { - total_time += value.linear_execution_time; - }); - } - - table_items.push(total_time.toFixed(floating_point_precision.selected)); - } - else if(table_value.indexOf("algorithm_parameter.") == 0) - { - //total execution time information - var block_name = table_value.split("algorithm_parameter.")[1]; - var algorithm_name = block_name.split("__")[0]; - var parameter_name = block_name.split("__")[1]; - if(report_algorithm_parameters_experiment[experiment_name][algorithm_name] != undefined) - { - var value = ""; - for(var i = 0; i < report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name].length; i++) - { - if(i > 0 && i < report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name].length -1 ) - { - value += ","; - } - value = report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name][i]; - } - - table_items.push(value); - } - else - { - table_items.push("-"); - } - } - else - { - //results information - table_items.push((report_experiments[experiment_name].results[analyzer_block][table_value].value).toFixed(floating_point_precision.selected)); - } - } - else - { - var experiment_alias = report_experiments_alias[experiment_name]; - table_items.push(experiment_alias); - } - - }); - - final_table.push(table_items); - - }); - - var csv_text = ""; - for(var i = 0; i < final_table.length; i++) - { - if(i != 0) - { - csv_text += "\n"; - } - - for(var j = 0; j < final_table[i].length; j++) - { - if( j != 0) - { - csv_text += separator; - } - csv_text += final_table[i][j]; - } - } - - var pre_base64_text = "data:text/plain;base64,"; - var base_64_csv_text = pre_base64_text + Base64.encode(csv_text); - return base_64_csv_text; - } - - //Retrieve chart from api and display on proper item - function _get_chart(scope, sub_content, content_type, chart_id) - { - var required_plotter = []; - var set_plotter = '' - if(sub_content.selected_plotter != undefined) - { - //required_plotter.push(sub_content.selected_plotter); - set_plotter = sub_content.selected_plotter; - var requested_dataformat = ''; - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].name == sub_content.selected_plotter) - { - requested_dataformat = scope.report.plotters[i].dataformat; - break; - } - } - - //Get default plotter for required dataformat - for (var i = 0; i < scope.report.defaultplotters.length; i++) - { - if(scope.report.defaultplotters[i].dataformat == requested_dataformat) - { - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].dataformat == requested_dataformat && scope.report.plotters[i].name != sub_content.defaultplotter.plotter) - { - required_plotter.push(scope.report.plotters[i].name); - } - } - } - else - { - //Get default plotter for required dataformat - for (var i = 0; i < scope.report.defaultplotters.length; i++) - { - if(scope.report.defaultplotters[i].dataformat == sub_content.description) - { - sub_content.defaultplotter = scope.report.defaultplotters[i]; - break; - } - } - - required_plotter.push(sub_content.defaultplotter.plotter); - set_plotter = sub_content.defaultplotter.plotter; - - //Get other plotters for required dataformat - for (var i = 0; i < scope.report.plotters.length; i++) - { - if(scope.report.plotters[i].dataformat == sub_content.description && scope.report.plotters[i].name != sub_content.defaultplotter.plotter) - { - required_plotter.push(scope.report.plotters[i].name); - } - } - } - - var plotterparameter = []; - //get plotterparameters valid for requested plotter - var required_plotter_id = undefined; - for(var i = 0; i < scope.report.plotters.length; i++) - { - if(required_plotter[0] == scope.report.plotters[i].name) - { - required_plotter_id = scope.report.plotters[i].id - } - } - - //Get other plotterparameter - for (var i = 0; i < scope.report.plotterparameter.length; i++) - { - if(required_plotter_id == undefined) - { - plotterparameter.push(scope.report.plotterparameter[i].name); - } - else - { - if(scope.report.plotterparameter[i].plotter == required_plotter_id) - { - plotterparameter.push(scope.report.plotterparameter[i].name); - } - } - } - - var chart_name = sub_content.name; - - var legend_experiments = ''; - for(var i = 0; i < scope.report.experiments.length; i++) - { - if(i == 0) - legend_experiments = scope.report_experiments_alias[scope.report.experiments[i]]; - else - legend_experiments = legend_experiments+ "&" +scope.report_experiments_alias[scope.report.experiments[i]]; - } - - var request_data = { - experiment: scope.report.experiments, - analyzer: [scope.report.analyzer], - output: [chart_name], - plotter: set_plotter, - legend: legend_experiments, - //height: 300, - //width: 400, - }; - - base_url = scope.report.url_prefix; - - var plot_detail = {}; - plot_detail["required_plotter"] = required_plotter; - plot_detail["data"] = request_data; - if(sub_content.selected_template != undefined)// && sub_content.selected_template != "Default") - { - plot_detail["selected_template"] = sub_content.selected_template; - request_data.parameter = plot_detail["selected_template"]; - } - else - { - plot_detail["selected_template"] = sub_content.defaultplotter.parameter; - request_data.parameter = plot_detail["selected_template"]; - } - - if(sub_content.merged != undefined)// && sub_content.selected_template != "Default") - { - plot_detail["merged"] = sub_content.merged; - request_data.merged = plot_detail["merged"]; - } - else - { - plot_detail["merged"] = true; - request_data.merged = plot_detail["merged"]; - } - - beat.experiments.utils.getPlotData(base_url, - request_data, required_plotter, plotterparameter, content_type, - function(r_image_data, selected_content_type) { - download(r_image_data, chart_id + "." + content_type.toLowerCase(), selected_content_type); - } - ); - } - - -}); - - -//Directive used to handle table settings click -app.directive("aliasexperiment", function($compile) -{ - return { - link:function(scope, element, attrs) - { - var alias_name = scope.$parent.$parent.$parent.$parent.report_experiments_alias[scope.name]; - createAlias(scope.name, alias_name); - - /* - element.on("blur", function() - { - val = $(this).val(); - if (!val) { - alert("Alias for experiment" + scope.name + " can't be empty!"); - } - else { - var experiment_name = this.id.split("input_")[1]; - createAlias(experiment_name, val); - } - }); - */ - - element.bind("click", function() - { - var input_element = document.getElementById("input_"+scope.name); - var icon_element = document.getElementById("icon_"+scope.name); - var button_element = document.getElementById("button_alias_"+scope.name); - if(! $(input_element).hasClass("input-disabled")) - { - if ($(input_element).val()) - { - $(input_element).addClass("input-disabled"); - $(input_element).attr("disabled", true); - $(icon_element).removeClass("fa-unlock"); - $(icon_element).addClass("fa-lock"); - $(button_element).addClass("setalias"); - var experiment_name = attrs.id.split("button_alias_")[1]; - var alias_name = $(input_element).val(); - $(input_element).val(alias_name); - createAlias(experiment_name, alias_name); - } - else - { - alert("Alias for experiment" + scope.name + " can't be empty!"); - } - } - else - { - $(input_element).removeClass("input-disabled"); - $(input_element).attr("disabled", false); - $(icon_element).removeClass("fa-lock"); - $(icon_element).addClass("fa-unlock"); - $(button_element).removeClass("setalias"); - - } - }); - - function createAlias(experiment_name, alias_name) - { - scope.report_experiments_alias[experiment_name] = alias_name; - scope.$parent.$parent.$parent.$parent.report_experiments_alias[experiment_name] = alias_name; - - if(!scope.$$phase) - { - //$digest or $apply - var parent_scope = scope.$parent.$parent.$parent.$parent - var table_details = parent_scope.tables_details; - - for(var i = 0; i < parent_scope.report.orderedcontent.length; i++) - { - var element = document.getElementById(parent_scope.report.orderedcontent[i]); - - $(element).remove(); - - var id_content = parent_scope.report.orderedcontent[i]; - var type = id_content.split("_")[0]; - parent_scope.$parent.$broadcast("addSavedElement", id_content, type); - } - } - } - } - }; -}); - - -////Directive used to generate the dynamic table loading partials -//app.directive("chartdropdown", function(){ -// return { -// restrict: 'E', -// scope: true, -// replace: true, -// Â Â Â Â templateUrl:"/reports/partials/reportChartDropDown/", -// link: function(scope, element, attrs) -// { -// scope.dattrs = attrs; -// var element_id = (element.context.id).split("selector_"); -// var selected_template = scope.plots_details[element_id[1]].selected_template; -// if(selected_template != undefined) -// { -// -// scope.dattrs.selected_template = selected_template; -// var selector_name = "#"+element.context.id + " select"; -// } -// else -// { -// scope.dattrs.selected_template = "Default"; -// } -// -// element.bind("change", function() -// { -// var selected_template = element.context.children[0].selectedOptions[0].label; -// var elem_id = (attrs.id).split("selector_"); -// -// scope.plots_details[elem_id[1]].selected_template = selected_template; -// -// -// var type = "afdaf"; -// var id_content = elem_id[1]; -// scope.$parent.report.content[id_content].selected_template = selected_template; -// scope.$parent.$broadcast("redrawGraphElement", id_content, type); -// -// }); -// -// } -// -// }; -//}); diff --git a/beat/web/reports/static/reports/app/directives/saveReportItems.js b/beat/web/reports/static/reports/app/directives/saveReportItems.js index 0b3e4119c6b1e453c5fa5604f3c8785631ff6fef..772b85c0a49ea12e99366b6cbb62d0d1bfaf9214 100644 --- a/beat/web/reports/static/reports/app/directives/saveReportItems.js +++ b/beat/web/reports/static/reports/app/directives/saveReportItems.js @@ -20,68 +20,21 @@ * with the BEAT platform. If not, see http://www.gnu.org/licenses/. */ -//Directive for opening smart_selector list on "Add a report item" button click that displays options +// Saves the report angular.module('reportApp').directive("savereportitems", ['$compile', 'GroupsService', function($compile, GroupsService){ return function(scope, element, attrs){ //add new report item element.bind("click", function(){ - //let savecontent = []; - let savecontent = {}; - if(scope.plots_details != undefined){ - angular.forEach(scope.plots_details, function(value, key){ - //savecontent.push(key, value); - savecontent[key] = value; - }); - } - if(scope.tables_details != undefined){ - angular.forEach(scope.tables_details, function(value, key){ - savecontent[key] = value; - //savecontent.push(key, value); - }); - - if(scope.floating_point_precision.selected != undefined){ - savecontent["floating_point_precision"] = scope.floating_point_precision.selected; - } - } - if(scope.report_experiments_alias != undefined){ - let alias_experiments = {}; - angular.forEach(scope.report_experiments_alias, function(value, key){ - alias_experiments[key] = value; - }); - savecontent["alias_experiments"] = alias_experiments; - } - - if(!(jQuery.isEmptyObject(scope.sorted_experiments_keys_tables)) && !(jQuery.isEmptyObject(scope.sorted_experiments_keys_reverse)) && !(jQuery.isEmptyObject(scope.sorted_experiments_keys_tables_sortkey))){ - savecontent["sorted_tables_experiments"] = scope.sorted_experiments_keys_tables; - savecontent["sorted_tables_alias_experiments"] = scope.sorted_experiments_alias_keys_tables; - savecontent["sorted_tables_keys_reverse"] = scope.sorted_experiments_keys_reverse; - savecontent["sorted_tables_sortkey"] = scope.sorted_experiments_keys_tables_sortkey; - } - - // save group data - savecontent['groups'] = GroupsService.serializeGroups(); - //call set report content from factory let mydict = {}; - mydict["experiments"] = scope.report.experiments; - mydict["content"] = savecontent; - - for(let i = 0; i < scope.report.experiments.length; i++){ - scope.report_experiments_alias_from_content[scope.report.experiments[i]] = scope.report_experiments_alias[scope.report.experiments[i]]; - } + mydict["content"] = { + 'groups': GroupsService.serializeGroups() + }; - updateReport(mydict); - }); - - - function updateReport(data){ - scope.reportFactory.updateReport(scope.user, scope.report_id, data, scope.url_prefix) + scope.reportFactory.updateReport(scope.user, scope.report_id, mydict, scope.url_prefix) .error(function (error){ - scope.status = `Unable to update report data: ${error ? error.message : ''}`; - }); - - } + }); }; }]); diff --git a/beat/web/reports/static/reports/app/directives/sortData.js b/beat/web/reports/static/reports/app/directives/sortData.js deleted file mode 100644 index 9f9f9a0231dfae07554d448964a19aca76df514a..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/sortData.js +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to handle table settings click -angular.module('reportApp').directive("sortdata", function($compile){ - return { - link:function(scope, element, attrs){ - element.bind("click", function(){ - let the_parent = scope.$parent.$parent.$parent.$parent; - let analyzer_block = undefined; - let report_experiments = the_parent.report_experiments; - let report = the_parent.report; - let table_id = attrs.sorttblid; //get table id - the_parent.sorted_tables.push(table_id); - - if(the_parent.sorted_experiments_keys_reverse[table_id] == undefined){ - the_parent.sorted_experiments_keys_reverse[table_id] = true; - } - else{ - the_parent.sorted_experiments_keys_reverse[table_id] = !the_parent.sorted_experiments_keys_reverse[table_id]; - } - - the_parent.sorted_experiments_keys_tables_sortkey[table_id] = attrs.sortth; //set the sortKey to the param passed - - if(the_parent.sorted_experiments_keys_tables_sortkey[table_id] != "experiment"){ - let local_sort_list = []; - - if(analyzer_block == undefined){ - angular.forEach(report_experiments, function(value, key){ - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer){ - if(value_analyzer.algorithm == report.analyzer && (key_analyzer in report_experiments[key].declaration.analyzers)){ - report_experiments[key].analyzer_block = key_analyzer; - analyzer_block = report_experiments[key].analyzer_block; - } - }); - }); - } - - if(the_parent.sorted_experiments_keys_tables_sortkey[table_id].indexOf("execution_time.") == 0){ - //execution time information - let block_name = the_parent.sorted_experiments_keys_tables_sortkey[table_id].split("execution_time.")[1].split("[s]")[0]; - angular.forEach(report_experiments, function(value, key){ - let local_sort_dict = {}; - local_sort_dict["experiment"] = key; - let itemValue = ""; - - if(Object.keys(report_experiments[key].execution_info).length === 0){ - itemValue = "-"; - } - else{ - if(report_experiments[key].execution_info[block_name] == undefined){ - itemValue = "-"; - } - else{ - itemValue = (report_experiments[key].execution_info[block_name].linear_execution_time); - } - } - - local_sort_dict["value"] = itemValue; - local_sort_list.push(local_sort_dict); - }); - } - else if(the_parent.sorted_experiments_keys_tables_sortkey[table_id].indexOf("experiment.") == 0){ - //total execution time information - let block_name = the_parent.sorted_experiments_keys_tables_sortkey[table_id].split("execution_time.")[1]; - - angular.forEach(report_experiments, function(value, key){ - let local_sort_dict = {}; - local_sort_dict["experiment"] = key; - let itemValue = ""; - let total_time = 0; - - if(Object.keys(report_experiments[key].execution_info).length === 0){ - total_time = "-"; - } - else{ - angular.forEach(report_experiments[key].execution_info, function(value, key){ - total_time += value.linear_execution_time; - }); - } - - itemValue = total_time; - - local_sort_dict["value"] = itemValue; - local_sort_list.push(local_sort_dict); - }); - } - else if(the_parent.sorted_experiments_keys_tables_sortkey[table_id].indexOf("algorithm_parameter.") == 0){ - //total execution time information - let block_name = the_parent.sorted_experiments_keys_tables_sortkey[table_id].split("algorithm_parameter.")[1]; - let algorithm_name = block_name.split("__")[0]; - let parameter_name = block_name.split("__")[1]; - - angular.forEach(report_experiments, function(value, key){ - - let local_sort_dict = {}; - local_sort_dict["experiment"] = key; - let itemValue = ""; - - if(the_parent.report_algorithm_parameters_experiment[key][algorithm_name] != undefined){ - let value = ""; - if(the_parent.report_algorithm_parameters_experiment[key][algorithm_name][parameter_name] != undefined){ - for(let i = 0; i < the_parent.report_algorithm_parameters_experiment[key][algorithm_name][parameter_name].length; i++){ - if(i > 0 && i < the_parent.report_algorithm_parameters_experiment[key][algorithm_name][parameter_name].length -1 ){ - value += ","; - } - value = the_parent.report_algorithm_parameters_experiment[key][algorithm_name][parameter_name][i]; - } - } - else if(the_parent.report["all_experiments"][key]["declaration"]["globals"][algorithm_name][parameter_name] != undefined){ - //get globals value - value = the_parent.report["all_experiments"][key]["declaration"]["globals"][algorithm_name][parameter_name]; - } - else{ - //nothing is defined - value = "-"; - } - - itemValue = value; - } - else{ - itemValue = "-"; - } - - local_sort_dict["value"] = itemValue; - local_sort_list.push(local_sort_dict); - }); - } - else{ - //results information - angular.forEach(report_experiments, function(value, key){ - let local_sort_dict = {}; - local_sort_dict["experiment"] = key; - local_sort_dict["value"] = report_experiments[key].results[analyzer_block][the_parent.sorted_experiments_keys_tables_sortkey[table_id]].value; - - local_sort_list.push(local_sort_dict); - - }); - - } - - if(the_parent.sorted_experiments_keys_reverse[table_id]){ - local_sort_list.sort(function(a, b){ - return a.value - b.value; - }); - } - else{ - local_sort_list.sort(function(a, b){ - return b.value - a.value; - }); - } - - the_parent.sorted_experiments_keys_tables[table_id] = []; - the_parent.sorted_experiments_alias_keys_tables[table_id] = []; - for(let i = 0; i < local_sort_list.length; i++){ - the_parent.sorted_experiments_keys_tables[table_id].push(local_sort_list[i]["experiment"]); - if(the_parent.report.status == "editable"){ - the_parent.sorted_experiments_alias_keys_tables[table_id].push(the_parent.report_experiments_alias[local_sort_list[i]["experiment"]]); - } - } - - } - else{ - let experiments_aliases = []; - for(let i = 0; i < the_parent.report.experiments.length; i++){ - let experiment_name = the_parent.report.experiments[i]; - let experiment_alias = the_parent.report_experiments_alias[experiment_name]; - experiments_aliases.push(experiment_alias); - } - - if(the_parent.sorted_experiments_keys_reverse[table_id]){ - experiments_aliases.sort(function(a, b){ - return a.value - b.value; - }); - } - else{ - experiments_aliases.reverse(function(a, b){ - return b.value - a.value; - }); - } - - the_parent.sorted_experiments_keys_tables[table_id] = []; - the_parent.sorted_experiments_alias_keys_tables[table_id] = []; - for(let i = 0; i < experiments_aliases.length; i++){ - for(let the_experiment_key in the_parent.report_experiments_alias){ - if(the_parent.report_experiments_alias[the_experiment_key] == experiments_aliases[i]){ - the_parent.sorted_experiments_keys_tables[table_id].push(the_experiment_key); - if(the_parent.report.status == "editable"){ - the_parent.sorted_experiments_alias_keys_tables[table_id].push(the_parent.report_experiments_alias[the_experiment_key]); - } - } - - } - } - } - - let name_to_remove = "experiment"; - let tables_details = the_parent.tables_details[table_id]; - for(let i = 0; i < tables_details.length; i++){ - if(tables_details[i].name == "experiment"){ - tables_details.splice(i,1); - break; - } - } - - let element = document.getElementById(table_id); - - $(element).attr('id', null); - $compile(element)(scope.$parent.$parent); - $(element).attr('id', table_id); - }); - } - }; -}); - diff --git a/beat/web/reports/static/reports/app/directives/tableDynamic.js b/beat/web/reports/static/reports/app/directives/tableDynamic.js deleted file mode 100644 index 40d296db4026c14d28686936f7ebb7fda0c227bc..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/tableDynamic.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to generate the dynamic table loading partials -angular.module('reportApp').directive("tableDynamic", function(){ - return { - restrict: 'A', - scope: true, - replace: true, - Â Â Â Â //templateUrl: "/reports/partials/reportTable/", - Â Â Â Â templateUrl: function(scope, elem, attrs){ - let prefix = elem['urlprefix']; - Â Â Â Â let the_url = prefix + "/reports/partials/reportTable/"; - return the_url; - }, - link: function(scope, elem, attrs){ - let prepend_item = {}; - prepend_item["name"] = "experiment"; - prepend_item["selected"] = true; - - scope.tables_details[attrs.tableid].unshift(prepend_item); - - angular.forEach(scope.tables_details, function(table_value, table_key){ - for(let i = 0; i < table_value.length; i++){ - if(table_value[i].name.indexOf("execution_time") > -1 && - table_value[i].name.indexOf("[s]") == -1){ - table_value[i].name = table_value[i].name + "[s]"; - } - }; - }); - - scope.dattrs = attrs; - } - }; -}); - diff --git a/beat/web/reports/static/reports/app/directives/tableItem.js b/beat/web/reports/static/reports/app/directives/tableItem.js new file mode 100644 index 0000000000000000000000000000000000000000..d602cc8d79883a39bee60227623666ccc4accd21 --- /dev/null +++ b/beat/web/reports/static/reports/app/directives/tableItem.js @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ + * Contact: beat.support@idiap.ch + * + * This file is part of the beat.web module of the BEAT platform. + * + * Commercial License Usage + * Licensees holding valid commercial BEAT licenses may use this file in + * accordance with the terms contained in a written agreement between you + * and Idiap. For further information contact tto@idiap.ch + * + * Alternatively, this file may be used under the terms of the GNU Affero + * Public License version 3 as published by the Free Software and appearing + * in the file LICENSE.AGPL included in the packaging of this file. + * The BEAT platform is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero Public License along + * with the BEAT platform. If not, see http://www.gnu.org/licenses/. + */ + +/* + * tableItem + * Desc: + * displays a table report item + */ +angular.module('reportApp') +.directive("tableItem", ['GroupsService', 'ExperimentsService', function(GroupsService, ExperimentsService){ + return { + scope: { + group: '=', + content: '=', + isViewingCsv: '=' + }, + link: function(scope){ + // aliases + scope.fields = scope.content.fields; + + // add 'expName' to the beginning of the fields to show in the table + // if it isnt already there + if(scope.fields.length === 0 || scope.fields[0] !== 'Experiment'){ + scope.fields.unshift('Experiment'); + } + + // get possible table entries + scope.tableables = ExperimentsService.tableables || {}; + + // gets the field type (int, float, string, nothing) + scope.getFieldType = (field) => { + if(field === scope.fields[0]){ + return 'string'; + } + + let hasFieldObj = Object.values(scope.tableables) + .find(o => o[field]); + let fVal = hasFieldObj ? hasFieldObj[field] : {}; + let type; + if(fVal.type){ + type = fVal.type; + } else if(Number.isSafeInteger(fVal)){ + type = 'integer'; + } else if(Number.isFinite(fVal)){ + type = 'float'; + } else if(typeof fVal === 'string'){ + type = 'string'; + } else { + type = undefined; + } + + return type; + }; + // gets the field val for the given exp + scope.getFieldVal = (expName, field) => { + let fVal = scope.tableables[expName] ? + scope.tableables[expName][field] : undefined; + let val; + if(field === scope.fields[0]){ + val = scope.group.aliases[expName].length > 0 ? scope.group.aliases[expName] : expName; + } else if(!fVal){ + val = '-'; + } else { + let tmp; + if(fVal.value){ + tmp = fVal.value; + } else { + tmp = fVal; + } + + let type = scope.getFieldType(field); + if(type && type.startsWith('float')){ + val = tmp.toFixed(parseInt(scope.content.precision)); + } else { + val = tmp; + } + } + + return val; + }; + + // need to nest actual value in an obj to get angular + // to watch it correctly + scope.sortField = { val: 'Experiment', isReversed: false }; + // sort rows (one row per exp) + scope.sortFunc = (expName) => { + return scope.getFieldType(scope.sortField.val) ? + scope.getFieldVal(expName, scope.sortField.val) : expName; + }; + // sets the new sort field and direction + scope.setSortField = (field) => { + if(scope.sortField.val === field){ + scope.sortField.isReversed = !scope.sortField.isReversed; + } else { + scope.sortField.val = field; + scope.sortField.isReversed = false; + } + }; + + // a different view of the table + scope.getCSV = () => { + let fields = scope.fields; + let exps = scope.group.experiments + // clone arr + .map(e => `${e}`) + .sort((ea, eb) => (scope.sortField.isReversed ? -1 : 1) * (scope.sortFunc(ea) > scope.sortFunc(eb) ? -1 : 1)) + ; + + let str = ''; + + let fieldsStr = fields + .map(f => `${f}(${scope.getFieldType(f)})`) + .join(','); + + let expsStrs = exps + .map(e => fields.map(f => `${scope.getFieldVal(e, f)}`).join(',')) + .join('\n'); + + str = `${fieldsStr}\n${expsStrs}`; + + return str; + }; + }, + template: ` +<div ng-if='isViewingCsv.val' class='panel-body'> + <pre>{{ getCSV() }}</pre> +</div> +<div ng-if='!isViewingCsv.val' class='panel-body' style='height: 100%; overflow-x: auto;'> + <table class="table table-striped table-hover"> + <thead> + <tr ui-sortable ng-model='fields'> + <th ng-repeat='field in fields'> + <span + ng-if="sortField.val == field" + class='glyphicon' + ng-class="{ + 'glyphicon-chevron-up': sortField.isReversed, + 'glyphicon-chevron-down': !sortField.isReversed + }" + > + </span> + <a role='button' ng-click='setSortField(field)'> + {{ field }} <i>({{ getFieldType(field) }})</i> + </a> + </th> + </tr> + </thead> + <tbody> + <tr ng-repeat="exp in group.experiments | orderBy:sortFunc:sortField.isReversed"> + <td ng-repeat='field in fields'> + {{ getFieldVal(exp, field) }} + </td> + </tr> + </tbody> + </table> +</div> +` + }; +}]); diff --git a/beat/web/reports/static/reports/app/directives/tablePrecision.js b/beat/web/reports/static/reports/app/directives/tablePrecision.js deleted file mode 100644 index ac3d582494b8c788fab3e7c015fb8a3715ac3852..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/tablePrecision.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to handle table settings click -angular.module('reportApp').directive("tableprecision", function($compile){ - return { - link:function(scope, element, attrs){ - element.bind("change", function(){ - fixFloatingPoint(scope.$parent.$parent.floating_point_precision.selected); - }); - - function fixFloatingPoint(selected_precision){ - if(!scope.$$phase){ - //$digest or $apply - let parent_scope = scope.$parent; - let table_details = parent_scope.tables_details; - - for(let i = 0; i < parent_scope.report.orderedcontent.length; i++){ - let element = document.getElementById(parent_scope.report.orderedcontent[i]); - - $(element).remove(); - - let id_content = parent_scope.report.orderedcontent[i]; - let type = id_content.split("_")[0]; - parent_scope.$parent.$parent.$broadcast("addSavedElement", id_content, type); - } - } - } - } - }; -}); - diff --git a/beat/web/reports/static/reports/app/directives/theColumn.js b/beat/web/reports/static/reports/app/directives/theColumn.js deleted file mode 100644 index c122954ff3e0d79afe8ecfe34eb6754754ce7f4a..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/theColumn.js +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -//Directive used to set proper item value in selected column -angular.module('reportApp').directive("thecolumn",['$compile', function ($compile) { - - return { - scope: { - thecolumn: "@" - }, - restrict: 'A', - template: '{{itemValue}}', - controller: ['$scope', function ($scope) { - - let the_parent = $scope.$parent.$parent.$parent.$parent; - let report_experiments = $scope.$parent.$parent.$parent.$parent.report_experiments; - let report_experiments_alias = $scope.$parent.$parent.$parent.$parent.report_experiments_alias; - let floating_point_precision = $scope.$parent.$parent.$parent.$parent.floating_point_precision; - let report = $scope.$parent.$parent.$parent.report; - let experiment_name = $scope.$parent.item; - - if(jQuery.isEmptyObject(report_experiments) || (report_experiments[experiment_name] == undefined)){ - return; - } - - let analyzer_block = report_experiments[experiment_name].analyzer_block; - let report_algorithm_parameters_experiment = $scope.$parent.$parent.$parent.$parent.report_algorithm_parameters_experiment; - - if($scope.thecolumn != "experiment"){ - if(analyzer_block == undefined){ - angular.forEach(report_experiments, function(value, key){ - angular.forEach(value.declaration.analyzers, function(value_analyzer, key_analyzer){ - if(value_analyzer.algorithm == report.analyzer && (key_analyzer in report_experiments[experiment_name].declaration.analyzers)){ - report_experiments[experiment_name].analyzer_block = key_analyzer; - analyzer_block = report_experiments[experiment_name].analyzer_block; - } - }); - }); - } - - if($scope.thecolumn.indexOf("execution_time.") == 0){ - //execution time information - let block_name = $scope.thecolumn.split("execution_time.")[1].split("[s]")[0]; - if(Object.keys(report_experiments[experiment_name].execution_info).length === 0){ - $scope.itemValue = "-"; - } - else{ - if(report_experiments[experiment_name].execution_info[block_name] == undefined){ - $scope.itemValue = "-"; - } - else{ - $scope.itemValue = (report_experiments[experiment_name].execution_info[block_name].linear_execution_time).toFixed(floating_point_precision.selected);; - } - } - } - else if($scope.thecolumn.indexOf("experiment.") == 0){ - //total execution time information - let block_name = $scope.thecolumn.split("execution_time.")[1]; - let total_time = 0; - if(Object.keys(report_experiments[experiment_name].execution_info).length === 0){ - total_time = "-"; - } - else{ - angular.forEach(report_experiments[experiment_name].execution_info, function(value, key){ - total_time += value.linear_execution_time; - }); - } - - $scope.itemValue = total_time.toFixed(floating_point_precision.selected); - } - else if($scope.thecolumn.indexOf("algorithm_parameter.") == 0){ - //total execution time information - let block_name = $scope.thecolumn.split("algorithm_parameter.")[1]; - let algorithm_name = block_name.split("__")[0]; - let parameter_name = block_name.split("__")[1]; - if(report_algorithm_parameters_experiment[experiment_name][algorithm_name] != undefined){ - let value = ""; - if(report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name] != undefined){ - for(let i = 0; i < report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name].length; i++){ - if(i > 0 && i < report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name].length -1 ){ - value += ","; - } - value = report_algorithm_parameters_experiment[experiment_name][algorithm_name][parameter_name][i]; - } - } - else if(report["all_experiments"][experiment_name]["declaration"]["globals"][algorithm_name][parameter_name] != undefined){ - //get globals value - value = report["all_experiments"][experiment_name]["declaration"]["globals"][algorithm_name][parameter_name]; - } - else{ - //nothing is defined - value = "-"; - } - - $scope.itemValue = value; - } - else{ - $scope.itemValue = "-"; - } - } - else{ - //results information - $scope.itemValue = (report_experiments[experiment_name].results[analyzer_block][$scope.thecolumn].value).toFixed(floating_point_precision.selected); - } - } - else{ - let experiment_alias = report_experiments_alias[experiment_name]; - $scope.itemValue = experiment_alias; - } - }]//, - //link: function(scope, element, attrs) - //{ - // console.log(scope); - // let report_experiments_alias = scope.$parent.$parent.$parent.$parent.report_experiments_alias; - // let experiment_name = scope.$parent.item; - // let experiment_alias = report_experiments_alias[experiment_name]; - // scope.$watch(scope.$parent.$parent.$parent.$parent.report_experiments_alias,function(newValue, oldValue) - // { - // console.log("changed"); - // console.log(report_experiments_alias); - // console.log(oldValue); - // console.log(newValue); - // }); - // - //} - }; -}]); - diff --git a/beat/web/reports/static/reports/app/directives/view/plotItem.js b/beat/web/reports/static/reports/app/directives/view/plotItem.js index 6b9d1cc7f948fabffb0fa68ef6b8989316cb25db..d853e89200fee6536ff48166e7bd6566d75ac99a 100644 --- a/beat/web/reports/static/reports/app/directives/view/plotItem.js +++ b/beat/web/reports/static/reports/app/directives/view/plotItem.js @@ -26,7 +26,7 @@ * displays a plot report item */ angular.module('reportApp') -.directive("groupPlotItem", ['ExperimentsService', function(ExperimentsService){ +.directive("groupPlotItem", ['ExperimentsService', 'PlotService', '$timeout', function(ExperimentsService, PlotService, $timeout){ return { scope: { group: '=', @@ -34,12 +34,19 @@ angular.module('reportApp') content: '=' }, link: function(scope){ + const group = scope.group; scope.domId = `${scope.group.name}_${scope.id}`; + scope.renderDivId = `${scope.domId}-render`; + + $timeout(function() { + PlotService.addPlot(scope.group, scope.id, scope.renderDivId); + }); }, template: ` <div class='panel-body'> - <p>{{ id }} content</p> - <strong class='text-danger'>Plot items in reports are not implemented yet.</strong> + <div class='panel-body'> + <div id='{{ renderDivId }}'></div> + </div> </div> ` }; diff --git a/beat/web/reports/static/reports/app/directives/view/tableItem.js b/beat/web/reports/static/reports/app/directives/view/tableItem.js index e34c6cfba152c7b1342ecd51ed11cf31c7d34190..39bd27a0fcc478eeeaf3cc4d7bd8356113eeaac2 100644 --- a/beat/web/reports/static/reports/app/directives/view/tableItem.js +++ b/beat/web/reports/static/reports/app/directives/view/tableItem.js @@ -26,7 +26,7 @@ * displays a table report item */ angular.module('reportApp') -.directive("groupTableItem", ['GroupsService', 'ExperimentsService', function(GroupsService, ExperimentsService){ +.directive("groupTableItem", [function(){ return { scope: { group: '=', @@ -34,123 +34,10 @@ angular.module('reportApp') content: '=' }, link: function(scope){ - // aliases - scope.fields = scope.content.fields; // ids scope.domId = `${scope.group.name}_${scope.id}`; scope.colSelectorId = `${scope.domId}_columnSelector`; - // add 'expName' to the beginning of the fields to show in the table - // if it isnt already there - if(scope.fields.length === 0 || scope.fields[0] !== 'Experiment'){ - scope.fields.unshift('Experiment'); - } - - // 1 - 10 - scope.floatingPointRange = [...(new Array(10)).keys()].map(i => i + 1); - - // get possible table entries - scope.tableables = ExperimentsService.tableables || {}; - - // gets the field type (int, float, string, nothing) - scope.getFieldType = (field) => { - if(field === scope.fields[0]){ - return 'string'; - } - - let hasFieldObj = Object.values(scope.tableables) - .find(o => o[field]); - let fVal = hasFieldObj ? hasFieldObj[field] : {}; - let type; - if(fVal.type){ - type = fVal.type; - } else if(Number.isSafeInteger(fVal)){ - type = 'integer'; - } else if(Number.isFinite(fVal)){ - type = 'float'; - } else if(typeof fVal === 'string'){ - type = 'string'; - } else { - type = undefined; - } - - return type; - }; - // gets the field val for the given exp - scope.getFieldVal = (expName, field) => { - const shortExpName = expName.split('/').pop(); - const tableables = scope.tableables[expName] || scope.tableables[shortExpName]; - const alias = Object.entries(scope.group.aliases) - .find(([e, a]) => e == expName || e.endsWith(shortExpName))[1]; - - let fVal = tableables ? - tableables[field] : undefined; - let val; - if(field === scope.fields[0]){ - val = alias.length > 0 ? alias : expName; - } else if(!fVal){ - val = '-'; - } else { - let tmp; - if(fVal.value){ - tmp = fVal.value; - } else { - tmp = fVal; - } - - let type = scope.getFieldType(field); - if(type && type.startsWith('float')){ - val = tmp.toFixed(parseInt(scope.content.precision)); - } else { - val = tmp; - } - } - - return val; - }; - - // need to nest actual value in an obj to get angular - // to watch it correctly - scope.sortField = { val: 'Experiment', isReversed: false }; - // sort rows (one row per exp) - scope.sortFunc = (expName) => { - return scope.getFieldType(scope.sortField.val) ? - scope.getFieldVal(expName, scope.sortField.val) : expName; - }; - // sets the new sort field and direction - scope.setSortField = (field) => { - if(scope.sortField.val === field){ - scope.sortField.isReversed = !scope.sortField.isReversed; - } else { - scope.sortField.val = field; - scope.sortField.isReversed = false; - } - }; - - // a different view of the table - scope.getCSV = () => { - let fields = scope.fields; - let exps = scope.group.experiments - // clone arr - .map(e => `${e}`) - .sort((ea, eb) => (scope.sortField.isReversed ? -1 : 1) * (scope.sortFunc(ea) > scope.sortFunc(eb) ? -1 : 1)) - ; - - let str = ''; - - let fieldsStr = fields - .map(f => `${f}(${scope.getFieldType(f)})`) - .join(','); - - let expsStrs = exps - .map(e => fields.map(f => `${scope.getFieldVal(e, f)}`).join(',')) - .join('\n'); - - str = `${fieldsStr}\n${expsStrs}`; - - return str; - }; - // toggle val for viewing CSV scope.isViewingCSV = { val: false }; scope.toggleViewingCSV = () => { @@ -168,42 +55,7 @@ angular.module('reportApp') </div> </div> </div> - <div class='row' style='margin-top: 5px;'> - <div class='col-sm-12'> - <div ng-if='isViewingCSV.val'> - <pre>{{ getCSV() }}</pre> - </div> - <div ng-if='!isViewingCSV.val' style='height: 100%; overflow-x: auto;'> - <table class="table table-striped table-hover"> - <thead> - <tr> - <th ng-repeat='field in fields track by $index'> - <span - ng-if="sortField.val == field" - class='glyphicon' - ng-class="{ - 'glyphicon-chevron-up': sortField.isReversed, - 'glyphicon-chevron-down': !sortField.isReversed - }" - > - </span> - <a role='button' ng-click='setSortField(field)'> - {{ field }} <i>({{ getFieldType(field) }})</i> - </a> - </th> - </tr> - </thead> - <tbody> - <tr ng-repeat="exp in group.experiments | orderBy:sortFunc:sortField.isReversed"> - <td ng-repeat='field in fields track by $index'> - {{ getFieldVal(exp, field) }} - </td> - </tr> - </tbody> - </table> - </div> - </div> - </div> + <div table-item group='group' content='content' is-viewing-csv='isViewingCSV'></div> </div> ` }; diff --git a/beat/web/reports/static/reports/app/factories/dataFactory.js b/beat/web/reports/static/reports/app/factories/dataFactory.js deleted file mode 100644 index aeb3cb67ffdca308685f23cce6ebcc15bddd0275..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/factories/dataFactory.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ -//This factory retrieves data from the static files and associates it with the $scope -angular.module('reportApp').factory('dataFactory', function($http){ - let getData = function (URL) { - //return $http.get(URL + 'itemcontent.json'); - let obj = {content:null}; - //return $http.get(URL); - $http.get(URL).success(function(data){ - obj.content = data; - }); - - return obj; - }; - - return { - getData: getData - }; -}); diff --git a/beat/web/reports/static/reports/app/services/experimentsService.js b/beat/web/reports/static/reports/app/services/experimentsService.js index 7407290d3b47fa22312ddca42c1783d07cb8d209..98a1999f035b702ec1288f8b7ccc7609b49c73f2 100644 --- a/beat/web/reports/static/reports/app/services/experimentsService.js +++ b/beat/web/reports/static/reports/app/services/experimentsService.js @@ -26,7 +26,7 @@ * Manages the experiments data, including storing it and generating * different views of the data */ -angular.module('reportApp').factory('ExperimentsService', ['experimentFactory', 'GroupsService', function(experimentFactory, GroupsService){ +angular.module('reportApp').factory('ExperimentsService', ['experimentFactory', 'GroupsService', 'UrlService', function(experimentFactory, GroupsService, UrlService){ // holds the raw exp data received from the server const expData = {}; // holds the view generated from `getTableablesFromExpName` @@ -146,12 +146,10 @@ angular.module('reportApp').factory('ExperimentsService', ['experimentFactory', }; // make sure there are no invalid experiments in the report's groups + // invalid -> in a group but not in the report const cleanGroups = (validExpNames) => { - console.log(`valid exp names: ${validExpNames}`); GroupsService.groups.forEach(g => { - console.log(`Found group: ${g.name}`); g.experiments.forEach(e => { - console.log(`Found exp in ${g.name}: ${e}`); // when the user can see the exp, the full name of the exp is available, // including the user who made it, and the toolchain const fullNameValid = validExpNames.includes(e); @@ -159,30 +157,43 @@ angular.module('reportApp').factory('ExperimentsService', ['experimentFactory', // only the actual name of the exp is available const partNameValid = validExpNames.includes(e.split('/').pop()); if(!(fullNameValid || partNameValid)){ - console.log(`NOT VALID: ${e}`); + console.log(`INVALID EXPERIMENT: ${e}`); g.removeExperiment(e); } }); }); }; - const loadExperiments = (...args) => { + // fetch the exp data and process it + const loadExperiments = () => { let expFetch; - if(args.length === 2){ - // 2 args -> get exps by report num - expFetch = experimentFactory.getAllExperimentResults(...args); - - } else if (args.length === 3){ - // 3 args -> by report author - expFetch = experimentFactory.getAllExperimentResultsForAuthor(...args); + const namePath = UrlService.getByNamePath(); + const numberPath = UrlService.getByNumberPath(); + + if(namePath && namePath.length > 0){ + // get exps by report num + const user = namePath.split('/')[1]; + const name = namePath.split('/')[2]; + expFetch = experimentFactory.getAllExperimentResultsForAuthor(user, name, ''); + } else if(numberPath && numberPath.length > 0){ + //by report author + const num = numberPath.split('/')[1]; + expFetch = experimentFactory.getAllExperimentResults('', num); } return expFetch .then((exps) => { + // save the exp names as they were given by the server Object.keys(exps).forEach(e => rawExpNames.push(e)); + // process the given exp data Object.entries(exps) .forEach(([expName, exp]) => { + // depending on the permissions of the user + // when viewing this report + // the author/toolchain may be hidden. + // to be safe, always process + // both the given name (either the full or short name) const shortName = expName.split('/').pop(); for(let n of [shortName, expName]){ expData[n] = exp; @@ -201,6 +212,8 @@ angular.module('reportApp').factory('ExperimentsService', ['experimentFactory', }); }; + loadExperiments(); + return { experimentNames: rawExpNames, experiments: expData, diff --git a/beat/web/reports/static/reports/app/services/groupsService.js b/beat/web/reports/static/reports/app/services/groupsService.js index 5410187409e96477e053f105583180c63c9b5ade..e4f8908f9fd5ec6a2346cd52e280895bef9a803d 100644 --- a/beat/web/reports/static/reports/app/services/groupsService.js +++ b/beat/web/reports/static/reports/app/services/groupsService.js @@ -23,8 +23,8 @@ /* * GroupsService * Desc: - * The datastore for the reports app, including data fetched from the - * server and cross-component app state + * The main datastore for the reports app, holding the tree of + * relationships between groups, experiments, aliases, and report items */ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(reportFactory){ let groupsServiceInstance = {}; @@ -47,6 +47,9 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( /* * deepFreeze func found http://stackoverflow.com/a/34776962 * changed to use ES6 functionality + * recursively freezes a JS obj so it cant be altered + * just a nice layer of safety to make sure + * the frontend doesnt change if the backend wont change */ const deepFreeze = (o) => { Object.freeze(o); @@ -114,6 +117,8 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( } // add an exp to this group + // optionally sets the analyzer + // initializes the new exp's alias to its name addExperiment (expName, analyzer) { let res = this._experimentNames.add(expName); if(this._experimentNames.size === 1 && analyzer && analyzer.length > 0){ @@ -127,7 +132,7 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( return res; } - // rm an exp from this group + // rm an exp from this group as well as its alias removeExperiment (expName) { let res = this._experimentNames.delete(expName); if(this._experimentNames.size === 0){ @@ -139,7 +144,7 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( return res; } - // add an item (table or plot) to this group + // add an item (table, plot, or text block) to this group // if the id already exists, it just replaces the old // element with the new one addReportItem (id, content) { @@ -157,7 +162,7 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( } } - // rm an exp from this group + // rm a report item from this group removeReportItem (id) { let idx = this._reportItems .indexOf(this._reportItems.find(o => o.id === id)); @@ -185,9 +190,16 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( // serializes groups as an object with form: // { - // <group name 1>: { experiments: [], reportItems: [], analyzer: '' }, + // <group name 1>: { + // experiments: [], + // reportItems: [], + // analyzer: '', + // aliases: {}, + // idx: 1 + // }, // ... // } + // the 'idx' saves the ordering of the groups groupsServiceInstance.serializeGroups = () => { return groupData .map((g, i) => { return { @@ -222,6 +234,7 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( }; // delete a group + // via MUTATING the groupdata groupsServiceInstance.deleteGroup = (name) => { let idx = groupData.indexOf(groupData.find(g => g.name === name)); if (idx > -1) { @@ -231,11 +244,17 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( // load group info from the serialized format: // { - // <group name 1>: { experiments: [], reportItems: [], analyzer: '' }, + // <group name 1>: { + // experiments: [], + // reportItems: [], + // analyzer: '', + // aliases: {}, + // idx: 1 + // }, // ... // } groupsServiceInstance.loadGroups = (data) => { - // wipe data and load groups + // wipe data groupData.splice(0, groupData.length); let safeData = data || {}; @@ -251,10 +270,15 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( }) .forEach(([groupName, gData]) => { let g = groupsServiceInstance.createGroup(groupName); + + // default group data to empty let analyzer = gData.analyzer || ''; let experiments = gData.experiments || []; let reportItems = gData.reportItems || []; let aliases = gData.aliases || {}; + + // save fields to group + // by MUTATING the group obj g.analyzer = analyzer; experiments.forEach(n => g.addExperiment(n)); reportItems.forEach(i => g.addReportItem(i.id, i.content)); @@ -262,64 +286,5 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function( }); }; - // save group info via sending to server - groupsServiceInstance.saveGroups = () => { - console.warn(`not implemented: groupsServiceInstance.saveGroups`); - }; - - // add experiment to group - groupsServiceInstance.addExperimentToGroup = (expName, groupName, analyzer) => { - checkForGroup(groupName); - - let group = groupData.find(g => g.name === groupName); - return group.addExperiment(expName, analyzer); - }; - - // rm experiment from group - groupsServiceInstance.removeExperimentFromGroup = (expName, groupName) => { - checkForGroup(groupName); - let group = groupData.find(g => g.name === groupName); - return group.removeExperiment(expName); - }; - - // gets experiments from a group - groupsServiceInstance.getGroupExperiments = (groupName) => { - checkForGroup(groupName); - let group = groupData.find(g => g.name === groupName); - return group.experiments; - }; - - // gets groups for an experiment - groupsServiceInstance.getExperimentGroups = (expName) => { - return groupData.filter(g => g.experiments.includes(expName)).map(g => g.name); - }; - - // add report item to group - groupsServiceInstance.addReportItemToGroup = (id, content, groupName) => { - checkForGroup(groupName); - - let group = groupData.find(g => g.name === groupName); - group.addReportItem(id, content); - }; - - // rm report item id from group - groupsServiceInstance.removeReportItemFromGroup = (id, groupName) => { - checkForGroup(groupName); - let group = groupData.find(g => g.name === groupName); - return group.removeReportItem(id); - }; - - // gets group for a report item's id - groupsServiceInstance.getReportItemGroup = (id) => { - return groupData.find(g => g.reportItems.find(i => i.id === id)); - }; - - // helper to assert that a group exists - function checkForGroup (groupName) { - if(!groupData.find(g => g.name === groupName)){ - throw new Error(`Could not find group "${JSON.stringify(groupName)}"`); - } - } - return groupsServiceInstance; }]); diff --git a/beat/web/reports/static/reports/app/services/plotService.js b/beat/web/reports/static/reports/app/services/plotService.js new file mode 100644 index 0000000000000000000000000000000000000000..95fdbb2f0b9d86d5eb7141a1ab28169aab6c1d30 --- /dev/null +++ b/beat/web/reports/static/reports/app/services/plotService.js @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ + * Contact: beat.support@idiap.ch + * + * This file is part of the beat.web module of the BEAT platform. + * + * Commercial License Usage + * Licensees holding valid commercial BEAT licenses may use this file in + * accordance with the terms contained in a written agreement between you + * and Idiap. For further information contact tto@idiap.ch + * + * Alternatively, this file may be used under the terms of the GNU Affero + * Public License version 3 as published by the Free Software and appearing + * in the file LICENSE.AGPL included in the packaging of this file. + * The BEAT platform is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero Public License along + * with the BEAT platform. If not, see http://www.gnu.org/licenses/. + */ + +/* + * PlotService + * Desc: + * Manages the plots in the report, + * including: + * - Adding new/saved + * - Configuring + * - Deleting + * - Rendering + */ +angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlService){ + const ps = {}; + + // these are provided by ReportService + let plotters; + let defaultPlotters; + let plotterParameters; + let reportNumber; + + // this 'queue' idea is the solution to trying to load plots before we receive all the data + // from the server that we need (report info, exp info, etc.). + // until the queue is processed (after which, no queue is needed), + // plots that want to be rendered are added to a queue to wait. + const queue = []; + let noQueueNeeded = false; + + // constructs the payload to send to the server + const constructPlotInfo = (group, itemId) => { + const content = group.reportItems.find(i => i.id === itemId).content; + + // defaults obj, in case we're using defaults + const defaults = defaultPlotters.find(p => p.dataformat === content.type); + if (!defaults) { + console.log(`No default plotter found for content type ${JSON.stringify(content.type)} out of:`); + console.log(defaultPlotters); + } + + // a plot obj can have different plotters, + let plotter = content.savedPlotter || plotters.find(p => p.name === defaults.plotter); + + // which can each have different configurations (plotter parameter instances) + let config = content.savedConfig || plotterParameters.find(pp => pp.name === defaults.parameter); + + // sanity check for the plotter & config + // the config's "plotter" field should be equal to the plotter's id field + if(!(config.plotter === plotter.id)){ + console.error(`Config plotter val "${config.plotter}" != plotter id "${plotter.id}":`); + console.log(config); + console.log(plotter); + }; + + // the data to be sent to the server + const requestData = { + report_number: reportNumber, + // exps in the group + experiment: group.experiments, + // group's analyzer + analyzer: [group.analyzer], + // ? + output: [content.name], + // plotter to use + plotter: plotter.name, + // config to use + parameter: config.name, + // string for making the legend in the plot + legend: group.experiments.map(e => group.aliases[e]).join('&'), + // whether one plot with all the exps' data, + // or one plot for each exp + merged: content.merged === undefined ? true : content.merged + }; + + // data to be used in to interact with the plot + // users can change the plotter used if theres more than 1 available for that + // plot type + const possiblePlotters = plotters + .filter(p => p.dataformat === content.type) + .map(p => p.name) + ; + + // users can choose which params to use if more than 1 available + // for that plotter + const possibleParameters = plotterParameters + .filter(pp => plotter.id === pp.plotter) + .map(pp => pp.name) + ; + + console.log(`Request data:`); + console.log(requestData); + console.log(`possible plotters:`); + console.log(possiblePlotters); + console.log(`possible parameters:`); + console.log(possibleParameters); + + const returnStruct = [requestData, possiblePlotters, possibleParameters]; + + return returnStruct; + }; + + // makes the call to the server, via some helper funcs found in the global namespace + const fetchRenderUsingStruct = (requestData, containerId) => { + // the 'url_prefix' field found throughout the BEAT code is confusing, + // but it seems to always be an empty string now + const urlPrefix = '';//UrlService.getApiSegment().split('/').filter(s => s.length > 0).join('/'); + + // promisify this utils func so we dont have to deal with callback hell + return new Promise((resolve, reject) => { + beat.experiments.utils.displayPlot( + // url_prefix + urlPrefix, + // element to append render to + document.querySelector(`#${containerId}`), + // spread out the request data to fill the next 3 spots + ...requestData, + // dont replace inner content + false, + // callback + (...args) => { + // resolve promise + resolve(...args); + } + ); + }); + }; + + // helper func to process a request to plot + const processItem = (group, itemId, containerId) => { + const reqData = constructPlotInfo(group, itemId); + return fetchRenderUsingStruct(reqData, containerId); + }; + + // used if we arent ready to directly service requests + const addItemToQueue = (group, itemId, containerId) => { + queue.push([ + group, + itemId, + containerId + ]); + }; + + // called by ReportService, + // or by someone having this report-level info. + // processes the queue and sets the plotService state such that we dont need to use + // the queue after this + ps.processQueue = (rsPlotters, rsDefaultPlotters, rsPlotterParameters, rsReportNumber) => { + plotters = rsPlotters; + defaultPlotters = rsDefaultPlotters; + plotterParameters = rsPlotterParameters; + reportNumber = rsReportNumber; + + noQueueNeeded = true; + const promises = queue.map(q => processItem(...q)); + queue.length = 0; + + return promises; + }; + + // chooses whether to add the plot request to a queue or service directly + // args: group, itemId, containerId + ps.addPlot = (...args) => noQueueNeeded ? processItem(...args) : addItemToQueue(...args); + + return ps; +}]); diff --git a/beat/web/reports/static/reports/app/services/reportService.js b/beat/web/reports/static/reports/app/services/reportService.js new file mode 100644 index 0000000000000000000000000000000000000000..160963c2a795750fda9b25f6074940297a0bdf6a --- /dev/null +++ b/beat/web/reports/static/reports/app/services/reportService.js @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ + * Contact: beat.support@idiap.ch + * + * This file is part of the beat.web module of the BEAT platform. + * + * Commercial License Usage + * Licensees holding valid commercial BEAT licenses may use this file in + * accordance with the terms contained in a written agreement between you + * and Idiap. For further information contact tto@idiap.ch + * + * Alternatively, this file may be used under the terms of the GNU Affero + * Public License version 3 as published by the Free Software and appearing + * in the file LICENSE.AGPL included in the packaging of this file. + * The BEAT platform is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero Public License along + * with the BEAT platform. If not, see http://www.gnu.org/licenses/. + */ + +/* + * ReportService + * Desc: + * Consumes the "report" object from the API and digests it into helper + * funcs and report-wide info. Basically an adaptor & bootstrap-er. + */ +angular.module('reportApp').factory('ReportService', ['GroupsService', 'plotterFactory', 'PlotService', 'reportFactory', 'UrlService', function(GroupsService, plotterFactory, PlotService, reportFactory, UrlService){ + const rs = {}; + + rs.isAnonymous = undefined; + rs.isOwner = undefined; + rs.status = undefined; + rs.number = undefined; + rs.user = undefined; + + rs.plotters = []; + rs.defaultPlotters = []; + rs.plotterParameters = []; + + // processed the report data received from the server, + // and bootstraps the state of various services + rs.processReport = (report) => { + console.log(report); + + // useful info about the app + rs.isAnonymous = report.anonymous; + rs.isOwner = report.is_owner; + rs.status = report.status; + rs.number = report.number; + rs.user = report.user; + + // start up our GroupsService + GroupsService.loadGroups(report.content.groups); + // if the report should not change, + // add a nice layer of immutability by freezing the Group tree + // (see GroupsService for more info) + const isEditable = rs.isOwner && rs.status === 'editable' && !rs.isAnonymous; + GroupsService.setEditable(isEditable); + + console.log(GroupsService.groups); + + // fetch all our plotter data + // these three fetches do not depend on eachother + const pPlotters = plotterFactory.getPlotters('') + .then(res => { + res.data.forEach(p => rs.plotters.push(p)); + }); + + const pDefaults = plotterFactory.getDefaultPlotters('') + .then(res => { + res.data.forEach(p => rs.defaultPlotters.push(p)); + }); + + const pParams = plotterFactory.getPlotterParameter('') + .then(res => { + res.data.forEach(p => rs.plotterParameters.push(p)); + }); + + // process the fetched plot info + return Promise.all([pPlotters, pDefaults, pParams]) + .then(() => PlotService.processQueue(rs.plotters, rs.defaultPlotters, rs.plotterParameters, rs.number)) + ; + }; + + // fetch the report data using either the by-name or by-number scheme, + // according to what URLService found + rs.fetchReport = () => { + const nameSeg = UrlService.getNameSegment(); + const numSeg = UrlService.getNumberSegment(); + + if(nameSeg){ + // the nameSeg is something like 'report/<user>/<report name>/' + let [user, reportId] = nameSeg.split('/').filter(s => s.length > 0).slice(1); + + return reportFactory.getReportInformation(user, reportId, '') + .then(res => rs.processReport(res.data)); + } else if(numSeg) { + // the numSeg is something like 'report/<report number>/' + let [number] = numSeg.split('/').filter(s => s.length > 0).slice(1); + + return reportFactory.getReportInformationFromNumber(number, '') + .then(res => rs.processReport(res.data)); + } else { + console.error('UrlService could not parse the current URL'); + } + }; + + rs.fetchReport() + .catch(e => console.error(e)); + + console.log(rs); + + return rs; +}]); diff --git a/beat/web/reports/static/reports/app/services/urlService.js b/beat/web/reports/static/reports/app/services/urlService.js index 57e1594cc934322fd587ae12409b5b687edb19d2..8350507daf60fdbd46f3201b7d124e6be4a3f210 100644 --- a/beat/web/reports/static/reports/app/services/urlService.js +++ b/beat/web/reports/static/reports/app/services/urlService.js @@ -47,7 +47,7 @@ angular.module('reportApp').factory('UrlService', [function(){ prefix = url.slice(0, idxSplit); // find how many '/' are in path via splitting str on '/' - if(path.split('/').length === 2){ + if(path.split('/').length === 3){ // report number reportByNumber = path; } else { @@ -56,6 +56,12 @@ angular.module('reportApp').factory('UrlService', [function(){ } }; + const getPrefix = () => prefix; + + const getApiSegment = () => apiSegment; + const getNameSegment = () => reportByName; + const getNumberSegment = () => reportByNumber; + const experimentPath = () => `${prefix}${experimentSegment}`; const blockPath = () => `${prefix}${blockSegment}`; const databasePath = () => `${prefix}${databaseSegment}`; @@ -66,8 +72,10 @@ angular.module('reportApp').factory('UrlService', [function(){ const getDatabaseUrl = (databaseName) => `${databasePath()}${databaseName}/`; const getApiUrl = (apiSubpath) => `${apiPath()}${apiSubpath}`; - const getCompileRstUrl = () => `${getApiUrl(`${reportByName}rst/`)}`; + const getCompileRstUrl = () => `${getApiUrl(`${reportByName || reportByNumber}rst/`)}`; const getRemoveExperimentUrl = () => `${getApiUrl(`${reportByName}remove/`)}`; + const getByNamePath = () => reportByName; + const getByNumberPath = () => reportByNumber; extractUsingCurrentUrl(); @@ -76,6 +84,12 @@ angular.module('reportApp').factory('UrlService', [function(){ getBlockUrl, getDatabaseUrl, getCompileRstUrl, - getRemoveExperimentUrl + getRemoveExperimentUrl, + getByNamePath, + getByNumberPath, + getApiSegment, + getNameSegment, + getNumberSegment, + getPrefix }; }]); diff --git a/beat/web/reports/static/reports/test/report-spec.js b/beat/web/reports/static/reports/test/report-spec.js index 57b186fb6962631c2ca0edcb91ad3b615b00658b..744037f10e1b4c2d54d1cc7d42a005c7a9a6be32 100644 --- a/beat/web/reports/static/reports/test/report-spec.js +++ b/beat/web/reports/static/reports/test/report-spec.js @@ -1,6 +1,30 @@ // general tests for the reports app describe('reports app', function(){ + // contain helpers for browser.wait + const until = protractor.ExpectedConditions; + // just use enter.perform() to send the enter key + const enter = browser.actions().sendKeys(protractor.Key.ENTER); + // since angular isnt configured correctly for protractor, + // dont make protractor wait for angular browser.ignoreSynchronization = true; + // just to make sure the window is maximized during these tests. + // helps with button clicking & such + browser.driver.manage().window().maximize(); + + // login to the default user ('user') once before running all these tests + beforeAll(function(){ + browser.get('http://localhost:8000/login/?next=/'); + //browser.findElement(by.partialLinkText('Sign-in')).click(); + browser.findElement(by.id('id_username')).sendKeys('user'); + browser.findElement(by.id('id_password')).sendKeys('user'); + browser.findElement(by.partialButtonText('Sign-in')).click(); + return browser.wait(function(){ + return browser.getCurrentUrl().then(function(url){ + const rxUserLoggedIn = /events\/user\//; + return rxUserLoggedIn.test(url); + }); + }); + }); // if there's an error in the web browser's console, // fail the test and print the error @@ -23,45 +47,26 @@ describe('reports app', function(){ // /reports describe('home', function(){ beforeEach(function(){ - browser.get('http://localhost:8000/reports'); + browser.get('http://localhost:8000/reports/user'); }); it('should load', function(){ - expect(browser.getTitle()).toEqual('BEAT - Public Reports'); - }); - - it('should have no reports', function(){ - let noReportsText = browser.findElement(by.className('not-found')); - expect(noReportsText.getText()).toBe('No report found'); + expect(browser.getTitle()).toEqual("BEAT - user's Reports"); }); }); // /reports/user describe('home for the test user', function(){ - // login to the default user ('user') once before running all these tests - beforeAll(function(){ - browser.get('http://localhost:8000/login/?next=/'); - //browser.findElement(by.partialLinkText('Sign-in')).click(); - browser.findElement(by.id('id_username')).sendKeys('user'); - browser.findElement(by.id('id_password')).sendKeys('user'); - browser.findElement(by.partialButtonText('Sign-in')).click(); - return browser.wait(function(){ - return browser.getCurrentUrl().then(function(url){ - const rxUserLoggedIn = /events\/user\//; - return rxUserLoggedIn.test(url); - }); - }); - }); // go to user's reports page before each test - beforeEach(function(){ + beforeAll(function(){ browser.get('http://localhost:8000/reports/user/'); }); // before adding a report, there shouldn't be any - it('should have no reports', function(){ - let noReportsText = browser.findElement(by.className('not-found')); - expect(noReportsText.getText()).toBe('No report found'); + it('should not have the "user/test" report', function(){ + let noReportsText = browser.findElement(by.css('.name > a')); + expect(noReportsText.getText()).not.toBe('user/test'); }); // create a report @@ -87,4 +92,432 @@ describe('reports app', function(){ expect(browser.getTitle()).toBe('BEAT - Report'); }); }); + + // go to the experiments page and add up to 5 already-ran experiments + describe('adding experiments to the "test" report', function(){ + // go to experiments page + beforeAll(function(){ + browser.get('http://localhost:8000/experiments/user/'); + }); + + it('should show the experiments list page', function(){ + expect(browser.getTitle()).toEqual("BEAT - user's Experiments"); + }); + + it('should list successfully-ran experiments accessible by user', function(){ + expect(browser.isElementPresent(by.css('.Done'))).toBeTruthy(); + }); + + it('should add up to the first 5 experiments to the "test" report', function(){ + let finishedExpTableRows = element.all(by.css('.Done')); + let addButton = element(by.css('#add-to-report')); + expect(addButton.getAttribute('disabled')).toBe('true'); + + let fiveRows = finishedExpTableRows.filter((r, i) => i < 5); + + fiveRows + .then(rs => Promise.all(rs.map(r => r.element(by.css('.report-checkbox')).element(by.css('input')).click()))) + .then(() => { + browser.wait(until.elementToBeClickable(addButton), 5000, 'Button still isnt clickable!'); + return browser.executeScript('arguments[0].click();', addButton.getWebElement()); + }) + .then(() => browser.wait(until.presenceOf(element(by.css('.modal'))), 5000, 'Element taking too long to appear in the DOM')) + .then(() => element(by.css('.chosen-single')).click()) + .then(() => element(by.css('.chosen-results')).element(by.css('.active-result')).click()) + .then(() => { + let submitButton = element(by.buttonText('Add')); + return submitButton.click(); + }) + .then(() => browser.wait(until.presenceOf(element(by.buttonText("View Report"))), 5000)) + .then(() => { + let headerText = element(by.css('.report-results > h5')); + expect(headerText.getText()).toContain('Successfully added'); + + return browser.get('http://localhost:8000/reports/user/test/'); + }) + .then(() => { + expect(element.all(by.css('#experiment-list-test > tbody > tr')).count()).toBeGreaterThan(0); + }) + ; + }); + }); + + // create 2 groups, 'group1' & 'group2' + describe('creating groups', function(){ + let newGroupInput = element(by.css('#createNewGroupInput')); + + it('should create the "group1" group using the enter key', function(){ + newGroupInput.sendKeys('group1') + .then(() => enter.perform()) + .then(() => browser.wait(until.textToBePresentInElementValue(element(by.css('#createNewGroupInput')), ''), 1000)) + .then(() => expect(element.all(by.css('#groupsLayout > div')).count()).toBe(1)) + ; + }); + + it('should create the "group2" group using the "+" button', function(){ + newGroupInput.sendKeys('group2') + .then(() => element(by.css('#space-for-report-items + div button')).click()) + .then(() => browser.wait(until.textToBePresentInElementValue(element(by.css('#createNewGroupInput')), ''), 1000)) + .then(() => expect(element.all(by.css('#groupsLayout > div')).count()).toBe(2)) + ; + }); + }); + + // make sure the initial report layouts page is correct + describe('report page state with <6 experiments & two groups', function(){ + describe('header block', function(){ + const header = element(by.css('.col-sm-12 > p.bs-callout.bs-callout-danger')); + + it('has 4 labels', function() { + expect(header.all(by.tagName('br')).count()).toBe(4); + }); + + it('shows the unique report id', function() { + expect(header.element(by.css('.fa-arrow-circle-right + a')).getAttribute('href')).toMatch(/\/reports\/[0-9]+/); + }); + + it('shows the created date', function() { + expect(header.element(by.css('.fa-calendar-o + strong')).getText()).toMatch(/.+ago/); + }); + + it('shows the "last edited" date', function() { + expect(header.element(by.css('.fa-calendar-o + strong + br + .fa-calendar-o + strong')).getText()).toMatch(/.+ago/); + }); + + it('shows that the report is editable', function() { + expect(header.element(by.css('.fa-warning + strong')).getText()).toBe('Editable'); + }); + }); + + describe('documentation panel', function(){ + it('shows the empty warning', function() { + expect(element(by.css('#description-display > div')).getAttribute('class')).toContain('alert-warning'); + }); + + it('has an "Add" button', function() { + expect(element(by.css('#btn-edit-doc > i')).getAttribute('class')).toContain('fa-edit'); + }); + }); + + describe('experiments list panel', function(){ + describe('inline toolbar', function(){ + const toolbar = element(by.css('#filters')); + + it('has 3 filters', function(){ + expect(toolbar.all(by.xpath("./div")).count()).toBe(3); + }); + + it('has a filter-rows widget', function(){ + expect(toolbar.element(by.css('#text-filter')).getAttribute('placeholder')).toBe('Filter rows...'); + }); + + it('has an attestation filter', function(){ + expect(toolbar.element(by.css('#attestation-filter')).all(by.tagName('option')).count()).toBe(3); + }); + + it('has a privacy filter', function(){ + expect(toolbar.element(by.css('#privacy-filter')).all(by.tagName('option')).count()).toBe(4); + }); + }); + + describe('table', function(){ + const table = element(by.css('#experiment-list-test')); + + it('has 8 columns', function(){ + const cols = table.all(by.css('thead th')); + expect(cols.count()).toBe(8); + + expect(cols.get(0).getAttribute('class')).toBe('delete'); + expect(cols.get(1).getAttribute('class')).toBe('attestation'); + expect(cols.get(2).getAttribute('class')).toBe('privacy'); + expect(cols.get(3).getAttribute('class')).toBe('status'); + expect(cols.get(4).getAttribute('class')).toBe('date'); + expect(cols.get(5).getText()).toBe('Name'); + expect(cols.get(6).getAttribute('class')).toBe('datasets'); + expect(cols.get(7).getAttribute('class')).toBe('analyzers'); + }); + + it('has 5 or less rows', function() { + const rows = table.all(by.css('tbody > tr')); + expect(rows.count()).toBeLessThan(6); + }); + + it('has a "Remove Selected Experiments" button', function() { + const b = element(by.buttonText('Remove Selected Experiments')); + expect(b.getAttribute('disabled')).toBeDefined(); + }); + }); + }); + + describe('report content block', function(){ + const groupsLayout = element(by.css('#groupsLayout')); + + describe('group1 container header', function(){ + const header = element(by.css('#group1-heading')); + const children = element.all(by.css('#group1-heading > h4 > *')); + + it('has 5 children: a collapse link, name widget, a button group, and the add items menu', function(){ + expect(children.count()).toBe(4); + }); + + describe('collapse link', function(){ + it('toggles "#collapse-group1"', function(){ + expect(children.get(0).getAttribute('href')).toContain('#collapse-group1'); + }); + }); + + describe('group name widget', function(){ + const widgetEls = children.get(1).all(by.tagName('span')); + const label = widgetEls.get(0); + const button = widgetEls.get(1); + + it('has value "group1"', function(){ + expect(label.getText()).toBe('group1'); + }); + + describe('edit button', function(){ + it('has the pencil glyphicon', function(){ + expect(button.getAttribute('class')).toBe('glyphicon glyphicon-pencil'); + }); + + it('is clickable', function(){ + // no direct way to check if clickable... + // so make sure that its not disabled & its displayed instead + expect(button.getAttribute('disabled')).toBeNull(); + expect(button.isDisplayed()).toBeTruthy(); + }); + }); + + }); + + describe('button group', function(){ + const grp = children.get(2); + const btnChildren = grp.all(by.className('btn')); + + it('is a btn group', function(){ + expect(grp.getAttribute('class')).toContain('btn-group'); + }); + + it('is an action buttons', function(){ + expect(grp.getAttribute('class')).toContain('action-buttons'); + }); + + it('has btn children', function() { + const btnChildren = grp.all(by.className('btn')); + expect(btnChildren.count()).toBe(2); + }); + + it('has a button to delete a group with a red "X"', function(){ + expect(btnChildren.get(0).getAttribute('title')).toBe('Delete Group'); + expect(btnChildren.get(0).element(by.css('i')).getAttribute('class')).toContain('fa-times'); + }); + + it('has a button to drag & sort the group with a 4-directional arrow', function(){ + expect(btnChildren.get(1).getAttribute('title')).toBe('Drag to re-order group'); + expect(btnChildren.get(1).element(by.css('i')).getAttribute('class')).toContain('fa-arrows'); + }); + }); + + describe('add items menu', function(){ + const grp = children.get(3); + const buttons = grp.all(by.tagName('button')); + + it('has 3 buttons', function(){ + expect(buttons.count()).toBe(3); + }); + + it('is all disabled', function(){ + expect(buttons.filter(b => b.getAttribute('disabled').then(d => d)).count()).toBe(3); + }); + + it('has a button to add plots', function(){ + const el = element(by.buttonText('Add Plot')); + expect(el).toBeDefined(); + }); + + it('has a button to add tables', function(){ + const el = element(by.buttonText('Add Table')); + expect(el).toBeDefined(); + }); + + it('has a button to add text blocks', function(){ + const el = element(by.buttonText('Add Text Block')); + expect(el).toBeDefined(); + }); + }); + }); + + describe('group1 experiments panel', function(){ + const header = element(by.css('#group1-explist-heading')); + const body = element(by.css('#collapse-group1-explist')); + + it('is visible', function(){ + expect(header.isDisplayed()).toBeTruthy(); + expect(body.isDisplayed()).toBeTruthy(); + }); + + it('is empty', function(){ + expect(element.all(by.css('#collapse-group1-explist > .panel-body > *')).count()).toBe(0); + }); + + describe('header button', function(){ + const button = element(by.css('#group1_exp_add_dropdown')); + + it('is non-disabled', function(){ + expect(button.getAttribute('disabled')).toBeNull(); + }); + + it('has the text "Add Experiment"', function(){ + expect(button.getText()).toBe('Add Experiment'); + }); + }); + }); + + describe('group1 content panel', function(){ + it('doesnt exist', function(){ + expect(element.all(by.css('#collapse-group1 > *')).count()).toBe(1); + }); + }); + }); + }); + + describe('group experiments panel management', function(){ + const g1ExpPanel = element(by.css('#collapse-group1 > .panel-body > .panel')); + const addButton = element(by.css('#group1_exp_add_dropdown')); + + // add back the exp to group1 + afterAll(function(){ + return addButton.click() + .then(() => { + // make sure list opened correctly & add an exp + const parent = addButton.element(by.xpath('..')); + const list = parent.element(by.css('ul')); + const lis = list.all(by.css('li')); + + return lis.get(0).element(by.css('a')).click(); + }); + }); + + it('adds 1 experiment to group1', function(){ + // open add exp menu + addButton.click() + .then(() => { + // make sure list opened correctly & add an exp + const parent = addButton.element(by.xpath('..')); + expect(parent.getAttribute('class')).toContain('open'); + const list = parent.element(by.css('ul')); + const lis = list.all(by.css('li')); + expect(lis.count()).toBeGreaterThan(0); + + return lis.get(0).element(by.css('a')).click(); + }) + .then(() => { + // check state of group after adding exp + const analyzer = element(by.css('#group1-explist-heading > h4 > i')); + expect(analyzer.isDisplayed()).toBeTruthy(); + expect(analyzer.getInnerHtml()).not.toBe(''); + + const expsBody = element(by.css('#collapse-group1-explist > .panel-body')); + expect(expsBody.getInnerHtml()).not.toBe(''); + }); + }); + + describe('group1 experiment table state with 1 experiment', function(){ + const expsTable = element(by.css('#collapse-group1-explist > .panel-body > table')); + const headers = expsTable.all(by.css('thead > tr > th')); + const row = expsTable.element(by.css('tbody > tr')); + + describe('column layout', function(){ + it('has 4 columns', function(){ + expect(headers.count()).toBe(4); + }); + + it('has an empty col for rm exp buttons', function() { + expect(headers.get(0).getText()).toBe(''); + }); + + it('has experiment names col', function() { + expect(headers.get(1).getText()).toBe('Experiment'); + }); + + it('has dbs/protocols col', function() { + expect(headers.get(2).getText()).toBe('Databases/Protocols'); + }); + + it('has aliases col', function() { + expect(headers.get(3).getText()).toBe('Alias'); + }); + }); + + describe('row layout', function(){ + const cells = row.all(by.css('td')); + + it('has 4 entries', function() { + expect(cells.count()).toBe(4); + }); + + it('has a delete button in the first row', function() { + expect(cells.get(0).element(by.tagName('span')).getAttribute('class')).toContain('btn-delete'); + }); + + it('has the experiment name and a link to the experiment in the second row', function() { + const a = cells.get(1).element(by.css('a')); + expect(a.getText()).not.toBe(''); + }); + + it('has a list of formatted dbs & protocols in the third row', function() { + const els = cells.get(2).all(by.css('span')); + expect(els.count()).toBeGreaterThan(0); + expect(els.element(by.css('a')).getText()).toMatch(/\S+@\S+/); + }); + + it('has an editable alias input in the fourth row', function() { + const input = cells.get(3).element(by.css('input')); + const pExpName = cells.get(1).element(by.css('a')).getText(); + pExpName + .then(expName => { + const lastSeg = expName.split('/').filter(s => s.length > 0).pop(); + expect(input.getAttribute('value')).toBe(lastSeg); + expect(input.getAttribute('disabled')).toBeNull(); + }); + }); + + }); + }); + + describe('removing 1 experiment', function(){ + beforeAll(function(){ + const rmExpButton = element(by.css('#collapse-group1-explist > tbody > .btn-delete')); + return rmExpButton.click(); + }); + + it('removes the exp table', function(){ + expect(g1ExpPanel.getInnerHtml()).toBe(''); + }); + + it('removes the analyzer tag', function() { + expect(element.all(by.css('#group1-explist-heading > h4 > *')).count()).toBe(2); + }); + + it('lets the user add any experiment again', function() { + const expRowsCount = element.all(by.css('#experiment-list-test tbody > tr')).count(); + + Promise.all([expRowsCount, addOptionsCount, element(by.css('#group1_exp_add_dropdown')).click()]) + .then(([expCount]) => + Promise.all([ + expCount, + element('#group1_exp_add_dropdown').element(by.xpath('..')).element(by.css('ul')).all(by.css('li')).count() + ]) + ) + .then(([expCount, optsCount]) => { + expect(expCount).toBe(optsCount); + }); + }); + }); + }); + + // should have 1 exp in group + describe('adding & removing report items to groups', function(){ + + }); }); diff --git a/beat/web/reports/templates/reports/dialogs/report_remove_item.html b/beat/web/reports/templates/reports/dialogs/report_remove_item.html deleted file mode 100644 index 4bc2feeabf65b8a9a093798ab2506847894d316e..0000000000000000000000000000000000000000 --- a/beat/web/reports/templates/reports/dialogs/report_remove_item.html +++ /dev/null @@ -1,40 +0,0 @@ -{% comment %} - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. -{% endcomment %} -<div id="{{ dialog_id }}" class="report_remove_item" title="Report" style="display:none"> - <p class="explanation">Remove item from report</p> - - - <div class="explanation_text"> - <p class="experiments"> - Do you wish to delete this item from your report? - </p> - </div> - <div class="warnings" style="display:none"> - <p class="experiments">Sucessfully removed report item</p> - <ul class="experimentslist"></ul> - </div> - - <div class="errors" style="display:none"> - <p class="errors">Some errors occured while attempting to remove the report item:</p> - <ul class="errorslist"></ul> - </div> -</div> diff --git a/beat/web/reports/templates/reports/dialogs/report_saved.html b/beat/web/reports/templates/reports/dialogs/report_saved.html deleted file mode 100644 index ec97e677216732586740f73eb9822f3b9024185e..0000000000000000000000000000000000000000 --- a/beat/web/reports/templates/reports/dialogs/report_saved.html +++ /dev/null @@ -1,29 +0,0 @@ -{% comment %} - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. -{% endcomment %} -<div id="{{ dialog_id }}" class="report_remove_experiment" title="Report" style="display:none"> - <p class="explanation">Report status</p> - - - <div class="explanation_text"> - <p>Your report has been successfully saved</p> - </div> -</div> diff --git a/beat/web/reports/templates/reports/panels/experiment_table.html b/beat/web/reports/templates/reports/panels/experiment_table.html index 9be394bc81ebf532ced9b3824d68f9c757cd2b4e..401cefc135c5f3ba4a836f73a15a375381fffa35 100644 --- a/beat/web/reports/templates/reports/panels/experiment_table.html +++ b/beat/web/reports/templates/reports/panels/experiment_table.html @@ -72,7 +72,7 @@ <table id="{{ panel_id }}" class="table table-hover table-condensed object-list experiment-list"> <thead> <tr> - {% if not report_number and owner and obj.get_status_display == 'Editable' %} + {% if not report_number and owner and report_status == 'Editable' %} <th class='delete'></th> {% endif %} <th class="attestation"></th> @@ -88,7 +88,7 @@ {% for obj in objects %} {% with obj.get_status_display as status %} <tr class="{{ status }}"> - {% if not report_number and owner and obj.get_status_display == 'Editable' %} + {% if not report_number and owner and report_status == 'Editable' %} <td class="delete"> <input name='ctrl.expNamesToRemove[]' @@ -159,7 +159,7 @@ </div> </div><!-- col --> </div><!-- row --> - {% if not report_number and owner and obj.get_status_display == 'Editable' %} + {% if not report_number and owner and report_status == 'Editable' %} <div> <button ng-disabled='ctrl.expNamesToRemove.length == 0' diff --git a/beat/web/reports/templates/reports/panels/viewer.html b/beat/web/reports/templates/reports/panels/viewer.html index c3a84b884604276df4a0cf4ae52d586b966df73b..262adcd5f55d8bc45c1b02b0235685589e033f9c 100644 --- a/beat/web/reports/templates/reports/panels/viewer.html +++ b/beat/web/reports/templates/reports/panels/viewer.html @@ -46,18 +46,22 @@ </div>{# collapse #} </div>{# panel #} + {% if not report_number and owner %} <div class="panel panel-default" ng-if="report.experiments.length != 0" > <div class="panel-heading" role="tab" id="info-heading"> <h4 class="panel-title"> <a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-info" aria-expanded="true" aria-controls="collapse-info">Experiments List</a> </h4> </div>{# panel-heading #} + <div id="collapse-info" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading"> <div class="panel-body"> - {% experiment_table exps owner report_number "experiment-list-test" %} + {% experiment_table exps owner report_number "experiment-list-test" status %} </div>{# panel-body #} </div>{# collapse #} </div>{# panel #} + {% endif %} + <div ng-if="report.experiments.length == 0" class="alert alert-warning"{% if not owner or status != 'Editable' %}style="display:none;"{% endif %}> <i class="fa fa-warning fa-lg"></i> You have <strong>not added any experiments</strong> in this report yet. You may add experiments from <a href="{{ URL_PREFIX }}/experiments/{{ object.author.username }}/">any experiment list page</a> to unlock editing features for this report. </div> diff --git a/beat/web/reports/templates/reports/partials/reportChartDropDown.html b/beat/web/reports/templates/reports/partials/reportChartDropDown.html deleted file mode 100644 index fa1e939d54acb1ee1cb9879086059829fdd77dbc..0000000000000000000000000000000000000000 --- a/beat/web/reports/templates/reports/partials/reportChartDropDown.html +++ /dev/null @@ -1,26 +0,0 @@ -{% comment %} - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. -{% endcomment %} -<div> -<select> - <option ng-model="selectedName" ng-repeat="(key, value) in report.plotterparameter" ng-selected="'{$ value.name $}' == '{$ dattrs.selected_template $}'" value="{$ value.name $}">{$ value.name $}</i></p> -</select> -</div> diff --git a/beat/web/reports/templates/reports/partials/reportGeneralInfo.html b/beat/web/reports/templates/reports/partials/reportGeneralInfo.html deleted file mode 100644 index 23564e2ec0341a4254ee42619454eefdd39c8f4c..0000000000000000000000000000000000000000 --- a/beat/web/reports/templates/reports/partials/reportGeneralInfo.html +++ /dev/null @@ -1,70 +0,0 @@ -{% comment %} - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. -{% endcomment %} -<div class="reportInfo view"> -<div class="reportInfoContainer"> - <div class="span3 report"> - <div class="reportBody"> - <div class="row table-responsive"> - <div class="col-sm-12"> - <table class="table table-hover table-striped table-condensed"> - <thead> - <tr> - <th>Experiments</th> - <th ng-if=" report.status == 'editable' && report.number != report_number" class="experiment_alias_title">Experiments Alias</th> - </tr> - </thead> - <tbody> - <tr class="counter" ng-repeat="(name, information) in report.all_experiments"> - <td ng-if=" report.status == 'editable' && report.number != report_number"> - <a id='{$ name $}' class='button remove_experiment {$ report.status $}' removeexperiment> - <i class='fa fa-times fa-lg'></i> - </a> - <a ng-if="report.status == 'editable' && report.number != report_number" href="{$ report.url_prefix $}/experiments/{$ name $}/">{$ name $} - </a> - <a ng-if="report.status != 'editable' && report.number != report_number" href="{$ report.url_prefix $}/experiments/{$ name $}/">{$ report_experiments_alias[name] $} - </a> - </td> - <td> - <a ng-if="report.number == report_number || (report.status == 'published' && report.number != report_number)" href="{$ report.url_prefix $}/experiments/{$ name $}/">{$ report_experiments_alias[name] $} - </a> - <div ng-if=" report.status == 'editable' && report.number != report_number" id='{$ name $}' class="experiment_alias"> - <a ng-if=" report.status == 'editable' && report.number != report_number" id='button_alias_{$ name $}' class='button edit_alias setalias {$ report.status $}' aliasexperiment> - <i id ='icon_{$ name $}' class='fa fa-lock fa-lg'></i> - </a> - <input id='input_{$ name $}' class="form-control input-sm experiment_alias input-disabled" type="text" name="experiment_alias" value='{$ report_experiments_alias[name] $}' disabled="disabled" style="width:90%;display:inline"> - </div> - </td> - </tr> - </tbody> - </table> - </div> - </div> - <div class="form form-inline"> - <div ng-if="report.status == 'editable' && report.number != report_number" class="form-group tableprecision {$ dattrs.reportstatus $} {$ dattrs.accessnumber $}" tableprecision> - <label for="float-precision">Floating-point Precision: </label> - <select id="float-precision" ng-model="floating_point_precision.selected" class="form-control input-sm" ng-options="item for item in floating_point_precision ">Select the floating point precision for your tables in the report</select> - <p class="help">Select the floating point precision for your tables in the report.</p> - </div> - </div> - </div> - </div> -</div> diff --git a/beat/web/reports/templates/reports/partials/reportSingleTable.html b/beat/web/reports/templates/reports/partials/reportSingleTable.html deleted file mode 100644 index 5d2e92a631a9812484a9ad50f040a1856ba27694..0000000000000000000000000000000000000000 --- a/beat/web/reports/templates/reports/partials/reportSingleTable.html +++ /dev/null @@ -1,58 +0,0 @@ -{% comment %} - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. -{% endcomment %} -<div id="{$ dattrs.tableid $}"> - -<div class="row"> - <div class="col-sm-12"> - <div class="pull-left action-buttons"> - <a ng-if="dattrs.reportstatus == 'editable' && dattrs.accessnumber != 'number'" class="btn btn-success btn-sm settings {$ dattrs.reportstatus $} {$ dattrs.accessnumber $}" buttonsettings><i class="fa fa-cog fa-lg"></i> Settings</a> - <a ng-if="dattrs.reportstatus == 'editable' && dattrs.accessnumber != 'number'" class="btn btn-danger btn-sm item_delete {$ dattrs.reportstatus $} {$ dattrs.accessnumber $}" buttondeleteitem><i class="fa fa-times fa-lg"></i> Delete</a> - <a class="btn btn-primary btn-sm item_export {$ dattrs.reportstatus $} {$ dattrs.accessnumber $}" buttonexportitem><i class="fa fa-download fa-lg"></i> Export Table</a> - </div> - </div> -</div> - -<div class="row table-responsive"> - <div class="col-sm-12"> - <table class="table table-hover table-striped table-condensed report-table"> - <thead> - <tr> - <th ng-repeat="(key, value) in tables_details[dattrs.tableid]" ng-if="value.selected" class="tableitemspace" sortth="{$ value.name $}" sorttblid="{$ dattrs.tableid $}" sortdata> - <span style="white-space:nowrap"> - <span ng-if="(sorted_tables | contains:dattrs.tableid)" class="glyphicon sort-icon" ng-show="sorted_experiments_keys_tables_sortkey[dattrs.tableid]==value.name" ng-class="{'glyphicon-chevron-up':sorted_experiments_keys_reverse[dattrs.tableid],'glyphicon-chevron-down':!(sorted_experiments_keys_reverse[dattrs.tableid])}"></span> - <span ng-if="!(sorted_tables | contains:dattrs.tableid) && sorted_experiments_keys_reverse[dattrs.tableid]!=undefined" class="glyphicon sort-icon" ng-show="sorted_experiments_keys_tables_sortkey[dattrs.tableid]==value.name" ng-class="{'glyphicon-chevron-up':sorted_experiments_keys_reverse[dattrs.tableid],'glyphicon-chevron-down':!(sorted_experiments_keys_reverse[dattrs.tableid])}"></span> - <small style="white-space:nowrap"><span style="color:#D3D3D3" ng-if="!(sorted_tables | contains:dattrs.tableid) || sorted_experiments_keys_reverse[dattrs.tableid]==undefined || sorted_experiments_keys_tables_sortkey[dattrs.tableid]!=value.name" class="glyphicon glyphicon-sort sort-icon" ng-show="sorted_experiments_keys_tables_sortkey[dattrs.tableid]!=value.name"></span></small> - {$ value.name $} - </span> - </th> - </tr> - </thead> - <tbody> - <tr ng-if="!(sorted_tables | contains:dattrs.tableid)" ng-repeat="(exp_key, exp_val) in report_experiments" item="exp_key"> - <tr ng-if="(dattrs.reportstatus == 'editable' || dattrs.reportstatus == 'published') && sorted_tables | contains:dattrs.tableid" ng-repeat="(exp_key, exp_val) in sorted_experiments_keys_tables[dattrs.tableid]" item="exp_val"> - <tr ng-if="(dattrs.reportstatus == 'locked') && sorted_tables | contains:dattrs.tableid" ng-repeat="(exp_key, exp_val) in sorted_experiments_keys_tables[dattrs.tableid]" item="exp_val"> - </tr> - </tbody> - </table> - </div> -</div> -</div> diff --git a/beat/web/reports/templates/reports/report.html b/beat/web/reports/templates/reports/report.html index 1cc1a514a06543230ed7dc246329487fe457e487..d27e338a141b2d1baa1783b52f789b45e8e62f86 100644 --- a/beat/web/reports/templates/reports/report.html +++ b/beat/web/reports/templates/reports/report.html @@ -83,31 +83,22 @@ <script src="{% fingerprint "reports/app/factories/reportFactory.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/factories/experimentFactory.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/factories/plotterFactory.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/factories/dataFactory.js" %}" type="text/javascript" charset="utf-8"></script> <!-- services --> <script src="{% fingerprint "reports/app/services/groupsService.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/services/experimentsService.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/services/urlService.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/services/reportService.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/services/plotService.js" %}" type="text/javascript" charset="utf-8"></script> <!-- directives --> <!-- old --> - <script src="{% fingerprint "reports/app/directives/addReportItem.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/aliasExperiment.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/buttonDeleteItem.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/buttonExportItem.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/buttonSettings.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/item.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/loadedContent.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/lockReport.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/myReportInfo.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/publishReport.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/removeExperiment.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/saveReportItems.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/sortData.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/tableDynamic.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/tablePrecision.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/theColumn.js" %}" type="text/javascript" charset="utf-8"></script> + + <!-- new --> + <script src="{% fingerprint "reports/app/directives/tableItem.js" %}" type="text/javascript" charset="utf-8"></script> <!-- edit view --> {% if not report_number and report.get_status_display == 'Editable' and owner %} @@ -122,7 +113,6 @@ <script src="{% fingerprint "reports/app/directives/edit/tableFieldSelector.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/edit/tableItem.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/edit/textItem.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/edit/viewSerialized.js" %}" type="text/javascript" charset="utf-8"></script> {% else %} <!-- readonly view --> <script src="{% fingerprint "reports/app/directives/view/layout.js" %}" type="text/javascript" charset="utf-8"></script> @@ -145,10 +135,10 @@ {% block content %} {% if author %} - <div class="col-sm-12" ng-app="reportApp" ng-controller="reportController" ng-init="init('{{ author }}', '{{report_name}}', '{{ URL_PREFIX }}', '{% fingerprint "reports/app/data/itemcontent.json" %}', '{% fingerprint "reports/app/data/table_itemcontent.json" %}')"> + <div class="col-sm-12" ng-app="reportApp" ng-controller="reportController" ng-init="init('{{ author }}', '{{report_name}}', '{{ URL_PREFIX }}')"> {% endif %} {% if report_number %} - <div class="col-sm-12" ng-app="reportApp" ng-controller="reportController" ng-init="initWithReportNumber('{{report_number}}', '{{ URL_PREFIX }}', '{% fingerprint "reports/app/data/itemcontent.json" %}', '{% fingerprint "reports/app/data/table_itemcontent.json" %}')"> + <div class="col-sm-12" ng-app="reportApp" ng-controller="reportController" ng-init="initWithReportNumber('{{report_number}}', '{{ URL_PREFIX }}')"> {% endif %} {% csrf_token %} @@ -220,9 +210,6 @@ {% smart_selector "smart_selector_detail" %} {% report_lock "report_lock" %} {% report_publish "report_publish" %} -{% report_remove_experiment "report_remove_experiment" %} -{% report_remove_item "report_remove_item" %} -{% report_saved "report_saved" %} <script type="text/javascript"> var smart_selector = new beat.ui.SmartSelector('smart_selector'); diff --git a/beat/web/reports/templatetags/report_tags.py b/beat/web/reports/templatetags/report_tags.py index a42ada0b8aa7e4024726ffdaed0281bf644fbb7a..4fd790f01f2f2d5f8ecb0aa0be58665eda52dc72 100644 --- a/beat/web/reports/templatetags/report_tags.py +++ b/beat/web/reports/templatetags/report_tags.py @@ -217,48 +217,13 @@ register.inclusion_tag('reports/dialogs/report_publish.html')(report_publish) #-------------------------------------------------- -def report_remove_experiment(id): - return { 'dialog_id': id, - 'URL_PREFIX': settings.URL_PREFIX - } - - -register.inclusion_tag('reports/dialogs/report_remove_experiment.html')(report_remove_experiment) - - -#-------------------------------------------------- - - -def report_remove_item(id): - return { 'dialog_id': id, - 'URL_PREFIX': settings.URL_PREFIX - } - - -register.inclusion_tag('reports/dialogs/report_remove_item.html')(report_remove_item) - - -#-------------------------------------------------- - - -def report_saved(id): - return { 'dialog_id': id, - 'URL_PREFIX': settings.URL_PREFIX - } - - -register.inclusion_tag('reports/dialogs/report_saved.html')(report_saved) - - -#-------------------------------------------------- - - @register.inclusion_tag('reports/panels/experiment_table.html', takes_context=True) -def experiment_table(context, objects, owner, report_number, id): +def experiment_table(context, objects, owner, report_number, id, status): return dict( request=context['request'], objects=objects, owner=owner, panel_id=id, - report_number=report_number + report_number=report_number, + report_status=status ) diff --git a/buildout.cfg b/buildout.cfg index e88744cd59492da38ee5ec15a713d80b168003e0..a92f4885ede9fb46960d633b74bcdfc3b5b7b902 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -103,8 +103,8 @@ eggs = ${buildout:eggs} [node] recipe = gp.recipe.node -npms = bower -scripts = bower +npms = bower protractor +scripts = bower protractor webdriver-manager [bower] recipe = bowerrecipe diff --git a/doc/admin/installation.rst b/doc/admin/installation.rst index 87d4598d623cbe9576dd728b7254812db3d04a33..308e4ec86bcb207201fe23f305064d0b25d3d047 100644 --- a/doc/admin/installation.rst +++ b/doc/admin/installation.rst @@ -195,19 +195,11 @@ End-to-End Testing Setup ===== -Currently, testing the BEAT web platform with Protractor requires additional setup after successfully setting up the project locally: - -- Install Protractor - - .. code:: bash - - ./parts/buildout-node/node-*/bin/npm i -g protractor - -- Download/update the webdriver-manager's dependencies (Selenium & more) +Currently, testing the BEAT web platform with Protractor requires additional setup after successfully setting up the project locally. Download/update the webdriver-manager's dependencies (Selenium & more): .. code:: bash - ./parts/buildout-node/node-*/bin/webdriver-manager update + ./bin/webdriver-manager update Running tests with the provided script ====================================== @@ -235,7 +227,7 @@ _____________________________ .. code:: bash - ./parts/buildout-node/node-*/bin/webdriver-manager start + ./bin/webdriver-manager start .. important:: @@ -245,7 +237,7 @@ _____________________________ .. code:: bash - ./parts/buildout-node/node-*/bin/protractor protractor-conf.js + ./bin/protractor protractor-conf.js - If you started your webdriver server as a background process, you can kill all webdriver processes diff --git a/protractor-conf.js b/protractor-conf.js index 00bf9926fe894fb31d4e4a27af2f3ea9dfb5934e..3a546abfb6d1b50a39b553c3108215fa109987d9 100644 --- a/protractor-conf.js +++ b/protractor-conf.js @@ -7,5 +7,8 @@ exports.config = { ], allScriptsTimeout: 60000, + // disable some selenium~browser notification than can steal focus + notify: false, + //resultJsonOutputFile: './protractor-test-results.json' } diff --git a/protractor.sh b/protractor.sh index 87ee1bc03530f34c944da88a0c0a32b9922960ff..7799234e27a9e3e982ddf783d6a801bd0d0271f3 100755 --- a/protractor.sh +++ b/protractor.sh @@ -50,9 +50,9 @@ fi # run the web server beat_cmd='./bin/django runserver' # spin up web manager -webdriver_cmd='./parts/buildout-node/node-*/bin/webdriver-manager start' +webdriver_cmd='./bin/webdriver-manager start' # run tests -protractor_cmd='./parts/buildout-node/node-*/bin/protractor ./protractor-conf.js' +protractor_cmd='./bin/protractor ./protractor-conf.js' # start bg processes echo 'Output from the BEAT web server &' \