This is an automated email from the ASF dual-hosted git repository. kbhatt pushed a commit to branch branch-2.0 in repository https://gitbox.apache.org/repos/asf/atlas.git
commit a9da759e5f342592179cc4cde574420d84d8529e Author: kevalbhatt <kbh...@apache.org> AuthorDate: Mon Oct 12 15:49:09 2020 +0530 ATLAS-3954: UI: Type system property table improvement (cherry picked from commit 3c0b2746d0065b1d95b4511c46a8655d4167096e) --- dashboardv2/public/css/scss/common.scss | 10 + dashboardv2/public/css/scss/graph.scss | 36 +++- dashboardv2/public/css/scss/table.scss | 28 +++ .../js/external_lib/atlas-lineage/dist/index.js | 2 +- .../atlas-lineage/src/Utils/LineageUtils.js | 8 +- .../js/external_lib/atlas-lineage/src/index.js | 78 +++++-- .../AdministratorLayoutView_tmpl.html | 2 +- .../detail_page/DetailPageLayoutView_tmpl.html | 2 +- .../js/templates/graph/LineageLayoutView_tmpl.html | 24 +-- .../templates/graph/TypeSystemTreeView_tmpl.html | 67 +++++- dashboardv2/public/js/utils/CommonViewFunction.js | 29 ++- .../public/js/views/graph/LineageLayoutView.js | 35 +-- .../public/js/views/graph/TypeSystemTreeView.js | 234 ++++++++++++--------- dashboardv3/public/css/scss/common.scss | 10 + dashboardv3/public/css/scss/graph.scss | 36 +++- dashboardv3/public/css/scss/table.scss | 29 +++ .../js/external_lib/atlas-lineage/dist/index.js | 2 +- .../atlas-lineage/src/Utils/LineageUtils.js | 8 +- .../js/external_lib/atlas-lineage/src/index.js | 78 +++++-- .../AdministratorLayoutView_tmpl.html | 2 +- .../detail_page/DetailPageLayoutView_tmpl.html | 2 +- .../js/templates/graph/LineageLayoutView_tmpl.html | 24 +-- .../templates/graph/TypeSystemTreeView_tmpl.html | 67 +++++- dashboardv3/public/js/utils/CommonViewFunction.js | 29 ++- .../public/js/views/graph/LineageLayoutView.js | 35 +-- .../public/js/views/graph/TypeSystemTreeView.js | 234 ++++++++++++--------- 26 files changed, 789 insertions(+), 322 deletions(-) diff --git a/dashboardv2/public/css/scss/common.scss b/dashboardv2/public/css/scss/common.scss index b51a6f2..e93eef1 100644 --- a/dashboardv2/public/css/scss/common.scss +++ b/dashboardv2/public/css/scss/common.scss @@ -180,6 +180,11 @@ pre { .json-string { color: olive; + + &.cursor { + cursor: pointer; + text-decoration: underline; + } } } @@ -191,6 +196,11 @@ pre { .panel-body .memory-details { pre { &.code-block { + &.fixed-height { + max-height: 112px; + overflow: auto; + } + &.shrink { height: 144px; diff --git a/dashboardv2/public/css/scss/graph.scss b/dashboardv2/public/css/scss/graph.scss index 971cf60..cd5e220 100644 --- a/dashboardv2/public/css/scss/graph.scss +++ b/dashboardv2/public/css/scss/graph.scss @@ -193,7 +193,7 @@ span#zoom_in { width: 100%; right: 0; padding: 0 !important; - z-index: 9999; + z-index: 99; overflow: hidden !important; background: white; @@ -266,4 +266,38 @@ span#zoom_in { box-shadow: 0px 0px 3px 1px #80808080; } +} + + +.box-panel.fix-box { + position: fixed; + top: 0; + right: 0; + bottom: 0; + height: 100vh; + max-height: 100vh; + z-index: 999; + bottom: 0; + width: 400px; + overflow: auto; + border-radius: 0px; + margin: 0 !important; + + &.slide-from-left.size-lg { + left: -413px; + + &.show-box-panel { + left: 0; + margin: 0 !important; + } + } + + .body { + tbody { + overflow: auto; + height: calc(100vh - 48px); + position: absolute; + padding-bottom: 15px; + } + } } \ No newline at end of file diff --git a/dashboardv2/public/css/scss/table.scss b/dashboardv2/public/css/scss/table.scss index 519d083..3db8a4c 100644 --- a/dashboardv2/public/css/scss/table.scss +++ b/dashboardv2/public/css/scss/table.scss @@ -41,6 +41,7 @@ tr.empty { } .entity-detail-table, +.type-node-details, .relationship-detail-table { position: relative; @@ -66,6 +67,26 @@ tr.empty { } } +.type-node-details { + .header { + .pretty.p-switch .state:before { + border: 1px solid white; + } + + .pretty.p-switch .state label:after { + background-color: white !important; + } + + .pretty.p-switch.p-fill input:checked~.state label:after { + background-color: #4a90e2 !important; + } + + .pretty.p-switch.p-fill input:checked~.state.p-primary:before { + background-color: white !important; + } + } +} + .backgrid { td { white-space: normal; @@ -98,6 +119,13 @@ tr.empty { } } } + + .debuggging-table-header { + padding-right: 0px !important; + button{ + float: right; + } + } } .backgrid-paginator ul { diff --git a/dashboardv2/public/js/external_lib/atlas-lineage/dist/index.js b/dashboardv2/public/js/external_lib/atlas-lineage/dist/index.js index c2f68bb..e82cb48 100644 --- a/dashboardv2/public/js/external_lib/atlas-lineage/dist/index.js +++ b/dashboardv2/public/js/external_lib/atlas-lineage/dist/index.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("platform"),require("dagreD3")):"function"==typeof define&&define.amd?define(["platform","dagreD3"],e):"object"==typeof exports?exports.LineageHelper=e(require("platform"),require("dagreD3")):t.LineageHelper=e(t.platform,t.dagreD3)}(window,(function(t,e){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i. [...] \ No newline at end of file +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("platform"),require("dagreD3")):"function"==typeof define&&define.amd?define(["platform","dagreD3"],e):"object"==typeof exports?exports.LineageHelper=e(require("platform"),require("dagreD3")):t.LineageHelper=e(t.platform,t.dagreD3)}(window,(function(t,e){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i. [...] \ No newline at end of file diff --git a/dashboardv2/public/js/external_lib/atlas-lineage/src/Utils/LineageUtils.js b/dashboardv2/public/js/external_lib/atlas-lineage/src/Utils/LineageUtils.js index 7c482b3..55f363e 100644 --- a/dashboardv2/public/js/external_lib/atlas-lineage/src/Utils/LineageUtils.js +++ b/dashboardv2/public/js/external_lib/atlas-lineage/src/Utils/LineageUtils.js @@ -374,7 +374,7 @@ const LineageUtils = { reader.addEventListener("load", () => callback(reader.result)); reader.readAsDataURL(file); }, - imgShapeRender: function (parent, bbox, node, { dagreD3, defsEl, imgBasePath, guid }) { + imgShapeRender: function (parent, bbox, node, { dagreD3, defsEl, imgBasePath, guid, isRankdirToBottom }) { var that = this, viewGuid = guid, imageIconPath = this.getEntityIconPath({ entityData: node, imgBasePath }), @@ -391,7 +391,7 @@ const LineageUtils = { var shapeSvg = parent .append("circle") .attr("fill", "url(#img_" + imgName + ")") - .attr("r", "24px") + .attr("r", isRankdirToBottom ? "30px" : "24px") .attr("data-stroke", node.id) .attr("stroke-width", "2px") .attr("class", "nodeImage " + (currentNode ? "currentNode" : node.isProcess ? "process" : "node")); @@ -478,8 +478,8 @@ const LineageUtils = { }); } }) - .attr("x", "4") - .attr("y", currentNode ? "3" : "4") + .attr("x", isRankdirToBottom ? "11" : "4") + .attr("y", isRankdirToBottom ? "20" : currentNode ? "3" : "4") .attr("width", "40") .attr("height", "40"); } diff --git a/dashboardv2/public/js/external_lib/atlas-lineage/src/index.js b/dashboardv2/public/js/external_lib/atlas-lineage/src/index.js index 1ac517a..3ceb3d9 100644 --- a/dashboardv2/public/js/external_lib/atlas-lineage/src/index.js +++ b/dashboardv2/public/js/external_lib/atlas-lineage/src/index.js @@ -26,6 +26,7 @@ import "./styles/style.scss"; export default class LineageHelper { constructor(options) { + this.options = {}; this._updateOptions(options); const { el, manualTrigger = false } = this.options; if (el === undefined) { @@ -33,6 +34,7 @@ export default class LineageHelper { } this.initReturnObj = { init: (arg) => this.init(arg), + updateOptions: (options) => this._updateAllOptions(options), createGraph: (opt = {}) => this._createGraph(this.options, this.graphOptions, opt), clear: (arg) => this.clear(arg), refresh: (arg) => this.refresh(arg), @@ -78,12 +80,27 @@ export default class LineageHelper { return this.initReturnObj; } /** + * [updateAllOptions] + * @param {[type]} + * @return {[type]} + */ + _updateAllOptions(options) { + Object.assign(this.options, options); + var svgRect = this.svg.node().getBoundingClientRect(); + this.graphOptions.width = this.options.width || svgRect.width; + this.graphOptions.height = this.options.height || svgRect.height; + const { svg, width, height, guid } = this.graphOptions; + const { fitToScreen } = this.options; + svg.select("g").node().removeAttribute("transform"); + svg.attr("viewBox", "0 0 " + width + " " + height).attr("enable-background", "new 0 0 " + width + " " + height); + this.centerAlign({ fitToScreen, guid }); + } + /** * [updateOptions get the options from user and appedn add it in this,option context] * @param {[Object]} options [lib options from user] * @return {[null]} [null] */ _updateOptions(options) { - this.options = {}; Object.assign(this.options, { filterObj: { isProcessHideCheck: false, isDeletedEntityHideCheck: false } }, options); } /** @@ -200,7 +217,7 @@ export default class LineageHelper { if (node && node.attributes) { downloadFileName = `${node.attributes.qualifiedName || node.attributes.name || "lineage_export"}.png`; } else { - downloadFileName = "lineage_export.png"; + downloadFileName = "export.png"; } } @@ -258,6 +275,7 @@ export default class LineageHelper { this.svg = select(el); if (!(el instanceof SVGElement)) { + this.svg.selectAll("*").remove(); this.svg = this.svg .append("svg") .attr("xmlns", "http://www.w3.org/2000/svg") @@ -385,7 +403,19 @@ export default class LineageHelper { * @return {[type]} [description] */ _createGraph( - { data = {}, imgBasePath, isShowTooltip, isShowHoverPath, onLabelClick, onPathClick, onNodeClick, zoom, fitToScreen }, + { + data = {}, + imgBasePath, + isShowTooltip, + isShowHoverPath, + onLabelClick, + onPathClick, + onNodeClick, + zoom, + fitToScreen, + getToolTipContent, + toolTipTitle + }, graphOptions, { refresh } ) { @@ -393,7 +423,8 @@ export default class LineageHelper { this.options.beforeRender(); } const that = this, - { svg, g, width, height } = graphOptions; + { svg, g, width, height } = graphOptions, + isRankdirToBottom = this.options.dagreOptions && this.options.dagreOptions.rankdir === "tb"; if (svg instanceof selection === false) { throw new Error("svg is not initialized or something went wrong while creatig graph instance"); @@ -428,6 +459,7 @@ export default class LineageHelper { render.shapes().img = function () { return LineageUtils.imgShapeRender(...arguments, { ...graphOptions, + isRankdirToBottom: isRankdirToBottom, imgBasePath: that._getValueFromUser(imgBasePath), defsEl }); @@ -437,19 +469,26 @@ export default class LineageHelper { .attr("class", "d3-tip") .offset([10, 0]) .html((d) => { - var value = g.node(d); - var htmlStr = ""; - if (value.id !== this.guid) { - htmlStr = "<h5 style='text-align: center;'>" + (value.isLineage ? "Lineage" : "Impact") + "</h5>"; - } - htmlStr += "<h5 class='text-center'><span style='color:#359f89'>" + value.toolTipLabel + "</span></h5> "; - if (value.typeName) { - htmlStr += "<h5 class='text-center'><span>(" + value.typeName + ")</span></h5> "; - } - if (value.queryText) { - htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> "; + if (getToolTipContent && typeof getToolTipContent === "function") { + return getToolTipContent(d, g.node(d)); + } else { + var value = g.node(d); + var htmlStr = ""; + if (toolTipTitle) { + htmlStr = "<h5 style='text-align: center;'>" + toolTipTitle + "</h5>"; + } else if (value.id !== this.guid) { + htmlStr = "<h5 style='text-align: center;'>" + (value.isLineage ? "Lineage" : "Impact") + "</h5>"; + } + + htmlStr += "<h5 class='text-center'><span style='color:#359f89'>" + value.toolTipLabel + "</span></h5> "; + if (value.typeName) { + htmlStr += "<h5 class='text-center'><span>(" + value.typeName + ")</span></h5> "; + } + if (value.queryText) { + htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> "; + } + return "<div class='tip-inner-scroll'>" + htmlStr + "</div>"; } - return "<div class='tip-inner-scroll'>" + htmlStr + "</div>"; }); svg.call(tooltip); @@ -463,7 +502,12 @@ export default class LineageHelper { //change text postion svgGroupEl .selectAll("g.nodes g.label") - .attr("transform", "translate(2,-35)") + .attr("transform", () => { + if (isRankdirToBottom) { + return "translate(2,-20)"; + } + return "translate(2,-35)"; + }) .on("mouseenter", function (d) { event.preventDefault(); select(this).classed("highlight", true); diff --git a/dashboardv2/public/js/templates/administrator/AdministratorLayoutView_tmpl.html b/dashboardv2/public/js/templates/administrator/AdministratorLayoutView_tmpl.html index f9ca214..85bf9ba 100644 --- a/dashboardv2/public/js/templates/administrator/AdministratorLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/administrator/AdministratorLayoutView_tmpl.html @@ -37,7 +37,7 @@ <div id="r_adminTableLayoutView"> </div> </div> - <div id="tab-typeSystem" role="typeSystem" class="tab-pane animated fadeIn" style="position: relative;"> + <div id="tab-typeSystem" role="typeSystem" class="tab-pane" style="position: relative;"> <div id="r_typeSystemTreeLayoutView"> </div> </div> diff --git a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html index 824dbdc..5854dd7 100644 --- a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html @@ -91,7 +91,7 @@ </div> </div> </div> - <div id="tab-lineage" role="lineage" class="tab-pane animated fadeIn"> + <div id="tab-lineage" role="lineage" class="tab-pane"> <div id="r_lineageLayoutView" class="animated position-relative" align="center"> <div class="fontLoader-relative"> <i class="fa fa-refresh fa-spin-custom"></i> diff --git a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html index 8e6e6b2..f6f61e2 100644 --- a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html @@ -124,22 +124,22 @@ </button> </div> </div> - <div class="box-panel size-lg node-details slide-from-left lineage-node-detail"> - <div class="header clearfix"> - <h4><span data-id="typeName"></span></h4> - <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> - <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> - </div> - <div class="body"> - <table class="table bold-key"> - <tbody data-id="nodeDetailTable"></tbody> - </table> - </div> - </div> <div class="fontLoader"> <i class="fa fa-refresh fa-spin-custom"></i> </div> <div class="legends pull-left" style="height: 25px; padding: 2px;"></div> <div class="svg" style="height: 100%; width: 100%"></div> </div> +<div class="box-panel size-lg slide-from-left lineage-node-detail fix-box"> + <div class="header clearfix"> + <h4><span data-id="typeName"></span></h4> + <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> + <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> + </div> + <div class="body"> + <table class="table bold-key"> + <tbody data-id="nodeDetailTable"></tbody> + </table> + </div> +</div> <div class="hidden-svg"></div> \ No newline at end of file diff --git a/dashboardv2/public/js/templates/graph/TypeSystemTreeView_tmpl.html b/dashboardv2/public/js/templates/graph/TypeSystemTreeView_tmpl.html index 5340de4..005c061 100644 --- a/dashboardv2/public/js/templates/graph/TypeSystemTreeView_tmpl.html +++ b/dashboardv2/public/js/templates/graph/TypeSystemTreeView_tmpl.html @@ -15,16 +15,30 @@ * limitations under the License. --> <div id="typeSystemTreeViewPage" data-id="typeSystemTreeViewPage" class="systemTypeTree" style="height: calc(100vh - 180px); width: 100%; position: relative;overflow: hidden;"> - <div class="box-panel size-lg node-details slide-from-left lineage-node-detail"> + <div class="box-panel size-lg type-node-details fix-box slide-from-left lineage-node-detail"> <div class="header clearfix"> - <h4><span data-id="typeName"></span></h4> - <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> - <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> + <div class="typeDetailHeader"> + <h4 style="padding-right: 67px;"><span data-id="typeName"></span></h4> + <div class="pretty p-switch p-fill" style="position: absolute;top: 13px;right: 32px;"> + <input type="checkbox" data-id="noValueToggle" title="Show empty values" /> + <div class="state p-primary"> + <label></label> + </div> + </div> + <span data-id="box-close" class="btn btn-sm btn-close "><i class="fa fa-close"></i></span> + </div> + <div class="typeAttrDetailHeader" style="display: none;"> + <span data-id="box-back" class="btn btn-sm btn-close" style="left: 0px; right: auto;"><i class="fa fa-angle-left"></i></span> + <h4 style="padding-left: 27px;"><span data-id="typeAttrDetailHeader"></span></h4> + </div> </div> <div class="body"> <table class="table bold-key"> - <tbody data-id="nodeDetailTable"></tbody> + <tbody data-id="nodeDetailTable" class="hide-empty-value"></tbody> </table> + <div data-id="attribute-table" style="height: calc(100vh - 60px);display: none"> + <pre class="code-block" style="height: 100%"></pre> + </div> </div> </div> <div class="fontLoader"> @@ -49,7 +63,6 @@ <div class="body"> <div class="col-sm-12 no-padding"> <div class="srchType clearfix"> - <label class="srchTitle">Search Lineage Entity: </label> <div class=""> <div class="col-sm-12 no-padding temFilter"> <select data-id="typeSearch"></select> @@ -59,28 +72,62 @@ </div> </div> </div> + <div class="box-panel setting-box"> + <div class="header clearfix"> + <h4>Settings</h4> + <span data-id="box-close" class="btn btn-sm btn-close"><i class="fa fa-close"></i></span> + </div> + <div class="body"> + <div class="showOnlyHoverPath form-group text-left col-sm-12"> + <div class="pretty p-switch p-fill"> + <input type="checkbox" checked class="pull-left" data-id="showOnlyHoverPath" value="" /> + <div class="state p-primary"> + <label>On hover show current path</label> + </div> + </div> + </div> + <div class="showTooltip form-group text-left col-sm-12"> + <div class="pretty p-switch p-fill"> + <input type="checkbox" class="pull-left" data-id="showTooltip" value="" /> + <div class="state p-primary"> + <label>Show node details on hover</label> + </div> + </div> + </div> + </div> + </div> <div class="graph-button-group pull-right"> <div> - <button data-id="reset" class="btn btn-action btn-gray btn-sm" title="Realign Lineage"> + <button data-id="reset" class="btn btn-action btn-gray btn-sm" title="Reset"> <i class="fa fa-retweet"></i> </button> </div> <div> + <button data-id="saveSvg" class="btn btn-action btn-gray btn-sm" title="Export to PNG"> + <i class="fa fa-camera"></i> + </button> + </div> + <div> + <button type="button" data-id="setting-toggler" title="Settings" class="btn btn-action btn-gray btn-sm"> + <i class="fa fa-gear"></i> + </button> + </div> + <div> <button type="button" data-id="filter-toggler" title="Filter" class="btn btn-action btn-gray btn-sm"><i class="fa fa-filter"></i></button> </div> <div> <button type="button" data-id="search-toggler" title="Search" class="btn btn-action btn-gray btn-sm"><i class="fa fa-search"></i></button> </div> <div class="btn-group"> - <button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom In" data-id="zoom-in"> + <button type="button" class="btn btn-action btn-gray btn-sm" title="Zoom In" data-id="zoom-in"> <i class="fa fa-search-plus"></i> </button> - <button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom Out" data-id="zoom-out"> + <button type="button" class="btn btn-action btn-gray btn-sm" title="Zoom Out" data-id="zoom-out"> <i class="fa fa-search-minus"></i> </button> </div> <div> - <button type="button" data-id="fullScreen-toggler" title="Full screen" class="btn btn-action btn-gray btn-sm fullscreen_lineage"> + <button type="button" data-id="fullScreen-toggler" title="Full screen" class="btn btn-action btn-gray btn-sm"> <i class="fa fa-expand"></i> </button> </div> diff --git a/dashboardv2/public/js/utils/CommonViewFunction.js b/dashboardv2/public/js/utils/CommonViewFunction.js index b116681..4fcb0fc 100644 --- a/dashboardv2/public/js/utils/CommonViewFunction.js +++ b/dashboardv2/public/js/utils/CommonViewFunction.js @@ -79,6 +79,8 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum sortBy = options.sortBy, valueObject = options.valueObject, extractJSON = options.extractJSON, + getArrayOfStringElement = options.getArrayOfStringElement, + getArrayOfStringFormat = options.getArrayOfStringFormat, isTable = _.isUndefined(options.isTable) ? true : options.isTable, attributeDefs = options.attributeDefs, formatIntVal = options.formatIntVal, @@ -108,6 +110,9 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum return "N/A"; }, getValue = function(val, key) { + if (options && options.getValue) { + val = options.getValue(val, key); + } if (!_.isUndefined(val) && !_.isNull(val)) { if ((_.isNumber(val) || !_.isNaN(parseInt(val))) && formatIntVal) { return numberFormat(val); @@ -185,7 +190,12 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum if (_.isString(inputOutputField) || _.isBoolean(inputOutputField) || _.isNumber(inputOutputField)) { var tempVarfor$check = inputOutputField.toString(); if (tempVarfor$check.indexOf("$") == -1) { - valueOfArray.push('<span class="json-string">' + getValue(inputOutputField, key) + '</span>'); + var tmpVal = getValue(inputOutputField, key) + if (getArrayOfStringElement) { + valueOfArray.push(getArrayOfStringElement(tmpVal, key)); + } else { + valueOfArray.push('<span class="json-string">' + tmpVal + '</span>'); + } } } else if (_.isObject(inputOutputField) && !id) { var attributesList = inputOutputField; @@ -251,7 +261,11 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum } } if (valueOfArray.length) { - subLink = valueOfArray.join(', '); + if (getArrayOfStringFormat) { + subLink = getArrayOfStringFormat(valueOfArray, key); + } else { + subLink = valueOfArray.join(', '); + } } return subLink === "" ? getEmptyString(key) : subLink; } @@ -297,12 +311,17 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum if (_.isObject(valueObject[key]) && !_.isEmpty(valueObject[key])) { var matchedLinkString = val.match(/href|value-loader\w*/g), matchedJson = val.match(/json-value|json-string\w*/g), + matchedKey = val.match(/json-key\w*/g), isMatchLinkStringIsSingle = matchedLinkString && matchedLinkString.length <= 5, isMatchJSONStringIsSingle = matchedJson && matchedJson.length == 1, expandCollapseButton = ""; - if ((matchedJson && !isMatchJSONStringIsSingle) || (matchedLinkString && !isMatchLinkStringIsSingle)) { - expandCollapseButton = '<button class="expand-collapse-button"><i class="fa"></i></button>'; - htmlTag = '<pre class="shrink code-block ' + (isMatchJSONStringIsSingle ? 'fixed-height' : '') + '">' + expandCollapseButton + '<code>' + val + '</code></pre>'; + if ((matchedJson) || (matchedLinkString)) { + var className = "code-block fixed-height"; + if (!isMatchJSONStringIsSingle) { + className += " shrink"; + expandCollapseButton = '<button class="expand-collapse-button"><i class="fa"></i></button>'; + } + htmlTag = '<pre class="' + className + '">' + expandCollapseButton + '<code>' + val + '</code></pre>'; } } table += '<tr class="' + appendClass + '"><td>' + (_.escape(key) + listCount) + '</td><td>' + htmlTag + '</td></tr>'; diff --git a/dashboardv2/public/js/views/graph/LineageLayoutView.js b/dashboardv2/public/js/views/graph/LineageLayoutView.js index 5d0b70b..aa26580 100644 --- a/dashboardv2/public/js/views/graph/LineageLayoutView.js +++ b/dashboardv2/public/js/views/graph/LineageLayoutView.js @@ -134,13 +134,13 @@ define(['require', }, onShow: function() { this.$('.fontLoader').show(); - this.$el.resizable({ - handles: ' s', - minHeight: 375, - stop: function(event, ui) { - ui.element.height(($(this).height())); - }, - }); + // this.$el.resizable({ + // handles: ' s', + // minHeight: 375, + // stop: function(event, ui) { + // ui.element.height(($(this).height())); + // }, + // }); }, onClickLineageFullscreenToggler: function(e) { var icon = $(e.currentTarget).find('i'), @@ -152,6 +152,11 @@ define(['require', icon.parent('button').attr("data-original-title", "Default View"); } panel.toggleClass('fullscreen-mode'); + var node = this.$("svg").parent()[0].getBoundingClientRect(); + this.LineageHelperRef.updateOptions({ + width: node.width, + height: node.height + }); }, onCheckUnwantedEntity: function(e) { var that = this; @@ -210,6 +215,8 @@ define(['require', }, onClickResetLineage: function() { this.LineageHelperRef.refresh(); + this.searchNodeObj.selectedNode = ""; + this.ui.lineageTypeSearch.data({ refresh: true }).val("").trigger("change"); }, onClickSaveSvg: function(e, a) { this.LineageHelperRef.exportLineage(); @@ -249,10 +256,6 @@ define(['require', }) }, createGraph: function(data) { - // if (_.isEmpty(this.g._nodes)) { - // this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>'); - // return; - // } var that = this; $('.resizeGraph').css("height", this.$('.svg').height() + "px"); @@ -364,9 +367,13 @@ define(['require', }).on('change.select2', function(e) { e.stopPropagation(); e.stopImmediatePropagation(); - var selectedNode = $('[data-id="typeSearch"]').val(); - that.searchNodeObj.selectedNode = selectedNode; - that.LineageHelperRef.searchNode({ guid: selectedNode }); + if (!that.ui.lineageTypeSearch.data("refresh")) { + var selectedNode = $('[data-id="typeSearch"]').val(); + that.searchNodeObj.selectedNode = selectedNode; + that.LineageHelperRef.searchNode({ guid: selectedNode }); + } else { + that.ui.lineageTypeSearch.data("refresh", false); + } }); if (this.searchNodeObj.selectedNode) { this.ui.lineageTypeSearch.val(this.searchNodeObj.selectedNode); diff --git a/dashboardv2/public/js/views/graph/TypeSystemTreeView.js b/dashboardv2/public/js/views/graph/TypeSystemTreeView.js index 3095bca..90734a4 100644 --- a/dashboardv2/public/js/views/graph/TypeSystemTreeView.js +++ b/dashboardv2/public/js/views/graph/TypeSystemTreeView.js @@ -55,16 +55,23 @@ define([ typeSystemTreeViewPage: "[data-id='typeSystemTreeViewPage']", boxClose: '[data-id="box-close"]', nodeDetailTable: '[data-id="nodeDetailTable"]', + attributeTable: '[data-id="attribute-table"]', typeSearch: '[data-id="typeSearch"]', filterServiceType: '[data-id="filterServiceType"]', onZoomIn: '[data-id="zoom-in"]', onZoomOut: '[data-id="zoom-out"]', filterBox: ".filter-box", searchBox: ".search-box", + settingBox: '.setting-box', filterToggler: '[data-id="filter-toggler"]', + settingToggler: '[data-id="setting-toggler"]', searchToggler: '[data-id="search-toggler"]', reset: '[data-id="reset"]', - fullscreenToggler: '[data-id="fullScreen-toggler"]' + fullscreenToggler: '[data-id="fullScreen-toggler"]', + noValueToggle: "[data-id='noValueToggle']", + showOnlyHoverPath: '[data-id="showOnlyHoverPath"]', + showTooltip: '[data-id="showTooltip"]', + saveSvg: '[data-id="saveSvg"]', }, /** ui events hash */ events: function() { @@ -73,9 +80,19 @@ define([ events["click " + this.ui.onZoomIn] = "onClickZoomIn"; events["click " + this.ui.onZoomOut] = "onClickZoomOut"; events["click " + this.ui.filterToggler] = "onClickFilterToggler"; + events["click " + this.ui.settingToggler] = 'onClickSettingToggler'; events["click " + this.ui.searchToggler] = "onClickSearchToggler"; + events["click " + this.ui.saveSvg] = 'onClickSaveSvg'; events["click " + this.ui.fullscreenToggler] = "onClickFullscreenToggler"; events["click " + this.ui.reset] = "onClickReset"; + events["click " + this.ui.noValueToggle] = function() { + this.showAllProperties = !this.showAllProperties; + this.ui.noValueToggle.attr("data-original-title", (this.showAllProperties ? "Hide" : "Show") + " empty values"); + Utils.togglePropertyRelationshipTableEmptyValues({ + "inputType": this.ui.noValueToggle, + "tableEl": this.ui.nodeDetailTable + }); + }; return events; }, @@ -90,7 +107,35 @@ define([ this.initializeGraph(); this.fetchGraphData(); }, - onRender: function() {}, + onRender: function() { + var that = this; + this.$el.on("click", "code li[data-def]", function() { + if (that.selectedDetailNode) { + var dataObj = $(this).data(), + defObj = that.selectedDetailNode[dataObj.def], + newData = null; + if (dataObj.def === "businessAttributes") { + newData = defObj[dataObj.attribute]; + } else { + newData = _.filter(defObj, { name: dataObj.attribute }); + } + that.ui.attributeTable.find("pre").html('<code style="max-height: 100%">' + Utils.JSONPrettyPrint(newData, function(val) { + return val; + }) + '</code>'); + that.$el.find('[data-id="typeAttrDetailHeader"]').text(dataObj.def); + that.ui.nodeDetailTable.hide("slide", { direction: "right" }, 400); + that.ui.attributeTable.show("slide", { direction: "left" }, 400); + that.$el.find(".typeDetailHeader").hide(); + that.$el.find(".typeAttrDetailHeader").show() + } + }); + this.$el.on("click", "span[data-id='box-back']", function() { + that.ui.nodeDetailTable.show("slide", { direction: "right" }, 400); + that.ui.attributeTable.hide("slide", { direction: "left" }, 400); + that.$el.find(".typeDetailHeader").show(); + that.$el.find(".typeAttrDetailHeader").hide() + }) + }, fetchGraphData: function(options) { var that = this; var entityTypeDef = that.entityDefCollection.fullCollection.toJSON(); @@ -101,7 +146,7 @@ define([ } if (entityTypeDef.length) { that.generateData($.extend(true, {}, { data: entityTypeDef }, options)).then(function(graphObj) { - that.createGraph(); + that.createGraph(options); }); } }, @@ -161,91 +206,56 @@ define([ if (options.data) { if (options.filter) { - var pendingSubList = {}, - pendingSuperList = {}, - temp = {}, - doneList = {}, - traveseSubSuper = function(obj, ignoreSubTypes) { - var fromEntityId = obj.guid; - if (!ignoreSubTypes && obj.subTypes.length) { - _.each(obj.subTypes, function(subType) { - var tempObj = doneList[subType] || temp[subType]; - if (tempObj) { + // filter + var pendingSuperList = {}, + outOfFilterData = {}, + doneList = {}; + + var linkParents = function(obj) { + if (obj && obj.superTypes.length) { + _.each(obj.superTypes, function(superType) { + var fromEntityId = obj.guid; + var tempObj = doneList[superType] || outOfFilterData[superType]; + if (tempObj) { + if (!doneList[superType]) { setNode(tempObj.guid, tempObj); - setEdge(fromEntityId, tempObj.guid); - } else { - if (pendingSubList[subType]) { - pendingSubList[subType].push(fromEntityId); - } else { - pendingSubList[subType] = [fromEntityId]; - } } - }); - } - if (obj.superTypes.length) { - _.each(obj.superTypes, function(superType) { - var tempObj = doneList[superType] || temp[superType]; - if (tempObj) { - setNode(tempObj.guid, tempObj); - setEdge(tempObj.guid, fromEntityId); - if (tempObj.superTypes.length) { - traveseSubSuper(tempObj, true); - } + setEdge(tempObj.guid, fromEntityId); + linkParents(tempObj); + } else { + if (pendingSuperList[superType]) { + pendingSuperList[superType].push(fromEntityId); } else { - if (pendingSuperList[superType]) { - pendingSuperList[superType].push(fromEntityId); - } else { - pendingSuperList[superType] = [fromEntityId]; - } + pendingSuperList[superType] = [fromEntityId]; } - }); - } - }; + } + }); + } + } _.each(options.data, function(obj) { var fromEntityId = obj.guid; + if (pendingSuperList[obj.name]) { + doneList[obj.name] = obj; + setNode(fromEntityId, obj); + _.map(pendingSuperList[obj.name], function(guid) { + setEdge(fromEntityId, guid); + }); + delete pendingSuperList[obj.name]; + linkParents(obj); + } if (obj.serviceType === options.filter) { doneList[obj.name] = obj; setNode(fromEntityId, obj); - if (pendingSubList[obj.name]) { - _.map(pendingSubList[obj.name], function(guid) { - setEdge(guid, fromEntityId); - }); - delete pendingSubList[obj.name]; - } - if (pendingSuperList[obj.name]) { - _.map(pendingSuperList[obj.name], function(guid) { - setEdge(fromEntityId, guid); - }); - delete pendingSuperList[obj.name]; - } - traveseSubSuper(obj); - } else { - if (pendingSubList[obj.name]) { - setNode(fromEntityId, obj); - doneList[obj.name] = obj; - _.map(pendingSubList[obj.name], function(guid) { - setEdge(guid, fromEntityId); - }); - delete pendingSubList[obj.name]; - } - if (pendingSuperList[obj.name]) { - var fromEntityId = obj.guid; - setNode(fromEntityId, obj); - doneList[obj.name] = obj; - _.map(pendingSuperList[obj.name], function(guid) { - setEdge(fromEntityId, guid); - }); - delete pendingSuperList[obj.name]; - } - if (!doneList[obj.name]) { - temp[obj.name] = obj; - } + linkParents(obj); + } else if (!doneList[obj.name] && !outOfFilterData[obj.name]) { + outOfFilterData[obj.name] = obj; } }); - pendingSubList = null; pendingSuperList = null; doneList = null; + outOfFilterData = null; } else { + // Without filter var pendingList = {}, doneList = {}; @@ -308,11 +318,19 @@ define([ onClickFilterToggler: function() { this.toggleBoxPanel({ el: this.ui.filterBox }); }, + onClickSettingToggler: function() { + this.toggleBoxPanel({ el: this.ui.settingBox }); + }, onClickSearchToggler: function() { this.toggleBoxPanel({ el: this.ui.searchBox }); }, onClickReset: function() { this.fetchGraphData({ refresh: true }); + this.ui.typeSearch.data({ refresh: true }).val("").trigger("change"); + this.ui.filterServiceType.data({ refresh: true }).val("").trigger("change"); + }, + onClickSaveSvg: function(e, a) { + this.LineageHelperRef.exportLineage({ downloadFileName: "TypeSystemView" }); }, onClickFullscreenToggler: function(e) { var icon = $(e.currentTarget).find("i"), @@ -324,42 +342,65 @@ define([ icon.parent("button").attr("data-original-title", "Default View"); } panel.toggleClass("fullscreen-mode"); + var node = this.$("svg.main").parent()[0].getBoundingClientRect(); + this.LineageHelperRef.updateOptions({ + width: node.width, + height: node.height + }); }, updateDetails: function(data) { this.$("[data-id='typeName']").text(Utils.getName(data)); - delete data.id; + + this.selectedDetailNode = {}; + this.selectedDetailNode.atttributes = data.attributeDefs; + this.selectedDetailNode.businessAttributes = data.businessAttributeDefs; + this.selectedDetailNode.relationshipAttributes = data.relationshipAttributeDefs; //atttributes data["atttributes"] = (data.attributeDefs || []).map(function(obj) { return obj.name; }); - delete data.attributeDefs; //businessAttributes data["businessAttributes"] = _.keys(data.businessAttributeDefs); - delete data.businessAttributeDefs; //relationshipAttributes data["relationshipAttributes"] = (data.relationshipAttributeDefs || []).map(function(obj) { return obj.name; }); - delete data.relationshipAttributeDefs; - - console.log(data); this.ui.nodeDetailTable.html( CommonViewFunction.propertyTable({ scope: this, guidHyperLink: false, + getValue: function(val, key) { + if (key && key.toLowerCase().indexOf("time") > 0) { + return Utils.formatDate({ date: val }); + } else { + return val; + } + }, + getArrayOfStringElement: function(val, key) { + var def = null, + classname = "json-string"; + if (key === "atttributes" || key === "businessAttributes" || key === "relationshipAttributes") { + def = key; + classname += " cursor"; + } + return "<li class='" + classname + "' " + (def ? 'data-def="' + def + '" data-attribute="' + val + '"' : '') + ">" + val + "</li>" + }, + getArrayOfStringFormat: function(valueArray) { + return valueArray.join(""); + }, getEmptyString: function(key) { if (key === "subTypes" || key === "superTypes" || key === "atttributes" || key === "relationshipAttributes") { return "[]"; } return "N/A"; }, - valueObject: _.omit(data, ["isLineage", "isIncomplete", "label", "shape", "toolTipLabel", "updatedValues"]), + valueObject: _.omit(data, ["id", "attributeDefs", "relationshipAttributeDefs", "businessAttributeDefs", "isLineage", "isIncomplete", "label", "shape", "toolTipLabel", "updatedValues"]), sortBy: true }) ); }, - createGraph: function(refresh) { + createGraph: function(opt) { this.LineageHelperRef.createGraph(); }, filterData: function(value) { @@ -377,12 +418,14 @@ define([ setDataManually: true, width: node.width, height: node.height, - isShowHoverPath: true, zoom: true, fitToScreen: true, dagreOptions: { rankdir: "tb" }, + toolTipTitle: "Type", + isShowHoverPath: function() { return that.ui.showOnlyHoverPath.prop('checked') }, + isShowTooltip: function() { return that.ui.showTooltip.prop('checked') }, onNodeClick: function(d) { that.onClickNodeToggler(); that.updateDetails(that.LineageHelperRef.getNode(d.clickedData, true)); @@ -425,14 +468,17 @@ define([ this.ui.typeSearch .select2({ closeOnSelect: true, - placeholder: "Select Node" + placeholder: "Select Type" }) .on("change.select2", function(e) { e.stopPropagation(); e.stopImmediatePropagation(); - var selectedNode = $('[data-id="typeSearch"]').val(); - //that.searchNodeObj.selectedNode = selectedNode; - that.LineageHelperRef.searchNode({ guid: selectedNode }); + if (!that.ui.typeSearch.data("refresh")) { + var selectedNode = $('[data-id="typeSearch"]').val(); + that.LineageHelperRef.searchNode({ guid: selectedNode }); + } else { + that.ui.typeSearch.data("refresh", false); + } }); if (!this.ui.filterServiceType.data("select2")) { this.ui.filterServiceType @@ -443,15 +489,13 @@ define([ .on("change.select2", function(e) { e.stopPropagation(); e.stopImmediatePropagation(); - var selectedNode = $('[data-id="filterServiceType"]').val(); - that.filterData(selectedNode); - //that.searchNodeObj.selectedNode = selectedNode; - //that.LineageHelperRef.searchNode({ guid: selectedNode }); + if (!that.ui.filterServiceType.data("refresh")) { + var selectedNode = $('[data-id="filterServiceType"]').val(); + that.filterData(selectedNode); + } else { + that.ui.filterServiceType.data("refresh", false); + } }); - // if (this.searchNodeObj.selectedNode) { - // this.ui.typeSearch.val(this.searchNodeObj.selectedNode); - // this.ui.typeSearch.trigger("change.select2"); - // } } } }); diff --git a/dashboardv3/public/css/scss/common.scss b/dashboardv3/public/css/scss/common.scss index 008dca0..c620838 100644 --- a/dashboardv3/public/css/scss/common.scss +++ b/dashboardv3/public/css/scss/common.scss @@ -180,6 +180,11 @@ pre { .json-string { color: olive; + + &.cursor { + cursor: pointer; + text-decoration: underline; + } } } @@ -191,6 +196,11 @@ pre { .panel-body .memory-details { pre { &.code-block { + &.fixed-height { + max-height: 112px; + overflow: auto; + } + &.shrink { height: 144px; diff --git a/dashboardv3/public/css/scss/graph.scss b/dashboardv3/public/css/scss/graph.scss index abfa42c..69d451b 100644 --- a/dashboardv3/public/css/scss/graph.scss +++ b/dashboardv3/public/css/scss/graph.scss @@ -197,7 +197,7 @@ span#zoom_in { width: 100%; right: 0; padding: 0 !important; - z-index: 9999; + z-index: 99; overflow: hidden !important; background: white; @@ -277,4 +277,38 @@ span#zoom_in { box-shadow: 0px 0px 3px 1px #80808080; } +} + + +.box-panel.fix-box { + position: fixed; + top: 0; + right: 0; + bottom: 0; + height: 100vh; + max-height: 100vh; + z-index: 999; + bottom: 0; + width: 400px; + overflow: auto; + border-radius: 0px; + margin: 0 !important; + + &.slide-from-left.size-lg { + left: -413px; + + &.show-box-panel { + left: 0; + margin: 0 !important; + } + } + + .body { + tbody { + overflow: auto; + height: calc(100vh - 48px); + position: absolute; + padding-bottom: 15px; + } + } } \ No newline at end of file diff --git a/dashboardv3/public/css/scss/table.scss b/dashboardv3/public/css/scss/table.scss index 519d083..6b78edf 100644 --- a/dashboardv3/public/css/scss/table.scss +++ b/dashboardv3/public/css/scss/table.scss @@ -41,6 +41,7 @@ tr.empty { } .entity-detail-table, +.type-node-details, .relationship-detail-table { position: relative; @@ -66,6 +67,26 @@ tr.empty { } } +.type-node-details { + .header { + .pretty.p-switch .state:before { + border: 1px solid white; + } + + .pretty.p-switch .state label:after { + background-color: white !important; + } + + .pretty.p-switch.p-fill input:checked~.state label:after { + background-color: #4a90e2 !important; + } + + .pretty.p-switch.p-fill input:checked~.state.p-primary:before { + background-color: white !important; + } + } +} + .backgrid { td { white-space: normal; @@ -98,6 +119,14 @@ tr.empty { } } } + + .debuggging-table-header { + padding-right: 0px !important; + + button { + float: right; + } + } } .backgrid-paginator ul { diff --git a/dashboardv3/public/js/external_lib/atlas-lineage/dist/index.js b/dashboardv3/public/js/external_lib/atlas-lineage/dist/index.js index c2f68bb..e82cb48 100644 --- a/dashboardv3/public/js/external_lib/atlas-lineage/dist/index.js +++ b/dashboardv3/public/js/external_lib/atlas-lineage/dist/index.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("platform"),require("dagreD3")):"function"==typeof define&&define.amd?define(["platform","dagreD3"],e):"object"==typeof exports?exports.LineageHelper=e(require("platform"),require("dagreD3")):t.LineageHelper=e(t.platform,t.dagreD3)}(window,(function(t,e){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i. [...] \ No newline at end of file +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("platform"),require("dagreD3")):"function"==typeof define&&define.amd?define(["platform","dagreD3"],e):"object"==typeof exports?exports.LineageHelper=e(require("platform"),require("dagreD3")):t.LineageHelper=e(t.platform,t.dagreD3)}(window,(function(t,e){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i. [...] \ No newline at end of file diff --git a/dashboardv3/public/js/external_lib/atlas-lineage/src/Utils/LineageUtils.js b/dashboardv3/public/js/external_lib/atlas-lineage/src/Utils/LineageUtils.js index 7c482b3..55f363e 100644 --- a/dashboardv3/public/js/external_lib/atlas-lineage/src/Utils/LineageUtils.js +++ b/dashboardv3/public/js/external_lib/atlas-lineage/src/Utils/LineageUtils.js @@ -374,7 +374,7 @@ const LineageUtils = { reader.addEventListener("load", () => callback(reader.result)); reader.readAsDataURL(file); }, - imgShapeRender: function (parent, bbox, node, { dagreD3, defsEl, imgBasePath, guid }) { + imgShapeRender: function (parent, bbox, node, { dagreD3, defsEl, imgBasePath, guid, isRankdirToBottom }) { var that = this, viewGuid = guid, imageIconPath = this.getEntityIconPath({ entityData: node, imgBasePath }), @@ -391,7 +391,7 @@ const LineageUtils = { var shapeSvg = parent .append("circle") .attr("fill", "url(#img_" + imgName + ")") - .attr("r", "24px") + .attr("r", isRankdirToBottom ? "30px" : "24px") .attr("data-stroke", node.id) .attr("stroke-width", "2px") .attr("class", "nodeImage " + (currentNode ? "currentNode" : node.isProcess ? "process" : "node")); @@ -478,8 +478,8 @@ const LineageUtils = { }); } }) - .attr("x", "4") - .attr("y", currentNode ? "3" : "4") + .attr("x", isRankdirToBottom ? "11" : "4") + .attr("y", isRankdirToBottom ? "20" : currentNode ? "3" : "4") .attr("width", "40") .attr("height", "40"); } diff --git a/dashboardv3/public/js/external_lib/atlas-lineage/src/index.js b/dashboardv3/public/js/external_lib/atlas-lineage/src/index.js index 1ac517a..3ceb3d9 100644 --- a/dashboardv3/public/js/external_lib/atlas-lineage/src/index.js +++ b/dashboardv3/public/js/external_lib/atlas-lineage/src/index.js @@ -26,6 +26,7 @@ import "./styles/style.scss"; export default class LineageHelper { constructor(options) { + this.options = {}; this._updateOptions(options); const { el, manualTrigger = false } = this.options; if (el === undefined) { @@ -33,6 +34,7 @@ export default class LineageHelper { } this.initReturnObj = { init: (arg) => this.init(arg), + updateOptions: (options) => this._updateAllOptions(options), createGraph: (opt = {}) => this._createGraph(this.options, this.graphOptions, opt), clear: (arg) => this.clear(arg), refresh: (arg) => this.refresh(arg), @@ -78,12 +80,27 @@ export default class LineageHelper { return this.initReturnObj; } /** + * [updateAllOptions] + * @param {[type]} + * @return {[type]} + */ + _updateAllOptions(options) { + Object.assign(this.options, options); + var svgRect = this.svg.node().getBoundingClientRect(); + this.graphOptions.width = this.options.width || svgRect.width; + this.graphOptions.height = this.options.height || svgRect.height; + const { svg, width, height, guid } = this.graphOptions; + const { fitToScreen } = this.options; + svg.select("g").node().removeAttribute("transform"); + svg.attr("viewBox", "0 0 " + width + " " + height).attr("enable-background", "new 0 0 " + width + " " + height); + this.centerAlign({ fitToScreen, guid }); + } + /** * [updateOptions get the options from user and appedn add it in this,option context] * @param {[Object]} options [lib options from user] * @return {[null]} [null] */ _updateOptions(options) { - this.options = {}; Object.assign(this.options, { filterObj: { isProcessHideCheck: false, isDeletedEntityHideCheck: false } }, options); } /** @@ -200,7 +217,7 @@ export default class LineageHelper { if (node && node.attributes) { downloadFileName = `${node.attributes.qualifiedName || node.attributes.name || "lineage_export"}.png`; } else { - downloadFileName = "lineage_export.png"; + downloadFileName = "export.png"; } } @@ -258,6 +275,7 @@ export default class LineageHelper { this.svg = select(el); if (!(el instanceof SVGElement)) { + this.svg.selectAll("*").remove(); this.svg = this.svg .append("svg") .attr("xmlns", "http://www.w3.org/2000/svg") @@ -385,7 +403,19 @@ export default class LineageHelper { * @return {[type]} [description] */ _createGraph( - { data = {}, imgBasePath, isShowTooltip, isShowHoverPath, onLabelClick, onPathClick, onNodeClick, zoom, fitToScreen }, + { + data = {}, + imgBasePath, + isShowTooltip, + isShowHoverPath, + onLabelClick, + onPathClick, + onNodeClick, + zoom, + fitToScreen, + getToolTipContent, + toolTipTitle + }, graphOptions, { refresh } ) { @@ -393,7 +423,8 @@ export default class LineageHelper { this.options.beforeRender(); } const that = this, - { svg, g, width, height } = graphOptions; + { svg, g, width, height } = graphOptions, + isRankdirToBottom = this.options.dagreOptions && this.options.dagreOptions.rankdir === "tb"; if (svg instanceof selection === false) { throw new Error("svg is not initialized or something went wrong while creatig graph instance"); @@ -428,6 +459,7 @@ export default class LineageHelper { render.shapes().img = function () { return LineageUtils.imgShapeRender(...arguments, { ...graphOptions, + isRankdirToBottom: isRankdirToBottom, imgBasePath: that._getValueFromUser(imgBasePath), defsEl }); @@ -437,19 +469,26 @@ export default class LineageHelper { .attr("class", "d3-tip") .offset([10, 0]) .html((d) => { - var value = g.node(d); - var htmlStr = ""; - if (value.id !== this.guid) { - htmlStr = "<h5 style='text-align: center;'>" + (value.isLineage ? "Lineage" : "Impact") + "</h5>"; - } - htmlStr += "<h5 class='text-center'><span style='color:#359f89'>" + value.toolTipLabel + "</span></h5> "; - if (value.typeName) { - htmlStr += "<h5 class='text-center'><span>(" + value.typeName + ")</span></h5> "; - } - if (value.queryText) { - htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> "; + if (getToolTipContent && typeof getToolTipContent === "function") { + return getToolTipContent(d, g.node(d)); + } else { + var value = g.node(d); + var htmlStr = ""; + if (toolTipTitle) { + htmlStr = "<h5 style='text-align: center;'>" + toolTipTitle + "</h5>"; + } else if (value.id !== this.guid) { + htmlStr = "<h5 style='text-align: center;'>" + (value.isLineage ? "Lineage" : "Impact") + "</h5>"; + } + + htmlStr += "<h5 class='text-center'><span style='color:#359f89'>" + value.toolTipLabel + "</span></h5> "; + if (value.typeName) { + htmlStr += "<h5 class='text-center'><span>(" + value.typeName + ")</span></h5> "; + } + if (value.queryText) { + htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> "; + } + return "<div class='tip-inner-scroll'>" + htmlStr + "</div>"; } - return "<div class='tip-inner-scroll'>" + htmlStr + "</div>"; }); svg.call(tooltip); @@ -463,7 +502,12 @@ export default class LineageHelper { //change text postion svgGroupEl .selectAll("g.nodes g.label") - .attr("transform", "translate(2,-35)") + .attr("transform", () => { + if (isRankdirToBottom) { + return "translate(2,-20)"; + } + return "translate(2,-35)"; + }) .on("mouseenter", function (d) { event.preventDefault(); select(this).classed("highlight", true); diff --git a/dashboardv3/public/js/templates/administrator/AdministratorLayoutView_tmpl.html b/dashboardv3/public/js/templates/administrator/AdministratorLayoutView_tmpl.html index f9ca214..85bf9ba 100644 --- a/dashboardv3/public/js/templates/administrator/AdministratorLayoutView_tmpl.html +++ b/dashboardv3/public/js/templates/administrator/AdministratorLayoutView_tmpl.html @@ -37,7 +37,7 @@ <div id="r_adminTableLayoutView"> </div> </div> - <div id="tab-typeSystem" role="typeSystem" class="tab-pane animated fadeIn" style="position: relative;"> + <div id="tab-typeSystem" role="typeSystem" class="tab-pane" style="position: relative;"> <div id="r_typeSystemTreeLayoutView"> </div> </div> diff --git a/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html index 17a8d10..18fc1f9 100644 --- a/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html +++ b/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html @@ -94,7 +94,7 @@ </div> </div> </div> - <div id="tab-lineage" role="lineage" class="tab-pane animated fadeIn"> + <div id="tab-lineage" role="lineage" class="tab-pane"> <div id="r_lineageLayoutView" class="animated position-relative" align="center"> <div class="fontLoader-relative"> <i class="fa fa-refresh fa-spin-custom"></i> diff --git a/dashboardv3/public/js/templates/graph/LineageLayoutView_tmpl.html b/dashboardv3/public/js/templates/graph/LineageLayoutView_tmpl.html index 8e6e6b2..f6f61e2 100644 --- a/dashboardv3/public/js/templates/graph/LineageLayoutView_tmpl.html +++ b/dashboardv3/public/js/templates/graph/LineageLayoutView_tmpl.html @@ -124,22 +124,22 @@ </button> </div> </div> - <div class="box-panel size-lg node-details slide-from-left lineage-node-detail"> - <div class="header clearfix"> - <h4><span data-id="typeName"></span></h4> - <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> - <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> - </div> - <div class="body"> - <table class="table bold-key"> - <tbody data-id="nodeDetailTable"></tbody> - </table> - </div> - </div> <div class="fontLoader"> <i class="fa fa-refresh fa-spin-custom"></i> </div> <div class="legends pull-left" style="height: 25px; padding: 2px;"></div> <div class="svg" style="height: 100%; width: 100%"></div> </div> +<div class="box-panel size-lg slide-from-left lineage-node-detail fix-box"> + <div class="header clearfix"> + <h4><span data-id="typeName"></span></h4> + <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> + <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> + </div> + <div class="body"> + <table class="table bold-key"> + <tbody data-id="nodeDetailTable"></tbody> + </table> + </div> +</div> <div class="hidden-svg"></div> \ No newline at end of file diff --git a/dashboardv3/public/js/templates/graph/TypeSystemTreeView_tmpl.html b/dashboardv3/public/js/templates/graph/TypeSystemTreeView_tmpl.html index 5340de4..005c061 100644 --- a/dashboardv3/public/js/templates/graph/TypeSystemTreeView_tmpl.html +++ b/dashboardv3/public/js/templates/graph/TypeSystemTreeView_tmpl.html @@ -15,16 +15,30 @@ * limitations under the License. --> <div id="typeSystemTreeViewPage" data-id="typeSystemTreeViewPage" class="systemTypeTree" style="height: calc(100vh - 180px); width: 100%; position: relative;overflow: hidden;"> - <div class="box-panel size-lg node-details slide-from-left lineage-node-detail"> + <div class="box-panel size-lg type-node-details fix-box slide-from-left lineage-node-detail"> <div class="header clearfix"> - <h4><span data-id="typeName"></span></h4> - <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> - <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span> + <div class="typeDetailHeader"> + <h4 style="padding-right: 67px;"><span data-id="typeName"></span></h4> + <div class="pretty p-switch p-fill" style="position: absolute;top: 13px;right: 32px;"> + <input type="checkbox" data-id="noValueToggle" title="Show empty values" /> + <div class="state p-primary"> + <label></label> + </div> + </div> + <span data-id="box-close" class="btn btn-sm btn-close "><i class="fa fa-close"></i></span> + </div> + <div class="typeAttrDetailHeader" style="display: none;"> + <span data-id="box-back" class="btn btn-sm btn-close" style="left: 0px; right: auto;"><i class="fa fa-angle-left"></i></span> + <h4 style="padding-left: 27px;"><span data-id="typeAttrDetailHeader"></span></h4> + </div> </div> <div class="body"> <table class="table bold-key"> - <tbody data-id="nodeDetailTable"></tbody> + <tbody data-id="nodeDetailTable" class="hide-empty-value"></tbody> </table> + <div data-id="attribute-table" style="height: calc(100vh - 60px);display: none"> + <pre class="code-block" style="height: 100%"></pre> + </div> </div> </div> <div class="fontLoader"> @@ -49,7 +63,6 @@ <div class="body"> <div class="col-sm-12 no-padding"> <div class="srchType clearfix"> - <label class="srchTitle">Search Lineage Entity: </label> <div class=""> <div class="col-sm-12 no-padding temFilter"> <select data-id="typeSearch"></select> @@ -59,28 +72,62 @@ </div> </div> </div> + <div class="box-panel setting-box"> + <div class="header clearfix"> + <h4>Settings</h4> + <span data-id="box-close" class="btn btn-sm btn-close"><i class="fa fa-close"></i></span> + </div> + <div class="body"> + <div class="showOnlyHoverPath form-group text-left col-sm-12"> + <div class="pretty p-switch p-fill"> + <input type="checkbox" checked class="pull-left" data-id="showOnlyHoverPath" value="" /> + <div class="state p-primary"> + <label>On hover show current path</label> + </div> + </div> + </div> + <div class="showTooltip form-group text-left col-sm-12"> + <div class="pretty p-switch p-fill"> + <input type="checkbox" class="pull-left" data-id="showTooltip" value="" /> + <div class="state p-primary"> + <label>Show node details on hover</label> + </div> + </div> + </div> + </div> + </div> <div class="graph-button-group pull-right"> <div> - <button data-id="reset" class="btn btn-action btn-gray btn-sm" title="Realign Lineage"> + <button data-id="reset" class="btn btn-action btn-gray btn-sm" title="Reset"> <i class="fa fa-retweet"></i> </button> </div> <div> + <button data-id="saveSvg" class="btn btn-action btn-gray btn-sm" title="Export to PNG"> + <i class="fa fa-camera"></i> + </button> + </div> + <div> + <button type="button" data-id="setting-toggler" title="Settings" class="btn btn-action btn-gray btn-sm"> + <i class="fa fa-gear"></i> + </button> + </div> + <div> <button type="button" data-id="filter-toggler" title="Filter" class="btn btn-action btn-gray btn-sm"><i class="fa fa-filter"></i></button> </div> <div> <button type="button" data-id="search-toggler" title="Search" class="btn btn-action btn-gray btn-sm"><i class="fa fa-search"></i></button> </div> <div class="btn-group"> - <button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom In" data-id="zoom-in"> + <button type="button" class="btn btn-action btn-gray btn-sm" title="Zoom In" data-id="zoom-in"> <i class="fa fa-search-plus"></i> </button> - <button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom Out" data-id="zoom-out"> + <button type="button" class="btn btn-action btn-gray btn-sm" title="Zoom Out" data-id="zoom-out"> <i class="fa fa-search-minus"></i> </button> </div> <div> - <button type="button" data-id="fullScreen-toggler" title="Full screen" class="btn btn-action btn-gray btn-sm fullscreen_lineage"> + <button type="button" data-id="fullScreen-toggler" title="Full screen" class="btn btn-action btn-gray btn-sm"> <i class="fa fa-expand"></i> </button> </div> diff --git a/dashboardv3/public/js/utils/CommonViewFunction.js b/dashboardv3/public/js/utils/CommonViewFunction.js index 40d489e..2573a60 100644 --- a/dashboardv3/public/js/utils/CommonViewFunction.js +++ b/dashboardv3/public/js/utils/CommonViewFunction.js @@ -79,6 +79,8 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum sortBy = options.sortBy, valueObject = options.valueObject, extractJSON = options.extractJSON, + getArrayOfStringElement = options.getArrayOfStringElement, + getArrayOfStringFormat = options.getArrayOfStringFormat, isTable = _.isUndefined(options.isTable) ? true : options.isTable, attributeDefs = options.attributeDefs, formatIntVal = options.formatIntVal, @@ -108,6 +110,9 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum return "N/A"; }, getValue = function(val, key) { + if (options && options.getValue) { + val = options.getValue(val, key); + } if (!_.isUndefined(val) && !_.isNull(val)) { if ((_.isNumber(val) || !_.isNaN(parseInt(val))) && formatIntVal) { return numberFormat(val); @@ -185,7 +190,12 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum if (_.isString(inputOutputField) || _.isBoolean(inputOutputField) || _.isNumber(inputOutputField)) { var tempVarfor$check = inputOutputField.toString(); if (tempVarfor$check.indexOf("$") == -1) { - valueOfArray.push('<span class="json-string">' + getValue(inputOutputField, key) + '</span>'); + var tmpVal = getValue(inputOutputField, key) + if (getArrayOfStringElement) { + valueOfArray.push(getArrayOfStringElement(tmpVal, key)); + } else { + valueOfArray.push('<span class="json-string">' + tmpVal + '</span>'); + } } } else if (_.isObject(inputOutputField) && !id) { var attributesList = inputOutputField; @@ -251,7 +261,11 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum } } if (valueOfArray.length) { - subLink = valueOfArray.join(', '); + if (getArrayOfStringFormat) { + subLink = getArrayOfStringFormat(valueOfArray, key); + } else { + subLink = valueOfArray.join(', '); + } } return subLink === "" ? getEmptyString(key) : subLink; } @@ -297,12 +311,17 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum if (_.isObject(valueObject[key]) && !_.isEmpty(valueObject[key])) { var matchedLinkString = val.match(/href|value-loader\w*/g), matchedJson = val.match(/json-value|json-string\w*/g), + matchedKey = val.match(/json-key\w*/g), isMatchLinkStringIsSingle = matchedLinkString && matchedLinkString.length <= 5, isMatchJSONStringIsSingle = matchedJson && matchedJson.length == 1, expandCollapseButton = ""; - if ((matchedJson && !isMatchJSONStringIsSingle) || (matchedLinkString && !isMatchLinkStringIsSingle)) { - expandCollapseButton = '<button class="expand-collapse-button"><i class="fa"></i></button>'; - htmlTag = '<pre class="shrink code-block ' + (isMatchJSONStringIsSingle ? 'fixed-height' : '') + '">' + expandCollapseButton + '<code>' + val + '</code></pre>'; + if ((matchedJson) || (matchedLinkString)) { + var className = "code-block fixed-height"; + if (!isMatchJSONStringIsSingle) { + className += " shrink"; + expandCollapseButton = '<button class="expand-collapse-button"><i class="fa"></i></button>'; + } + htmlTag = '<pre class="' + className + '">' + expandCollapseButton + '<code>' + val + '</code></pre>'; } } table += '<tr class="' + appendClass + '"><td>' + (_.escape(key) + listCount) + '</td><td>' + htmlTag + '</td></tr>'; diff --git a/dashboardv3/public/js/views/graph/LineageLayoutView.js b/dashboardv3/public/js/views/graph/LineageLayoutView.js index 5d0b70b..aa26580 100644 --- a/dashboardv3/public/js/views/graph/LineageLayoutView.js +++ b/dashboardv3/public/js/views/graph/LineageLayoutView.js @@ -134,13 +134,13 @@ define(['require', }, onShow: function() { this.$('.fontLoader').show(); - this.$el.resizable({ - handles: ' s', - minHeight: 375, - stop: function(event, ui) { - ui.element.height(($(this).height())); - }, - }); + // this.$el.resizable({ + // handles: ' s', + // minHeight: 375, + // stop: function(event, ui) { + // ui.element.height(($(this).height())); + // }, + // }); }, onClickLineageFullscreenToggler: function(e) { var icon = $(e.currentTarget).find('i'), @@ -152,6 +152,11 @@ define(['require', icon.parent('button').attr("data-original-title", "Default View"); } panel.toggleClass('fullscreen-mode'); + var node = this.$("svg").parent()[0].getBoundingClientRect(); + this.LineageHelperRef.updateOptions({ + width: node.width, + height: node.height + }); }, onCheckUnwantedEntity: function(e) { var that = this; @@ -210,6 +215,8 @@ define(['require', }, onClickResetLineage: function() { this.LineageHelperRef.refresh(); + this.searchNodeObj.selectedNode = ""; + this.ui.lineageTypeSearch.data({ refresh: true }).val("").trigger("change"); }, onClickSaveSvg: function(e, a) { this.LineageHelperRef.exportLineage(); @@ -249,10 +256,6 @@ define(['require', }) }, createGraph: function(data) { - // if (_.isEmpty(this.g._nodes)) { - // this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>'); - // return; - // } var that = this; $('.resizeGraph').css("height", this.$('.svg').height() + "px"); @@ -364,9 +367,13 @@ define(['require', }).on('change.select2', function(e) { e.stopPropagation(); e.stopImmediatePropagation(); - var selectedNode = $('[data-id="typeSearch"]').val(); - that.searchNodeObj.selectedNode = selectedNode; - that.LineageHelperRef.searchNode({ guid: selectedNode }); + if (!that.ui.lineageTypeSearch.data("refresh")) { + var selectedNode = $('[data-id="typeSearch"]').val(); + that.searchNodeObj.selectedNode = selectedNode; + that.LineageHelperRef.searchNode({ guid: selectedNode }); + } else { + that.ui.lineageTypeSearch.data("refresh", false); + } }); if (this.searchNodeObj.selectedNode) { this.ui.lineageTypeSearch.val(this.searchNodeObj.selectedNode); diff --git a/dashboardv3/public/js/views/graph/TypeSystemTreeView.js b/dashboardv3/public/js/views/graph/TypeSystemTreeView.js index 3095bca..90734a4 100644 --- a/dashboardv3/public/js/views/graph/TypeSystemTreeView.js +++ b/dashboardv3/public/js/views/graph/TypeSystemTreeView.js @@ -55,16 +55,23 @@ define([ typeSystemTreeViewPage: "[data-id='typeSystemTreeViewPage']", boxClose: '[data-id="box-close"]', nodeDetailTable: '[data-id="nodeDetailTable"]', + attributeTable: '[data-id="attribute-table"]', typeSearch: '[data-id="typeSearch"]', filterServiceType: '[data-id="filterServiceType"]', onZoomIn: '[data-id="zoom-in"]', onZoomOut: '[data-id="zoom-out"]', filterBox: ".filter-box", searchBox: ".search-box", + settingBox: '.setting-box', filterToggler: '[data-id="filter-toggler"]', + settingToggler: '[data-id="setting-toggler"]', searchToggler: '[data-id="search-toggler"]', reset: '[data-id="reset"]', - fullscreenToggler: '[data-id="fullScreen-toggler"]' + fullscreenToggler: '[data-id="fullScreen-toggler"]', + noValueToggle: "[data-id='noValueToggle']", + showOnlyHoverPath: '[data-id="showOnlyHoverPath"]', + showTooltip: '[data-id="showTooltip"]', + saveSvg: '[data-id="saveSvg"]', }, /** ui events hash */ events: function() { @@ -73,9 +80,19 @@ define([ events["click " + this.ui.onZoomIn] = "onClickZoomIn"; events["click " + this.ui.onZoomOut] = "onClickZoomOut"; events["click " + this.ui.filterToggler] = "onClickFilterToggler"; + events["click " + this.ui.settingToggler] = 'onClickSettingToggler'; events["click " + this.ui.searchToggler] = "onClickSearchToggler"; + events["click " + this.ui.saveSvg] = 'onClickSaveSvg'; events["click " + this.ui.fullscreenToggler] = "onClickFullscreenToggler"; events["click " + this.ui.reset] = "onClickReset"; + events["click " + this.ui.noValueToggle] = function() { + this.showAllProperties = !this.showAllProperties; + this.ui.noValueToggle.attr("data-original-title", (this.showAllProperties ? "Hide" : "Show") + " empty values"); + Utils.togglePropertyRelationshipTableEmptyValues({ + "inputType": this.ui.noValueToggle, + "tableEl": this.ui.nodeDetailTable + }); + }; return events; }, @@ -90,7 +107,35 @@ define([ this.initializeGraph(); this.fetchGraphData(); }, - onRender: function() {}, + onRender: function() { + var that = this; + this.$el.on("click", "code li[data-def]", function() { + if (that.selectedDetailNode) { + var dataObj = $(this).data(), + defObj = that.selectedDetailNode[dataObj.def], + newData = null; + if (dataObj.def === "businessAttributes") { + newData = defObj[dataObj.attribute]; + } else { + newData = _.filter(defObj, { name: dataObj.attribute }); + } + that.ui.attributeTable.find("pre").html('<code style="max-height: 100%">' + Utils.JSONPrettyPrint(newData, function(val) { + return val; + }) + '</code>'); + that.$el.find('[data-id="typeAttrDetailHeader"]').text(dataObj.def); + that.ui.nodeDetailTable.hide("slide", { direction: "right" }, 400); + that.ui.attributeTable.show("slide", { direction: "left" }, 400); + that.$el.find(".typeDetailHeader").hide(); + that.$el.find(".typeAttrDetailHeader").show() + } + }); + this.$el.on("click", "span[data-id='box-back']", function() { + that.ui.nodeDetailTable.show("slide", { direction: "right" }, 400); + that.ui.attributeTable.hide("slide", { direction: "left" }, 400); + that.$el.find(".typeDetailHeader").show(); + that.$el.find(".typeAttrDetailHeader").hide() + }) + }, fetchGraphData: function(options) { var that = this; var entityTypeDef = that.entityDefCollection.fullCollection.toJSON(); @@ -101,7 +146,7 @@ define([ } if (entityTypeDef.length) { that.generateData($.extend(true, {}, { data: entityTypeDef }, options)).then(function(graphObj) { - that.createGraph(); + that.createGraph(options); }); } }, @@ -161,91 +206,56 @@ define([ if (options.data) { if (options.filter) { - var pendingSubList = {}, - pendingSuperList = {}, - temp = {}, - doneList = {}, - traveseSubSuper = function(obj, ignoreSubTypes) { - var fromEntityId = obj.guid; - if (!ignoreSubTypes && obj.subTypes.length) { - _.each(obj.subTypes, function(subType) { - var tempObj = doneList[subType] || temp[subType]; - if (tempObj) { + // filter + var pendingSuperList = {}, + outOfFilterData = {}, + doneList = {}; + + var linkParents = function(obj) { + if (obj && obj.superTypes.length) { + _.each(obj.superTypes, function(superType) { + var fromEntityId = obj.guid; + var tempObj = doneList[superType] || outOfFilterData[superType]; + if (tempObj) { + if (!doneList[superType]) { setNode(tempObj.guid, tempObj); - setEdge(fromEntityId, tempObj.guid); - } else { - if (pendingSubList[subType]) { - pendingSubList[subType].push(fromEntityId); - } else { - pendingSubList[subType] = [fromEntityId]; - } } - }); - } - if (obj.superTypes.length) { - _.each(obj.superTypes, function(superType) { - var tempObj = doneList[superType] || temp[superType]; - if (tempObj) { - setNode(tempObj.guid, tempObj); - setEdge(tempObj.guid, fromEntityId); - if (tempObj.superTypes.length) { - traveseSubSuper(tempObj, true); - } + setEdge(tempObj.guid, fromEntityId); + linkParents(tempObj); + } else { + if (pendingSuperList[superType]) { + pendingSuperList[superType].push(fromEntityId); } else { - if (pendingSuperList[superType]) { - pendingSuperList[superType].push(fromEntityId); - } else { - pendingSuperList[superType] = [fromEntityId]; - } + pendingSuperList[superType] = [fromEntityId]; } - }); - } - }; + } + }); + } + } _.each(options.data, function(obj) { var fromEntityId = obj.guid; + if (pendingSuperList[obj.name]) { + doneList[obj.name] = obj; + setNode(fromEntityId, obj); + _.map(pendingSuperList[obj.name], function(guid) { + setEdge(fromEntityId, guid); + }); + delete pendingSuperList[obj.name]; + linkParents(obj); + } if (obj.serviceType === options.filter) { doneList[obj.name] = obj; setNode(fromEntityId, obj); - if (pendingSubList[obj.name]) { - _.map(pendingSubList[obj.name], function(guid) { - setEdge(guid, fromEntityId); - }); - delete pendingSubList[obj.name]; - } - if (pendingSuperList[obj.name]) { - _.map(pendingSuperList[obj.name], function(guid) { - setEdge(fromEntityId, guid); - }); - delete pendingSuperList[obj.name]; - } - traveseSubSuper(obj); - } else { - if (pendingSubList[obj.name]) { - setNode(fromEntityId, obj); - doneList[obj.name] = obj; - _.map(pendingSubList[obj.name], function(guid) { - setEdge(guid, fromEntityId); - }); - delete pendingSubList[obj.name]; - } - if (pendingSuperList[obj.name]) { - var fromEntityId = obj.guid; - setNode(fromEntityId, obj); - doneList[obj.name] = obj; - _.map(pendingSuperList[obj.name], function(guid) { - setEdge(fromEntityId, guid); - }); - delete pendingSuperList[obj.name]; - } - if (!doneList[obj.name]) { - temp[obj.name] = obj; - } + linkParents(obj); + } else if (!doneList[obj.name] && !outOfFilterData[obj.name]) { + outOfFilterData[obj.name] = obj; } }); - pendingSubList = null; pendingSuperList = null; doneList = null; + outOfFilterData = null; } else { + // Without filter var pendingList = {}, doneList = {}; @@ -308,11 +318,19 @@ define([ onClickFilterToggler: function() { this.toggleBoxPanel({ el: this.ui.filterBox }); }, + onClickSettingToggler: function() { + this.toggleBoxPanel({ el: this.ui.settingBox }); + }, onClickSearchToggler: function() { this.toggleBoxPanel({ el: this.ui.searchBox }); }, onClickReset: function() { this.fetchGraphData({ refresh: true }); + this.ui.typeSearch.data({ refresh: true }).val("").trigger("change"); + this.ui.filterServiceType.data({ refresh: true }).val("").trigger("change"); + }, + onClickSaveSvg: function(e, a) { + this.LineageHelperRef.exportLineage({ downloadFileName: "TypeSystemView" }); }, onClickFullscreenToggler: function(e) { var icon = $(e.currentTarget).find("i"), @@ -324,42 +342,65 @@ define([ icon.parent("button").attr("data-original-title", "Default View"); } panel.toggleClass("fullscreen-mode"); + var node = this.$("svg.main").parent()[0].getBoundingClientRect(); + this.LineageHelperRef.updateOptions({ + width: node.width, + height: node.height + }); }, updateDetails: function(data) { this.$("[data-id='typeName']").text(Utils.getName(data)); - delete data.id; + + this.selectedDetailNode = {}; + this.selectedDetailNode.atttributes = data.attributeDefs; + this.selectedDetailNode.businessAttributes = data.businessAttributeDefs; + this.selectedDetailNode.relationshipAttributes = data.relationshipAttributeDefs; //atttributes data["atttributes"] = (data.attributeDefs || []).map(function(obj) { return obj.name; }); - delete data.attributeDefs; //businessAttributes data["businessAttributes"] = _.keys(data.businessAttributeDefs); - delete data.businessAttributeDefs; //relationshipAttributes data["relationshipAttributes"] = (data.relationshipAttributeDefs || []).map(function(obj) { return obj.name; }); - delete data.relationshipAttributeDefs; - - console.log(data); this.ui.nodeDetailTable.html( CommonViewFunction.propertyTable({ scope: this, guidHyperLink: false, + getValue: function(val, key) { + if (key && key.toLowerCase().indexOf("time") > 0) { + return Utils.formatDate({ date: val }); + } else { + return val; + } + }, + getArrayOfStringElement: function(val, key) { + var def = null, + classname = "json-string"; + if (key === "atttributes" || key === "businessAttributes" || key === "relationshipAttributes") { + def = key; + classname += " cursor"; + } + return "<li class='" + classname + "' " + (def ? 'data-def="' + def + '" data-attribute="' + val + '"' : '') + ">" + val + "</li>" + }, + getArrayOfStringFormat: function(valueArray) { + return valueArray.join(""); + }, getEmptyString: function(key) { if (key === "subTypes" || key === "superTypes" || key === "atttributes" || key === "relationshipAttributes") { return "[]"; } return "N/A"; }, - valueObject: _.omit(data, ["isLineage", "isIncomplete", "label", "shape", "toolTipLabel", "updatedValues"]), + valueObject: _.omit(data, ["id", "attributeDefs", "relationshipAttributeDefs", "businessAttributeDefs", "isLineage", "isIncomplete", "label", "shape", "toolTipLabel", "updatedValues"]), sortBy: true }) ); }, - createGraph: function(refresh) { + createGraph: function(opt) { this.LineageHelperRef.createGraph(); }, filterData: function(value) { @@ -377,12 +418,14 @@ define([ setDataManually: true, width: node.width, height: node.height, - isShowHoverPath: true, zoom: true, fitToScreen: true, dagreOptions: { rankdir: "tb" }, + toolTipTitle: "Type", + isShowHoverPath: function() { return that.ui.showOnlyHoverPath.prop('checked') }, + isShowTooltip: function() { return that.ui.showTooltip.prop('checked') }, onNodeClick: function(d) { that.onClickNodeToggler(); that.updateDetails(that.LineageHelperRef.getNode(d.clickedData, true)); @@ -425,14 +468,17 @@ define([ this.ui.typeSearch .select2({ closeOnSelect: true, - placeholder: "Select Node" + placeholder: "Select Type" }) .on("change.select2", function(e) { e.stopPropagation(); e.stopImmediatePropagation(); - var selectedNode = $('[data-id="typeSearch"]').val(); - //that.searchNodeObj.selectedNode = selectedNode; - that.LineageHelperRef.searchNode({ guid: selectedNode }); + if (!that.ui.typeSearch.data("refresh")) { + var selectedNode = $('[data-id="typeSearch"]').val(); + that.LineageHelperRef.searchNode({ guid: selectedNode }); + } else { + that.ui.typeSearch.data("refresh", false); + } }); if (!this.ui.filterServiceType.data("select2")) { this.ui.filterServiceType @@ -443,15 +489,13 @@ define([ .on("change.select2", function(e) { e.stopPropagation(); e.stopImmediatePropagation(); - var selectedNode = $('[data-id="filterServiceType"]').val(); - that.filterData(selectedNode); - //that.searchNodeObj.selectedNode = selectedNode; - //that.LineageHelperRef.searchNode({ guid: selectedNode }); + if (!that.ui.filterServiceType.data("refresh")) { + var selectedNode = $('[data-id="filterServiceType"]').val(); + that.filterData(selectedNode); + } else { + that.ui.filterServiceType.data("refresh", false); + } }); - // if (this.searchNodeObj.selectedNode) { - // this.ui.typeSearch.val(this.searchNodeObj.selectedNode); - // this.ui.typeSearch.trigger("change.select2"); - // } } } });