Commit a05107a0 by Hemanth Yamijala

ATLAS-658 Improve Lineage with Backbone porting (kevalbhatt18 via yhemanth)

parent aaf2971a
......@@ -691,7 +691,7 @@ ul[data-id=branchList] li {
max-width: 140px;
}
.appndList {
.appendList {
max-height: 200px;
overflow: auto;
max-width: 140px;
......@@ -720,7 +720,54 @@ text {
}
.edgePath path {
stroke: #333;
stroke-width: 1.5px;
stroke: #000;
/* stroke-width: 1.5px;*/
}
.node .label {
fill: #868686;
}
.branchChildDiv {
padding-left: 15px;
}
.branchListParentInput .form-control {
border-right: none;
box-shadow: none;
border-radius: 4px;
}
.branchListParentInput .input-group-addon {
background-color: #fff;
}
.branchListParentInput {
padding-bottom: 18px;
display: list-item;
}
.backButton {
display: block;
width: 35px;
height: 35px;
line-height: 46px;
text-align: center;
background-color: #323544;
color: #fff;
position: fixed;
left: 5px;
top: 90px;
font-size: 11px;
}
.backButton:hover,
.backButton:active {
color: #fff;
}
.zoomButtonGroup {
position: absolute;
top: 4px;
right: 5px;
}
......@@ -32,9 +32,7 @@ define(['require',
* @constructs
*/
initialize: function() {
},
initialize: function() {},
bindErrorEvents: function() {
this.bind("error", Utils.defaultErrorHandler);
},
......@@ -45,9 +43,7 @@ define(['require',
firstPage: 0,
pageSize: Globals.settings.PAGE_SIZE
},
mode: 'client',
/**
* override the parseRecords of PageableCollection for our use
*/
......@@ -57,7 +53,7 @@ define(['require',
query: resp.query,
queryType: resp.queryType,
requestId: resp.requestId
}
};
try {
if (!this.modelAttrName) {
throw new Error("this.modelAttrName not defined for " + this);
......@@ -119,18 +115,14 @@ define(['require',
'name': k
}, defaults, v);
});
return retCols;
},
nonCrudOperation: function(url, requestMethod, options) {
return Backbone.sync.call(this, null, this, _.extend({
url: url,
type: requestMethod
}, options));
}
});
return BaseCollection;
});
......@@ -45,6 +45,5 @@ define(['require',
tableCols: {}
}
);
return VCommonList;
});
......@@ -39,8 +39,8 @@ define(['require',
}
var arr = [];
resp[this.modelAttrName].rows.forEach(function(d) {
arr.push(d)
})
arr.push(d);
});
return arr;
} catch (e) {
console.log(e);
......
......@@ -41,8 +41,8 @@ define(['require',
resp[this.modelAttrName].forEach(function(d) {
arr.push({
tags: d
})
})
});
});
return arr;
} catch (e) {
console.log(e);
......
......@@ -55,7 +55,7 @@ define(['require',
Handlebars.registerHelper('toHumanDate', function(val) {
if (!val) return "";
return val //localization.formatDate(val, 'f');
return val;//localization.formatDate(val, 'f');
});
Handlebars.registerHelper('tt', function(str) {
//return localization.tt(str);
......
......@@ -15,23 +15,23 @@
* limitations under the License.
-->
<div class="clearfix">
<div class="form-group pull-right no-margin">
<div data-id="control" class="pull-right"></div>
<label class="select pull-right">
<select data-id="pageSize" class="form-control">
<option selected>10</option>
<option>25</option>
<option>50</option>
<option>100</option>
</select>
</label>
</div>
<div class="form-group pull-right no-margin">
<div data-id="control" class="pull-right"></div>
<label class="select pull-right">
<select data-id="pageSize" class="form-control">
<option selected>10</option>
<option>25</option>
<option>50</option>
<option>100</option>
</select>
</label>
</div>
</div>
<div class="position-relative thick-border">
<div data-id="r_tableList" class="table-responsive tableBorder"> </div>
<div data-id="r_tableSpinner"></div>
<div data-id="r_tableList" class="table-responsive tableBorder"> </div>
<div data-id="r_tableSpinner"></div>
</div>
<div class="row banded">
<div data-id="r_footerRecords" class="col-sm-6 margin-top-10"></div>
<div data-id="r_pagination" class="col-sm-6 text-right"></div>
</div>
\ No newline at end of file
<div data-id="r_footerRecords" class="col-sm-6 margin-top-10"></div>
<div data-id="r_pagination" class="col-sm-6 text-right"></div>
</div>
......@@ -15,32 +15,27 @@
* limitations under the License.
-->
<div class="modal-dialog {{mainClass}}" role="document">
<div class="modal-content">
{{#if title}}
<div class="modal-header">
<a class="close">&times;</a>
<h4 class="modal-title">
<div class="modal-content">
{{#if title}}
<div class="modal-header">
<a class="close">&times;</a>
<h4 class="modal-title">
{{#if titleHtml}}
{{{tt title}}}
{{else}}
{{tt title}}
{{/if}}
</h4>
</div>
{{/if}}
{{#if contentWithFooter}}
{{else}}
<div class="modal-body">{{content}}</div>
{{#if showFooter}}
<div class="modal-footer" >
<a href="#" class="btn ok btn-success">{{tt okText}}</a>
{{#if allowCancel}}
{{#if cancelText}}
<a href="#" class="btn btn-default cancel">{{tt cancelText}}</a>
{{/if}}
{{/if}}
</div>
{{/if}}
{{/if}}
</div>
</div>
\ No newline at end of file
</div>
{{/if}} {{#if contentWithFooter}} {{else}}
<div class="modal-body">{{content}}</div>
{{#if showFooter}}
<div class="modal-footer">
<button class="btn ok btn-success">{{tt okText}}</button>
{{#if allowCancel}} {{#if cancelText}}
<button class="btn btn-default cancel">{{tt cancelText}}</button>
{{/if}} {{/if}}
</div>
{{/if}} {{/if}}
</div>
</div>
......@@ -15,10 +15,7 @@
* limitations under the License.
-->
<div class="col-sm-12">
<ol class="breadcrumb">
<li><a href="#!/dashboard/assetPage">Home</a></li>
<li class="active breadcrumbName"></li>
</ol>
<a href="javascript:void(0);" class="backButton" data-id="backButton" title="Back To Result"><i class="fa fa-chevron-left fa-2x"></i></a>
<div class="panel panel-default lineageLayout" style="display:none">
<div id="r_lineageLayoutView"></div>
</div>
......
......@@ -27,7 +27,11 @@
</div> -->
<div class="graph" id="tree-container">
</div>
<div>
<svg width=100% height=350> </svg>
<div style="position:relative">
<svg width=100% height=350></svg>
<div class="zoomButtonGroup">
<button class="zoomButton" id="zoom_in">+</button>
<button class="zoomButton" id="zoom_out">-</button>
</div>
</div>
</div>
......@@ -14,4 +14,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
<div id="r_tagLayoutView"></div>
\ No newline at end of file
<div id="r_tagLayoutView"></div>
......@@ -19,7 +19,7 @@
<div class="form-group">
<label class="control-label col-sm-4">Tag definition</label>
<div class="col-sm-8 input-spacing">
<select class="form-control" data-id="addTagOptions" id="addTagID" required>
<select class="form-control" data-id="addTagOptions" required>
</select>
</div>
</div>
......
......@@ -16,9 +16,28 @@
* limitations under the License.
*/
define(['require', 'backgrid'], function(require) {
define(['require', 'backgrid', 'asBreadcrumbs'], function(require) {
'use strict';
$.asBreadcrumbs.prototype.generateChildrenInfo = function() {
var self = this;
this.$children.each(function() {
var $this = $(this);
self.childrenInfo.push({
$this: $this,
outerWidth: $this.outerWidth(),
$content: $(self.options.dropdownContent($this))
});
});
if (this.options.overflow === "left") {
this.childrenInfo.reverse();
}
this.childrenLength = this.childrenInfo.length;
};
String.prototype.trunc = String.prototype.trunc ||
function(n) {
return (this.length > n) ? this.substr(0, n - 1) + '...' : this;
};
/*
* HtmlCell renders any html code
* @class Backgrid.HtmlCell
......@@ -71,7 +90,5 @@ define(['require', 'backgrid'], function(require) {
this.delegateEvents();
return this;
}
});
});
......@@ -96,20 +96,20 @@
return { found: false, 'value': value };
},
getLocalStorage: function(key, value) {
var keyValue = localStorage.getItem(key)
var keyValue = localStorage.getItem(key);
if (!keyValue || keyValue == "undefined") {
return this.setLocalStorage(key, value);
} else {
return { found: true, 'value': keyValue };
}
}
}
};
Utils.cookie = {
setCookie: function(cname, cvalue) {
//var d = new Date();
//d.setTime(d.getTime() + (exdays*24*60*60*1000));
//var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; "
document.cookie = cname + "=" + cvalue + "; ";
return { found: false, 'value': cvalue };
},
getCookie: function(findString) {
......@@ -132,7 +132,7 @@
return setCookie(key, value);
}
}
}
};
Utils.getQueryParams = function(qs) {
qs = qs.split('+').join(' ');
var params = {},
......@@ -142,7 +142,7 @@
params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
}
return params;
}
};
Utils.setUrl = function(options) {
if (options) {
......@@ -150,11 +150,11 @@
var hashUrl = window.location.hash.split("?");
if (hashUrl.length > 1) {
var param = Utils.getQueryParams(hashUrl[1]);
options.urlParams = _.extend(param, options.urlParams)
options.urlParams = _.extend(param, options.urlParams);
}
}
if (options.urlParams) {
var urlParams = "?"
var urlParams = "?";
_.each(options.urlParams, function(value, key, obj) {
urlParams += key + "=" + value + "&";
});
......@@ -163,6 +163,6 @@
}
Backbone.history.navigate(options.url, { trigger: options.trigger != undefined ? options.trigger : true });
}
}
};
return Utils;
});
\ No newline at end of file
......@@ -79,7 +79,7 @@ define(['require',
_.extend(this, _.pick(options, 'globalVent', 'collection', 'vent'));
this.entityModel = new VEntity();
this.searchCollection = this.collection;
this.fetchList = 0
this.fetchList = 0;
this.commonTableOptions = {
collection: this.searchCollection,
includeFilter: false,
......@@ -297,11 +297,11 @@ define(['require',
var modelObject = model.toJSON();
if (modelObject.$typeName$ && modelObject.instanceInfo) {
var guid = model.toJSON().instanceInfo.guid;
++that.fetchList
++that.fetchList;
model.getEntity(guid, {
beforeSend: function() {},
success: function(data) {
--that.fetchList
--that.fetchList;
that.checkTableFetch();
if (data.definition && data.definition.values && data.definition.values.name) {
return that.$('td a[data-id="' + guid + '"]').html(data.definition.values.name);
......@@ -318,11 +318,11 @@ define(['require',
return '<a href="#!/dashboard/detailPage/' + guid + '" data-id="' + guid + '"></a>';
} else if (!modelObject.$typeName$) {
var guid = model.toJSON().guid;
++that.fetchList
++that.fetchList;
model.getEntity(guid, {
beforeSend: function() {},
success: function(data) {
--that.fetchList
--that.fetchList;
that.checkTableFetch();
if (data.definition && data.definition.values && data.definition.values.name) {
return that.$('td a[data-id="' + guid + '"]').html(data.definition.values.name);
......
......@@ -37,10 +37,15 @@ define(['require',
RLineageLayoutView: "#r_lineageLayoutView",
},
/** ui selector cache */
ui: {},
ui: {
backButton: "[data-id='backButton']"
},
/** ui events hash */
events: function() {
var events = {};
events['click ' + this.ui.backButton] = function() {
Backbone.history.history.back();
};
return events;
},
/**
......
......@@ -61,7 +61,7 @@ define(['require',
this.bindEvents();
this.fetchGraphData();
this.data = {};
this.fetchList = 0
this.fetchList = 0;
},
bindEvents: function() {
this.listenTo(this.inputCollection, 'reset', function() {
......@@ -87,7 +87,16 @@ define(['require',
onRender: function() {
this.$('.fontLoader').show();
this.g = new dagreD3.graphlib.Graph()
.setGraph({})
.setGraph({
nodesep: 50,
ranksep: 90,
rankdir: "LR",
marginx: 20,
marginy: 20,
transition: function transition(selection) {
return selection.transition().duration(500);
}
})
.setDefaultEdgeLabel(function() {
return {};
});
......@@ -102,13 +111,16 @@ define(['require',
var obj = {};
if (data && data.definition && data.definition.values) {
var values = data.definition.values;
obj['label'] = values.name
obj['label'] = values.name.trunc(20);
obj['toolTiplabel'] = values.name;
obj['id'] = data.GUID;
if (values.queryText) {
obj['queryText'] = values.queryText;
}
obj['shape'] = "img";
} else {
obj['label'] = vertices[val].values.name;
obj['toolTiplabel'] = values.name;
}
obj['class'] = "type-TOP";
that.g.setNode(data.GUID, obj);
......@@ -125,7 +137,7 @@ define(['require',
}
function fetchLoadProcess(id) {
++that.fetchList
++that.fetchList;
that.entityModel.getEntity(id, {
beforeSend: function() {},
success: function(data) {
......@@ -137,29 +149,29 @@ define(['require',
}
function makeNode(c) {
var edges = c.edges,
vertices = c.vertices,
allKeys = [];
_.each(c.edges, function(val, key, obj) {
allKeys.push(key)
allKeys.push(key);
_.each(val, function(val1, key1, obj1) {
allKeys.push(val1)
allKeys.push(val1);
});
});
var uniquNode = _.uniq(allKeys);
_.each(uniquNode, function(val, key) {
var obj = {}
var obj = {};
if (vertices[val] && vertices[val].values) {
obj['label'] = vertices[val].values.name;
obj['label'] = vertices[val].values.name.trunc(20);
obj['toolTiplabel'] = vertices[val].values.name;
obj['id'] = val;
obj['class'] = "type-TOP";
obj['shape'] = "img";
obj['typeName'] = vertices[val].values.vertexId.values.typeName;
that.g.setNode(val, obj);
} else {
fetchLoadProcess(val);
}
});
}
_.each(collection.models, function(values) {
......@@ -170,12 +182,12 @@ define(['require',
that.edgesAndvertices = {
edges: {},
vertices: valuObj.vertices
}
};
_.each(valuObj.edges, function(val, key, obj) {
_.each(val, function(val1, key1, obj1) {
var chiledParent = {};
if (!obj[val1]) {
that.startingPoint.push(val1)
that.startingPoint.push(val1);
}
that.edgesAndvertices.edges[val1] = [key];
});
......@@ -203,62 +215,145 @@ define(['require',
},
createGraph: function(edgesAndvertices, startingPoint) {
var that = this;
this.g.nodes().forEach(function(v) {
var node = that.g.node(v);
// Round the corners of the nodes
node.rx = node.ry = 5;
});
// Set up edges, no special attributes.
// For input
var lastVal = "";
_.each(startingPoint, function(val, key, obj) {
that.g.setEdge(val, edgesAndvertices.edges[val][0]);
lastVal = edgesAndvertices.edges[val][0];
_.each(edgesAndvertices.edges[val], function(val1) {
that.g.setEdge(val, val1);
createRemaningEdge(edgesAndvertices.edges, val1);
});
});
createRemaningEdge(edgesAndvertices.edges, lastVal);
function createRemaningEdge(obj, starting) {
if (obj[starting] && obj[starting].length) {
that.g.setEdge(starting, obj[starting]);
createRemaningEdge(obj, obj[starting]);
_.each(obj[starting], function(val, key) {
that.g.setEdge(starting, val);
createRemaningEdge(obj, val);
});
}
}
if (this.outputState) {
// Create the renderer
var render = new dagreD3.render();
render.shapes().img = function circle(parent, bbox, node) {
//var r = Math.max(bbox.width, bbox.height) / 2,
var shapeSvg = parent.insert("image")
.attr("class", "nodeImage")
.attr("xlink:href", function(d) {
if (node) {
if (node.typeName) {
if (node.id == that.guid) {
return '../img/icon-table-active.png';
} else {
return '../img/icon-table.png';
}
} else {
if (node.id == that.guid) {
return '../img/icon-gear-active.png';
} else {
return '../img/icon-gear.png';
}
}
}
}).attr("x", "-20px")
.attr("y", "-20px")
.attr("width", "40px")
.attr("height", "40px");
/*shapeSvg = parent.insert("circle", ":first-child")
.attr("x", 35)
.attr("y", 35)
.attr("r", 20);*/
node.intersect = function(point) {
//return dagreD3.intersect.circle(node, points, point);
return dagreD3.intersect.circle(node, 20, point);
};
return shapeSvg;
};
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select(this.$("svg")[0]),
svgGroup = svg.append("g");
var zoom = d3.behavior.zoom().on("zoom", function() {
svgGroup.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
var zoom = d3.behavior.zoom()
.scaleExtent([0.5, 6])
.on("zoom", zoomed)
function zoomed() {
svgGroup.attr("transform",
"translate(" + zoom.translate() + ")" +
"scale(" + zoom.scale() + ")"
);
}
function interpolateZoom(translate, scale) {
var self = this;
return d3.transition().duration(350).tween("zoom", function() {
var iTranslate = d3.interpolate(zoom.translate(), translate),
iScale = d3.interpolate(zoom.scale(), scale);
return function(t) {
zoom
.scale(iScale(t))
.translate(iTranslate(t));
zoomed();
};
});
}
function zoomClick() {
var clicked = d3.event.target,
direction = 1,
factor = 0.2,
target_zoom = 1,
center = [that.g.graph().width / 2, that.g.graph().height / 2],
extent = zoom.scaleExtent(),
translate = zoom.translate(),
translate0 = [],
l = [],
view = { x: translate[0], y: translate[1], k: zoom.scale() };
d3.event.preventDefault();
direction = (this.id === 'zoom_in') ? 1 : -1;
target_zoom = zoom.scale() * (1 + factor * direction);
if (target_zoom < extent[0] || target_zoom > extent[1]) {
return false;
}
translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
view.k = target_zoom;
l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
view.x += center[0] - l[0];
view.y += center[1] - l[1];
interpolateZoom([view.x, view.y], view.k);
}
d3.selectAll('button.zoomButton').on('click', zoomClick);
var tooltip = d3Tip()
.attr('class', 'd3-tip')
.html(function(d) {
var value = that.g.node(d)
var htmlStr = "<h5>Name: <span style='color:#359f89'>" + value.label + "</span></h5> ";
var value = that.g.node(d);
var htmlStr = "<h5>Name: <span style='color:#359f89'>" + value.toolTiplabel + "</span></h5> ";
if (value.queryText) {
htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> "
htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> ";
}
return htmlStr;
});
svg.call(zoom)
.call(tooltip);
this.$('.fontLoader').hide();
// Run the renderer. This is what draws the final graph.
this.g.graph().rankDir = 'LR';
//render(d3.select(this.$("svg g")[0]), this.g);
render(svgGroup, this.g);
svg.on("dblclick.zoom", function() {
return null;
})
svgGroup.selectAll("g.nodes g.node")
svg.on("dblclick.zoom", null)
.on("wheel.zoom", null);
//change text postion
svgGroup.selectAll("g.nodes g.label")
.attr("transform", "translate(2,-30)");
svgGroup.selectAll("g.nodes image")
.on('mouseover', function(d) {
tooltip.show(d);
})
......@@ -275,11 +370,8 @@ define(['require',
.scale(initialScale)
.event(svg);
//svg.attr('height', this.g.graph().height * initialScale + 40);
}
}
});
return LineageLayoutView;
});
......@@ -39,7 +39,6 @@ define(['require',
/** ui selector cache */
ui: {
tagClick: '[data-id="tagClick"]',
DetailValue: "[data-id='detailValue']",
addTag: "[data-id='addTag']",
},
/** ui events hash */
......
......@@ -81,10 +81,10 @@ define(['require',
tagsAndTypeGenerator: function(collection, element, searchString) {
if (element == "listType") {
var searchType = "dsl";
var icon = "fa fa-cogs"
var icon = "fa fa-cogs";
} else {
var searchType = "fulltext";
var icon = "fa fa-tags"
var icon = "fa fa-tags";
}
var str = '';
_.each(this[collection].fullCollection.models, function(model) {
......
......@@ -34,9 +34,10 @@ define(['require',
addTagOptions: "[data-id='addTagOptions']",
tagAttribute: "[data-id='tagAttribute']"
},
events: {
'change #addTagID': 'onChangeTagDefination'
events: function() {
var events = {};
events["change " + this.ui.addTagOptions] = 'onChangeTagDefination';
return events;
},
/**
* intialize a new AddTagModel Layout
......@@ -47,19 +48,20 @@ define(['require',
_.extend(this, _.pick(options, 'vent', 'modalCollection', 'guid'));
this.collection = new VTagList();
this.commonCollection = new VCommonList();
var modal = new Modal({
this.modal = new Modal({
title: 'Add Tag',
content: this,
okText: 'Save',
cancelText: "Cancel",
allowCancel: true,
}).open();
var saveBtn = this.modal.$el.find('.btn-success');
saveBtn[0].setAttribute('disabled', true);
this.on('ok', function() {
that.saveTagData();
});
this.on('closeModal', function() {
modal.trigger('cancel');
this.modal.trigger('cancel');
});
this.bindEvents();
},
......@@ -77,14 +79,17 @@ define(['require',
}, this);
},
tagsCollection: function() {
var str = '<option selected="true" style="display:none;"></option>';
for (var i = 0; i < this.collection.fullCollection.models.length; i++) {
var tags = this.collection.fullCollection.models[i].get("tags");
var str = '<option>' + tags + '</option>';
this.ui.addTagOptions.append(str);
str += '<option>' + tags + '</option>';
this.ui.addTagOptions.html(str);
}
},
onChangeTagDefination: function() {
this.ui.tagAttribute.empty();
var saveBtn = this.modal.$el.find('.btn-success');
saveBtn.prop("disabled", false);
var tagname = this.ui.addTagOptions.val();
this.fetchTagSubData(tagname);
},
......
......@@ -138,7 +138,6 @@ define(['require',
content: that.name + " has been created"
});
that.collection.reset();
},
error: function(model, response) {
if (response.responseJSON && response.responseJSON.error) {
......
......@@ -21,6 +21,7 @@ ATLAS-409 Atlas will not import avro tables with schema read from a file (dosset
ATLAS-379 Create sqoop and falcon metadata addons (venkatnrangan,bvellanki,sowmyaramesh via shwethags)
ALL CHANGES:
ATLAS-658 Improve Lineage with Backbone porting (kevalbhatt18 via yhemanth)
ATLAS-491 Business Catalog / Taxonomy (jspeidel via yhemanth)
ATLAS-713 Entity lineage based on entity id (shwethags)
ATLAS-736 UI - BUG :: displaying timestamp values for hive_db description (kevalbhatt18 via yhemanth)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment