LineageLayoutView.js 18.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/**
 * 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',
    'backbone',
    'hbs!tmpl/graph/LineageLayoutView_tmpl',
    'collection/VLineageList',
    'models/VEntity',
24
    'utils/Utils',
25 26
    'LineageHelper',
    'd3',
27
    'dagreD3',
28
    'd3-tip',
29
    'utils/Enums',
30
    'utils/UrlLinks',
31
    'utils/Globals',
32
    'utils/CommonViewFunction',
33 34
    'platform',
    'jquery-ui'
35
], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, LineageHelper, d3, dagreD3, d3Tip, Enums, UrlLinks, Globals, CommonViewFunction, platform) {
36 37 38 39 40 41 42 43
    'use strict';

    var LineageLayoutView = Backbone.Marionette.LayoutView.extend(
        /** @lends LineageLayoutView */
        {
            _viewName: 'LineageLayoutView',

            template: LineageLayoutViewtmpl,
44
            className: "resizeGraph",
45 46 47 48 49 50

            /** Layout sub regions */
            regions: {},

            /** ui selector cache */
            ui: {
51
                graph: ".graph",
52
                checkHideProcess: "[data-id='checkHideProcess']",
53 54
                checkDeletedEntity: "[data-id='checkDeletedEntity']",
                selectDepth: 'select[data-id="selectDepth"]',
55 56 57 58
                filterToggler: '[data-id="filter-toggler"]',
                settingToggler: '[data-id="setting-toggler"]',
                searchToggler: '[data-id="search-toggler"]',
                boxClose: '[data-id="box-close"]',
59
                lineageFullscreenToggler: '[data-id="fullScreen-toggler"]',
60 61 62
                filterBox: '.filter-box',
                searchBox: '.search-box',
                settingBox: '.setting-box',
63 64
                lineageTypeSearch: '[data-id="typeSearch"]',
                searchNode: '[data-id="searchNode"]',
65
                nodeDetailTable: '[data-id="nodeDetailTable"]',
66
                showOnlyHoverPath: '[data-id="showOnlyHoverPath"]',
67 68
                showTooltip: '[data-id="showTooltip"]',
                saveSvg: '[data-id="saveSvg"]',
69 70 71
                resetLineage: '[data-id="resetLineage"]',
                onZoomIn: '[data-id="zoom-in"]',
                onZoomOut: '[data-id="zoom-out"]'
72
            },
73 74 75 76 77 78
            templateHelpers: function() {
                return {
                    width: "100%",
                    height: "100%"
                };
            },
79 80 81
            /** ui events hash */
            events: function() {
                var events = {};
82 83
                events["click " + this.ui.checkHideProcess] = 'onCheckUnwantedEntity';
                events["click " + this.ui.checkDeletedEntity] = 'onCheckUnwantedEntity';
84
                events['change ' + this.ui.selectDepth] = 'onSelectDepthChange';
85 86 87
                events["click " + this.ui.filterToggler] = 'onClickFilterToggler';
                events["click " + this.ui.boxClose] = 'toggleBoxPanel';
                events["click " + this.ui.settingToggler] = 'onClickSettingToggler';
88
                events["click " + this.ui.lineageFullscreenToggler] = 'onClickLineageFullscreenToggler';
89
                events["click " + this.ui.searchToggler] = 'onClickSearchToggler';
90
                events["click " + this.ui.saveSvg] = 'onClickSaveSvg';
91
                events["click " + this.ui.resetLineage] = 'onClickResetLineage';
92 93
                events["click " + this.ui.onZoomIn] = 'onClickZoomIn';
                events["click " + this.ui.onZoomOut] = 'onClickZoomOut';
94 95 96 97 98 99 100 101
                return events;
            },

            /**
             * intialize a new LineageLayoutView Layout
             * @constructs
             */
            initialize: function(options) {
102
                _.extend(this, _.pick(options, 'processCheck', 'guid', 'entity', 'entityName', 'entityDefCollection', 'actionCallBack', 'fetchCollection', 'attributeDefs'));
103 104
                this.collection = new VLineageList();
                this.typeMap = {};
105 106
                this.apiGuid = {};
                this.edgeCall;
107 108
                this.filterObj = {
                    isProcessHideCheck: false,
109
                    isDeletedEntityHideCheck: false,
110 111
                    depthCount: ''
                };
112 113 114
                this.searchNodeObj = {
                    selectedNode: ''
                }
115
            },
116 117
            onRender: function() {
                var that = this;
118 119
                this.ui.searchToggler.prop("disabled", true);
                this.$graphButtonsEl = this.$(".graph-button-group button,select[data-id='selectDepth']")
120 121 122 123 124 125 126
                this.fetchGraphData();
                if (this.layoutRendered) {
                    this.layoutRendered();
                }
                if (this.processCheck) {
                    this.hideCheckForProcess();
                }
127
                //this.initializeGraph();
128 129 130 131 132 133
                this.ui.selectDepth.select2({
                    data: _.sortBy([3, 6, 9, 12, 15, 18, 21]),
                    tags: true,
                    dropdownCssClass: "number-input",
                    multiple: false
                });
134 135 136
            },
            onShow: function() {
                this.$('.fontLoader').show();
137 138 139 140 141 142 143
                // this.$el.resizable({
                //     handles: ' s',
                //     minHeight: 375,
                //     stop: function(event, ui) {
                //         ui.element.height(($(this).height()));
                //     },
                // });
144 145
            },
            onClickLineageFullscreenToggler: function(e) {
146
                var icon = $(e.currentTarget).find('i'),
147 148
                    panel = $(e.target).parents('.tab-pane').first();
                icon.toggleClass('fa-expand fa-compress');
149 150 151 152
                if (icon.hasClass('fa-expand')) {
                    icon.parent('button').attr("data-original-title", "Full Screen");
                } else {
                    icon.parent('button').attr("data-original-title", "Default View");
153
                }
154
                panel.toggleClass('fullscreen-mode');
155 156 157 158 159
                var node = this.$("svg").parent()[0].getBoundingClientRect();
                this.LineageHelperRef.updateOptions({
                    width: node.width,
                    height: node.height
                });
160
            },
161
            onCheckUnwantedEntity: function(e) {
162
                var that = this;
163
                //this.initializeGraph();
164 165 166 167 168
                if ($(e.target).data("id") === "checkHideProcess") {
                    this.filterObj.isProcessHideCheck = e.target.checked;
                } else {
                    this.filterObj.isDeletedEntityHideCheck = e.target.checked;
                }
169
                this.LineageHelperRef.refresh();
170
            },
171 172 173 174
            toggleBoxPanel: function(options) {
                var el = options && options.el,
                    nodeDetailToggler = options && options.nodeDetailToggler,
                    currentTarget = options.currentTarget;
175 176 177
                this.$el.find('.show-box-panel').removeClass('show-box-panel');
                if (el && el.addClass) {
                    el.addClass('show-box-panel');
178
                }
179 180
                this.$('circle.node-detail-highlight').removeClass("node-detail-highlight");
            },
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
            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');
                }
            },
            toggleDisableState: function(options) {
                var el = options.el,
                    disabled = options.disabled;
                if (el && el.prop) {
                    if (disabled) {
                        el.prop("disabled", disabled);
                    } else {
                        el.prop("disabled", !el.prop("disabled"));
                    }
                }
            },
