You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by kb...@apache.org on 2019/06/10 09:45:47 UTC
[atlas] branch branch-0.8 updated: ATLAS-3259 : UI: Lineage
improvements for branch-0.8
This is an automated email from the ASF dual-hosted git repository.
kbhatt pushed a commit to branch branch-0.8
in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/branch-0.8 by this push:
new c3f767e ATLAS-3259 : UI: Lineage improvements for branch-0.8
c3f767e is described below
commit c3f767e2d33757515c39fedb48c3aee1cd229240
Author: kevalbhatt <kb...@apache.org>
AuthorDate: Wed Jun 5 14:27:45 2019 +0530
ATLAS-3259 : UI: Lineage improvements for branch-0.8
---
dashboardv2/public/css/scss/graph.scss | 318 +++----
dashboardv2/public/css/scss/override.scss | 2 +-
.../entity-icon/disabled/falcon_feed_creation.png | Bin 0 -> 6830 bytes
.../disabled/falcon_feed_replication.png | Bin 0 -> 6830 bytes
.../img/entity-icon/disabled/falcon_process.png | Bin 0 -> 6830 bytes
.../disabled/impala_column_lineage_disabled.png | Bin 0 -> 5630 bytes
.../disabled/impala_process_disabled.png | Bin 0 -> 6214 bytes
.../img/entity-icon/falcon_feed_creation.png | Bin 0 -> 9620 bytes
.../img/entity-icon/falcon_feed_replication.png | Bin 0 -> 9620 bytes
.../public/img/entity-icon/falcon_process.png | Bin 0 -> 9620 bytes
.../img/entity-icon/impala_column_lineage.png | Bin 0 -> 7417 bytes
.../public/img/entity-icon/impala_process.png | Bin 0 -> 8176 bytes
dashboardv2/public/img/icon-gear-active.png | Bin 18088 -> 0 bytes
dashboardv2/public/img/icon-gear-delete.png | Bin 17677 -> 0 bytes
dashboardv2/public/img/icon-gear.png | Bin 8302 -> 0 bytes
dashboardv2/public/img/icon-table-active.png | Bin 14468 -> 0 bytes
dashboardv2/public/img/icon-table-delete.png | Bin 14117 -> 0 bytes
dashboardv2/public/img/icon-table.png | Bin 6417 -> 0 bytes
dashboardv2/public/js/main.js | 3 +-
dashboardv2/public/js/router/Router.js | 1 +
.../js/templates/graph/LineageLayoutView_tmpl.html | 101 ++-
dashboardv2/public/js/utils/Helper.js | 135 +++
dashboardv2/public/js/utils/Overrides.js | 75 --
dashboardv2/public/js/utils/Utils.js | 9 -
.../js/views/detail_page/DetailPageLayoutView.js | 4 +-
.../public/js/views/graph/LineageLayoutView.js | 975 ++++++++++++++-------
dashboardv2/public/js/views/graph/LineageUtils.js | 304 +++++++
27 files changed, 1326 insertions(+), 601 deletions(-)
diff --git a/dashboardv2/public/css/scss/graph.scss b/dashboardv2/public/css/scss/graph.scss
index 3646261..1328304 100644
--- a/dashboardv2/public/css/scss/graph.scss
+++ b/dashboardv2/public/css/scss/graph.scss
@@ -34,10 +34,18 @@
font-family: $font_1;
}
+ transition: opacity 0.3s linear;
+
rect {
stroke: $color_mountain_mist_approx;
fill: $white;
stroke-width: 1.5px;
+
+ &.serach-rect {
+ stroke: $color_keppel_approx;
+ fill: transparent;
+ stroke-width: 2.5px
+ }
}
.label {
@@ -50,6 +58,11 @@
transition: all 0.3s;
stroke-width: 1.5px;
+ &.node-detail-highlight {
+ stroke: $color_havelock_blue_approx;
+ stroke-width: 2px;
+ }
+
&.nodeImage {
&.green:hover {
stroke: #ffb203;
@@ -90,6 +103,12 @@
}
}
+.invisible {
+ .node circle {
+ transition: all 0s;
+ }
+}
+
.edgePath {
.path {
cursor: pointer;
@@ -189,80 +208,6 @@ g.type-TK>rect {
height: 100%;
width: 100%;
overflow: hidden;
-
- .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;
}
.graph-button-group {
@@ -273,115 +218,40 @@ g.type-TK>rect {
.zoom-button-group {}
}
-.lineage-fltr-panel,
-.lineage-search-panel {
+.box-panel {
position: absolute;
+ top: 37px;
border: 1px solid #ccc;
width: 250px;
max-height: 99%;
overflow: auto;
transition: all 0.3s ease;
right: -273px;
- box-shadow: 7px 1px 28px -3px;
- background-color: #f5f5f5;
+ background-color: $white;
z-index: 999;
+ box-shadow: 1px 19px 22px -17px;
+ border-radius: 10px;
+ max-height: 88%;
- .header {
- background: black;
- color: white;
- text-align: center;
- margin-bottom: 15px;
- position: absolute;
- width: 100%;
+ &.slide-from-left {
+ left: -273px;
+ right: 0px;
- >h4 {
- padding: 0px 36px 0px 10px;
- word-break: break-all;
- }
-
- .fltr-togler,
- .search-togler {
- position: absolute;
- right: 0px;
- top: 0px;
+ &.size-lg {
+ left: -373px;
}
}
- .body {
- padding: 10px;
- margin-top: 39px;
- width: 100%;
- position: relative;
- height: 150px;
- overflow: auto;
+ &.size-lg {
+ width: 350px;
}
-}
-.lineage-details.node-details.open {
- overflow: hidden !important;
- min-height: 300px;
+ &.show-box-panel {
+ right: 0px !important;
- & span[data-id='close'] {
- margin: 7px;
- position: absolute;
- right: 0;
- z-index: 99;
- }
-
- & div[data-id="entityList"] {
- position: relative;
- overflow: auto;
- max-height: 250px;
- top: 40px;
- }
-
- & h4.title {
- position: fixed;
- width: 100%;
- }
-
- & table {
- & tbody td {
- word-wrap: break-word
+ &.slide-from-left {
+ left: 0;
}
-
- table-layout: fixed;
- }
-}
-
-.lineage-details {
- position: absolute;
- left: 0;
- overflow: auto;
- top: 0px;
- max-height: 100%;
- box-shadow: 4px 13px 14px -12px;
- background: #e7e7e7;
- transform: scaleX(0);
- width: 35%;
- transition: transform 0.3s ease-in;
-
- &.open {
- transform: scaleX(1);
- }
-
- .title {
- background: black;
- color: white;
- padding: 10px 38px 10px 10px;
- word-break: break-all;
- margin-top: 0;
- }
-
- .close-details {
- position: absolute;
- top: 0;
- color: white;
- left: 0;
- height: 21px;
- width: 21px;
- cursor: pointer;
- font-size: 16px;
}
.entity-list {
@@ -397,9 +267,6 @@ g.type-TK>rect {
text-align: left;
&.deleted-relation {
- a {
- color: #BB5838 !important;
- }
.deleteBtn {
padding: 2px 8px !important;
@@ -407,27 +274,63 @@ g.type-TK>rect {
}
}
}
-}
-.show-filter-panel,
-.show-search-panel {
- right: 0px !important;
-}
+ .header {
+ background: $color_havelock_blue_approx;
+ color: white;
+ position: relative;
+ text-align: center;
+ width: 100%;
+ position: sticky;
+ height: 37px;
+ top: 0;
+ z-index: 999;
+
+ >h4 {
+ padding: 0px 36px 0px 10px;
+ word-break: break-all;
+ }
+
+ .btn-close {
+ position: absolute;
+ right: 0px;
+ top: 0px;
+ font-size: 18px;
+
+ &:hover {
+ color: $white;
+ }
+ }
+ }
+
+ .body {
+ padding: 10px;
+ width: 100%;
+ position: relative;
+ height: calc(100% - 37px);
+ overflow: hidden;
+ }
+}
.btn-gray {
border: 1px solid #686868;
color: $dark_gray;
background: white;
-}
-.btn-gray:hover {
- border: 1px solid #686868;
- color: $dark_gray !important;
- background-color: white !important;
+ &[disabled] {
+ opacity: .3;
+ }
+
+ &:hover {
+ border: 1px solid #686868;
+ color: $dark_gray !important;
+ background-color: white !important;
+ }
}
+
span#zoom_in {
border-bottom: 1px solid #625555;
}
@@ -445,6 +348,11 @@ span#zoom_in {
position: relative;
width: 100%;
height: 64vh;
+ overflow: hidden !important;
+
+ &.auto-height {
+ height: auto !important;
+ }
}
.active.fullscreen-mode {
@@ -471,4 +379,56 @@ span#zoom_in {
.lineage-box {
padding: 10px !important;
}
+
+ .box-panel {
+ margin: 10px !important;
+ }
+}
+
+@keyframes zoominoutsinglefeatured {
+ 0% {
+ transform: scale(1, 1);
+ }
+
+ 50% {
+ transform: scale(1.2, 1.2);
+ }
+
+ 100% {
+ transform: scale(1, 1);
+ }
+}
+
+.wobble {
+ animation: zoominoutsinglefeatured 1s 5;
+}
+
+.hover {
+
+ g.node {
+ opacity: 0.1 !important;
+ }
+
+ g.edgePath {
+ opacity: 0 !important;
+ }
+
+ g.node.hover-active,
+ g.edgePath.hover-active-node {
+ opacity: 1 !important;
+ }
+}
+
+.lineage-node-detail {
+ .table-quickMenu {
+ td:nth-child(1n) {
+ width: 150px;
+ }
+
+ word-break: break-all;
+ }
+}
+
+.hidden-svg {
+ visibility: hidden;
}
\ No newline at end of file
diff --git a/dashboardv2/public/css/scss/override.scss b/dashboardv2/public/css/scss/override.scss
index 089393e..bf3a513 100644
--- a/dashboardv2/public/css/scss/override.scss
+++ b/dashboardv2/public/css/scss/override.scss
@@ -48,7 +48,7 @@
.modal-body {
position: relative;
padding: 15px;
- max-height: 400px;
+ max-height: 72vh;
min-height: 70px;
overflow: auto;
.btn+.btn {
diff --git a/dashboardv2/public/img/entity-icon/disabled/falcon_feed_creation.png b/dashboardv2/public/img/entity-icon/disabled/falcon_feed_creation.png
new file mode 100644
index 0000000..b98be6c
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/falcon_feed_creation.png differ
diff --git a/dashboardv2/public/img/entity-icon/disabled/falcon_feed_replication.png b/dashboardv2/public/img/entity-icon/disabled/falcon_feed_replication.png
new file mode 100644
index 0000000..b98be6c
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/falcon_feed_replication.png differ
diff --git a/dashboardv2/public/img/entity-icon/disabled/falcon_process.png b/dashboardv2/public/img/entity-icon/disabled/falcon_process.png
new file mode 100644
index 0000000..b98be6c
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/falcon_process.png differ
diff --git a/dashboardv2/public/img/entity-icon/disabled/impala_column_lineage_disabled.png b/dashboardv2/public/img/entity-icon/disabled/impala_column_lineage_disabled.png
new file mode 100755
index 0000000..3b9b8cb
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/impala_column_lineage_disabled.png differ
diff --git a/dashboardv2/public/img/entity-icon/disabled/impala_process_disabled.png b/dashboardv2/public/img/entity-icon/disabled/impala_process_disabled.png
new file mode 100755
index 0000000..a207acb
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/impala_process_disabled.png differ
diff --git a/dashboardv2/public/img/entity-icon/falcon_feed_creation.png b/dashboardv2/public/img/entity-icon/falcon_feed_creation.png
new file mode 100644
index 0000000..ddb3829
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/falcon_feed_creation.png differ
diff --git a/dashboardv2/public/img/entity-icon/falcon_feed_replication.png b/dashboardv2/public/img/entity-icon/falcon_feed_replication.png
new file mode 100644
index 0000000..ddb3829
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/falcon_feed_replication.png differ
diff --git a/dashboardv2/public/img/entity-icon/falcon_process.png b/dashboardv2/public/img/entity-icon/falcon_process.png
new file mode 100644
index 0000000..ddb3829
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/falcon_process.png differ
diff --git a/dashboardv2/public/img/entity-icon/impala_column_lineage.png b/dashboardv2/public/img/entity-icon/impala_column_lineage.png
new file mode 100755
index 0000000..453ac96
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/impala_column_lineage.png differ
diff --git a/dashboardv2/public/img/entity-icon/impala_process.png b/dashboardv2/public/img/entity-icon/impala_process.png
new file mode 100755
index 0000000..c5e17c5
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/impala_process.png differ
diff --git a/dashboardv2/public/img/icon-gear-active.png b/dashboardv2/public/img/icon-gear-active.png
deleted file mode 100644
index 7dffb90..0000000
Binary files a/dashboardv2/public/img/icon-gear-active.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-gear-delete.png b/dashboardv2/public/img/icon-gear-delete.png
deleted file mode 100644
index 90590fc..0000000
Binary files a/dashboardv2/public/img/icon-gear-delete.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-gear.png b/dashboardv2/public/img/icon-gear.png
deleted file mode 100644
index dc935e9..0000000
Binary files a/dashboardv2/public/img/icon-gear.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-table-active.png b/dashboardv2/public/img/icon-table-active.png
deleted file mode 100644
index 4427a05..0000000
Binary files a/dashboardv2/public/img/icon-table-active.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-table-delete.png b/dashboardv2/public/img/icon-table-delete.png
deleted file mode 100644
index 67a6c8f..0000000
Binary files a/dashboardv2/public/img/icon-table-delete.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-table.png b/dashboardv2/public/img/icon-table.png
deleted file mode 100644
index 1b1e4f0..0000000
Binary files a/dashboardv2/public/img/icon-table.png and /dev/null differ
diff --git a/dashboardv2/public/js/main.js b/dashboardv2/public/js/main.js
index 389ed5b..6c2dded 100644
--- a/dashboardv2/public/js/main.js
+++ b/dashboardv2/public/js/main.js
@@ -174,6 +174,7 @@ require.config({
require(['App',
'router/Router',
+ 'utils/Helper',
'utils/CommonViewFunction',
'utils/Globals',
'utils/UrlLinks',
@@ -183,7 +184,7 @@ require(['App',
'bootstrap',
'd3',
'select2'
-], function(App, Router, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList) {
+], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList) {
var that = this;
this.asyncFetchCounter = 5;
this.entityDefCollection = new VEntityList();
diff --git a/dashboardv2/public/js/router/Router.js b/dashboardv2/public/js/router/Router.js
index d90c901..13f8704 100644
--- a/dashboardv2/public/js/router/Router.js
+++ b/dashboardv2/public/js/router/Router.js
@@ -104,6 +104,7 @@ define([
this.postRouteExecute();
},
preRouteExecute: function() {
+ $(".tooltip").tooltip("hide");
// console.log("Pre-Route Change Operations can be performed here !!");
},
postRouteExecute: function(name, args) {
diff --git a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html
index 2c92103..8679c3b 100644
--- a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html
@@ -16,10 +16,10 @@
-->
<!-- <div class="graph-toolbar clearfix"></div> -->
<div class="white-bg no-padding lineage-box">
- <div class="lineage-fltr-panel">
+ <div class="box-panel filter-box">
<div class="header clearfix">
<h4>Filters</h4>
- <span data-id="fltr-togler" style="margin: 7px" class="btn btn-action btn-sm fltr-togler"><i class="fa fa-close"></i></span>
+ <span data-id="box-close" class="btn btn-sm btn-close"><i class="fa fa-close"></i></span>
</div>
<div class="body">
<div class="hideProcessContainer form-group text-left col-sm-12">
@@ -46,31 +46,102 @@
</div>
</div>
</div>
+ <div class="box-panel search-box">
+ <div class="header clearfix">
+ <h4>Search</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="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>
+ </div>
+ </div>
+ </div>
+ </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 type="button" data-id="fltr-togler" class="btn btn-action btn-gray btn-sm"><i class="fa fa-filter"></i></button>
+ <button data-id="resetLineage" class="btn btn-action btn-gray btn-sm" title="Realign Lineage">
+ <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="fullScreen-toggler" class="btn btn-action btn-gray btn-sm fullscreen_lineage"><i class="fa fa-expand"></i></button>
+ <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" id="zoom_in" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom In" data-id="refreshBtn"> <i class="fa fa-search-plus"></i></button>
<button type="button" id="zoom_out" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom Out" data-id="refreshBtn"> <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"><i class="fa fa-expand"></i></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 table-quickMenu'>
+ <thead>
+ <tr>
+ <th>Key</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <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;">
- <span style="margin-right: 8px; color:#fb4200;"><i class="fa fa-circle-o fa-fw" aria-hidden="true"></i>Current Entity</span>
- <span style="margin-right: 8px; color:#df9b00;"><i class="fa fa-long-arrow-right fa-fw" aria-hidden="true"></i>Lineage</span>
- <span style="margin-right: 8px; color:#fb4200;"><i class="fa fa-long-arrow-right fa-fw" aria-hidden="true"></i>Impact</span>
- </div>
- <svg width="100%" height="calc(100% - 28px)" viewBox="0 0 854 330" enable-background="new 0 0 854 330" xml:space="preserve"></svg>
- <div class="lineage-details node-details">
- <span data-id="close" style="margin: 7px;position: absolute;right: 0" class="btn btn-action btn-sm fltr-togler"><i class="fa fa-close"></i></span>
- <h4 class="title"><span data-id="typeName"></span></h4>
- <div class="col-md-12" data-id="entityList">
- </div>
+ <span style="margin-right: 8px; color:#fb4200;"><i class="fa fa-circle-o fa-fw"></i>Current Entity</span>
+ <span style="margin-right: 8px; color:#df9b00;"><i class="fa fa-long-arrow-right fa-fw"></i>Lineage</span>
+ <span style="margin-right: 8px; color:#fb4200;"><i class="fa fa-long-arrow-right fa-fw"></i>Impact</span>
</div>
-</div>
\ No newline at end of file
+ <svg width="{{width}}" height="{{height}}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"></svg>
+</div>
+<div class="hidden-svg"></div>
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/Helper.js b/dashboardv2/public/js/utils/Helper.js
new file mode 100644
index 0000000..f93b88b
--- /dev/null
+++ b/dashboardv2/public/js/utils/Helper.js
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+define(['require',
+ 'utils/Utils',
+ 'marionette'
+], function(require, Utils) {
+ 'use strict';
+ _.mixin({
+ isEmptyArray: function(val) {
+ if (val && _.isArray(val)) {
+ return _.isEmpty(val);
+ } else {
+ return false;
+ }
+ },
+ toArrayifObject: function(val) {
+ return _.isObject(val) ? [val] : val;
+ },
+ startsWith: function(str, matchStr) {
+ if (str && matchStr && _.isString(str) && _.isString(matchStr)) {
+ return str.lastIndexOf(matchStr, 0) === 0
+ } else {
+ return;
+ }
+ },
+ isUndefinedNull: function(val) {
+ if (_.isUndefined(val) || _.isNull(val)) {
+ return true
+ } else {
+ return false;
+ }
+ },
+ trim: function(val) {
+ if (val && val.trim) {
+ return val.trim();
+ } else {
+ return val;
+ }
+ },
+ isTypePrimitive: function(type) {
+ if (type === "int" || type === "byte" || type === "short" || type === "long" || type === "float" || type === "double" || type === "string" || type === "boolean" || type === "date") {
+ return true;
+ }
+ return false;
+ }
+ });
+ var getPopoverEl = function(e) {
+ return $(e.target).parent().data("bs.popover") || $(e.target).data("bs.popover") || $(e.target).parents('.popover').length;
+ }
+ $(document).on('click DOMMouseScroll mousewheel', function(e) {
+ if (e.originalEvent) {
+ // Do action if it is triggered by a human.
+ //e.isImmediatePropagationStopped();
+ var isPopOverEl = getPopoverEl(e)
+ if (!isPopOverEl) {
+ $('.popover').popover('hide');
+ } else if (isPopOverEl.$tip) {
+ $('.popover').not(isPopOverEl.$tip).popover('hide');
+ }
+ }
+ });
+ $('body').on('hidden.bs.popover', function(e) {
+ $(e.target).data("bs.popover").inState = { click: false, hover: false, focus: false }
+ });
+ $('body').on('show.bs.popover', '[data-js="popover"]', function() {
+ $('.popover').not(this).popover('hide');
+ });
+ $('body').on('keypress', 'input.number-input,.number-input .select2-search__field', function(e) {
+ if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
+ return false;
+ }
+ });
+ $('body').on('keypress', 'input.number-input-negative,.number-input-negative .select2-search__field', function(e) {
+ if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
+ if (e.which == 45) {
+ if (this.value.length) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ });
+ $('body').on('keypress', 'input.number-input-exponential,.number-input-exponential .select2-search__field', function(e) {
+ if ((e.which != 8 && e.which != 0) && (e.which < 48 || e.which > 57) && (e.which != 69 && e.which != 101 && e.which != 43 && e.which != 45 && e.which != 46 && e.which != 190)) {
+ return false;
+ }
+ });
+ $("body").on('click', '.dropdown-menu.dropdown-changetitle li a', function() {
+ $(this).parents('li').find(".btn:first-child").html($(this).text() + ' <span class="caret"></span>');
+ });
+ $("body").on('click', '.btn', function() {
+ $(this).blur();
+ });
+
+ // For placeholder support
+ if (!('placeholder' in HTMLInputElement.prototype)) {
+ var originalRender = Backbone.Marionette.LayoutView.prototype.render;
+ Backbone.Marionette.LayoutView.prototype.render = function() {
+ originalRender.apply(this, arguments);
+ this.$('input, textarea').placeholder();
+ }
+ }
+ $('body').on('click', 'pre.code-block .expand-collapse-button', function(e) {
+ var $el = $(this).parents('.code-block');
+ if ($el.hasClass('shrink')) {
+ $el.removeClass('shrink');
+ } else {
+ $el.addClass('shrink');
+ }
+ });
+
+ // For adding tooltip globally
+ $('body').tooltip({
+ selector: '[title]',
+ placement: 'bottom',
+ container: 'body'
+ });
+
+})
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/Overrides.js b/dashboardv2/public/js/utils/Overrides.js
index d49a5fc..61c9595 100644
--- a/dashboardv2/public/js/utils/Overrides.js
+++ b/dashboardv2/public/js/utils/Overrides.js
@@ -49,81 +49,6 @@ define(['require', 'utils/Utils', 'marionette', 'backgrid', 'asBreadcrumbs', 'jq
]);
}
- _.mixin({
- isEmptyArray: function(val) {
- if (val && _.isArray(val)) {
- return _.isEmpty(val);
- } else {
- return false;
- }
- },
- isUndefinedNull: function(val) {
- if (_.isUndefined(val) || _.isNull(val)) {
- return true
- } else {
- return false;
- }
- },
- trim: function(val) {
- if (val && val.trim) {
- return val.trim();
- } else {
- return val;
- }
- }
- });
- var getPopoverEl = function(e) {
- return $(e.target).parent().data("bs.popover") || $(e.target).data("bs.popover") || $(e.target).parents('.popover').length;
- }
- $('body').on('click DOMMouseScroll mousewheel', function(e) {
- if (e.originalEvent) {
- // Do action if it is triggered by a human.
- //e.isImmediatePropagationStopped();
- var isPopOverEl = getPopoverEl(e)
- if (!isPopOverEl) {
- $('.popover').popover('hide');
- } else if (isPopOverEl.$tip) {
- $('.popover').not(isPopOverEl.$tip).popover('hide');
- }
- }
- });
- $('body').on('hidden.bs.popover', function(e) {
- $(e.target).data("bs.popover").inState = { click: false, hover: false, focus: false }
- });
- $('body').on('show.bs.popover', '[data-js="popover"]', function() {
- $('.popover').not(this).popover('hide');
- });
- $('body').on('keypress', 'input.number-input,.number-input .select2-search__field', function(e) {
- if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
- return false;
- }
- });
- $('body').on('keypress', 'input.number-input-negative,.number-input-negative .select2-search__field', function(e) {
- if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
- if (e.which == 45) {
- if (this.value.length) {
- return false;
- }
- } else {
- return false;
- }
- }
- });
- $('body').on('keypress', 'input.number-input-exponential,.number-input-exponential .select2-search__field', function(e) {
- if ((e.which != 8 && e.which != 0) && (e.which < 48 || e.which > 57) && (e.which != 69 && e.which != 101 && e.which != 43 && e.which != 45 && e.which != 46 && e.which != 190)) {
- return false;
- }
- });
-
- // For placeholder support
- if (!('placeholder' in HTMLInputElement.prototype)) {
- var originalRender = Backbone.Marionette.LayoutView.prototype.render;
- Backbone.Marionette.LayoutView.prototype.render = function() {
- originalRender.apply(this, arguments);
- this.$('input, textarea').placeholder();
- }
- }
-
String.prototype.trunc = String.prototype.trunc ||
function(n) {
return (this.length > n) ? this.substr(0, n - 1) + '...' : this;
diff --git a/dashboardv2/public/js/utils/Utils.js b/dashboardv2/public/js/utils/Utils.js
index 5e90972..81dc953 100644
--- a/dashboardv2/public/js/utils/Utils.js
+++ b/dashboardv2/public/js/utils/Utils.js
@@ -768,14 +768,5 @@ define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums',
this.attr(attributeName, firstString);
}
}
-
- $('body').on('click', 'pre.code-block .expand-collapse-button', function(e) {
- var $el = $(this).parents('.code-block');
- if ($el.hasClass('shrink')) {
- $el.removeClass('shrink');
- } else {
- $el.addClass('shrink');
- }
- });
return Utils;
});
\ No newline at end of file
diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
index 685fcac..6faa8a8 100644
--- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
@@ -336,9 +336,9 @@ define(['require',
_.each(tagObject, function(val) {
var checkTagOrTerm = Utils.checkTagOrTerm(val);
if (checkTagOrTerm.term) {
- termData += '<span class="btn btn-action btn-sm btn-blue btn-icon term" data-id="tagClick" data-href="' + val.typeName + '"><span>' + val.typeName + '</span><i class="fa fa-close" data-id="deleteTag" data-type="term"></i></span>';
+ termData += '<span class="btn btn-action btn-sm btn-blue btn-icon term" data-id="tagClick" data-href="' + val.typeName + '"><span title="' + val.typeName + '">' + val.typeName + '</span><i class="fa fa-close" title="Delete Term" data-id="deleteTag" data-type="term"></i></span>';
} else {
- tagData += '<span class="btn btn-action btn-sm btn-icon btn-blue" data-id="tagClick"><span>' + val.typeName + '</span><i class="fa fa-close" data-id="deleteTag" data-type="tag"></i></span>';
+ tagData += '<span class="btn btn-action btn-sm btn-icon btn-blue" data-id="tagClick"><span title="' + val.typeName + '">' + val.typeName + '</span><i class="fa fa-close" title="Delete Tag" data-id="deleteTag" data-type="tag"></i></span>';
}
});
this.ui.tagList.find("span.btn").remove();
diff --git a/dashboardv2/public/js/views/graph/LineageLayoutView.js b/dashboardv2/public/js/views/graph/LineageLayoutView.js
index 5ba2f2f..881a059 100644
--- a/dashboardv2/public/js/views/graph/LineageLayoutView.js
+++ b/dashboardv2/public/js/views/graph/LineageLayoutView.js
@@ -22,14 +22,16 @@ define(['require',
'collection/VLineageList',
'models/VEntity',
'utils/Utils',
+ 'views/graph/LineageUtils',
'dagreD3',
'd3-tip',
'utils/Enums',
'utils/UrlLinks',
'utils/Globals',
+ 'utils/CommonViewFunction',
'platform',
'jquery-ui'
-], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, dagreD3, d3Tip, Enums, UrlLinks, Globals, platform) {
+], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, LineageUtils, dagreD3, d3Tip, Enums, UrlLinks, Globals, CommonViewFunction, platform) {
'use strict';
var LineageLayoutView = Backbone.Marionette.LayoutView.extend(
@@ -49,24 +51,41 @@ define(['require',
checkHideProcess: "[data-id='checkHideProcess']",
checkDeletedEntity: "[data-id='checkDeletedEntity']",
selectDepth: 'select[data-id="selectDepth"]',
- fltrTogler: '[data-id="fltr-togler"]',
- lineageFilterPanel: '.lineage-fltr-panel',
- LineageFullscreenToggler: '[data-id="fullScreen-toggler"]',
- lineageDetailClose: '[data-id="close"]',
- nodeEntityList: '[data-id="entityList"]'
+ filterToggler: '[data-id="filter-toggler"]',
+ settingToggler: '[data-id="setting-toggler"]',
+ searchToggler: '[data-id="search-toggler"]',
+ boxClose: '[data-id="box-close"]',
+ lineageFullscreenToggler: '[data-id="fullScreen-toggler"]',
+ filterBox: '.filter-box',
+ searchBox: '.search-box',
+ settingBox: '.setting-box',
+ lineageTypeSearch: '[data-id="typeSearch"]',
+ searchNode: '[data-id="searchNode"]',
+ nodeDetailTable: '[data-id="nodeDetailTable"]',
+ showOnlyHoverPath: '[data-id="showOnlyHoverPath"]',
+ showTooltip: '[data-id="showTooltip"]',
+ saveSvg: '[data-id="saveSvg"]',
+ resetLineage: '[data-id="resetLineage"]'
+ },
+ templateHelpers: function() {
+ return {
+ width: "100%",
+ height: "100%"
+ };
},
-
/** ui events hash */
events: function() {
var events = {};
events["click " + this.ui.checkHideProcess] = 'onCheckUnwantedEntity';
events["click " + this.ui.checkDeletedEntity] = 'onCheckUnwantedEntity';
events['change ' + this.ui.selectDepth] = 'onSelectDepthChange';
- events["click " + this.ui.fltrTogler] = 'onClickFiltrTogler';
- events["click " + this.ui.LineageFullscreenToggler] = 'onClickLineageFullscreenToggler';
- events["click " + this.ui.lineageDetailClose] = function() {
- this.toggleLineageInfomationSlider({ close: true });
- };
+ events["click " + this.ui.filterToggler] = 'onClickFilterToggler';
+ events["click " + this.ui.boxClose] = 'toggleBoxPanel';
+ events["click " + this.ui.settingToggler] = 'onClickSettingToggler';
+ events["click " + this.ui.lineageFullscreenToggler] = 'onClickLineageFullscreenToggler';
+ events["click " + this.ui.searchToggler] = 'onClickSearchToggler';
+ events["click " + this.ui.saveSvg] = 'onClickSaveSvg';
+ events["click " + this.ui.resetLineage] = 'onClickResetLineage';
return events;
},
@@ -75,18 +94,20 @@ define(['require',
* @constructs
*/
initialize: function(options) {
- _.extend(this, _.pick(options, 'processCheck', 'guid', 'entityDefCollection', 'actionCallBack', 'fetchCollection'));
+ _.extend(this, _.pick(options, 'processCheck', 'guid', 'entity', 'entityName', 'entityDefCollection', 'actionCallBack', 'fetchCollection', 'attributeDefs'));
this.collection = new VLineageList();
this.lineageData = null;
this.typeMap = {};
this.apiGuid = {};
- this.asyncFetchCounter = 0;
this.edgeCall;
this.filterObj = {
isProcessHideCheck: false,
isDeletedEntityHideCheck: false,
depthCount: ''
};
+ this.searchNodeObj = {
+ selectedNode: ''
+ }
},
initializeGraph: function() {
@@ -106,12 +127,19 @@ define(['require',
return {};
});
},
-
onRender: function() {
var that = this;
this.fetchGraphData();
+
+
if (platform.name === "IE") {
this.$('svg').css('opacity', '0');
+
+ }
+
+ if (platform.name === "Microsoft Edge" || platform.name === "IE") {
+ $(that.ui.saveSvg).hide();
+
}
if (this.layoutRendered) {
this.layoutRendered();
@@ -141,22 +169,45 @@ define(['require',
var icon = $(e.currentTarget).find('i'),
panel = $(e.target).parents('.tab-pane').first();
icon.toggleClass('fa-expand fa-compress');
+ if (icon.hasClass('fa-expand')) {
+ icon.parent('button').attr("data-original-title", "Full Screen");
+ } else {
+ icon.parent('button').attr("data-original-title", "Default View");
+ }
panel.toggleClass('fullscreen-mode');
},
onCheckUnwantedEntity: function(e) {
var data = $.extend(true, {}, this.lineageData);
- this.fromToObj = {};
+ //this.fromToNodeData = {};
this.initializeGraph();
if ($(e.target).data("id") === "checkHideProcess") {
this.filterObj.isProcessHideCheck = e.target.checked;
} else {
this.filterObj.isDeletedEntityHideCheck = e.target.checked;
}
- this.generateData(data.relations, data.guidEntityMap);
+ this.generateData({ "relationshipMap": this.relationshipMap, "guidEntityMap": this.guidEntityMap });
+ },
+ toggleBoxPanel: function(options) {
+ var el = options && options.el,
+ nodeDetailToggler = options && options.nodeDetailToggler,
+ currentTarget = options.currentTarget;
+ this.$el.find('.show-box-panel').removeClass('show-box-panel');
+ if (el && el.addClass) {
+ el.addClass('show-box-panel');
+ }
+ this.$('circle.node-detail-highlight').removeClass("node-detail-highlight");
+ },
+ onClickNodeToggler: function(options) {
+ this.toggleBoxPanel({ el: this.$('.lineage-node-detail'), nodeDetailToggler: true });
+ },
+ onClickFilterToggler: function() {
+ this.toggleBoxPanel({ el: this.ui.filterBox });
+ },
+ onClickSettingToggler: function() {
+ this.toggleBoxPanel({ el: this.ui.settingBox });
},
- onClickFiltrTogler: function() {
- var lineageFilterPanel = this.ui.lineageFilterPanel;
- $(lineageFilterPanel).toggleClass("show-filter-panel");
+ onClickSearchToggler: function() {
+ this.toggleBoxPanel({ el: this.ui.searchBox });
},
onSelectDepthChange: function(e, options) {
this.initializeGraph();
@@ -167,19 +218,28 @@ define(['require',
fetchGraphData: function(options) {
var that = this,
queryParam = options && options.queryParam || {};
- this.fromToObj = {};
+ this.fromToNodeData = {};
this.$('.fontLoader').show();
this.$('svg>g').hide();
+ this.toggleDisableState({
+ "el": that.$(".graph-button-group button,select[data-id='selectDepth']")
+ });
this.collection.getLineage(this.guid, {
skipDefaultError: true,
queryParam: queryParam,
success: function(data) {
if (data.relations.length) {
- that.lineageData = $.extend(true, {}, data)
- that.generateData(data.relations, data.guidEntityMap);
+ that.lineageData = $.extend(true, {}, data);
+ that.relationshipMap = that.crateLineageRelationshipHashMap(data);
+ that.guidEntityMap = $.extend(true, {}, data.guidEntityMap);
+ that.generateData({ "relationshipMap": that.relationshipMap, "guidEntityMap": that.guidEntityMap });
+ that.toggleDisableState({
+ "el": that.$(".graph-button-group button,select[data-id='selectDepth']")
+ });
} else {
that.noLineage();
that.hideCheckForProcess();
+
}
},
cust_error: function(model, response) {
@@ -195,7 +255,6 @@ define(['require',
noLineage: function() {
this.$('.fontLoader').hide();
this.$('.depth-container').hide();
- //this.$('svg').height('100');
this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No lineage data found</text>');
if (this.actionCallBack) {
this.actionCallBack();
@@ -204,210 +263,257 @@ define(['require',
hideCheckForProcess: function() {
this.$('.hideProcessContainer').hide();
},
- generateData: function(relations, guidEntityMap) {
- var that = this;
-
- function isProcess(node) {
- if (_.isUndefined(node) || node.typeName == "Process") {
- return true;
- }
- var entityDef = that.entityDefCollection.fullCollection.find({ name: node.typeName });
- return _.contains(Utils.getNestedSuperTypes({ data: entityDef.toJSON(), collection: that.entityDefCollection }), "Process")
+ isProcess: function(node) {
+ var typeName = node.typeName,
+ superTypes = node.superTypes,
+ entityDef = node.entityDef;
+ if (typeName == "Process") {
+ return true;
}
-
- function isDeleted(node) {
- if (_.isUndefined(node)) {
- return
- }
- return Enums.entityStateReadOnly[node.status];
+ return _.contains(superTypes, "Process");
+ },
+ isDeleted: function(node) {
+ if (_.isUndefined(node)) {
+ return
}
+ return Enums.entityStateReadOnly[node.status];
+ },
+ isNodeToBeUpdated: function(node) {
+ var isProcessHideCheck = this.filterObj.isProcessHideCheck,
+ isDeletedEntityHideCheck = this.filterObj.isDeletedEntityHideCheck
+ var returnObj = {
+ isProcess: (isProcessHideCheck && node.isProcess),
+ isDeleted: (isDeletedEntityHideCheck && node.isDeleted)
- function isNodeToBeUpdated(node) {
- var isProcessHideCheck = that.filterObj.isProcessHideCheck,
- isDeletedEntityHideCheck = that.filterObj.isDeletedEntityHideCheck
- var returnObj = {
- isProcess: (isProcessHideCheck && isProcess(node)),
- isDeleted: (isDeletedEntityHideCheck && isDeleted(node))
-
- };
- returnObj["update"] = returnObj.isProcess || returnObj.isDeleted;
- return returnObj;
+ };
+ returnObj["update"] = returnObj.isProcess || returnObj.isDeleted;
+ return returnObj;
+ },
+ getNestedSuperTypes: function(options) {
+ var entityDef = options.entityDef;
+ return Utils.getNestedSuperTypes({ data: entityDef, collection: this.entityDefCollection })
+ },
+ getEntityDef: function(typeName) {
+ var entityDef = null;
+ if (typeName) {
+ entityDef = this.entityDefCollection.fullCollection.find({ name: typeName });
+ entityDef = entityDef ? entityDef.toJSON() : entityDef;
}
-
- function getServiceType(typeName) {
- var serviceType = null;
- if (typeName) {
- var entityDef = that.entityDefCollection.fullCollection.find({ name: typeName });
- if (entityDef) {
- serviceType = entityDef.get("serviceType") || null;
- }
+ return entityDef;
+ },
+ getServiceType: function(options) {
+ if (!options) {
+ return;
+ }
+ var typeName = options.typeName,
+ entityDef = options.entityDef,
+ serviceType = null;
+ if (typeName) {
+ if (entityDef) {
+ serviceType = entityDef.serviceType || null;
}
- return serviceType;
}
-
- function makeNodeObj(relationObj) {
- var obj = {};
- obj['shape'] = "img";
- obj['typeName'] = relationObj.typeName
- obj['label'] = relationObj.displayText.trunc(18);
- obj['toolTipLabel'] = relationObj.displayText;
- obj['id'] = relationObj.guid;
- obj['isLineage'] = true;
- obj['queryText'] = relationObj.queryText;
- obj['serviceType'] = getServiceType(relationObj.typeName);
- if (relationObj.status) {
- obj['status'] = relationObj.status;
+ return serviceType;
+ },
+ crateLineageRelationshipHashMap: function(data) {
+ var that = this,
+ relations = data && data.relations,
+ guidEntityMap = data && data.guidEntityMap,
+ makeNodeData = function(relationObj) {
+ var obj = $.extend(true, {
+ shape: "img",
+ label: relationObj.displayText.trunc(18),
+ toolTipLabel: relationObj.displayText,
+ id: relationObj.guid,
+ isLineage: true,
+ entityDef: this.getEntityDef(relationObj.typeName)
+ }, relationObj);
+ obj["serviceType"] = this.getServiceType({ typeName: relationObj.typeName, entityDef: obj.entityDef });
+ obj["superTypes"] = this.getNestedSuperTypes({ entityDef: obj.entityDef });
+ obj['isProcess'] = this.isProcess(obj);
+ obj['isDeleted'] = this.isDeleted(obj);
+ return obj;
+ }.bind(this),
+ newHashMap = {};
+ _.each(relations, function(obj) {
+ if (!that.fromToNodeData[obj.fromEntityId]) {
+ that.fromToNodeData[obj.fromEntityId] = makeNodeData(guidEntityMap[obj.fromEntityId]);
}
- if (that.filterObj.isProcessHideCheck) {
- obj['isProcess'] = relationObj.isProcess;
+ if (!that.fromToNodeData[obj.toEntityId]) {
+ that.fromToNodeData[obj.toEntityId] = makeNodeData(guidEntityMap[obj.toEntityId]);
+ }
+ if (newHashMap[obj.fromEntityId]) {
+ newHashMap[obj.fromEntityId].push(obj.toEntityId);
} else {
- obj['isProcess'] = isProcess(relationObj);
+ newHashMap[obj.fromEntityId] = [obj.toEntityId];
}
-
- return obj;
- }
-
- var newRelations = [],
- finalRelations = relations,
- isHideFilterOn = this.filterObj.isProcessHideCheck || this.filterObj.isDeletedEntityHideCheck;
- if (isHideFilterOn) {
- _.each(relations, function(obj, index, relationArr) {
- var toNodeToBeUpdated = isNodeToBeUpdated(guidEntityMap[obj.toEntityId]);
- var fromNodeToBeUpdated = isNodeToBeUpdated(guidEntityMap[obj.fromEntityId]);
- if (toNodeToBeUpdated.update) {
- if (that.filterObj.isProcessHideCheck) {
- //We have already checked entity is process or not inside isNodeToBeUpdated();
- guidEntityMap[obj.toEntityId]["isProcess"] = true;
- }
- _.filter(relationArr, function(flrObj) {
- if (flrObj.fromEntityId === obj.toEntityId) {
- if (that.filterObj.isDeletedEntityHideCheck && isDeleted(guidEntityMap[flrObj.toEntityId])) {
- return;
+ });
+ return newHashMap;
+ },
+ generateData: function(options) {
+ var that = this,
+ relationshipMap = options && $.extend(true, {}, options.relationshipMap) || {},
+ guidEntityMap = options && options.guidEntityMap || {},
+ styleObj = {
+ fill: 'none',
+ stroke: '#ffb203',
+ width: 3
+ },
+ getStyleObjStr = function(styleObj) {
+ return 'fill:' + styleObj.fill + ';stroke:' + styleObj.stroke + ';stroke-width:' + styleObj.width;
+ },
+ filterRelationshipMap = relationshipMap,
+ isHideFilterOn = this.filterObj.isProcessHideCheck || this.filterObj.isDeletedEntityHideCheck,
+ getNewToNodeRelationship = function(toNodeGuid) {
+ if (toNodeGuid && relationshipMap[toNodeGuid]) {
+ var newRelationship = [];
+ _.each(relationshipMap[toNodeGuid], function(guid) {
+ var nodeToBeUpdated = that.isNodeToBeUpdated(that.fromToNodeData[guid]);
+ if (nodeToBeUpdated.update) {
+ var newRelation = getNewToNodeRelationship(guid);
+ if (newRelation) {
+ newRelationship = newRelationship.concat(newRelation);
}
- newRelations.push({
- fromEntityId: obj.fromEntityId,
- toEntityId: flrObj.toEntityId
- });
+ } else {
+ newRelationship.push(guid);
}
- })
- } else if (fromNodeToBeUpdated.update) {
- if (that.filterObj.isProcessHideCheck) {
- //We have already checked entity is process or not inside isNodeToBeUpdated();
- guidEntityMap[obj.fromEntityId]["isProcess"] = true;
- }
-
- _.filter(relationArr, function(flrObj) {
- if (that.filterObj.isDeletedEntityHideCheck && isDeleted(guidEntityMap[flrObj.fromEntityId])) {
- return;
- }
- if (flrObj.toEntityId === obj.fromEntityId) {
- newRelations.push({
- fromEntityId: flrObj.fromEntityId,
- toEntityId: obj.toEntityId
- });
+ });
+ return newRelationship;
+ } else {
+ return null;
+ }
+ },
+ getToNodeRelation = function(toNodes, fromNodeToBeUpdated) {
+ var toNodeRelationship = [];
+ _.each(toNodes, function(toNodeGuid) {
+ var toNodeToBeUpdated = that.isNodeToBeUpdated(that.fromToNodeData[toNodeGuid]);
+ if (toNodeToBeUpdated.update) {
+ // To node need to updated
+ if (pendingFromRelationship[toNodeGuid]) {
+ toNodeRelationship = toNodeRelationship.concat(pendingFromRelationship[toNodeGuid]);
+ } else {
+ var newToNodeRelationship = getNewToNodeRelationship(toNodeGuid);
+ if (newToNodeRelationship) {
+ toNodeRelationship = toNodeRelationship.concat(newToNodeRelationship);
+ }
}
- })
+ } else {
+ //when bothe node not to be updated.
+ toNodeRelationship.push(toNodeGuid);
+ }
+ });
+ return toNodeRelationship;
+ },
+ pendingFromRelationship = {};
+ if (isHideFilterOn) {
+ filterRelationshipMap = {};
+ _.each(relationshipMap, function(toNodes, fromNodeGuid) {
+ var fromNodeToBeUpdated = that.isNodeToBeUpdated(that.fromToNodeData[fromNodeGuid]),
+ toNodeList = getToNodeRelation(toNodes, fromNodeToBeUpdated);
+ if (fromNodeToBeUpdated.update) {
+ if (pendingFromRelationship[fromNodeGuid]) {
+ pendingFromRelationship[fromNodeGuid] = pendingFromRelationship[fromNodeGuid].concat(toNodeList);
+ } else {
+ pendingFromRelationship[fromNodeGuid] = toNodeList;
+ }
} else {
- newRelations.push(obj);
+ if (filterRelationshipMap[fromNodeGuid]) {
+ filterRelationshipMap[fromNodeGuid] = filterRelationshipMap[fromNodeGuid].concat(toNodeList);
+ } else {
+ filterRelationshipMap[fromNodeGuid] = toNodeList;
+ }
}
- });
- finalRelations = newRelations;
+ })
}
- _.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]);
- }
- if (!that.fromToObj[obj.toEntityId]) {
- that.fromToObj[obj.toEntityId] = makeNodeObj(guidEntityMap[obj.toEntityId]);
- that.g.setNode(obj.toEntityId, that.fromToObj[obj.toEntityId]);
- }
- var styleObj = {
- fill: 'none',
- stroke: '#ffb203',
- width: 3
+ _.each(filterRelationshipMap, function(toNodesList, fromNodeGuid) {
+ if (!that.g._nodes[fromNodeGuid]) {
+ that.g.setNode(fromNodeGuid, that.fromToNodeData[fromNodeGuid]);
}
- that.g.setEdge(obj.fromEntityId, obj.toEntityId, { 'arrowhead': "arrowPoint", lineInterpolate: 'basis', "style": "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width + "", 'styleObj': styleObj });
- });
+ _.each(toNodesList, function(toNodeGuid) {
+ if (!that.g._nodes[toNodeGuid]) {
+ that.g.setNode(toNodeGuid, that.fromToNodeData[toNodeGuid]);
+ }
+ that.g.setEdge(fromNodeGuid, toNodeGuid, {
+ "arrowhead": 'arrowPoint',
+ "lineInterpolate": 'basis',
+ "style": getStyleObjStr(styleObj),
+ 'styleObj': styleObj
+ });
+ })
+ })
+
//if no relations found
- if (!finalRelations.length) {
+ if (_.isEmpty(filterRelationshipMap)) {
this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>');
- } else {
- this.$('svg').html('<text></text>');
}
- if (this.fromToObj[this.guid]) {
- this.fromToObj[this.guid]['isLineage'] = false;
- this.checkForLineageOrImpactFlag(finalRelations, this.guid);
- }
- if (this.asyncFetchCounter == 0) {
- this.createGraph();
+ if (this.fromToNodeData[this.guid]) {
+ this.fromToNodeData[this.guid]['isLineage'] = false;
+ this.findImpactNodeAndUpdateData({ "relationshipMap": filterRelationshipMap, "guid": this.guid, "getStyleObjStr": getStyleObjStr });
}
+ this.renderLineageTypeSearch();
+ this.createGraph();
},
- checkForLineageOrImpactFlag: function(relations, guid) {
+ findImpactNodeAndUpdateData: function(options) {
var that = this,
- nodeFound = _.where(relations, { 'fromEntityId': guid });
- if (nodeFound.length) {
- _.each(nodeFound, function(node) {
- if (!node["traversed"]) {
- node["traversed"] = true;
- that.fromToObj[node.toEntityId]['isLineage'] = false;
+ relationshipMap = options.relationshipMap,
+ fromNodeGuid = options.guid,
+ getStyleObjStr = options.getStyleObjStr,
+ toNodeList = relationshipMap[fromNodeGuid];
+ if (toNodeList && toNodeList.length) {
+ if (!relationshipMap[fromNodeGuid]["traversed"]) {
+ relationshipMap[fromNodeGuid]["traversed"] = true;
+ _.each(toNodeList, function(toNodeGuid) {
+ that.fromToNodeData[toNodeGuid]['isLineage'] = false;
var styleObj = {
fill: 'none',
stroke: '#fb4200',
width: 3
}
- that.g.setEdge(node.fromEntityId, node.toEntityId, { 'arrowhead': "arrowPoint", lineInterpolate: 'basis', "style": "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width + "", 'styleObj': styleObj });
- that.checkForLineageOrImpactFlag(relations, node.toEntityId);
- }
- });
- }
- },
- 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.6,
- 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) {
- initialScale = 0;
- this.$('svg').addClass('noScale');
- }
- if (svgEl.parents('.panel.panel-fullscreen').length) {
- translateValue = [20, 20];
- if (svgEl.hasClass('noScale')) {
- if (!scaleEl.hasClass('scaleLinage')) {
- scaleEl.addClass('scaleLinage');
- initialScale = 1.6;
- } else {
- scaleEl.removeClass('scaleLinage');
- initialScale = 0;
- }
+ that.g.setEdge(fromNodeGuid, toNodeGuid, {
+ "arrowhead": 'arrowPoint',
+ "lineInterpolate": 'basis',
+ "style": getStyleObjStr(styleObj),
+ 'styleObj': styleObj
+ });
+ that.findImpactNodeAndUpdateData({
+ "relationshipMap": relationshipMap,
+ "guid": toNodeGuid,
+ "getStyleObjStr": getStyleObjStr
+ });
+ });
}
- } else {
- scaleEl.removeClass('scaleLinage');
}
- this.zoom.translate(translateValue)
- .scale(initialScale);
},
zoomed: function(that) {
this.$('svg').find('>g').attr("transform",
"translate(" + this.zoom.translate() + ")" +
"scale(" + this.zoom.scale() + ")"
);
+ LineageUtils.refreshGraphForIE({
+ edgeEl: this.$('svg .edgePath')
+ });
+ },
+ interpolateZoom: function(translate, scale, that, zoom) {
+ return d3.transition().duration(350).tween("zoom", function() {
+ var iTranslate = d3.interpolate(zoom.translate(), translate),
+ iScale = d3.interpolate(zoom.scale(), scale);
+ return function(t) {
+ zoom
+ .scale(iScale(t))
+ .translate(iTranslate(t));
+ that.zoomed();
+ };
+ });
},
createGraph: function() {
var that = this,
width = this.$('svg').width(),
- height = this.$('svg').height();
+ height = this.$('svg').height(),
+ imageObject = {};
+ $('.resizeGraph').css("height", height + "px");
+
this.g.nodes().forEach(function(v) {
var node = that.g.node(v);
// Round the corners of the nodes
@@ -419,6 +525,8 @@ define(['require',
var render = new dagreD3.render();
// Add our custom arrow (a hollow-point)
render.arrows().arrowPoint = function normal(parent, id, edge, type) {
+ var parentNode = parent && parent[0] && parent[0][0] && parent[0][0].parentNode ? parent[0][0].parentNode : parent;
+ d3.select(parentNode).select('path.path').attr('marker-end', "url(#" + id + ")");
var marker = parent.append("marker")
.attr("id", id)
.attr("viewBox", "0 0 10 10")
@@ -442,9 +550,12 @@ define(['require',
var shapeSvg = parent.append('circle')
.attr('fill', 'url(#img_' + node.id + ')')
.attr('r', '24px')
- .attr('data-stroke',node.id)
+ .attr('data-stroke', node.id)
+ .attr('stroke-width', "2px")
.attr("class", "nodeImage " + (currentNode ? "currentNode" : (node.isProcess ? "process" : "node")));
-
+ if (currentNode) {
+ shapeSvg.attr("stroke", "#fb4200")
+ }
parent.insert("defs")
.append("pattern")
.attr("x", "0%")
@@ -454,18 +565,66 @@ define(['require',
.attr("width", "100%")
.attr("height", "100%")
.append('image')
- .attr("xlink:href", function(d) {
+ .attr("href", function(d) {
+ var that = this;
if (node) {
- return Utils.getEntityIconPath({ entityData: node });
+ // to check for IE-10
+ var originLink = window.location.origin;
+ if (platform.name === "IE") {
+ originLink = window.location.protocol + "//" + window.location.host;
+ }
+ var imageIconPath = Utils.getEntityIconPath({ entityData: node }),
+ imagePath = ((originLink + Utils.getBaseUrl(window.location.pathname)) + imageIconPath);
+
+ var getImageData = function(options) {
+ var imagePath = options.imagePath,
+ ajaxOptions = {
+ "url": imagePath,
+ "method": "get",
+ "async": false,
+ }
+
+ if (platform.name !== "IE") {
+ ajaxOptions["mimeType"] = "text/plain; charset=x-user-defined";
+ }
+ $.ajax(ajaxOptions)
+ .always(function(data, status, xhr) {
+ if (data.status == 404) {
+ getImageData({
+ "imagePath": Utils.getEntityIconPath({ entityData: node, errorUrl: imagePath }),
+ "imageIconPath": imageIconPath
+ });
+ } else if (data) {
+ if (platform.name !== "IE") {
+ imageObject[imageIconPath] = 'data:image/png;base64,' + LineageUtils.base64Encode({ "data": data });
+ } else {
+ imageObject[imageIconPath] = imagePath;
+ }
+ }
+ });
+ }
+ if (_.keys(imageObject).indexOf(imageIconPath) === -1) {
+ getImageData({
+ "imagePath": imagePath,
+ "imageIconPath": imageIconPath
+ });
+ }
+
+ if (_.isUndefined(imageObject[imageIconPath])) {
+ // before img success
+ imageObject[imageIconPath] = [d3.select(that)];
+ } else if (_.isArray(imageObject[imageIconPath])) {
+ // before img success
+ imageObject[imageIconPath].push(d3.select(that));
+ } else {
+ d3.select(that).attr("xlink:href", imageObject[imageIconPath]);
+ return imageObject[imageIconPath];
+ }
}
})
- .attr("x", currentNode ? "3" : "6")
- .attr("y", currentNode ? "3" : "4")
- .attr("width", "40")
- .attr("height", "40")
- .on("error", function() {
- this.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', Utils.getEntityIconPath({ entityData: node, errorUrl: this.href.baseVal }));
- });
+ .attr("x", "4")
+ .attr("y", currentNode ? "3" : "4").attr("width", "40")
+ .attr("height", "40");
node.intersect = function(point) {
return dagreD3.intersect.circle(node, currentNode ? 24 : 21, point);
@@ -481,31 +640,16 @@ define(['require',
.attr("enable-background", "new 0 0 " + width + " " + height),
svgGroup = svg.append("g");
var zoom = this.zoom = d3.behavior.zoom()
- .scaleExtent([0.5, 6])
+ .center([width / 2, height / 2])
+ .scaleExtent([0.01, 50])
.on("zoom", that.zoomed.bind(this));
-
- function interpolateZoom(translate, scale) {
- var self = this;
- return d3.transition().duration(350).tween("zoom", function() {
- var iTranslate = d3.interpolate(zoom.translate(), translate),
- iScale = d3.interpolate(zoom.scale(), scale);
- return function(t) {
- zoom
- .scale(iScale(t))
- .translate(iTranslate(t));
- that.zoomed();
- };
- });
- }
-
function zoomClick() {
var clicked = d3.event.target,
direction = 1,
- factor = 0.2,
+ factor = 0.5,
target_zoom = 1,
- center = [that.g.graph().width / 2, that.g.graph().height / 2],
- extent = zoom.scaleExtent(),
+ center = [width / 2, height / 2],
translate = zoom.translate(),
translate0 = [],
l = [],
@@ -515,10 +659,6 @@ define(['require',
direction = (this.id === 'zoom_in') ? 1 : -1;
target_zoom = zoom.scale() * (1 + factor * direction);
- if (target_zoom < extent[0] || target_zoom > extent[1]) {
- return false;
- }
-
translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
view.k = target_zoom;
l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
@@ -526,7 +666,7 @@ define(['require',
view.x += center[0] - l[0];
view.y += center[1] - l[1];
- interpolateZoom([view.x, view.y], view.k);
+ that.interpolateZoom([view.x, view.y], view.k, that, zoom);
}
d3.selectAll(this.$('.lineageZoomButton')).on('click', zoomClick);
var tooltip = d3Tip()
@@ -555,10 +695,11 @@ define(['require',
}
render(svgGroup, this.g);
svg.on("dblclick.zoom", null)
- .on("wheel.zoom", null);
+ // .on("wheel.zoom", null);
//change text postion
svgGroup.selectAll("g.nodes g.label")
.attr("transform", "translate(2,-35)");
+ var waitForDoubleClick = null;
svgGroup.selectAll("g.nodes g.node")
.on('mouseenter', function(d) {
that.activeNode = true;
@@ -584,51 +725,72 @@ define(['require',
} else if ((currentELWidth.top) < 400) {
direction = ((currentELWidth.left) < 50) ? 'se' : 's';
}
- tooltip.direction(direction).show(d)
+ if (that.ui.showTooltip.prop('checked')) {
+ tooltip.direction(direction).show(d);
+ }
+
+ if (!that.ui.showOnlyHoverPath.prop('checked')) {
+ return;
+ }
+ that.$('svg').addClass('hover');
+ var nextNode = that.g.successors(d),
+ previousNode = that.g.predecessors(d),
+ nodesToHighlight = nextNode.concat(previousNode);
+ LineageUtils.onHoverFade({
+ opacity: 0.3,
+ selectedNode: d,
+ highlight: nodesToHighlight,
+ svg: that.svg
+ }).init();
})
- .on('dblclick', function(d) {
- tooltip.hide(d);
- Utils.setUrl({
- url: '#!/detailPage/' + d + '?tabActive=lineage',
- mergeBrowserUrl: false,
- trigger: true
- });
- }).on('mouseleave', function(d) {
+ .on('mouseleave', function(d) {
that.activeNode = false;
var nodeEL = this;
setTimeout(function(argument) {
if (!(that.activeTip || that.activeNode)) {
$(nodeEL).removeClass('active');
- tooltip.hide(d);
+ if (that.ui.showTooltip.prop('checked')) {
+ tooltip.hide(d);
+ }
}
- }, 400)
- }).on('click', function(d) {
+ }, 150);
+ if (!that.ui.showOnlyHoverPath.prop('checked')) {
+ return;
+ }
+ that.$('svg').removeClass('hover');
+ that.$('svg').removeClass('hover-active');
+ LineageUtils.onHoverFade({
+ opacity: 1,
+ selectedNode: d,
+ svg: that.svg
+ }).init();
+ })
+ .on('click', function(d) {
+ var el = this;
if (d3.event.defaultPrevented) return; // ignore drag
- that.toggleLineageInfomationSlider({ open: true, obj: d });
- svgGroup.selectAll('[data-stroke]').attr('stroke','none');
- svgGroup.selectAll('[data-stroke]').attr('stroke',function(c) {
- if (c == d) {
- return "#316132";
- } else {
- return 'none';
- }
- })
- that.updateRelationshipDetails({ obj: d });
+ d3.event.preventDefault();
+ if (waitForDoubleClick != null) {
+ clearTimeout(waitForDoubleClick)
+ waitForDoubleClick = null;
+ tooltip.hide(d);
+ Utils.setUrl({
+ url: '#!/detailPage/' + d + '?tabActive=lineage',
+ mergeBrowserUrl: false,
+ trigger: true
+ });
+ } else {
+ var currentEvent = d3.event
+ waitForDoubleClick = setTimeout(function() {
+ tooltip.hide(d);
+ that.onClickNodeToggler({ obj: d });
+ $(el).find('circle').addClass('node-detail-highlight');
+ that.updateRelationshipDetails({ guid: d });
+ waitForDoubleClick = null;
+ }, 150)
+ }
});
- 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;
});
@@ -639,81 +801,256 @@ define(['require',
});
// Center the graph
- this.setGraphZoomPositionCal();
+ LineageUtils.centerNode({
+ guid: that.guid,
+ svg: that.$('svg'),
+ g: this.g,
+ edgeEl: $('svg .edgePath'),
+ afterCenterZoomed: function(options) {
+ var newScale = options.newScale,
+ newTranslate = options.newTranslate;
+ that.zoom.scale(newScale);
+ that.zoom.translate(newTranslate);
+ }
+ }).init();
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);
+ LineageUtils.refreshGraphForIE({
+ edgeEl: this.$('svg .edgePath')
});
}
+ LineageUtils.DragNode({
+ svg: this.svg,
+ g: this.g,
+ guid: this.guid,
+ edgeEl: this.$('svg .edgePath')
+ }).init();
},
- toggleLineageInfomationSlider: function(options) {
- if (options.open && !this.$('.lineage-details').hasClass("open")) {
- this.$('.lineage-details').addClass('open');
- } else if (options.close && this.$('.lineage-details').hasClass("open")) {
- d3.selectAll('circle').attr("stroke", "none");
- this.$('.lineage-details').removeClass('open');
+ renderLineageTypeSearch: function() {
+ var that = this,
+ lineageData = $.extend(true, {}, this.lineageData),
+ data = [],
+ typeStr = '<option></option>';
+ if (!_.isEmpty(lineageData)) {
+ _.each(lineageData.guidEntityMap, function(obj, index) {
+ var nodeData = that.fromToNodeData[obj.guid];
+ if (that.filterObj.isProcessHideCheck && nodeData && nodeData.isProcess) {
+ return;
+ } else if (that.filterObj.isDeletedEntityHideCheck && nodeData && nodeData.isDeleted) {
+ return
+ }
+ typeStr += '<option value="' + obj.guid + '">' + obj.attributes.name + '</option>';
+ });
}
+ that.ui.lineageTypeSearch.html(typeStr);
+ this.initilizelineageTypeSearch();
},
- updateRelationshipDetails: function(options) {
+ initilizelineageTypeSearch: function() {
var that = this;
- var lineageData;
- for (var x in that.lineageData.guidEntityMap) {
- if (x == options.obj) {
- lineageData = that.lineageData.guidEntityMap[x]
- }
- }
- var data = lineageData,
- typeName = data.typeName || options.obj.name,
- searchString = options.searchString,
- listString = "";
- this.$("[data-id='typeName']").text(typeName);
- var getElement = function(options) {
- var showCofig = [
- "meaningNames",
- "meanings",
- "classificationNames",
- {
- "attributes": [
- "description",
- "name",
- "qualifiedName"
- ]
+ that.ui.lineageTypeSearch.select2({
+ closeOnSelect: true,
+ placeholder: 'Select Node'
+ }).on('change.select2', function(e) {
+ e.stopPropagation();
+ e.stopImmediatePropagation();
+ d3.selectAll(".serach-rect").remove();
+ var selectedNode = $('[data-id="typeSearch"]').val();
+ that.searchNodeObj.selectedNode = selectedNode;
+ LineageUtils.centerNode({
+ guid: selectedNode,
+ svg: $(that.svg[0]),
+ g: that.g,
+ edgeEl: $('svg .edgePath'),
+ afterCenterZoomed: function(options) {
+ var newScale = options.newScale,
+ newTranslate = options.newTranslate;
+ that.zoom.scale(newScale);
+ that.zoom.translate(newTranslate);
}
- ];
- var tbody = '';
- for (var x = 0; x < showCofig.length; x++) {
- if (typeof showCofig[x] === "object") {
- _.each(showCofig[x].attributes, function(element, index, list) {
- var dataToShow = data.attributes[element] ? data.attributes[element] : "N/A";
- tbody += '<tr><td class="html-cell renderable">' + element + '</td><td class="html-cell renderable">' + dataToShow + '</td></tr>';
- })
+ }).init();
+ that.svg.selectAll('.nodes g.label').attr('stroke', function(c, d) {
+ if (c == selectedNode) {
+ return "#316132";
} else {
- var dataToShow = data[showCofig[x]] ? data[showCofig[x]] : "N/A";
- dataToShow = dataToShow && dataToShow.length > 0 ? dataToShow : "N/A";
- tbody += '<tr><td class="html-cell renderable">' + showCofig[x] + '</td><td class="html-cell renderable">' + dataToShow + '</td></tr>';
+ return 'none';
}
+ });
+ // Using jquery for selector because d3 select is not working for few process entities.
+ d3.select($(".node#" + selectedNode)[0]).insert("rect", "circle")
+ .attr("class", "serach-rect")
+ .attr("x", -50)
+ .attr("y", -27.5)
+ .attr("width", 100)
+ .attr("height", 55);
+ d3.selectAll(".nodes circle").classed("wobble", function(d, i, nodes) {
+ if (d == selectedNode) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ });
+ if (that.searchNodeObj.selectedNode) {
+ that.ui.lineageTypeSearch.val(that.searchNodeObj.selectedNode);
+ that.ui.lineageTypeSearch.trigger("change.select2");
+ }
+ },
+ updateRelationshipDetails: function(options) {
+ var that = this,
+ guid = options.guid,
+ initialData = that.guidEntityMap[guid],
+ typeName = initialData.typeName || guid,
+ attributeDefs = that.g._nodes[guid] && that.g._nodes[guid].entityDef ? that.g._nodes[guid].entityDef.attributeDefs : null;
+ this.$("[data-id='typeName']").text(typeName);
+ this.entityModel = new VEntity({});
+ var config = {
+ guid: 'guid',
+ typeName: 'typeName',
+ name: 'name',
+ qualifiedName: 'qualifiedName',
+ owner: 'owner',
+ createTime: 'createTime',
+ status: 'status',
+ classificationNames: 'classifications',
+ meanings: 'term'
+ };
+ var data = {};
+ _.each(config, function(valKey, key) {
+ var val = initialData[key];
+ if (_.isUndefined(val) && initialData.attributes[key]) {
+ val = initialData.attributes[key];
+ }
+ if (val) {
+ data[valKey] = val;
}
- var thead = '<thead><tr><th class="renderable">Type</th><th class="renderable">Details</th></thead>';
- var table = '<table style="word-wrap: break-word;" class="table table-hover ">' + thead + '<tbody>' + tbody + '</body></table>';
- return table;
+ });
+ this.ui.nodeDetailTable.html(CommonViewFunction.propertyTable({
+ "scope": this,
+ "valueObject": data,
+ "attributeDefs": attributeDefs,
+ "sortBy": false
+ }));
+ },
+ onClickSaveSvg: function(e, a) {
+ var that = this;
+ var loaderTargetDiv = $(e.currentTarget).find('>i');
+ if (loaderTargetDiv.hasClass('fa-refresh')) {
+ Utils.notifyWarn({
+ content: "Please wait while the lineage gets downloaded"
+ });
+ return false; // return if the lineage is not loaded.
+ }
+
+
+ that.toggleLoader(loaderTargetDiv);
+ Utils.notifyInfo({
+ content: "Lineage will be downloaded in a moment."
+ });
+ setTimeout(function() {
+ var svg = that.$('svg')[0],
+ svgClone = svg.cloneNode(true),
+ scaleFactor = 1,
+ svgWidth = that.$('svg').width(),
+ svgHeight = that.$('svg').height();
+ if (platform.name === "Firefox") {
+ svgClone.setAttribute('width', svgWidth);
+ svgClone.setAttribute('height', svgHeight);
+ }
+ $('.hidden-svg').html(svgClone);
+ $(svgClone).find('>g').attr("transform", "scale(" + scaleFactor + ")");
+ var canvasOffset = { x: 150, y: 150 },
+ setWidth = (svgClone.getBBox().width + (canvasOffset.x)),
+ setHeight = (svgClone.getBBox().height + (canvasOffset.y)),
+ xAxis = svgClone.getBBox().x,
+ yAxis = svgClone.getBBox().y;
+ svgClone.attributes.viewBox.value = xAxis + "," + yAxis + "," + setWidth + "," + setHeight;
+
+ var createCanvas = document.createElement('canvas');
+ createCanvas.id = "canvas";
+ createCanvas.style.display = 'none';
+
+ var body = $('body').append(createCanvas),
+ canvas = $('canvas')[0];
+ canvas.width = (svgClone.getBBox().width * scaleFactor) + canvasOffset.x;
+ canvas.height = (svgClone.getBBox().height * scaleFactor) + canvasOffset.y;
+
+ var ctx = canvas.getContext('2d'),
+ data = (new XMLSerializer()).serializeToString(svgClone),
+ DOMURL = window.URL || window.webkitURL || window;
+
+ ctx.fillStyle = "#FFFFFF";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.strokeRect(0, 0, canvas.width, canvas.height);
+ ctx.restore();
+
+ var img = new Image(canvas.width, canvas.height);
+ var svgBlob = new Blob([data], { type: 'image/svg+xml;base64' });
+ if (platform.name === "Safari") {
+ svgBlob = new Blob([data], { type: 'image/svg+xml' });
+ }
+ var url = DOMURL.createObjectURL(svgBlob);
+
+ img.onload = function() {
+ try {
+ var a = document.createElement("a"),
+ entityAttributes = that.entity && that.entity.attributes;
+ a.download = ((entityAttributes && entityAttributes.qualifiedName) || "lineage_export") + ".png";
+ document.body.appendChild(a);
+ ctx.drawImage(img, 50, 50, canvas.width, canvas.height);
+ canvas.toBlob(function(blob) {
+ if (!blob) {
+ Utils.notifyError({
+ content: "There was an error in downloading Lineage!"
+ });
+ that.toggleLoader(loaderTargetDiv);
+ return;
+ }
+ a.href = DOMURL.createObjectURL(blob);
+ if (blob.size > 10000000) {
+ Utils.notifyWarn({
+ content: "The Image size is huge, please open the image in a browser!"
+ });
+ }
+ a.click();
+ that.toggleLoader(loaderTargetDiv);
+ if (platform.name === 'Safari') {
+ LineageUtils.refreshGraphForSafari({
+ edgeEl: that.$('svg g.node')
+ });
+ }
+ }, 'image/png');
+ $('.hidden-svg').html('');
+ createCanvas.remove();
+
+ } catch (err) {
+ Utils.notifyError({
+ content: "There was an error in downloading Lineage!"
+ });
+ that.toggleLoader(loaderTargetDiv);
+ }
+
+ };
+ img.src = url;
+
+ }, 0)
+ },
+ toggleLoader: function(element) {
+ if ((element).hasClass('fa-camera')) {
+ (element).removeClass('fa-camera').addClass("fa-spin-custom fa-refresh");
+ } else {
+ (element).removeClass("fa-spin-custom fa-refresh").addClass('fa-camera');
+ }
+ },
+ onClickResetLineage: function() {
+ this.createGraph()
+ },
+ toggleDisableState: function(options) {
+ var el = options.el;
+ if (el && el.prop) {
+ el.prop("disabled", !el.prop("disabled"));
}
- listString += getElement(data);
- this.ui.nodeEntityList.html(listString);
}
});
return LineageLayoutView;
diff --git a/dashboardv2/public/js/views/graph/LineageUtils.js b/dashboardv2/public/js/views/graph/LineageUtils.js
new file mode 100644
index 0000000..d2da39a
--- /dev/null
+++ b/dashboardv2/public/js/views/graph/LineageUtils.js
@@ -0,0 +1,304 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+define(['require'], function(require) {
+ 'use strict';
+ var LinegaeUtils = {};
+ LinegaeUtils.DragNode = function(options) {
+ var that = this,
+ g = options.g,
+ svg = options.svg,
+ guid = options.guid,
+ edgePathEl = options.edgeEl;
+ return {
+ init: function() {
+ var that = this;
+ //give IDs to each of the nodes so that they can be accessed
+ svg.selectAll("g.node rect")
+ .attr("id", function(d) {
+ return "node" + d;
+ });
+ svg.selectAll("g.edgePath path")
+ .attr("id", function(e) {
+ return e.v + "-" + e.w;
+ });
+ svg.selectAll("g.edgeLabel g")
+ .attr("id", function(e) {
+ return 'label_' + e.v + "-" + e.w;
+ });
+
+ g.nodes().forEach(function(v) {
+ var node = g.node(v);
+ node.customId = "node" + v;
+ })
+ g.edges().forEach(function(e) {
+ var edge = g.edge(e.v, e.w);
+ edge.customId = e.v + "-" + e.w
+ });
+ var nodeDrag = d3.behavior.drag()
+ .on("dragstart", this.dragstart)
+ .on("drag", function(d) { that.dragmove(this, d) });
+
+ var edgeDrag = d3.behavior.drag()
+ .on("dragstart", this.dragstart)
+ .on('drag', function(d) {
+ that.translateEdge(g.edge(d.v, d.w), d3.event.dx, d3.event.dy);
+ $('#' + g.edge(d.v, d.w).customId).attr('d', that.calcPoints(d));
+ });
+
+ nodeDrag.call(svg.selectAll("g.node"));
+ edgeDrag.call(svg.selectAll("g.edgePath"));
+ },
+ dragstart: function(d) {
+ d3.event.sourceEvent.stopPropagation();
+ },
+ dragmove: function(elem, d) {
+ var that = this,
+ node = d3.select(elem),
+ selectedNode = g.node(d),
+ prevX = selectedNode.x,
+ prevY = selectedNode.y;
+
+ selectedNode.x += d3.event.dx;
+ selectedNode.y += d3.event.dy;
+ node.attr('transform', 'translate(' + selectedNode.x + ',' + selectedNode.y + ')');
+
+ var dx = selectedNode.x - prevX,
+ dy = selectedNode.y - prevY;
+
+ g.edges().forEach(function(e) {
+ if (e.v == d || e.w == d) {
+ var edge = g.edge(e.v, e.w);
+ that.translateEdge(g.edge(e.v, e.w), dx, dy);
+ $('#' + edge.customId).attr('d', that.calcPoints(e));
+ var label = $('#label_' + edge.customId);
+ var xforms = label.attr('transform');
+ if (xforms != "") {
+ var parts = /translate\(\s*([^\s,)]+)[ ,]?([^\s,)]+)?/.exec(xforms),
+ X = parseInt(parts[1]) + dx,
+ Y = parseInt(parts[2]) + dy;
+ if (isNaN(Y)) {
+ Y = dy;
+ }
+ label.attr('transform', 'translate(' + X + ',' + Y + ')');
+ }
+ }
+ });
+ LinegaeUtils.refreshGraphForIE({ "edgeEl": edgePathEl })
+ },
+ translateEdge: function(e, dx, dy) {
+ e.points.forEach(function(p) {
+ p.x = p.x + dx;
+ p.y = p.y + dy;
+ });
+ },
+ calcPoints: function(e) {
+ var edge = g.edge(e.v, e.w),
+ tail = g.node(e.v),
+ head = g.node(e.w),
+ points = edge.points.slice(1, edge.points.length - 1),
+ afterslice = edge.points.slice(1, edge.points.length - 1);
+ points.unshift(this.intersectRect(tail, points[0]));
+ points.push(this.intersectRect(head, points[points.length - 1]));
+ return d3.svg.line()
+ .x(function(d) {
+ return d.x;
+ })
+ .y(function(d) {
+ return d.y;
+ })
+ .interpolate("basis")
+ (points);
+ },
+ intersectRect: function(node, point) {
+ var that = this,
+ x = node.x,
+ y = node.y,
+ dx = point.x - x,
+ dy = point.y - y,
+ w = node.id == guid ? 24 : 21,
+ h = node.id == guid ? 24 : 21,
+ sx = 0,
+ sy = 0;
+
+ if (Math.abs(dy) * w > Math.abs(dx) * h) {
+ // Intersection is top or bottom of rect.
+ if (dy < 0) {
+ h = -h;
+ }
+ sx = dy === 0 ? 0 : h * dx / dy;
+ sy = h;
+ } else {
+ // Intersection is left or right of rect.
+ if (dx < 0) {
+ w = -w;
+ }
+ sx = w;
+ sy = dx === 0 ? 0 : w * dy / dx;
+ }
+ return {
+ x: x + sx,
+ y: y + sy
+ };
+ },
+ }
+ }
+ LinegaeUtils.refreshGraphForSafari = function(options) {
+ var edgePathEl = options.edgeEl,
+ IEGraphRenderDone = 0;
+ edgePathEl.each(function(argument) {
+ var eleRef = this,
+ childNode = $(this).find('pattern');
+ setTimeout(function(argument) {
+ $(eleRef).find('defs').append(childNode);
+ }, 500);
+ });
+ }
+ LinegaeUtils.refreshGraphForIE = function(options) {
+ var edgePathEl = options.edgeEl,
+ IEGraphRenderDone = 0;
+ edgePathEl.each(function(argument) {
+ var childNode = $(this).find('marker');
+ $(this).find('marker').remove();
+ var eleRef = this;
+ ++IEGraphRenderDone;
+ setTimeout(function(argument) {
+ $(eleRef).find('defs').append(childNode);
+ --IEGraphRenderDone;
+ if (IEGraphRenderDone === 0) {
+ this.$('.fontLoader').hide();
+ this.$('svg').fadeTo(1000, 1)
+ }
+ }, 1000);
+ });
+ }
+ LinegaeUtils.centerNode = function(options) {
+ var nodeID = options.guid,
+ svg = options.svg,
+ g = options.g,
+ afterCenterZoomed = options.afterCenterZoomed,
+ zoom = d3.behavior.zoom(),
+ svgGroup = svg.find("g"),
+ edgePathEl = options.edgeEl,
+ zoomBind = function() {
+ svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+ },
+ selectedNode = $(svg).find("g.nodes").find('>g#' + nodeID);
+ return {
+ init: function() {
+ if (selectedNode.length > 0) {
+ selectedNode = selectedNode;
+ var matrix = selectedNode.attr('transform').replace(/[^0-9\-.,]/g, '').split(',');
+ if (platform.name === "IE" || platform.name === "Microsoft Edge") {
+ var matrix = selectedNode.attr('transform').replace(/[a-z\()]/g, '').split(' ');
+ }
+ var x = matrix[0],
+ y = matrix[1];
+ } else {
+ selectedNode = $(svg).find("g.nodes").find('g').eq(1);
+ var x = g.graph().width / 2,
+ y = g.graph().height / 2;
+
+ }
+ var viewerWidth = $(svg).width(),
+ viewerHeight = $(svg).height(),
+ gBBox = d3.select('g').node().getBBox(),
+ zoomListener = zoom.scaleExtent([0.01, 50]).on("zoom", zoomBind),
+ scale = 1.2,
+ xa = -((x * scale) - (viewerWidth / 2)),
+ ya = -((y * scale) - (viewerHeight / 2));
+
+ zoom.translate([xa, ya]);
+ d3.select('g').transition()
+ .duration(350)
+ .attr("transform", "translate(" + xa + "," + ya + ")scale(" + scale + ")");
+ zoomListener.scale(scale);
+ zoomListener.translate([xa, ya]);
+ zoom.scale(scale);
+ afterCenterZoomed({ newScale: scale, newTranslate: [xa, ya] });
+ LinegaeUtils.refreshGraphForIE({ "edgeEl": edgePathEl })
+ }
+ }
+ }
+ LinegaeUtils.onHoverFade = function(options) {
+ var opacity = options.opacity,
+ d = options.selectedNode,
+ nodesToHighlight = options.highlight,
+ svg = options.svg,
+ isConnected = function(a, b, o) {
+ if (a === o || (b && b.length && b.indexOf(o) != -1)) {
+ return true;
+ }
+ },
+ node = svg.selectAll('.node'),
+ path = svg.selectAll('.edgePath');
+ return {
+ init: function() {
+ node.classed("hover-active", function(selectedNode, i, nodes) {
+ if (isConnected(d, nodesToHighlight, selectedNode)) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+ path.classed('hover-active-node', function(c) {
+ var _thisOpacity = c.v === d || c.w === d ? 1 : 0;
+ if (_thisOpacity) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ }
+ }
+
+ }
+ LinegaeUtils.base64Encode = function(options) {
+ var str = options.data,
+ CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+ out = "",
+ i = 0,
+ len = str.length,
+ c1, c2, c3;
+ while (i < len) {
+ c1 = str.charCodeAt(i++) & 0xff;
+ if (i == len) {
+ out += CHARS.charAt(c1 >> 2);
+ out += CHARS.charAt((c1 & 0x3) << 4);
+ out += "==";
+ break;
+ }
+ c2 = str.charCodeAt(i++);
+ if (i == len) {
+ out += CHARS.charAt(c1 >> 2);
+ out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
+ out += CHARS.charAt((c2 & 0xF) << 2);
+ out += "=";
+ break;
+ }
+ c3 = str.charCodeAt(i++);
+ out += CHARS.charAt(c1 >> 2);
+ out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
+ out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
+ out += CHARS.charAt(c3 & 0x3F);
+ }
+ return out;
+ }
+ return LinegaeUtils;
+});
\ No newline at end of file