You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by su...@apache.org on 2015/10/06 08:20:57 UTC

incubator-atlas git commit: ATLAS-204 Lineage I/O Lineage Enhancement (Anilsg via Suma Shivaprasad)

Repository: incubator-atlas
Updated Branches:
  refs/heads/master cf2c8bc0c -> ebd6d9e3c


ATLAS-204 Lineage I/O Lineage Enhancement (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/ebd6d9e3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/ebd6d9e3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/ebd6d9e3

Branch: refs/heads/master
Commit: ebd6d9e3c754535d834cf262db2968d07547272a
Parents: cf2c8bc
Author: Suma Shivaprasad <su...@gmail.com>
Authored: Tue Oct 6 11:49:47 2015 +0530
Committer: Suma Shivaprasad <su...@gmail.com>
Committed: Tue Oct 6 11:49:47 2015 +0530

----------------------------------------------------------------------
 .../public/modules/details/detailsController.js |   6 +-
 .../public/modules/details/detailsModule.js     |   2 +-
 .../public/modules/details/views/details.html   |   5 +-
 .../modules/lineage/lineage_ioController.js     | 749 ++++++++++++++++++
 .../modules/lineage/views/lineage_io.html       |  30 +
 .../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 +
 11 files changed, 787 insertions(+), 860 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/ebd6d9e3/dashboard/public/modules/details/detailsController.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/details/detailsController.js b/dashboard/public/modules/details/detailsController.js
index 7bfed9b..c469c37 100644
--- a/dashboard/public/modules/details/detailsController.js
+++ b/dashboard/public/modules/details/detailsController.js
@@ -15,7 +15,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 'use strict';
 
 angular.module('dgc.details').controller('DetailsController', ['$window', '$scope', '$stateParams', 'DetailsResource',
@@ -31,10 +30,11 @@ angular.module('dgc.details').controller('DetailsController', ['$window', '$scop
             $scope.schemas = data;
             $scope.tableName = data.values.name;
             $scope.isTable = data.typeName === 'Table';
+            $scope.onActivate('io');
         });
 
         $scope.isNumber = angular.isNumber;
-        
+
         $scope.isString = angular.isString;
 
         $scope.onActivate = function tabActivate(tabname) {
@@ -49,4 +49,4 @@ angular.module('dgc.details').controller('DetailsController', ['$window', '$scop
         };
 
     }
-]);
+]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/ebd6d9e3/dashboard/public/modules/details/detailsModule.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/details/detailsModule.js b/dashboard/public/modules/details/detailsModule.js
index 8bc5b53..987750a 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', 'dgc.lineage_io']);
+angular.module('dgc.details', ['dgc.lineage']);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/ebd6d9e3/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 bdf1c57..26d81ec 100644
--- a/dashboard/public/modules/details/views/details.html
+++ b/dashboard/public/modules/details/views/details.html
@@ -23,6 +23,7 @@
     <div role="tabpanel" class="col-lg-12">
         <h2>Name: {{details.values.name}}</h2>
         <h4>Description: {{details.values.description}}</h4>
+        <h4>Lineage: <ng-include data-table-type="io" src="'/modules/lineage/views/lineage_io.html'"/></h4> 
         <tabset>
             <tab heading="Details">
                 <table class="table table-bordered">
@@ -42,9 +43,9 @@
                 </table>
             </tab>
             <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="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>
+            <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/ebd6d9e3/dashboard/public/modules/lineage/lineage_ioController.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/lineage/lineage_ioController.js b/dashboard/public/modules/lineage/lineage_ioController.js
new file mode 100644
index 0000000..0a49ed0
--- /dev/null
+++ b/dashboard/public/modules/lineage/lineage_ioController.js
@@ -0,0 +1,749 @@
+/*
+ * 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').controller('Lineage_ioController', ['$element', '$scope', '$state', '$stateParams', 'lodash', 'LineageResource', '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();
+                                }
+                            }); 
+                    } else {
+                        $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 = true;
+        $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);
+                        } 
+                    }
+                } 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((window.innerHeight - 400), 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 - 130;
+                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);
+            $scope.requested = false;
+            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/ebd6d9e3/dashboard/public/modules/lineage/views/lineage_io.html
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/lineage/views/lineage_io.html b/dashboard/public/modules/lineage/views/lineage_io.html
new file mode 100644
index 0000000..377f273
--- /dev/null
+++ b/dashboard/public/modules/lineage/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 table-bordered" 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/ebd6d9e3/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
deleted file mode 100644
index ba9fb32..0000000
--- a/dashboard/public/modules/lineage_io/Find Results	
+++ /dev/null
@@ -1,30 +0,0 @@
-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/ebd6d9e3/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
deleted file mode 100644
index 11cefd7..0000000
--- a/dashboard/public/modules/lineage_io/lineage_ioController.js
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * 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/ebd6d9e3/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
deleted file mode 100644
index a4b8ef6..0000000
--- a/dashboard/public/modules/lineage_io/lineage_ioModule.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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/ebd6d9e3/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
deleted file mode 100644
index ba8f4b7..0000000
--- a/dashboard/public/modules/lineage_io/lineage_ioResource.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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/ebd6d9e3/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
deleted file mode 100644
index e7ac084..0000000
--- a/dashboard/public/modules/lineage_io/views/lineage_io.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-  ~ 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/ebd6d9e3/release-log.txt
----------------------------------------------------------------------
diff --git a/release-log.txt b/release-log.txt
index 4fa8339..db37eba 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-204 Lineage I/O Lineage Enhancement ( Anilsg via Suma Shivaprasad )
 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)