diff --git a/meteos_ui/content/machine_learning/overview/__init__.py b/meteos_ui/content/machine_learning/overview/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/meteos_ui/content/machine_learning/overview/panel.py b/meteos_ui/content/machine_learning/overview/panel.py new file mode 100644 index 0000000..7f54a19 --- /dev/null +++ b/meteos_ui/content/machine_learning/overview/panel.py @@ -0,0 +1,23 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.utils.translation import ugettext_lazy as _ +import horizon + +# This panel will be loaded from horizon, because specified in enabled file. +# To register REST api, import below here. +from meteos_ui.api import rest_api # noqa + + +class Overview(horizon.Panel): + name = _("Overview") + slug = "machine_learning.overview" diff --git a/meteos_ui/content/machine_learning/overview/tests.py b/meteos_ui/content/machine_learning/overview/tests.py new file mode 100644 index 0000000..172bc42 --- /dev/null +++ b/meteos_ui/content/machine_learning/overview/tests.py @@ -0,0 +1,19 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from openstack_dashboard.test import helpers as test + + +class OverviewTests(test.TestCase): + # Unit tests for Overview. + def test_me(self): + self.assertTrue(1 + 1 == 2) diff --git a/meteos_ui/content/machine_learning/overview/urls.py b/meteos_ui/content/machine_learning/overview/urls.py new file mode 100644 index 0000000..b31efda --- /dev/null +++ b/meteos_ui/content/machine_learning/overview/urls.py @@ -0,0 +1,20 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.conf.urls import url +from django.utils.translation import ugettext_lazy as _ +from horizon.browsers import views + +title = _("Overview") +urlpatterns = [ + url('', views.AngularIndexView.as_view(title=title), name='index'), +] diff --git a/meteos_ui/enabled/_1720_machine_learning_overview_panel.py b/meteos_ui/enabled/_1720_machine_learning_overview_panel.py new file mode 100644 index 0000000..9854858 --- /dev/null +++ b/meteos_ui/enabled/_1720_machine_learning_overview_panel.py @@ -0,0 +1,21 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# The slug of the panel to be added to HORIZON_CONFIG. Required. +PANEL = 'machine_learning.overview' +# The slug of the panel group the PANEL is associated with. +PANEL_GROUP = 'machine_learning' +# The slug of the dashboard the PANEL associated with. Required. +PANEL_DASHBOARD = 'project' + +# Python panel class of the PANEL to be added. +ADD_PANEL = 'meteos_ui.content.machine_learning.overview.panel.Overview' diff --git a/meteos_ui/enabled/_1720_machine_learning_templates_panel.py b/meteos_ui/enabled/_1730_machine_learning_templates_panel.py similarity index 100% rename from meteos_ui/enabled/_1720_machine_learning_templates_panel.py rename to meteos_ui/enabled/_1730_machine_learning_templates_panel.py diff --git a/meteos_ui/enabled/_1730_machine_learning_experiments_panel.py b/meteos_ui/enabled/_1740_machine_learning_experiments_panel.py similarity index 100% rename from meteos_ui/enabled/_1730_machine_learning_experiments_panel.py rename to meteos_ui/enabled/_1740_machine_learning_experiments_panel.py diff --git a/meteos_ui/enabled/_1740_machine_learning_datasets_panel.py b/meteos_ui/enabled/_1750_machine_learning_datasets_panel.py similarity index 100% rename from meteos_ui/enabled/_1740_machine_learning_datasets_panel.py rename to meteos_ui/enabled/_1750_machine_learning_datasets_panel.py diff --git a/meteos_ui/enabled/_1750_machine_learning_models_panel.py b/meteos_ui/enabled/_1760_machine_learning_models_panel.py similarity index 100% rename from meteos_ui/enabled/_1750_machine_learning_models_panel.py rename to meteos_ui/enabled/_1760_machine_learning_models_panel.py diff --git a/meteos_ui/enabled/_1760_machine_learning_model_evaluations_panel.py b/meteos_ui/enabled/_1770_machine_learning_model_evaluations_panel.py similarity index 100% rename from meteos_ui/enabled/_1760_machine_learning_model_evaluations_panel.py rename to meteos_ui/enabled/_1770_machine_learning_model_evaluations_panel.py diff --git a/meteos_ui/enabled/_1770_machine_learning_learnings_panel.py b/meteos_ui/enabled/_1780_machine_learning_learnings_panel.py similarity index 100% rename from meteos_ui/enabled/_1770_machine_learning_learnings_panel.py rename to meteos_ui/enabled/_1780_machine_learning_learnings_panel.py diff --git a/meteos_ui/static/dashboard/machine_learning/machine_learning.module.js b/meteos_ui/static/dashboard/machine_learning/machine_learning.module.js index 477f2e0..b5884c1 100644 --- a/meteos_ui/static/dashboard/machine_learning/machine_learning.module.js +++ b/meteos_ui/static/dashboard/machine_learning/machine_learning.module.js @@ -28,7 +28,8 @@ 'horizon.dashboard.machine_learning.datasets', 'horizon.dashboard.machine_learning.models', 'horizon.dashboard.machine_learning.model_evaluations', - 'horizon.dashboard.machine_learning.learnings' + 'horizon.dashboard.machine_learning.learnings', + 'horizon.dashboard.machine_learning.overview' ]) .config(config) diff --git a/meteos_ui/static/dashboard/machine_learning/overview/details.module.js b/meteos_ui/static/dashboard/machine_learning/overview/details.module.js new file mode 100644 index 0000000..03c2617 --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/details.module.js @@ -0,0 +1,215 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +(function () { + 'use strict'; + + angular + .module('horizon.framework.widgets') + .controller('OverviewController', OverviewController); + + OverviewController.$inject = [ + '$q', + '$scope', + 'horizon.dashboard.machine_learning.overview.basePath', + 'horizon.app.core.openstack-service-api.meteos' + ]; + + function OverviewController($q, $scope, basePath, meteos) { + + var topologyNodes = []; + var topologyLinks = []; + + var templates = meteos.getTemplates().then(function(response){ + response.data.items.map(addIcon, 'template'); + }); + + var experiments = meteos.getExperiments().then(function(response){ + response.data.items.map(addIcon, 'experiment'); + }); + + var datasets = meteos.getDatasets().then(function(response){ + response.data.items.map(addIcon, 'dataset'); + }); + + var models = meteos.getModels().then(function(response){ + response.data.items.map(addIcon, 'model'); + }); + + var evaluations = meteos.getModelEvaluations().then(function(response){ + response.data.items.map(addIcon, 'evaluation'); + }); + + var learnings = meteos.getLearnings().then(function(response){ + response.data.items.map(addIcon, 'learning'); + }); + + function addIcon(item){ + + item.icon = "meteos-" + this + ".svg"; + topologyNodes.push(item); + } + + var promiseAll = $q.all([templates, + experiments, + datasets, + models, + evaluations, + learnings]); + + promiseAll.then(drawTopology); + + function drawTopology() { + + angular.forEach(topologyNodes,function(record, index){ + if("template_id" in record){ + createIndex(index, record.template_id); + } + if("experiment_id" in record){ + createIndex(index, record.experiment_id); + } + if("model_id" in record){ + createIndex(index, record.model_id); + } + if("source_dataset_url" in record){ + if ( record.source_dataset_url.indexOf('internal') != -1) { + createIndex(index, record.source_dataset_url.split('//')[1]); + } + } + }); + + function createIndex(source_index, id){ + angular.forEach(topologyNodes,function(record,i){ + if(record.id == id){ + topologyLinks.push({"source": source_index, "target": i}) + } + }); + } + + var topology = { + "nodes":topologyNodes, + "links":topologyLinks} + + var width = 900, + height = 500; + + var force = d3.layout.force() + .charge(-2500) + .linkDistance(100) + .size([width, height]) + .nodes(topology.nodes) + .links(topology.links) + .start(); + + var zoom = d3.behavior.zoom() + .scaleExtent([1, 10]) + .on("zoom", zoomed); + + var svg = d3.select("#meteosTopologyCanvas").append("svg") + .attr("width", width) + .attr("height", height) + .append("g") + .call(zoom); + + var rect = svg.append("rect") + .attr("width", width) + .attr("height", height) + .style("fill", "none"); + + var container = svg.append("g"); + + var link = container.append("g") + .attr("class", "links") + .selectAll(".link") + .data(topology.links) + .enter().append("line") + .attr("class", "link"); + + var node = container.append("g") + .attr("class", "nodes") + .selectAll(".node") + .data(topology.nodes) + .enter().append("g") + .attr("class", "node") + .attr("cx", function(d) { return d.x; }) + .attr("cy", function(d) { return d.y; }) + .call(force.drag); + + var div = d3.select("#meteosMenu").append("div") + .style("width", "360px") + .style("height", "180px") + .style("background", "#d6dadf") + .style("position", "absolute") + .style("opacity", 0) + .style("text-overflow", "ellipsis") + .style("display", "inline-block") + .style("overflow", "hidden") + .style("border-radius", "8px") + .style("padding", "5px") + .style("box-shadow", "0px 0px 3px 3px #d6dadf"); + + node.append("image") + .attr("xlink:href", function(d) {return basePath + "/images/" + d.icon}) + .attr("x", -35) + .attr("y", -35) + .attr("width", 70) + .attr("height", 70); + + node.on("mouseover", function(d) { + div.transition() + .style("opacity", .9); + div.html(createMenu(d)) + .style("left", (d3.event.pageX - 200) + "px") + .style("top", (d3.event.pageY - 10) + "px"); + }); + + node.on("mouseout", function(d) { + div.transition() + .duration(600) + .style("opacity", 0); + }); + + node.append("text") + .attr("dx", 50) + .attr("dy", ".60em") + .text(function(d) { return d.name }); + + force.on("tick", function() { + link.attr("x1", function(d) { return d.source.x; }) + .attr("y1", function(d) { return d.source.y; }) + .attr("x2", function(d) { return d.target.x; }) + .attr("y2", function(d) { return d.target.y; }); + node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); + }); + + var hiddenFields=['x', 'y', 'px', 'py', + 'index','head','fixed','icon', 'stdout', + 'weight', 'links', 'name', 'created_at']; + + function createMenu(d){ + var form = ""; + angular.forEach(d, function(v, k){ + + if(hiddenFields.indexOf(k) == -1){ + form += "" + k + " : " + v + ""; + } + }); + return form; + } + + function zoomed() { + container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); + } + } + } +})(); diff --git a/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-dataset.svg b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-dataset.svg new file mode 100644 index 0000000..8443853 --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-dataset.svg @@ -0,0 +1,36 @@ + + + diff --git a/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-evaluation.svg b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-evaluation.svg new file mode 100644 index 0000000..cb76cd7 --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-evaluation.svg @@ -0,0 +1,279 @@ + + + diff --git a/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-experiment.svg b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-experiment.svg new file mode 100644 index 0000000..869c946 --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-experiment.svg @@ -0,0 +1,39 @@ + + + diff --git a/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-learning.svg b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-learning.svg new file mode 100644 index 0000000..2518546 --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-learning.svg @@ -0,0 +1,27 @@ + + + diff --git a/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-model.svg b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-model.svg new file mode 100644 index 0000000..cbc2f7b --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-model.svg @@ -0,0 +1,31 @@ + + + diff --git a/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-template.svg b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-template.svg new file mode 100644 index 0000000..93167a7 --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/images/meteos-template.svg @@ -0,0 +1,27 @@ + + + diff --git a/meteos_ui/static/dashboard/machine_learning/overview/overview.module.js b/meteos_ui/static/dashboard/machine_learning/overview/overview.module.js new file mode 100644 index 0000000..7737600 --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/overview.module.js @@ -0,0 +1,52 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +(function() { + 'use strict'; + + /** + * @ngdoc overview + * @name horizon.dashboard.machine_learning.overview + * @ngModule + * @description + * Provides all the services and widgets require to display the experiment + * panel + */ + angular + .module('horizon.dashboard.machine_learning.overview', [ + 'ngRoute']) + .config(config); + + config.$inject = [ + '$provide', + '$windowProvider', + '$routeProvider' + ]; + + /** + * @name config + * @param {Object} $provide + * @param {Object} $windowProvider + * @param {Object} $routeProvider + * @description Routes used by this module. + * @returns {undefined} Returns nothing + */ + function config($provide, $windowProvider, $routeProvider) { + var path = $windowProvider.$get().STATIC_URL + 'dashboard/machine_learning/overview/'; + $provide.constant('horizon.dashboard.machine_learning.overview.basePath', path); + $routeProvider.when('/project/machine_learning/overview', { + templateUrl: path + 'panel.html' + }); + } +})(); diff --git a/meteos_ui/static/dashboard/machine_learning/overview/overview.module.spec.js b/meteos_ui/static/dashboard/machine_learning/overview/overview.module.spec.js new file mode 100644 index 0000000..86fb5dc --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/overview.module.spec.js @@ -0,0 +1,23 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +(function() { + 'use strict'; + + describe('horizon.dashboard.machine_learning.overview', function() { + it('should exist', function() { + expect(angular.module('horizon.dashboard.machine_learning.overview')).toBeDefined(); + }); + }); + +})(); diff --git a/meteos_ui/static/dashboard/machine_learning/overview/panel.html b/meteos_ui/static/dashboard/machine_learning/overview/panel.html new file mode 100644 index 0000000..295d0e9 --- /dev/null +++ b/meteos_ui/static/dashboard/machine_learning/overview/panel.html @@ -0,0 +1,8 @@ +