blob: b06c5d2a4607046482528ac41b1c180774e01d44 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {CUSTOM_EVENTS} from '../vue_custom_events.js';
import {GraphFilterInput} from './graph_filter_input.js';
import {GraphFilterItems} from './graph_filter_items.js';
import {GraphInboundInput} from './graph_inbound_input.js';
import {GraphOutboundInput} from './graph_outbound_input.js';
import {GraphVisualization} from './graph_visualization.js';
import {GraphSelectedNodeDetails} from './graph_selected_node_details.js';
import {PageUrlGenerator} from './page_url_generator.js';
import {parsePackageGraphModelFromJson} from '../process_graph_json.js';
import {generateFilterFromUrl} from '../url_processor.js';
import {PageModel} from '../page_model.js';
import {Node} from '../graph_model.js';
const PackageGraphPage = Vue.component('package-graph-page', {
components: {
'graph-filter-input': GraphFilterInput,
'graph-filter-items': GraphFilterItems,
'graph-inbound-input': GraphInboundInput,
'graph-outbound-input': GraphOutboundInput,
'graph-visualization': GraphVisualization,
'graph-selected-node-details': GraphSelectedNodeDetails,
'page-url-generator': PageUrlGenerator,
},
props: ['graphJson'],
/**
* Various references to objects used across the entire page.
* @typedef {Object} PageData
* @property {PageModel} pageModel The data store for the page.
* @property {number} graphDataUpdateTicker Incremented every time we want to
* trigger a visualization update. See graph_visualization.js for further
* explanation on this variable.
*/
/**
* @return {PageData} The objects used throughout the page.
*/
data: function() {
const graphModel = parsePackageGraphModelFromJson(this.graphJson);
const pageModel = new PageModel(graphModel);
return {
pageModel,
graphDataUpdateTicker: 0,
};
},
/**
* Parses out data from the current URL to initialize the visualization with.
*/
mounted: function() {
const includedNodesInUrl = generateFilterFromUrl(document.URL);
if (includedNodesInUrl.length !== 0) {
this.addNodesToFilter(includedNodesInUrl);
} else {
// TODO(yjlong): This is test data. Remove this when no longer needed.
this.addNodesToFilter([
'org.chromium.base',
'org.chromium.chrome.browser.gsa',
'org.chromium.chrome.browser.omaha',
'org.chromium.chrome.browser.media',
'org.chromium.ui.base',
]);
}
this.setOutboundDepth(1);
this.graphDataUpdateTicker++;
},
methods: {
/**
* @param {string} nodeName The node to add.
*/
addNodeToFilter: function(nodeName) {
this.pageModel.nodeFilterData.addNode(nodeName);
this.graphDataUpdateTicker++;
},
/**
* Adds all supplied nodes to the node filter, then increments
* `graphDataUpdateTicker` once at the end, even if `nodeNames` is empty.
* @param {!Array<string>} nodeNames The nodes to add.
*/
addNodesToFilter: function(nodeNames) {
for (const nodeName of nodeNames) {
this.pageModel.nodeFilterData.addNode(nodeName);
}
this.graphDataUpdateTicker++;
},
/**
* @param {string} nodeName The node to remove.
*/
removeNodeFromFilter: function(nodeName) {
this.pageModel.nodeFilterData.removeNode(nodeName);
this.graphDataUpdateTicker++;
},
/**
* @param {number} depth The new inbound depth.
*/
setInboundDepth: function(depth) {
this.pageModel.inboundDepthData.inboundDepth = depth;
this.graphDataUpdateTicker++;
},
/**
* @param {number} depth The new outbound depth.
*/
setOutboundDepth: function(depth) {
this.pageModel.outboundDepthData.outboundDepth = depth;
this.graphDataUpdateTicker++;
},
/**
* @param {?Node} node The selected node. May be `null`, which will reset
* the selection to the state with no node.
*/
graphNodeClicked: function(node) {
this.pageModel.selectedNodeDetailsData.selectedNode = node;
},
},
template: `
<div id="page-container">
<div id="page-controls">
<graph-filter-input
:node-ids="this.pageModel.getNodeIds()"
@${CUSTOM_EVENTS.FILTER_SUBMITTED}="this.addNodeToFilter"
></graph-filter-input>
<graph-filter-items
:node-filter-data="this.pageModel.nodeFilterData"
@${CUSTOM_EVENTS.FILTER_ELEMENT_CLICKED}="this.removeNodeFromFilter"
></graph-filter-items>
<graph-inbound-input
:inbound-depth-data="this.pageModel.inboundDepthData"
@${CUSTOM_EVENTS.INBOUND_DEPTH_UPDATED}="this.setInboundDepth"
></graph-inbound-input>
<graph-outbound-input
:outbound-depth-data="this.pageModel.outboundDepthData"
@${CUSTOM_EVENTS.OUTBOUND_DEPTH_UPDATED}="this.setOutboundDepth"
></graph-outbound-input>
</div>
<div id="graph-and-node-details-container">
<graph-visualization
:graph-data-update-ticker="this.graphDataUpdateTicker"
:page-model="this.pageModel"
@${CUSTOM_EVENTS.NODE_CLICKED}="graphNodeClicked"
></graph-visualization>
<graph-selected-node-details
:selected-node-details-data="this.pageModel.selectedNodeDetailsData"
@${CUSTOM_EVENTS.ADD_TO_FILTER_CLICKED}="addNodeToFilter"
@${CUSTOM_EVENTS.REMOVE_FROM_FILTER_CLICKED}="removeNodeFromFilter"
></graph-selected-node-details>
</div>
<page-url-generator
:node-filter-data="this.pageModel.nodeFilterData"
></page-url-generator>
</div>`,
});
export {
PackageGraphPage,
};