199 200
            onClickNodeToggler: function(options) {
                this.toggleBoxPanel({ el: this.$('.lineage-node-detail'), nodeDetailToggler: true });
201
            },
202
            onClickFilterToggler: function() {
203
                this.toggleBoxPanel({ el: this.ui.filterBox });
204 205
            },
            onClickSettingToggler: function() {
206
                this.toggleBoxPanel({ el: this.ui.settingBox });
207 208
            },
            onClickSearchToggler: function() {
209
                this.toggleBoxPanel({ el: this.ui.searchBox });
210
            },
211
            onSelectDepthChange: function(e, options) {
212
                //this.initializeGraph();
213 214 215
                this.filterObj.depthCount = e.currentTarget.value;
                this.fetchGraphData({ queryParam: { 'depth': this.filterObj.depthCount } });
            },
216 217
            onClickResetLineage: function() {
                this.LineageHelperRef.refresh();
218 219
                this.searchNodeObj.selectedNode = "";
                this.ui.lineageTypeSearch.data({ refresh: true }).val("").trigger("change");
220 221 222 223 224 225 226 227 228 229
            },
            onClickSaveSvg: function(e, a) {
                this.LineageHelperRef.exportLineage();
            },
            onClickZoomIn: function() {
                this.LineageHelperRef.zoomIn();
            },
            onClickZoomOut: function() {
                this.LineageHelperRef.zoomOut();
            },
230 231 232
            fetchGraphData: function(options) {
                var that = this,
                    queryParam = options && options.queryParam || {};
233 234
                this.$('.fontLoader').show();
                this.$('svg>g').hide();
235
                this.toggleDisableState({
236 237
                    "el": that.$graphButtonsEl,
                    disabled: true
238
                });
239
                this.collection.getLineage(this.guid, {
240
                    queryParam: queryParam,
241
                    success: function(data) {
242 243 244
                        if (that.isDestroyed) {
                            return;
                        }
245 246 247

                        that.createGraph(data);
                        that.renderLineageTypeSearch(data);
248
                    },
249
                    cust_error: function(model, response) {
250
                        that.noLineage();
251 252 253 254
                    },
                    complete: function() {
                        that.$('.fontLoader').hide();
                        that.$('svg>g').show();
255
                    }
256
                })
257
            },
