From 47be72e969344a494b01b759575d390275d911dc Mon Sep 17 00:00:00 2001
From: Mariia Pukhliakova <mariia.pukhliakova@id.ethz.ch>
Date: Mon, 10 Feb 2020 13:05:43 +0100
Subject: [PATCH] SSDM-9301 Move BBB-HUB in ELN

---
 .../1/as/webapps/eln-lims/html/etc/config.js  |   2 +-
 .../html/plugins/bbb-hub/BBBServerFacade.js   | 142 +++++++++++++++
 .../html/plugins/bbb-hub/UiComponents.js      | 104 +++++++++++
 .../eln-lims/html/plugins/bbb-hub/plugin.js   |  37 ++++
 .../html/plugins/bbb-hub/snakemake-table.js   | 169 ++++++++++++++++++
 .../html/plugins/bbb-hub/snakemake-trigger.js | 161 +++++++++++++++++
 6 files changed, 614 insertions(+), 1 deletion(-)
 create mode 100644 openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/BBBServerFacade.js
 create mode 100644 openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/UiComponents.js
 create mode 100644 openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/plugin.js
 create mode 100644 openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/snakemake-table.js
 create mode 100644 openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/snakemake-trigger.js

diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/etc/config.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/etc/config.js
index 589cda418e5..549b910bf1c 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/etc/config.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/etc/config.js
@@ -30,7 +30,7 @@ loadJSResorce("./etc/InstanceProfile.js", onLoadInstanceProfileResorceFunc);
 //</PROFILE_PLACEHOLDER>
 
 var PLUGINS_CONFIGURATION = {
-    extraPlugins : ["life-sciences", "flow", "microscopy"]
+    extraPlugins : ["life-sciences", "flow", "microscopy", "bbb-hub"]
 };
 
 var options = {
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/BBBServerFacade.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/BBBServerFacade.js
new file mode 100644
index 00000000000..32c4989cf99
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/BBBServerFacade.js
@@ -0,0 +1,142 @@
+var BBBServerFacade = new function() {
+    this.getExperiment = function($container, model) {
+        require(["openbis",
+                 "as/dto/sample/fetchoptions/SampleFetchOptions",
+                 "as/dto/experiment/fetchoptions/ExperimentFetchOptions",
+                 "as/dto/experiment/id/ExperimentIdentifier",
+                 "as/dto/dataset/fetchoptions/DataSetFetchOptions"],
+        function(openbis, SampleFetchOptions,
+                          ExperimentFetchOptions,
+                          ExperimentIdentifier,
+                          DataSetFetchOptions) {
+
+            var v3 = new openbis(null);
+            v3._private.sessionToken = mainController.openbisV1._internal.sessionToken;
+
+            var webAppContext = v3.getWebAppContext();
+
+            var dataSetFetchOptions = new DataSetFetchOptions();
+            dataSetFetchOptions.withType();
+            dataSetFetchOptions.withPhysicalData();
+
+            var experimentId = new ExperimentIdentifier(model.experiment.identifier);
+            var fetchOptions = new ExperimentFetchOptions();
+            fetchOptions.withDataSetsUsing(dataSetFetchOptions);
+            fetchOptions.withType();
+
+            var sampleFetchOptions = new SampleFetchOptions();
+            sampleFetchOptions.withType().withPropertyAssignments().withPropertyType();
+            sampleFetchOptions.withProperties();
+            fetchOptions.withSamplesUsing(sampleFetchOptions);
+            v3.getExperiments([experimentId], fetchOptions).done(function(result) {
+                var experiment = result[model.experiment.identifier];
+                if (experiment.type.code == "BBB") {
+                    SnakemakeTrigger.paintTriggerContainers($container, model, experiment);
+                }
+            });
+        });
+    }
+
+    this.getExperiments = function($content) {
+        require(["openbis", "as/dto/sample/fetchoptions/SampleFetchOptions",
+                            "as/dto/experiment/fetchoptions/ExperimentFetchOptions",
+                            "as/dto/experiment/id/ExperimentIdentifier",
+                            "as/dto/dataset/fetchoptions/DataSetFetchOptions",
+                            "as/dto/experiment/search/ExperimentSearchCriteria",
+                            "as/dto/project/fetchoptions/ProjectFetchOptions"],
+        function(openbis, SampleFetchOptions,
+                          ExperimentFetchOptions,
+                          ExperimentIdentifier,
+                          DataSetFetchOptions,
+                          ExperimentSearchCriteria,
+                          ProjectFetchOptions) {
+
+            var v3 = new openbis();
+
+            v3.loginAsAnonymousUser().done(function(sessionToken) {
+                v3._private.sessionToken = sessionToken;
+                var webAppContext = v3.getWebAppContext();
+
+                var fetchOptions = new ExperimentFetchOptions();
+                fetchOptions.withType();
+                fetchOptions.withProperties();
+                fetchOptions.withRegistrator();
+
+                var projectFetchOptions = new ProjectFetchOptions();
+                projectFetchOptions.withSpace();
+
+                fetchOptions.withProjectUsing(projectFetchOptions);
+
+                var searchCriteria = new ExperimentSearchCriteria();
+                searchCriteria.withType();
+
+                v3.searchExperiments(searchCriteria, fetchOptions).done(function(result) {
+                    BBBServerFacade.getRoleAssignment($content, result.objects);
+                });
+            }).fail(function(result) {
+                console.log("Call failed to server: " + JSON.stringify(result));
+            });
+        });
+    }
+
+    this.getRoleAssignment = function ($content, experiments) {
+        require(["openbis", "as/dto/roleassignment/fetchoptions/RoleAssignmentFetchOptions",
+                            "as/dto/roleassignment/search/RoleAssignmentSearchCriteria"],
+        function(openbis, RoleAssignmentFetchOptions, RoleAssignmentSearchCriteria) {
+
+            var v3 = new openbis();
+
+            v3.loginAsAnonymousUser().done(function(sessionToken) {
+                v3._private.sessionToken = sessionToken;
+                var webAppContext = v3.getWebAppContext();
+
+                var criteria = new RoleAssignmentSearchCriteria();
+                criteria.withOrOperator();
+                criteria.withProject();
+                criteria.withSpace();
+
+                var fetchOptions = new RoleAssignmentFetchOptions();
+                fetchOptions.withSpace();
+                fetchOptions.withProject();
+                fetchOptions.withUser();
+                fetchOptions.withAuthorizationGroup();
+
+                v3.searchRoleAssignments(criteria, fetchOptions).done(function(result) {
+                    SnakemakeTable.paintTable($content, experiments, result.objects);
+                });
+            }).fail(function(result) {
+                console.log("Call failed to server: " + JSON.stringify(result));
+            });
+        });
+    }
+
+    this.callCustomASService = function(params, $model, action) {
+        var result_div = $('#callback_message');
+
+        require(["openbis",
+                 "as/dto/service/id/CustomASServiceCode",
+                 "as/dto/service/CustomASServiceExecutionOptions",
+                 "as/dto/experiment/id/ExperimentIdentifier"],
+        function(openbis, CustomASServiceCode, CustomASServiceExecutionOptions, ExperimentIdentifier) {
+
+            var v3 = new openbis(null);
+            v3._private.sessionToken = mainController.openbisV1._internal.sessionToken;
+            var webAppContext = mainController.openbisV3.getWebAppContext();
+            webAppContext['entityIdentifier'] = $model.experiment.identifier;
+
+            var serviceCode = new CustomASServiceCode("snakemake_service");
+            var options = new CustomASServiceExecutionOptions();
+
+            options.withParameter("webapp_context", webAppContext)
+            Object.keys(params).forEach(function(key) {
+                options.withParameter(key, params[key]);
+            });
+
+            v3.executeCustomASService(serviceCode, options).done(function(result) {
+                result_json = JSON.parse(result);
+                action(result_json)
+            });
+        });
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/UiComponents.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/UiComponents.js
new file mode 100644
index 00000000000..36e1f12a640
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/UiComponents.js
@@ -0,0 +1,104 @@
+var UiComponents = new function() {
+
+    this.addDropdown = function(label, options, $container, selectAction) {
+        var $dropdown = UiComponents.getDropdown(options);
+        $inputGroup = UiComponents.getInputGroup($dropdown, label);
+        $inputGroup.css("margin-top", "3px");
+        $container.append($inputGroup);
+        $dropdown.select2({ width : "100%", theme : "bootstrap", minimumResultsForSearch: 10 });
+        if (selectAction) {
+           $dropdown.on('select2:select', function (e) {
+               selectAction(e.params.data.id);
+           });
+        }
+        $inputGroup.getValue = function() {
+           return $dropdown.val();
+        }
+        return $inputGroup;
+    }
+
+    this.getDropdown = function(options, value) {
+        var $input = $("<select>", { class : "form-control", type : "text" });
+        $input.append($("<option>", { "disabled" : true, "selected" : true, "value" : true }).text(" -- select an option -- "));
+        for (option of options) {
+            var $option = $("<option>");
+            $option.text(option.label);
+            $option.attr("value", option.value);
+            $input.append($option);
+        }
+        if (value) {
+            $input.val(value);
+        }
+        return $input;
+    }
+
+    this.getInputGroup = function($input, label) {
+        var $inputGroup = $("<div>", { class : "input-group" });
+        $inputGroup.append($("<span>", { class : "input-group-addon" }).text(label).css({ 'min-width' : '150px' }));
+        $inputGroup.append($input);
+        return $inputGroup;
+    }
+
+    this.getButton = function($html, action, size, icon) {
+        var buttonSize = size ? size : 'md';
+        var $button = $('<button>', {
+            type : 'button',
+            class : 'btn btn-default btn-' + buttonSize,
+            'aria-label' : 'Left Align'
+        });
+        if(icon) {
+            var $icon = $('<span>', { class : 'glyphicon ' + icon });
+            $icon.css("margin-right", "0.5rem");
+            $button.append($icon);
+        }
+        if($html) {
+            $button.append($("<span>").text($html));
+        }
+        if(action) {
+            $button.click(action);
+        }
+        return $button;
+    }
+
+    this.getFieldset = function(legendText) {
+        var $fieldset = $('<fieldset>');
+        if (legendText) {
+            var $legend = $('<legend>', { class : 'section-legend' }).append(legendText)
+            $fieldset.append($legend);
+        }
+        return $fieldset;
+    }
+
+    this.getLoader = function() {
+        return $('<div>').attr('class', 'loader col-centered');
+    }
+
+    // blocks given $component or whole screen of none given
+    this.startLoading = function($component) {
+        var params = {
+            message : this.getLoader(),
+            css: {
+                border: 'none',
+                padding: '15px',
+                backgroundColor: 'transparent',
+            },
+            overlayCSS: {
+                opacity : 0.1,
+            }
+        };
+        if ($component) {
+            $component.block(params);
+        } else {
+            $.blockUI(params);
+        }
+    }
+
+    // unblocks given $component or whole screen of none given
+    this.stopLoading = function($component) {
+        if ($component) {
+            $component.unblock();
+        } else {
+            $.unblockUI();
+        }
+    }
+}
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/plugin.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/plugin.js
new file mode 100644
index 00000000000..b6803e35362
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/plugin.js
@@ -0,0 +1,37 @@
+function BBBHubTechnology() {
+    this.init();
+}
+
+$.extend(BBBHubTechnology.prototype, ELNLIMSPlugin.prototype, {
+    // This code is copy of openBis plugin. It was taken from here:
+    // https://sissource.ethz.ch/sis/bbb-hub/tree/master/openbis/core-plugins/bbb-hub/1/as/webapps/snakemake/html/js
+    // Now it is a ELN plugin.
+
+	init: function() {
+        loadJSResorce("./plugins/bbb-hub/UiComponents.js");
+        loadJSResorce("./plugins/bbb-hub/BBBServerFacade.js");
+        loadJSResorce("./plugins/bbb-hub/snakemake-table.js");
+        loadJSResorce("./plugins/bbb-hub/snakemake-trigger.js");
+	},
+
+	experimentFormTop : function($container, model) {
+	    BBBServerFacade.getExperiment($container, model);
+    },
+
+    experimentFormBottom : function($container, model) {
+    },
+
+    getExtraUtilities : function() {
+        return [{
+            icon : "fa fa-table",
+            uniqueViewName : "BBB_VIEW_NAME_TEST",
+            label : "Snakemake",
+            paintView : function($header, $content) {
+                    $header.append($("<h1>").append("Public Index Page"));
+                    BBBServerFacade.getExperiments($content);
+                }
+            }];
+    }
+});
+
+profile.plugins.push(new BBBHubTechnology());
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/snakemake-table.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/snakemake-table.js
new file mode 100644
index 00000000000..a6add5714f1
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/snakemake-table.js
@@ -0,0 +1,169 @@
+var SnakemakeTable = new function() {
+
+    this.paintTable = function(container, experiments, roles) {
+        var columns = [];
+
+        columns.push({
+            label : 'Code',
+            property : 'code',
+            isExportable: false,
+            sortable : true
+        });
+
+        columns.push({
+            label : 'Description',
+            property : 'description',
+            isExportable: false,
+            sortable : true
+        });
+
+        columns.push({
+            label : 'Group',
+            property : 'group',
+            isExportable: false,
+            sortable : true
+        });
+
+        columns.push({
+            label : 'E-mail',
+            property : 'email',
+            isExportable: false,
+            sortable : true
+        });
+
+        columns.push({
+            label : 'Special access',
+            property : 'specialAccess',
+            isExportable: false,
+            sortable : true
+        });
+
+        var getDataList = function(callback) {
+            var entities = [];
+
+            var rolesMap = SnakemakeTable.rolesMap(roles);
+
+            var dataList = [];
+
+            for (i = 0; i < experiments.length; i++) {
+                if (experiments[i].type === undefined || experiments[i].type.code !== "BBB") {
+                    continue;
+                }
+
+                var desc = experiments[i].properties["BBB.DESCRIPTION"];
+                var group = experiments[i].properties["BBB.GROUP"];
+                var registrator = experiments[i].registrator;
+                var projectCode = experiments[i].project.code;
+                var spaceCode = experiments[i].project.space.code;
+
+                var model = {		'code' : experiments[i].code,
+                                    'description' : desc === undefined ? "" : desc,
+                                    'group' : group === undefined ? "" : group,
+                                    'email' : registrator === null ? "" : registrator.email,
+                                    'specialAccess' : SnakemakeTable.getSpecialAccess(rolesMap, projectCode, spaceCode)
+                };
+
+                dataList.push(model);
+            }
+            callback(dataList);
+        };
+
+        var dataGridController = new DataGridController(null, columns, [], null, getDataList, null, true, "ENTITY_TABLE_BBB", null, 90);
+        dataGridController.init(container);
+    }
+
+    this.prepareData = function(experiments, roles) {
+        var data = [];
+
+        var rolesMap = SnakemakeTable.rolesMap(roles);
+
+        for (i = 0; i < experiments.length; i++) {
+            var row = [];
+
+            if (experiments[i].type === undefined || experiments[i].type.code !== "BBB") {
+                continue;
+            }
+
+            var desc = experiments[i].properties["BBB.DESCRIPTION"];
+            var group = experiments[i].properties["BBB.GROUP"];
+            var registrator = experiments[i].registrator;
+            var projectCode = experiments[i].project.code;
+            var spaceCode = experiments[i].project.space.code;
+
+            row.push(experiments[i].code);
+            row.push(desc === undefined ? "" : desc);
+            row.push(group === undefined ? "" : group);
+            row.push(registrator === null ? "" : registrator.email);
+            row.push(SnakemakeTable.getSpecialAccess(rolesMap, projectCode, spaceCode));
+
+            data.push(row);
+        }
+
+        return data;
+    }
+
+    this.getSpecialAccess = function(rolesMap, projectCode, spaceCode) {
+        var projectUsers = rolesMap["projects"][projectCode] === undefined ? "" : rolesMap["projects"][projectCode]["users"].join(", ");
+        var projectGroups = rolesMap["projects"][projectCode] === undefined ? "" : rolesMap["projects"][projectCode]["groups"].join(", ");
+
+        var spaceUsers = rolesMap["space"][spaceCode] === undefined ? "" : rolesMap["space"][spaceCode]["users"].join(", ");
+        var spaceGroups = rolesMap["space"][spaceCode] === undefined ? "" : rolesMap["space"][spaceCode]["groups"].join(", ");
+
+        var users = projectUsers + (projectUsers !== "" && spaceUsers !== "" ? ", " : "") + spaceUsers;
+        var groups = projectGroups + (projectGroups !== "" && spaceGroups !== ""  ? ", " : "") + spaceGroups;
+
+        var access = "";
+        if (users !== "") {
+            access += "<span style='font-weight:bold'>Users: </span>" + users;
+        }
+
+        if (groups !== "") {
+            if (access !== "") {
+                access += "<br/>";
+            }
+            access += "<span style='font-weight:bold'>Groups: </span>" + groups;
+        }
+
+        return access;
+    }
+
+    this.rolesMap = function(roles) {
+        var rolesMap = new Map();
+
+        var projects = new Map();
+        var spaces = new Map();
+
+        rolesMap["projects"] = projects;
+        rolesMap["space"] = spaces;
+
+        for (i = 0; i < roles.length; i++) {
+            var user = roles[i].user == null ? null : roles[i].user.userId;
+            var group = roles[i].authorizationGroup == null ? null : roles[i].authorizationGroup.code;
+
+            if (roles[i].project !== null) {
+                var value = projects[roles[i].project.code];
+                projects[roles[i].project.code] = SnakemakeTable.appendValue(value, user, group);
+            } else {
+                var value = spaces[roles[i].space.code];
+                spaces[roles[i].space.code] = SnakemakeTable.appendValue(value, user, group);
+            }
+        }
+
+        return rolesMap;
+    }
+
+    this.appendValue = function(value, user, group) {
+        if (value === undefined) {
+            value = new Map();
+            value["users"] = new Array();
+            value["groups"] = new Array();
+        }
+
+        if (user !== null) {
+            value["users"].push(user);
+        } else {
+            value["groups"].push(group);
+        }
+        return value;
+    }
+}
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/snakemake-trigger.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/snakemake-trigger.js
new file mode 100644
index 00000000000..a3756fdfc4a
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/plugins/bbb-hub/snakemake-trigger.js
@@ -0,0 +1,161 @@
+var SnakemakeTrigger = new function() {
+
+    var groups;
+    var propTypeCodeToLabelMap = {};
+    var dataSetPaths;
+    var $formContainerAll;
+    var $formContainerGroups;
+    var $dropdownGroupBy;
+    var $dropdownGroup1;
+    var $dropdownGroup2;
+    var $button;
+    var $model;
+
+    this.paintTriggerContainers = function($container, model, experiment) {
+        $model = model;
+        SnakemakeTrigger.paintFormContainers($container);
+        SnakemakeTrigger.paintProcessAll();
+        SnakemakeTrigger.paintGroupBy(experiment);
+        SnakemakeTrigger.paintGroupValues();
+        groups = SnakemakeTrigger.getGroups(experiment);
+        files = SnakemakeTrigger.getFiles(experiment);
+    }
+
+    this.paintFormContainers = function($container) {
+        var $fieldsetAll = UiComponents.getFieldset("Process all comparisons");
+        var $fieldsetGroups = UiComponents.getFieldset("Pick groups to compare");
+        $formContainerAll = $('<div>').addClass('form-group');
+        $formContainerGroups = $('<div>').addClass('form-group');
+        $fieldsetAll.append($formContainerAll);
+        $fieldsetGroups.append($formContainerGroups);
+        $container.append($fieldsetAll).append($fieldsetGroups);
+    }
+
+    this.paintProcessAll = function() {
+        var $buttonAll = UiComponents.getButton("Start processing", SnakemakeTrigger.startProcessingAll);
+        $formContainerAll.append($buttonAll);
+    }
+
+    this.paintGroupBy = function(experiment) {
+        var groupByOptions = [];
+        if (experiment.samples.length > 0) {
+            var sample = experiment.samples[0];
+            for (var i = 0; i < sample.type.propertyAssignments.length; i++) {
+                var propertyAssignment = sample.type.propertyAssignments[i];
+                groupByOptions.push({
+                    label: propertyAssignment.propertyType.label,
+                    value: propertyAssignment.propertyType.code,
+                });
+                propTypeCodeToLabelMap[propertyAssignment.propertyType.code] = propertyAssignment.propertyType.label;
+            }
+        }
+
+        $dropdownGroupBy = UiComponents.addDropdown("Group by", groupByOptions, $formContainerGroups, SnakemakeTrigger.paintGroupValues);
+    }
+
+    this.paintGroupValues = function(propertyType) {
+        if (propertyType) {
+            var groupOptions = groups[propertyType].map(function(value) { return {
+                label: value,
+                value: value,
+            }});
+        } else {
+            var groupOptions = [];
+        }
+
+        if ($dropdownGroup1) {
+            $dropdownGroup1.remove();
+        }
+        if ($dropdownGroup2) {
+            $dropdownGroup2.remove();
+        }
+        if ($button) {
+            $button.remove();
+        }
+
+        $dropdownGroup1 = UiComponents.addDropdown("Group 1", groupOptions, $formContainerGroups);
+        $dropdownGroup2 = UiComponents.addDropdown("Group 2", groupOptions, $formContainerGroups);
+
+        $button = UiComponents.getButton("Start processing", SnakemakeTrigger.startProcessing);
+        $button.css("margin-top", "20px");
+        $formContainerGroups.append($button);
+    }
+
+    this.getGroups = function(experiment) {
+        var groups = {};
+        for (var i = 0; i < experiment.samples.length; i++) {
+            var sample = experiment.samples[i];
+            // collect groups
+            for (var propertyKey in sample.properties) {
+                if (sample.properties.hasOwnProperty(propertyKey)) {
+                    var propertyValue = sample.properties[propertyKey];
+                    if (groups.hasOwnProperty(propertyKey) == false) {
+                        groups[propertyKey] = [];
+                    }
+                    if (groups[propertyKey].indexOf(propertyValue) == -1) {
+                        groups[propertyKey].push(propertyValue);
+                    }
+                }
+            }
+        }
+        return groups;
+    }
+
+    this.getFiles = function(experiment) {
+        dataSetPaths = [];
+        for (var i = 0; i < experiment.dataSets.length; i++) {
+            var dataSet = experiment.dataSets[i];
+            if (dataSet.type.code == "FASTQ" || dataSet.type.code == "METADATA") {
+                var path = dataSet.physicalData.shareId + "/" + dataSet.physicalData.location;
+                dataSetPaths.push(path);
+            }
+        }
+    }
+
+    this.startProcessingAll = function() {
+        UiComponents.startLoading();
+        var jsonrpc = {
+            "method": "start_processing_all",
+            "params": {
+                "data_set_paths": dataSetPaths
+            }
+        };
+        BBBServerFacade.callCustomASService(jsonrpc, $model, function(result) {
+            UiComponents.stopLoading();
+            if (result.success) {
+              alert("Processing started.");
+            } else {
+              alert("Error: " + result.data);
+            }
+        });
+    }
+
+    this.startProcessing = function() {
+        var groupSelection = {
+            groupBy: propTypeCodeToLabelMap[$dropdownGroupBy.getValue()],
+            group1: $dropdownGroup1.getValue(),
+            group2: $dropdownGroup2.getValue(),
+        }
+        if (!groupSelection.groupBy || !groupSelection.group1 || !groupSelection.group2) {
+            alert("Select both groups first.");
+            return;
+        }
+        UiComponents.startLoading();
+
+        var jsonrpc = {
+            "method": "start_processing",
+            "params": {
+                "group_selection": groupSelection,
+                "data_set_paths": dataSetPaths
+            }
+        };
+        BBBServerFacade.callCustomASService(jsonrpc, $model, function(result) {
+            UiComponents.stopLoading();
+            if (result.success) {
+                alert("Processing started.");
+            } else {
+                alert("Error: " + result.data);
+            }
+        });
+    }
+}
\ No newline at end of file
-- 
GitLab