Repository: atlas Updated Branches: refs/heads/branch-0.8 d2110c379 -> 5d4f18d51
ATLAS-2917: Filter added for Lineage to hide Process entity. Signed-off-by: Sarath Subramanian <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/5d4f18d5 Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/5d4f18d5 Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/5d4f18d5 Branch: refs/heads/branch-0.8 Commit: 5d4f18d51d7a3f37bc1a9e0a914fd0a75c866036 Parents: d2110c3 Author: kevalbhatt <[email protected]> Authored: Tue Oct 16 15:20:47 2018 -0700 Committer: Sarath Subramanian <[email protected]> Committed: Tue Oct 16 15:20:47 2018 -0700 ---------------------------------------------------------------------- dashboardv2/public/css/scss/graph.scss | 75 ++++++- .../detail_page/DetailPageLayoutView_tmpl.html | 2 +- .../templates/graph/LineageLayoutView_tmpl.html | 25 ++- dashboardv2/public/js/utils/Utils.js | 22 +++ .../views/detail_page/DetailPageLayoutView.js | 30 ++- .../public/js/views/graph/LineageLayoutView.js | 194 +++++++++++++++---- 6 files changed, 294 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/atlas/blob/5d4f18d5/dashboardv2/public/css/scss/graph.scss ---------------------------------------------------------------------- diff --git a/dashboardv2/public/css/scss/graph.scss b/dashboardv2/public/css/scss/graph.scss index 2d7e8a3..4081dc7 100644 --- a/dashboardv2/public/css/scss/graph.scss +++ b/dashboardv2/public/css/scss/graph.scss @@ -111,11 +111,9 @@ g.type-TK>rect { fill: $color_bright_turquoise_approx; } -.zoomButtonGroup { - background-color: $white; +.hideProcessContainer { position: absolute; - top: 4px; - right: 5px; + top: 12px; } .legends { @@ -124,4 +122,73 @@ g.type-TK>rect { font-family: 'Source Sans Pro'; } } +} + +.lineage-box { + .lineage-edge-details { + position: absolute; + left: 0; + overflow: auto; + top: 0px; + max-height: 100%; + box-shadow: 4px 13px 14px -12px; + background: #e7e7e7; + transform: scaleX(0); + width: 200px; + transition: transform 0.3s ease-in; + &.open { + transform: scaleX(1); + } + .title { + background: black; + color: white; + padding: 10px; + padding-left: 17px; + margin-top: 0; + font-size: 14px; + .navigation-font { + font-family: sans-serif; + padding: 0px 5px; + color: #fb4200; + } + } + .close-details { + position: absolute; + top: 0; + color: white; + left: 0; + height: 21px; + width: 21px; + cursor: pointer; + font-size: 16px; + } + .propagation-list { + overflow: auto; + list-style-type: none; + list-style-position: outside; + padding-left: 30px; + } + .overlay { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + background: #d2d2d2b8; + z-index: 99; + } + ul>li { + word-wrap: break-word; + margin-bottom: 5px; + text-align: left; + } + } +} + +.lineage-filter-box { + background-color: #e6e6e6; + padding: 4px; + border-radius: 5px; + width: 100%; + box-shadow: 1px 3px 3px 2px #bfbfbf; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/atlas/blob/5d4f18d5/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html index b893af3..c241a72 100644 --- a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html @@ -57,7 +57,7 @@ <button type="button" id="expand_collapse_panel" class="expand_collapse_panel" title="Collapse"><i class="fa fa-chevron-up" aria-hidden="true"></i></button> </div> </div> - <div id="panel_body" class="panel-body graph-bg resize-graph animated" align="center" style="height:375px;"> + <div id="panel_body" class="panel-body graph-bg resize-graph animated" align="center"> <div id="r_lineageLayoutView"> <div class="fontLoader"> <i class="fa fa-refresh fa-spin-custom"></i> http://git-wip-us.apache.org/repos/asf/atlas/blob/5d4f18d5/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html index 76241db..55b9864 100644 --- a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html @@ -14,17 +14,30 @@ * See the License for the specific language governing permissions and * limitations under the License. --> -<div style="position: absolute;height: calc(100% - 45px);width: calc(100% - 30px);"> +<!-- <div class="graph-toolbar clearfix"></div> --> +<!-- for 0.8 we used position of lineage-box - Relative --> +<div style="position: relative;height:100%;width:100%;" class="white-bg no-padding lineage-box"> + <div class="lineage-filter-box clearfix"> + <div class="hideProcessContainer"> + <span class="pull-left"><b>Load Process:</b> </span> + <span class="pull-left">Show</span> + <label class="switch pull-left"> + <input type="checkbox" class="switch-input" data-id="checkHideProcess" value="" /> + <span class="switch-slider"></span> + </label> + <span class="pull-left">Hide</span> + </div> + <div class="zoomButtonGroup pull-right"> + <span type="button" id="zoom_in" class="btn btn-atlas btn-md lineageZoomButton" title="Zoom In" data-id="refreshBtn"> <i class="fa fa-search-plus"></i></span> + <span type="button" id="zoom_out" class="btn btn-atlas btn-md lineageZoomButton" title="Zoom Out" data-id="refreshBtn"> <i class="fa fa-search-minus"></i></span> + </div> + </div> <div class="fontLoader"> <i class="fa fa-refresh fa-spin-custom"></i> </div> - <svg width="100%" height="100%" " viewBox="0 0 854 330" enable-background="new 0 0 854 330" xml:space="preserve"></svg> + <svg width="100%" height="calc(100% - 80px)" viewBox="0 0 854 330" enable-background="new 0 0 854 330" xml:space="preserve"></svg> <div class="legends" style="height: 20px"> <i class="fa fa-long-arrow-right" aria-hidden="true" style="margin-right: 12px; color:#8bc152;"> <span>Lineage</span></i> <i class="fa fa-long-arrow-right" aria-hidden="true" style="color:#fb4200;"> <span>Impact</span></i> </div> - <div class="zoomButtonGroup"> - <span type="button" id="zoom_in" class="btn btn-action btn-md lineageZoomButton" title="Zoom In" data-id="refreshBtn"> <i class="fa fa-search-plus"></i></span> - <span type="button" id="zoom_out" class="btn btn-action btn-md lineageZoomButton" title="Zoom Out" data-id="refreshBtn"> <i class="fa fa-search-minus"></i></span> - </div> </div> http://git-wip-us.apache.org/repos/asf/atlas/blob/5d4f18d5/dashboardv2/public/js/utils/Utils.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/utils/Utils.js b/dashboardv2/public/js/utils/Utils.js index 21d387a..57831d7 100644 --- a/dashboardv2/public/js/utils/Utils.js +++ b/dashboardv2/public/js/utils/Utils.js @@ -534,6 +534,28 @@ define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', }); } } + Utils.getNestedSuperTypes = function(options) { + var data = options.data, + collection = options.collection, + superTypes = []; + + var getData = function(data, collection) { + superTypes = superTypes.concat(data.superTypes); + + if (data.superTypes && data.superTypes.length) { + _.each(data.superTypes, function(superTypeName) { + if (collection.fullCollection) { + var collectionData = collection.fullCollection.findWhere({ name: superTypeName }).toJSON(); + } else { + var collectionData = collection.findWhere({ name: superTypeName }).toJSON(); + } + return getData(collectionData, collection); + }); + } + } + getData(data, collection); + return _.uniq(superTypes); + } Utils.getNestedSuperTypeObj = function(options) { var flag = 0, data = options.data, http://git-wip-us.apache.org/repos/asf/atlas/blob/5d4f18d5/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js index 08a3dea..626cd54 100644 --- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js +++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js @@ -108,7 +108,6 @@ define(['require', */ initialize: function(options) { _.extend(this, _.pick(options, 'value', 'collection', 'id', 'entityDefCollection', 'typeHeaders', 'enumDefCollection', 'classificationDefCollection')); - this.bindEvents(); }, bindEvents: function() { var that = this; @@ -176,6 +175,7 @@ define(['require', } } this.hideLoader(); + this.activeEntityDef = this.entityDefCollection.fullCollection.find({ name: collectionJSON.typeName }); var obj = { entity: collectionJSON, guid: this.id, @@ -212,6 +212,26 @@ define(['require', this.renderReplicationAuditTableLayoutView(obj); } + var processCheck = false, + containsList = Utils.getNestedSuperTypes({ data: this.activeEntityDef.toJSON(), collection: this.entityDefCollection }), + superType = _.find(containsList, function(type) { + if (type === "DataSet" || type === "Process") { + if (type === "Process") { + processCheck = true; + } + return true; + } + }); + + this.renderLineageLayoutView({ + processCheck: processCheck, + guid: this.id, + entityDefCollection: this.entityDefCollection, + actionCallBack: function() { + that.$('#expand_collapse_panel').click(); + } + }); + // To render Schema check attribute "schemaElementsAttribute" var schemaOptions = this.entityDefCollection.fullCollection.find({ name: collectionJSON.typeName }).get('options'); if (schemaOptions && schemaOptions.hasOwnProperty('schemaElementsAttribute') && schemaOptions.schemaElementsAttribute !== "") { @@ -232,15 +252,9 @@ define(['require', }, onRender: function() { var that = this; + this.bindEvents(); Utils.showTitleLoader(this.$('.page-title .fontLoader'), this.$('.entityDetail')); this.$('.fontLoader').show(); // to show tab loader - this.renderLineageLayoutView({ - guid: this.id, - entityDefCollection: this.entityDefCollection, - actionCallBack: function() { - that.$('#expand_collapse_panel').click(); - } - }); this.$(".resize-graph").resizable({ handles: ' s', minHeight: 375, http://git-wip-us.apache.org/repos/asf/atlas/blob/5d4f18d5/dashboardv2/public/js/views/graph/LineageLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/graph/LineageLayoutView.js b/dashboardv2/public/js/views/graph/LineageLayoutView.js index bb5d52e..5385bc4 100644 --- a/dashboardv2/public/js/views/graph/LineageLayoutView.js +++ b/dashboardv2/public/js/views/graph/LineageLayoutView.js @@ -25,8 +25,9 @@ define(['require', 'dagreD3', 'd3-tip', 'utils/Enums', - 'utils/UrlLinks' -], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, dagreD3, d3Tip, Enums, UrlLinks) { + 'utils/UrlLinks', + 'platform' +], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, dagreD3, d3Tip, Enums, UrlLinks, platform) { 'use strict'; var LineageLayoutView = Backbone.Marionette.LayoutView.extend( @@ -41,12 +42,14 @@ define(['require', /** ui selector cache */ ui: { - graph: ".graph" + graph: ".graph", + checkHideProcess: "[data-id='checkHideProcess']" }, /** ui events hash */ events: function() { var events = {}; + events["click " + this.ui.checkHideProcess] = 'onCheckHideProcess'; return events; }, @@ -55,19 +58,17 @@ define(['require', * @constructs */ initialize: function(options) { - _.extend(this, _.pick(options, 'guid', 'entityDefCollection', 'actionCallBack')); - this.entityModel = new VEntity(); + _.extend(this, _.pick(options, 'processCheck', 'guid', 'entityDefCollection', 'actionCallBack', 'fetchCollection')); this.collection = new VLineageList(); + this.lineageData = null; this.typeMap = {}; + this.apiGuid = {}; this.asyncFetchCounter = 0; - this.fetchGraphData(); + this.edgeCall; }, - onRender: function() { - var that = this; - this.$('.fontLoader').show(); - if (this.layoutRendered) { - this.layoutRendered(); - } + + initializeGraph: function() { + this.g = {}; this.g = new dagreD3.graphlib.Graph() .setGraph({ nodesep: 50, @@ -83,6 +84,31 @@ define(['require', return {}; }); }, + + onRender: function() { + var that = this; + this.fetchGraphData(); + if (platform.name === "IE") { + this.$('svg').css('opacity', '0'); + } + if (this.layoutRendered) { + this.layoutRendered(); + } + if (this.processCheck) { + this.hideCheckForProcess(); + } + this.initializeGraph(); + }, + onShow: function() { + this.$('.fontLoader').show(); + }, + onCheckHideProcess: function(e) { + var data = $.extend(true, {}, this.lineageData); + this.fromToObj = {}; + this.initializeGraph(); + this.generateData(data.relations, data.guidEntityMap, e.target.checked); + }, + fetchGraphData: function() { var that = this; this.fromToObj = {}; @@ -90,12 +116,15 @@ define(['require', skipDefaultError: true, success: function(data) { if (data.relations.length) { + that.lineageData = $.extend(true, {}, data) that.generateData(data.relations, data.guidEntityMap); } else { that.noLineage(); + that.hideCheckForProcess(); } }, cust_error: function(model, response) { + that.lineageData = []; that.noLineage(); } }) @@ -103,14 +132,22 @@ define(['require', noLineage: function() { this.$('.fontLoader').hide(); //this.$('svg').height('100'); - this.$('svg').html('<text x="' + (this.$('svg').width() - 150) / 2 + '" y="' + this.$('svg').height() / 2 + '" fill="black">No lineage data found</text>'); + this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No lineage data found</text>'); if (this.actionCallBack) { this.actionCallBack(); } }, - generateData: function(relations, guidEntityMap) { + hideCheckForProcess: function() { + this.$('.hideProcessContainer').hide(); + }, + generateData: function(relations, guidEntityMap, hideProcess) { var that = this; + function isProcess(typeName) { + var entityDef = that.entityDefCollection.fullCollection.find({ name: typeName }); + return _.contains(Utils.getNestedSuperTypes({ data: entityDef.toJSON(), collection: that.entityDefCollection}), "Process") + } + function makeNodeObj(relationObj) { var obj = {}; obj['shape'] = "img"; @@ -123,15 +160,53 @@ define(['require', if (relationObj.status) { obj['status'] = relationObj.status; } - var entityDef = that.entityDefCollection.fullCollection.find({ name: relationObj.typeName }); - if (entityDef && entityDef.get('superTypes')) { - obj['isProcess'] = _.contains(entityDef.get('superTypes'), "Process") ? true : false; + if (hideProcess) { + obj['isProcess'] = relationObj.isProcess; + } else { + obj['isProcess'] = isProcess(relationObj.typeName); } return obj; } - _.each(relations, function(obj, index) { + var newRelations = []; + + if (hideProcess) { + _.each(relations, function(obj, index, relationArr) { + var isFromEntityIdProcess = isProcess(guidEntityMap[obj.fromEntityId].typeName); + var isToEntityProcess = isProcess(guidEntityMap[obj.toEntityId].typeName); + if (isToEntityProcess) { + guidEntityMap[obj.toEntityId]["isProcess"] = true; + _.filter(relationArr, function(flrObj) { + if (flrObj.fromEntityId === obj.toEntityId) { + newRelations.push({ + fromEntityId: obj.fromEntityId, + toEntityId: flrObj.toEntityId + }); + } + }) + } else if (isFromEntityIdProcess) { + guidEntityMap[obj.fromEntityId]["isProcess"] = true; + _.filter(relationArr, function(flrObj) { + if (flrObj.toEntityId === obj.fromEntityId) { + newRelations.push({ + fromEntityId: flrObj.fromEntityId, + toEntityId: obj.toEntityId + }); + } + }) + } else { + newRelations.push(obj); + } + }); + } + + + var finalRelations = hideProcess ? newRelations : relations; + + + + _.each(finalRelations, function(obj, index) { if (!that.fromToObj[obj.fromEntityId]) { that.fromToObj[obj.fromEntityId] = makeNodeObj(guidEntityMap[obj.fromEntityId]); that.g.setNode(obj.fromEntityId, that.fromToObj[obj.fromEntityId]); @@ -142,14 +217,15 @@ define(['require', } var styleObj = { fill: 'none', - stroke: '#8bc152' + stroke: '#8bc152', + width: 2 } - that.g.setEdge(obj.fromEntityId, obj.toEntityId, { 'arrowhead': "arrowPoint", lineInterpolate: 'basis', "style": "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + "", 'styleObj': styleObj }); + that.g.setEdge(obj.fromEntityId, obj.toEntityId, { 'arrowhead': "arrowPoint", lineInterpolate: 'basis', "style": "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width + "", 'styleObj': styleObj }); }); if (this.fromToObj[this.guid]) { this.fromToObj[this.guid]['isLineage'] = false; - this.checkForLineageOrImpactFlag(relations, this.guid); + this.checkForLineageOrImpactFlag(finalRelations, this.guid); } if (this.asyncFetchCounter == 0) { this.createGraph(); @@ -174,23 +250,33 @@ define(['require', }); } }, + toggleInformationSlider: function(options) { + if (options.open && !this.$('.lineage-edge-details').hasClass("open")) { + this.$('.lineage-edge-details').addClass('open'); + } else if (options.close && this.$('.lineage-edge-details').hasClass("open")) { + d3.selectAll('circle').attr("stroke", "none"); + this.$('.lineage-edge-details').removeClass('open'); + } + }, setGraphZoomPositionCal: function(argument) { var initialScale = 1.2, svgEl = this.$('svg'), scaleEl = this.$('svg').find('>g'), translateValue = [(this.$('svg').width() - this.g.graph().width * initialScale) / 2, (this.$('svg').height() - this.g.graph().height * initialScale) / 2] if (_.keys(this.g._nodes).length > 15) { - translateValue = [((this.$('svg').width() / 2)) / 2, 20]; initialScale = 0; this.$('svg').addClass('noScale'); } - if (svgEl.parents('.panel.panel-fullscreen').length && svgEl.hasClass('noScale')) { - if (!scaleEl.hasClass('scaleLinage')) { - scaleEl.addClass('scaleLinage'); - initialScale = 1.2; - } else { - scaleEl.removeClass('scaleLinage'); - initialScale = 0; + if (svgEl.parents('.panel.panel-fullscreen').length) { + translateValue = [20, 20]; + if (svgEl.hasClass('noScale')) { + if (!scaleEl.hasClass('scaleLinage')) { + scaleEl.addClass('scaleLinage'); + initialScale = 1.2; + } else { + scaleEl.removeClass('scaleLinage'); + initialScale = 0; + } } } else { scaleEl.removeClass('scaleLinage'); @@ -205,7 +291,9 @@ define(['require', ); }, createGraph: function() { - var that = this; + var that = this, + width = this.$('svg').width(), + height = this.$('svg').height(); this.g.nodes().forEach(function(v) { var node = that.g.node(v); // Round the corners of the nodes @@ -287,7 +375,12 @@ define(['require', return shapeSvg; }; // Set up an SVG group so that we can translate the final graph. - var svg = this.svg = d3.select(this.$("svg")[0]), + if (this.$("svg").find('.output').length) { + this.$("svg").find('.output').parent('g').remove(); + } + var svg = this.svg = d3.select(this.$("svg")[0]) + .attr("viewBox", "0 0 " + width + " " + height) + .attr("enable-background", "new 0 0 " + width + " " + height), svgGroup = svg.append("g"); var zoom = this.zoom = d3.behavior.zoom() .scaleExtent([0.5, 6]) @@ -340,7 +433,7 @@ define(['require', d3.selectAll(this.$('span.lineageZoomButton')).on('click', zoomClick); var tooltip = d3Tip() .attr('class', 'd3-tip') - .offset([-18, 0]) + .offset([10, 0]) .html(function(d) { var value = that.g.node(d); var htmlStr = ""; @@ -359,7 +452,9 @@ define(['require', svg.call(zoom) .call(tooltip); - this.$('.fontLoader').hide(); + if (platform.name !== "IE") { + this.$('.fontLoader').hide(); + } render(svgGroup, this.g); svg.on("dblclick.zoom", null) .on("wheel.zoom", null); @@ -396,7 +491,7 @@ define(['require', .on('dblclick', function(d) { tooltip.hide(d); Utils.setUrl({ - url: '#!/detailPage/' + d, + url: '#!/detailPage/' + d + '?tabActive=lineage', mergeBrowserUrl: false, trigger: true }); @@ -410,6 +505,19 @@ define(['require', } }, 400) }); + svgGroup.selectAll("g.edgePath path.path").on('click', function(d) { + var data = { obj: _.find(that.lineageData.relations, { "fromEntityId": d.v, "toEntityId": d.w }) }, + relationshipId = data.obj.relationshipId; + require(['views/graph/PropagationPropertyModal'], function(PropagationPropertyModal) { + var view = new PropagationPropertyModal({ + edgeInfo: data, + relationshipId: relationshipId, + lineageData: that.lineageData, + apiGuid: that.apiGuid, + detailPageFetchCollection: that.fetchCollection + }); + }); + }) $('body').on('mouseover', '.d3-tip', function(el) { that.activeTip = true; }); @@ -423,7 +531,23 @@ define(['require', this.setGraphZoomPositionCal(); zoom.event(svg); //svg.attr('height', this.g.graph().height * initialScale + 40); - + if (platform.name === "IE") { + this.IEGraphRenderDone = 0; + this.$('svg .edgePath').each(function(argument) { + var childNode = $(this).find('marker'); + $(this).find('marker').remove(); + var eleRef = this; + ++that.IEGraphRenderDone; + setTimeout(function(argument) { + $(eleRef).find('defs').append(childNode); + --that.IEGraphRenderDone; + if (that.IEGraphRenderDone === 0) { + this.$('.fontLoader').hide(); + this.$('svg').fadeTo(1000, 1) + } + }, 1000); + }); + } } }); return LineageLayoutView;
