Repository: incubator-atlas Updated Branches: refs/heads/master 231512447 -> cf2c8bc0c
ATLAS-138 - Combine Input/Output graph ( Anilsg via Suma Shivaprasad) Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/cf2c8bc0 Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/cf2c8bc0 Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/cf2c8bc0 Branch: refs/heads/master Commit: cf2c8bc0c2821b9672761c6cf551783613f003ab Parents: 2315124 Author: Suma Shivaprasad <[email protected]> Authored: Tue Oct 6 11:41:35 2015 +0530 Committer: Suma Shivaprasad <[email protected]> Committed: Tue Oct 6 11:42:15 2015 +0530 ---------------------------------------------------------------------- dashboard/gruntfile.js | 2 +- .../public/modules/details/detailsModule.js | 2 +- .../public/modules/details/views/details.html | 1 + .../public/modules/lineage_io/Find Results | 30 + .../modules/lineage_io/lineage_ioController.js | 750 +++++++++++++++++++ .../modules/lineage_io/lineage_ioModule.js | 21 + .../modules/lineage_io/lineage_ioResource.js | 23 + .../modules/lineage_io/views/lineage_io.html | 30 + release-log.txt | 1 + 9 files changed, 858 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/dashboard/gruntfile.js ---------------------------------------------------------------------- diff --git a/dashboard/gruntfile.js b/dashboard/gruntfile.js index 76ca84a..07a5bf8 100644 --- a/dashboard/gruntfile.js +++ b/dashboard/gruntfile.js @@ -151,7 +151,7 @@ module.exports = function(grunt) { 'hostnames': ['*'], 'routes': { '/': distPath, - '/api': 'http://162.249.6.50:21000/api' + '/api': 'http://162.212.133.190:21000/api' } }] } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/dashboard/public/modules/details/detailsModule.js ---------------------------------------------------------------------- diff --git a/dashboard/public/modules/details/detailsModule.js b/dashboard/public/modules/details/detailsModule.js index 987750a..8bc5b53 100644 --- a/dashboard/public/modules/details/detailsModule.js +++ b/dashboard/public/modules/details/detailsModule.js @@ -18,4 +18,4 @@ 'use strict'; -angular.module('dgc.details', ['dgc.lineage']); +angular.module('dgc.details', ['dgc.lineage', 'dgc.lineage_io']); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/dashboard/public/modules/details/views/details.html ---------------------------------------------------------------------- diff --git a/dashboard/public/modules/details/views/details.html b/dashboard/public/modules/details/views/details.html index c0419cb..bdf1c57 100644 --- a/dashboard/public/modules/details/views/details.html +++ b/dashboard/public/modules/details/views/details.html @@ -44,6 +44,7 @@ <tab data-heading="Schema" data-ng-if="isTable"><ng-include src="'/modules/details/views/schema.html'"/></tab> <tab data-heading="Output" data-ng-if="isTable" data-disable="!tableName" data-select="onActivate('outputs')"><ng-include data-table-type="outputs" src="'/modules/lineage/views/lineage.html'"/></tab> <tab data-heading="Input" data-ng-if="isTable" data-disable="!tableName" data-select="onActivate('inputs')"><ng-include data-table-type="inputs" src="'/modules/lineage/views/lineage.html'"/></tab> + <tab data-heading="Lineage" data-ng-if="isTable" data-disable="!tableName" data-select="onActivate('io')"><ng-include data-table-type="io" src="'/modules/lineage_io/views/lineage_io.html'"/></tab> </tabset> </div> </div> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/dashboard/public/modules/lineage_io/Find Results ---------------------------------------------------------------------- diff --git a/dashboard/public/modules/lineage_io/Find Results b/dashboard/public/modules/lineage_io/Find Results new file mode 100644 index 0000000..ba9fb32 --- /dev/null +++ b/dashboard/public/modules/lineage_io/Find Results @@ -0,0 +1,30 @@ +Searching 16184 files for "LineageController" + +/Users/anilgayakwad/MPR/Anil/incubator-atlas/dashboard/public/modules/lineage/lineageController.js: + 18 'use strict'; + 19 + 20: angular.module('dgc.lineage').controller('LineageController', ['$element', '$scope', '$state', '$stateParams', 'lodash', 'LineageResource', 'd3', 'DetailsResource', '$q', + 21 function($element, $scope, $state, $stateParams, _, LineageResource, d3, DetailsResource, $q) { + 22 var guidsList = []; + +/Users/anilgayakwad/MPR/Anil/incubator-atlas/dashboard/public/modules/lineage/views/lineage.html: + 17 --> + 18 + 19: <div class="lineage-viz" data-ng-controller="LineageController"> + 20 <button type="button" class="btn btn-primary pull-right" ng-click="onReset()"> + 21 Reset + +2 matches across 2 files + + +Searching 16184 files for "lineage.html" + +/Users/anilgayakwad/MPR/Anil/incubator-atlas/dashboard/public/modules/details/views/details.html: + 43 </tab> + 44 <tab data-heading="Schema" data-ng-if="isTable"><ng-include src="'/modules/details/views/schema.html'"/></tab> + 45: <tab data-heading="Output" data-ng-if="isTable" data-disable="!tableName" data-select="onActivate('outputs')"><ng-include data-table-type="outputs" src="'/modules/lineage/views/lineage.html'"/></tab> + 46: <tab data-heading="Input" data-ng-if="isTable" data-disable="!tableName" data-select="onActivate('inputs')"><ng-include data-table-type="inputs" src="'/modules/lineage/views/lineage.html'"/></tab> + 47 + 48 <tab data-heading="Lineage" data-ng-if="isTable" data-disable="!tableName" data-select="onActivate('io')"><ng-include data-table-type="io" src="'/modules/lineage_io/views/lineage_io.html'"/></tab> + +2 matches in 1 file http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/dashboard/public/modules/lineage_io/lineage_ioController.js ---------------------------------------------------------------------- diff --git a/dashboard/public/modules/lineage_io/lineage_ioController.js b/dashboard/public/modules/lineage_io/lineage_ioController.js new file mode 100644 index 0000000..11cefd7 --- /dev/null +++ b/dashboard/public/modules/lineage_io/lineage_ioController.js @@ -0,0 +1,750 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +'use strict'; + +angular.module('dgc.lineage_io').controller('Lineage_ioController', ['$element', '$scope', '$state', '$stateParams', 'lodash', 'Lineage_ioResource', 'd3', 'DetailsResource', '$q', + function($element, $scope, $state, $stateParams, _, LineageResource, d3, DetailsResource, $q) { + var guidsList = []; + + function inVertObj(edgs) { + var newEdgsObj = {}; + + $.each(edgs, function(key, value) { + for (var k = 0; k < value.length; k++) { + newEdgsObj[value[k]] = newEdgsObj[value[k]] || []; + newEdgsObj[value[k]] = [key]; + } + }); + return newEdgsObj; + } + + function getCombinedLineageData(tableData, callRender) { + LineageResource.get({ + tableName: tableData.tableName, + type: 'outputs' + }, function lineageSuccess(response1) { + + LineageResource.get({ + tableName: tableData.tableName, + type: 'inputs' + }, function lineageSuccess(response) { + response.results.values.edges = inVertObj(response.results.values.edges); + + angular.forEach(response.results.values.edges, function(value, key) { + angular.forEach(response1.results.values.edges, function(value1, key1) { + if (key === key1) { + var array1 = value; + angular.forEach(value1, function(value2) { + array1.push(value2); + }); + response.results.values.edges[key] = array1; + response1.results.values.edges[key] = array1; + } + }); + }); + + angular.extend(response.results.values.edges, response1.results.values.edges); + angular.extend(response.results.values.vertices, response1.results.values.vertices); + + if (!_.isEmpty(response.results.values.vertices)) { + loadProcess(response.results.values.edges, response.results.values.vertices) + .then(function(res) { + guidsList = res; + + $scope.lineageData = transformData(response.results); + + if (callRender) { + render(); + } + }); + } + $scope.requested = false; + }); + + }); + + } + + + function loadProcess(edges, vertices) { + + var urlCalls = []; + var deferred = $q.defer(); + for (var guid in edges) { + if (!vertices.hasOwnProperty(guid)) { + urlCalls.push(DetailsResource.get({ + id: guid + }).$promise); + } + + } + $q.all(urlCalls) + .then(function(results) { + deferred.resolve(results); + }); + return deferred.promise; + } + + $scope.type = $element.parent().attr('data-table-type'); + $scope.requested = false; + $scope.height = $element[0].offsetHeight; + $scope.width = $element[0].offsetWidth; + + function render() { + renderGraph($scope.lineageData, { + eleObj: $element, + element: $element[0], + height: $scope.height, + width: $scope.width + }); + $scope.rendered = true; + } + + $scope.onReset = function() { + renderGraph($scope.lineageData, { + eleObj: $element, + element: $element[0], + height: $scope.height, + width: $scope.width + }); + }; + + $scope.$on('render-lineage', function(event, lineageData) { + if (lineageData.type === $scope.type) { + if (!$scope.lineageData) { + if (!$scope.requested) { + if ($scope.type === 'io') { + console.log($scope.type); + getCombinedLineageData(lineageData, true); + } else { + getCombinedLineageData(lineageData, true); + } + $scope.requested = true; + } + } else { + render(); + } + } + }); + + function transformData(metaData) { + var edges = metaData.values.edges, + vertices = metaData.values.vertices, + nodes = {}; + + function getNode(guid) { + var name, type, tip; + if (vertices.hasOwnProperty(guid)) { + name = vertices[guid].values.name; + type = vertices[guid].values.vertexId.values.typeName; + } else { + var loadProcess = getLoadProcessTypes(guid); + if (typeof loadProcess !== "undefined") { + name = loadProcess.name; + type = loadProcess.typeName; + tip = loadProcess.tip; + } else { + name = 'Load Process'; + type = 'Load Process'; + } + } + var vertex = { + guid: guid, + name: name, + type: type, + tip: tip + }; + if (!nodes.hasOwnProperty(guid)) { + nodes[guid] = vertex; + } + return nodes[guid]; + } + + function getLoadProcessTypes(guid) { + var procesRes = []; + angular.forEach(guidsList, function(value) { + if (value.id.id === guid) { + procesRes.name = value.values.name; + procesRes.typeName = value.typeName; + procesRes.tip = value.values.queryText; + } + }); + return procesRes; + } + + function attachParent(edge, node) { + edge.forEach(function eachPoint(childGuid) { + var childNode = getNode(childGuid); + node.children = node.children || []; + node.children.push(childNode); + childNode.parent = node.guid; + }); + } + + /* Loop through all edges and attach them to correct parent */ + for (var guid in edges) { + var edge = edges[guid], + node = getNode(guid); + + /* Attach parent to each endpoint of edge */ + attachParent(edge, node); + } + + var starTingObj = { + name: 'root', + guid: 'root', + children: [] + }; + + angular.forEach(nodes, function(value) { + if (!value.hasOwnProperty('parent')) { + starTingObj.children.push(value); + } + }); + + return starTingObj; + } + + function renderGraph(data, container) { + // ************** Generate the tree diagram ***************** + var element = d3.select(container.element), + widthg = Math.max(container.width, 1100), + //heightg = Math.max(container.height, 500), + heightg = Math.max((window.innerHeight - 380), 500), + + totalNodes = 0, + maxLabelLength = 0, + selectedNode = null, + draggingNode = null, + dragListener = null, + dragStarted = true, + domNode = null, + multiParents = null, + nodes = null, + tooltip = null, + node = null, + i = 0, + duration = 750, + root, + depthwidth = 10; + + + var viewerWidth = widthg - 15, + viewerHeight = heightg; + + var tree = d3.layout.tree().size([viewerHeight, viewerWidth]); + /*.size([viewerHeight, viewerWidth]); nodeSize([100, 200]);*/ + + container.eleObj.find(".graph").html(''); + container.eleObj.find("svg").remove(); + + // define a d3 diagonal projection for use by the node paths later on. + var diagonal = d3.svg.diagonal() + .projection(function(d) { + return [d.y, d.x]; + }); + + // A recursive helper function for performing some setup by walking through all nodes + + function visit(parent, visitFn, childrenFn) { + if (!parent) return; + + visitFn(parent); + + var children = childrenFn(parent); + if (children) { + var count = children.length; + for (var i = 0; i < count; i++) { + visit(children[i], visitFn, childrenFn); + } + } + } + + // Call visit function to establish maxLabelLength + visit(data, function(d) { + totalNodes++; + maxLabelLength = Math.max(d.name.length, maxLabelLength); + + }, function(d) { + return d.children && d.children.length > 0 ? d.children : null; + }); + + + // sort the tree according to the node names + + function sortTree() { + tree.sort(function(a, b) { + return b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1; + }); + } + // Sort the tree initially incase the JSON isn't in a sorted order. + sortTree(); + + // Define the zoom function for the zoomable tree + function zoom() { + svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); + } + + // define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents + var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", zoom); + /* Initialize tooltip */ + tooltip = d3.tip() + .attr('class', 'd3-tip') + .html(function(d) { + return '<pre class="alert alert-success">' + d.name + '</pre>'; + }); + + // define the baseSvg, attaching a class for styling and the zoomListener + var baseSvg = element.append('svg') + .attr("width", viewerWidth) + .attr("height", viewerHeight) + .attr("class", "overlay") + .call(zoomListener) + .on("dblclick.zoom", function() { + return null; + }) + .call(tooltip); + + + // Define the drag listeners for drag/drop behaviour of nodes. + dragListener = d3.behavior.drag() + .on("dragstart", function(d) { + if (d === root) { + return; + } + dragStarted = true; + nodes = tree.nodes(d); + d3.event.sourceEvent.stopPropagation(); + // it's important that we suppress the mouseover event on the node being dragged. Otherwise it will absorb the mouseover event and the underlying node will not detect it d3.select(this).attr('pointer-events', 'none'); + }) + .on("dragend", function(d) { + if (d === root) { + return; + } + domNode = this; + if (selectedNode) { + // now remove the element from the parent, and insert it into the new elements children + var index = draggingNode.parent.children.indexOf(draggingNode); + if (index > -1) { + draggingNode.parent.children.splice(index, 1); + } + if (typeof selectedNode.children !== 'undefined' || typeof selectedNode._children !== 'undefined') { + if (typeof selectedNode.children !== 'undefined') { + selectedNode.children.push(draggingNode); + } else { + selectedNode._children.push(draggingNode); + } + } else { + selectedNode.children = []; + selectedNode.children.push(draggingNode); + } + // Make sure that the node being added to is expanded so user can see added node is correctly moved + expand(selectedNode); + sortTree(); + endDrag(); + } else { + endDrag(); + } + }); + + function endDrag() { + selectedNode = null; + d3.selectAll('.ghostCircle').attr('class', 'ghostCircle'); + d3.select(domNode).attr('class', 'node'); + // now restore the mouseover event or we won't be able to drag a 2nd time + d3.select(domNode).select('.ghostCircle').attr('pointer-events', ''); + updateTempConnector(); + if (draggingNode !== null) { + update(root); + centerNode(draggingNode); + draggingNode = null; + } + } + + + function expand(d) { + if (d._children) { + d.children = d._children; + d.children.forEach(expand); + d._children = null; + } + } + + // Function to update the temporary connector indicating dragging affiliation + var updateTempConnector = function() { + var data = []; + if (draggingNode !== null && selectedNode !== null) { + // have to flip the source coordinates since we did this for the existing connectors on the original tree + data = [{ + source: { + x: selectedNode.y0, + y: selectedNode.x0 + }, + target: { + x: draggingNode.y0, + y: draggingNode.x0 + } + }]; + } + var link = svgGroup.selectAll(".templink").data(data); + + link.enter().append("path") + .attr("class", "templink") + .attr("d", d3.svg.diagonal()) + .attr('pointer-events', 'none'); + + link.attr("d", d3.svg.diagonal()); + + link.exit().remove(); + }; + + // Function to center node when clicked/dropped so node doesn't get lost when collapsing/moving with large amount of children. + + function centerNode(source) { + var scale = (depthwidth === 10) ? zoomListener.scale() : 0.4; + var x = -source.y0; + var y = -source.x0; + x = x * scale + 150; + y = y * scale + viewerHeight / 2; + d3.select('g').transition() + .duration(duration) + .attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")"); + zoomListener.scale(scale); + zoomListener.translate([x, y]); + } + + // Toggle children function + + // function toggleChildren(d) { + // if (d.children) { + // d._children = d.children; + // d.children = null; + // } else if (d._children) { + // d.children = d._children; + // d._children = null; + // } + // return d; + // } + + // Toggle children on click. + + // function click(d) { + // if (d3.event.defaultPrevented) return; // click suppressed + // d = toggleChildren(d); + // update(d); + // //centerNode(d); + // } + + //arrow + baseSvg.append("svg:defs") + .append("svg:marker") + .attr("id", "arrow") + .attr("viewBox", "0 0 10 10") + .attr("refX", 22) + .attr("refY", 5) + .attr("markerUnits", "strokeWidth") + .attr("markerWidth", 6) + .attr("markerHeight", 9) + .attr("orient", "auto") + .append("svg:path") + .attr("d", "M 0 0 L 10 5 L 0 10 z"); + + //marker for input type graph + baseSvg.append("svg:defs") + .append("svg:marker") + .attr("id", "input-arrow") + .attr("viewBox", "0 0 10 10") + .attr("refX", -15) + .attr("refY", 5) + .attr("markerUnits", "strokeWidth") + .attr("markerWidth", 6) + .attr("markerHeight", 9) + .attr("orient", "auto") + .append("svg:path") + .attr("d", "M -2 5 L 8 0 L 8 10 z"); + + function update(source) { + // Compute the new height, function counts total children of root node and sets tree height accordingly. + // This prevents the layout looking squashed when new nodes are made visible or looking sparse when nodes are removed + // This makes the layout more consistent. + var levelWidth = [1]; + var childCount = function(level, n) { + + if (n.children && n.children.length > 0) { + if (levelWidth.length <= level + 1) levelWidth.push(0); + + levelWidth[level + 1] += n.children.length; + n.children.forEach(function(d) { + childCount(level + 1, d); + }); + } + }; + childCount(0, root); + tree = tree.nodeSize([50, 100]); + + // Compute the new tree layout. + var nodes = tree.nodes(root).reverse(); + + nodes = _.uniq(nodes, 'guid'); + + _.each(nodes, function(o, i) { + var itemsOfTheSameDepth = _.where(nodes, { + depth: o.depth + }); + var indexOfCurrent = _.indexOf(itemsOfTheSameDepth, o); + var interval = viewerHeight / itemsOfTheSameDepth.length; + nodes[i].x = interval / 2 + (interval * indexOfCurrent); + }); + + var links = tree.links(nodes); + + _.each(links, function(o, i) { + //links[i].target = _.find(nodes, {guid: o.target.id}); + links[i].target = _.find(nodes, { + guid: o.target.guid + }); + }); + + // Set widths between levels based on maxLabelLength. + nodes.forEach(function(d) { + if (levelWidth.length > 1 && depthwidth === 10) { + for (var o = 0; o < levelWidth.length; o++) { + if (levelWidth[o] > 4) { + depthwidth = 70; + break; + } + } + } + var maxLebal = maxLabelLength; + if (depthwidth === 10) { + maxLebal = 20; + } + d.y = (d.depth * (maxLebal * depthwidth)); + }); + + // Update the nodes⦠+ node = svgGroup.selectAll("g.node") + .data(nodes, function(d) { + return d.id || (d.id = ++i); + }); + + // Enter any new nodes at the parent's previous position. + var nodeEnter = node.enter().append("g") + .call(dragListener) + .attr('class', function(d) { + if (d.guid === "root") { + return "hide"; + } else { + return ""; + } + }) + .classed('node', true) + .attr("transform", function() { + return "translate(" + source.y0 + "," + source.x0 + ")"; + }); + //.on('click', click); + + nodeEnter.append("image") + .attr("class", "nodeImage") + .attr("xlink:href", function(d) { + return d.type === 'Table' ? '../img/tableicon.png' : '../img/process.png'; + }) + .on('mouseover', function(d) { + if (d.type === 'LoadProcess' || 'Table') { + tooltip.show(d); + } + }) + .on('dblclick', function(d) { + $state.go("details", { + id: d.guid + }); + }) + .on('mouseout', function(d) { + if (d.type === 'LoadProcess' || 'Table') { + tooltip.hide(d); + } + }) + .attr("x", "-18px") + .attr("y", "-18px") + .attr("width", "34px") + .attr("height", "34px"); + + nodeEnter.append("text") + .attr("x", function(d) { + return d.children || d._children ? -10 : 10; + }) + .attr("dx", function(d) { + return d.children ? 50 : -50; + }) + .attr("dy", -24) + .attr('class', 'place-label') + .attr("text-anchor", function(d) { + return d.children || d._children ? "end" : "start"; + }) + .text(function(d) { + var nameDis = (d.name.length > 15) ? d.name.substring(0, 15) + "..." : d.name; + $(this).attr('title', d.name); + return nameDis; + }) + .style("fill-opacity", 0); + + // Update the text to reflect whether node has children or not. + node.select('text') + .attr("x", function(d) { + return d.children || d._children ? -10 : 10; + }) + .attr("text-anchor", function(d) { + return d.children || d._children ? "end" : "start"; + }) + .text(function(d) { + var nameDis = (d.name.length > 15) ? d.name.substring(0, 15) + "..." : d.name; + $(this).attr('title', d.name); + return nameDis; + }); + + // Change the circle fill depending on whether it has children and is collapsed + // Change the circle fill depending on whether it has children and is collapsed + node.select("image.nodeImage") + .attr("r", 4.5) + .attr("xlink:href", function(d) { + if (d._children) { + return d.type === 'Table' ? '../img/tableicon1.png' : '../img/process1.png'; + } + return d.type === 'Table' ? '../img/tableicon.png' : '../img/process.png'; + }); + + + // Transition nodes to their new position. + var nodeUpdate = node.transition() + .duration(duration) + .attr("transform", function(d) { + return "translate(" + d.y + "," + d.x + ")"; + }); + + // Fade the text in + nodeUpdate.select("text") + .style("fill-opacity", 1); + + // Transition exiting nodes to the parent's new position. + var nodeExit = node.exit().transition() + .duration(duration) + .attr("transform", function() { + return "translate(" + source.y + "," + source.x + ")"; + }) + .remove(); + + nodeExit.select("circle") + .attr("r", 0); + + nodeExit.select("text") + .style("fill-opacity", 0); + + // Update the links⦠+ var link = svgGroup.selectAll("path.link") + .data(links); + // .data(links, function(d) { + // return d.target.id; + // }); + + // Enter any new links at the parent's previous position. + link.enter().insert("path", "g") + .attr('class', function(d) { + if (d.source.guid === "root") { + return "hide"; + } else { + return ""; + } + }) + .classed('link', true) + .style('stroke', 'green') + .attr("d", function() { + var o = { + x: source.x0, + y: source.y0 + }; + return diagonal({ + source: o, + target: o + }); + }); + + // Transition links to their new position. + link.transition() + .duration(duration) + .attr("d", diagonal); + + // Transition exiting nodes to the parent's new position. + link.exit().transition() + .duration(duration) + .attr("d", function() { + var o = { + x: source.x, + y: source.y + }; + return diagonal({ + source: o, + target: o + }); + }) + .remove(); + + // Stash the old positions for transition. + nodes.forEach(function(d) { + d.x0 = d.x; + d.y0 = d.y; + }); + + if ($scope.type === 'inputs') { + link.attr("marker-start", "url(#input-arrow)"); //if input + } else { + link.attr("marker-end", "url(#arrow)"); //if input + } + } + + // Append a group which holds all nodes and which the zoom Listener can act upon. + var svgGroup = baseSvg.append("g") + .attr("transform", "translate(0,0)"); + + // Define the root + root = data; + root.x0 = viewerWidth / 2; + root.y0 = viewerHeight / 2; + + // Layout the tree initially and center on the root node. + update(root); + centerNode(root); + + var couplingParent1 = tree.nodes(root).filter(function(d) { + return d.name === 'cluster'; + })[0]; + var couplingChild1 = tree.nodes(root).filter(function(d) { + return d.name === 'JSONConverter'; + })[0]; + + multiParents = [{ + parent: couplingParent1, + child: couplingChild1 + }]; + + multiParents.forEach(function() { + svgGroup.append("path", "g"); + }); + } + + } +]); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/dashboard/public/modules/lineage_io/lineage_ioModule.js ---------------------------------------------------------------------- diff --git a/dashboard/public/modules/lineage_io/lineage_ioModule.js b/dashboard/public/modules/lineage_io/lineage_ioModule.js new file mode 100644 index 0000000..a4b8ef6 --- /dev/null +++ b/dashboard/public/modules/lineage_io/lineage_ioModule.js @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +'use strict'; + +angular.module('dgc.lineage_io', []); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/dashboard/public/modules/lineage_io/lineage_ioResource.js ---------------------------------------------------------------------- diff --git a/dashboard/public/modules/lineage_io/lineage_ioResource.js b/dashboard/public/modules/lineage_io/lineage_ioResource.js new file mode 100644 index 0000000..ba8f4b7 --- /dev/null +++ b/dashboard/public/modules/lineage_io/lineage_ioResource.js @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +'use strict'; + +angular.module('dgc.lineage_io').factory('Lineage_ioResource', ['$resource', function($resource) { + return $resource('/api/atlas/lineage/hive/table/:tableName/:type/graph', {}); +}]); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/dashboard/public/modules/lineage_io/views/lineage_io.html ---------------------------------------------------------------------- diff --git a/dashboard/public/modules/lineage_io/views/lineage_io.html b/dashboard/public/modules/lineage_io/views/lineage_io.html new file mode 100644 index 0000000..e7ac084 --- /dev/null +++ b/dashboard/public/modules/lineage_io/views/lineage_io.html @@ -0,0 +1,30 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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. + --> + +<div class="lineage-viz" data-ng-controller="Lineage_ioController"> + <button type="button" class="btn btn-primary pull-right" ng-click="onReset()"> + Reset + </button> + <div class="graph"> + <h4 data-ng-if="!requested && !lineageData">No lineage data found</h4> + <i data-ng-if="requested" class="fa fa-spinner fa-spin fa-5x"></i> + <svg > + <g/> + </svg> + </div> +</div> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/cf2c8bc0/release-log.txt ---------------------------------------------------------------------- diff --git a/release-log.txt b/release-log.txt index 503afd5..4fa8339 100644 --- a/release-log.txt +++ b/release-log.txt @@ -9,6 +9,7 @@ ATLAS-54 Rename configs in hive hook (shwethags) ATLAS-3 Mixed Index creation fails with Date types (suma.shivaprasad via shwethags) ALL CHANGES: +ATLAS-138 Combine Input/Output graph ( Anilsg via Suma Shivaprasad ) ATLAS-128 DSL - Add support for comparisions on list type (suma.shivaprasad via shwethags) ATLAS-168 Atlas UI - Max column in hive 4 (darshankumar89 via shwethags) ATLAS-155 Images do not show up on the dashboard (darshankumar89 via shwethags)