258 259 260 261 262 263 264 265 266 267 268 269 270
            createGraph: function(data) {
                var that = this;
                $('.resizeGraph').css("height", this.$('.svg').height() + "px");

                this.LineageHelperRef = new LineageHelper.default({
                    entityDefCollection: this.entityDefCollection.fullCollection.toJSON(),
                    data: data,
                    el: this.$('.svg')[0],
                    legendsEl: this.$('.legends')[0],
                    getFilterObj: function() {
                        return {
                            isProcessHideCheck: that.filterObj.isProcessHideCheck,
                            isDeletedEntityHideCheck: that.filterObj.isDeletedEntityHideCheck
271
                        }
272
                    },
273 274 275 276 277 278 279 280 281 282 283 284 285
                    isShowHoverPath: function() { return that.ui.showOnlyHoverPath.prop('checked') },
                    isShowTooltip: function() { return that.ui.showTooltip.prop('checked') },
                    onPathClick: function(d) {
                        console.log("Path Clicked");
                        if (d.pathRelationObj) {
                            var relationshipId = d.pathRelationObj.relationshipId;
                            require(['views/graph/PropagationPropertyModal'], function(PropagationPropertyModal) {
                                var view = new PropagationPropertyModal({
                                    edgeInfo: d.pathRelationObj,
                                    relationshipId: relationshipId,
                                    lineageData: data,
                                    apiGuid: that.apiGuid,
                                    detailPageFetchCollection: that.fetchCollection
286
                                });
287
                            });
288
                        }
289 290 291 292 293 294 295 296
                    },
                    onNodeClick: function(d) {
                        that.onClickNodeToggler();
                        that.updateRelationshipDetails({ guid: d.clickedData });
                    },
                    onLabelClick: function(d) {
                        var guid = d.clickedData;
                        if (that.guid == guid) {
297 298 299 300 301 302
                            Utils.notifyInfo({
                                html: true,
                                content: "You are already on " + "<b>" + that.entityName + "</b> detail page."
                            });
                        } else {
                            Utils.setUrl({
303
                                url: '#!/detailPage/' + guid + '?tabActive=lineage',
304 305 306 307
                                mergeBrowserUrl: false,
                                trigger: true
                            });
                        }
308 309 310 311 312 313
                    },
                    beforeRender: function() {
                        that.$('.fontLoader').show();
                        that.toggleDisableState({
                            "el": that.$graphButtonsEl,
                            disabled: true
314
                        });
315 316 317 318 319 320 321 322 323 324
                    },
                    afterRender: function() {
                        // Remove Loader
                        that.$('.fontLoader').hide();
                        if (data.relations.length) {
                            that.toggleDisableState({
                                "el": that.$graphButtonsEl,
                                disabled: false
                            });
                        }
325
                    }
326
                });
327 328 329 330 331 332 333
            },
            noLineage: function() {
                this.$('.fontLoader').hide();
                this.$('.depth-container').hide();
                this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No lineage data found</text>');
                if (this.actionCallBack) {
                    this.actionCallBack();
334
                }
335
            },
336 337 338 339
            hideCheckForProcess: function() {
                this.$('.hideProcessContainer').hide();
            },
            renderLineageTypeSearch: function(data) {
340 341 342
                var that = this;
                return new Promise(function(resolve, reject) {
                    try {
343 344 345 346
                        var typeStr = '<option></option>';
                        if (!_.isEmpty(data)) {
                            _.each(data.guidEntityMap, function(obj, index) {
                                var nodeData = that.LineageHelperRef.getNode(obj.guid);
347 348 349 350 351
                                if ((that.filterObj.isProcessHideCheck || that.filterObj.isDeletedEntityHideCheck) && nodeData && (nodeData.isProcess || nodeData.isDeleted)) {
                                    return;
                                }
                                typeStr += '<option value="' + obj.guid + '">' + obj.displayText + '</option>';
                            });
352
                        }
353 354 355 356 357 358 359 360
                        that.ui.lineageTypeSearch.html(typeStr);
                        that.initilizelineageTypeSearch();
                        resolve();
                    } catch (e) {
                        console.log(e);
                        reject(e);
                    }
                })
361
            },
362
            initilizelineageTypeSearch: function() {
363
                var that = this;
364
                this.ui.lineageTypeSearch.select2({
365 366 367 368 369
                    closeOnSelect: true,
                    placeholder: 'Select Node'
                }).on('change.select2', function(e) {
                    e.stopPropagation();
                    e.stopImmediatePropagation();
370 371 372 373 374 375 376
                    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);
                    }
377
                });
378 379 380
                if (this.searchNodeObj.selectedNode) {
                    this.ui.lineageTypeSearch.val(this.searchNodeObj.selectedNode);
                    this.ui.lineageTypeSearch.trigger("change.select2");
381 382
                }
            },
383
            updateRelationshipDetails: function(options) {
384
                var that = this,
385
                    guid = options.guid,
386 387 388 389 390
                    initialData = that.LineageHelperRef.getNode(guid);
                if (initialData === undefined) {
                    return;
                }
                var typeName = initialData.typeName || guid,
391
                    attributeDefs = initialData && initialData.entityDef ? initialData.entityDef.attributeDefs : null;
392
                this.$("[data-id='typeName']").text(typeName);
393
                this.entityModel = new VEntity({});
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
                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;
                    }
                });
                this.ui.nodeDetailTable.html(CommonViewFunction.propertyTable({
                    "scope": this,
                    "valueObject": data,
                    "attributeDefs": attributeDefs,
                    "sortBy": false
                }));
421
            }
422 423
        });
    return LineageLayoutView;
424
});