From 0bcc2fc62132faf36aece0eabb9fcacc226c459a Mon Sep 17 00:00:00 2001
From: Jess Sightler
Date: Mon, 9 Apr 2018 16:34:27 -0400
Subject: [PATCH 1/8] WINDUP-1895: Fix performance with extremely large #s of
packages
---
.../windup/web/services/model/Package.java | 16 +-
ui/src/main/webapp/css/windup-web.css | 180 +++++++++---------
ui/src/main/webapp/package.json | 1 +
.../analysis-context-form.component.ts | 1 +
.../package-registry.service.ts | 10 +-
ui/src/main/webapp/src/app/app.module.ts | 3 +
.../webapp/src/app/project/project.module.ts | 1 -
.../application-details.component.ts | 4 +-
.../js-tree-angular-wrapper.component.html | 2 +-
.../js-tree-angular-wrapper.component.ts | 140 ++------------
.../webapp/src/app/shared/shared.module.ts | 4 +
.../services/package-registry.service.spec.ts | 22 +--
ui/src/main/webapp/yarn.lock | 24 ++-
13 files changed, 164 insertions(+), 244 deletions(-)
diff --git a/model/src/main/java/org/jboss/windup/web/services/model/Package.java b/model/src/main/java/org/jboss/windup/web/services/model/Package.java
index 4d9692349..ba286f53b 100644
--- a/model/src/main/java/org/jboss/windup/web/services/model/Package.java
+++ b/model/src/main/java/org/jboss/windup/web/services/model/Package.java
@@ -46,11 +46,11 @@ public class Package implements Serializable
private Package parent;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "parent")
- private Set childs;
+ private Set children;
public Package()
{
- this.childs = new HashSet<>();
+ this.children = new HashSet<>();
}
/**
@@ -61,7 +61,7 @@ public Package()
public Package(String name)
{
this.name = name;
- this.childs = new HashSet<>();
+ this.children = new HashSet<>();
}
/**
@@ -74,7 +74,7 @@ public Package(String partialName, String fullName)
{
this.name = partialName;
this.fullName = fullName;
- this.childs = new HashSet<>();
+ this.children = new HashSet<>();
}
public Long getId()
@@ -163,9 +163,9 @@ public void setParent(Package parent)
this.parent = parent;
}
- public Collection getChilds()
+ public Collection getChildren()
{
- return childs;
+ return children;
}
/**
@@ -175,7 +175,7 @@ public Collection getChilds()
*/
public void addChild(Package child)
{
- this.childs.add(child);
+ this.children.add(child);
}
/**
@@ -185,7 +185,7 @@ public void addChild(Package child)
*/
public void removeChild(Package child)
{
- this.childs.remove(child);
+ this.children.remove(child);
}
diff --git a/ui/src/main/webapp/css/windup-web.css b/ui/src/main/webapp/css/windup-web.css
index c67e7f9e2..ed8eecf21 100644
--- a/ui/src/main/webapp/css/windup-web.css
+++ b/ui/src/main/webapp/css/windup-web.css
@@ -1,161 +1,161 @@
.nav-pf-vertical {
- width: 240px;
+ width: 240px;
}
.nav-pf-vertical .list-group-item > a {
- width: 240px;
+ width: 240px;
}
.form-errors {
- margin-bottom: 10px;
+ margin-bottom: 10px;
}
.layout-pf.layout-pf-fixed body {
- padding-top: unset;
+ padding-top: unset;
}
.container-fluid {
- padding-top: 60px;
+ padding-top: 60px;
}
.wizard-content .container-fluid {
- padding-top: 0px;
+ padding-top: 0px;
}
table.datatable, table.dataTable {
- height: unset;
+ height: unset;
}
.pointer {
- cursor: pointer;
+ cursor: pointer;
}
.page-header-no-border {
- border: 0 none;
- margin-bottom: 0;
+ border: 0 none;
+ margin-bottom: 0;
}
.page-header h1 {
- margin: 15px;
+ margin: 15px;
}
.page-header h1 span.slash {
- color: #555;
+ color: #555;
}
.page-header h1 {
- padding-left: 12pt;
+ padding-left: 12pt;
}
.page-header h1 div.main {
- border-bottom: 1px solid #add8e6;
- color: #005387;
- margin: 0 6em 0.5ex 0;
- width: auto;
+ border-bottom: 1px solid #add8e6;
+ color: #005387;
+ margin: 0 6em 0.5ex 0;
+ width: auto;
}
.page-header div.desc, div.tooltipLikeMessage {
- background: beige none repeat scroll 0 0;
- border: 1px solid #888;
- color: black;
- display: inline-block;
- font-size: 12pt;
- font-weight: normal;
- padding: 1ex 1em;
+ background: beige none repeat scroll 0 0;
+ border: 1px solid #888;
+ color: black;
+ display: inline-block;
+ font-size: 12pt;
+ font-weight: normal;
+ padding: 1ex 1em;
}
.page-header div.desc {
- margin: 0 15px 15px 30px;
+ margin: 0 15px 15px 30px;
}
div.tooltipLikeMessage {
- margin: 15px 0 0;
+ margin: 15px 0 0;
}
.page-header div.desc::before, div.tooltipLikeMessage::before {
- color: gray;
- content: "";
- cursor: help;
- display: inline-block;
- font-family: "Glyphicons Halflings";
- font-size: 12pt;
- font-style: normal;
- font-weight: normal;
- line-height: 1;
- padding: 0.3ex 0.3em;
- position: relative;
- top: 1px;
- vertical-align: top;
+ color: gray;
+ content: "";
+ cursor: help;
+ display: inline-block;
+ font-family: "Glyphicons Halflings";
+ font-size: 12pt;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ padding: 0.3ex 0.3em;
+ position: relative;
+ top: 1px;
+ vertical-align: top;
}
.windupPieGraph div.legend td.legendLabel {
- padding-left: 0.6ex;
+ padding-left: 0.6ex;
}
.clickable {
- cursor: pointer;
+ cursor: pointer;
}
.label-info {
- background-color: #696969;
+ background-color: #696969;
}
.label-danger {
- background-color: #f04124;
+ background-color: #f04124;
}
.welcome-help-text {
- padding-top: 15px;
+ padding-top: 15px;
}
th {
- font-size: 12px;
+ font-size: 12px;
}
td {
- font-size: 12px;
+ font-size: 12px;
}
.external-link::before {
- content: '\F2D2';
- font: normal normal normal 14px/1 FontAwesome;
- font-size: 12px;
- padding-right: 3px;
+ content: '\F2D2';
+ font: normal normal normal 14px/1 FontAwesome;
+ font-size: 12px;
+ padding-right: 3px;
}
.container-fluid .wu-frame {
- background: #e8e8e8;
- margin-left: 20px !important;
- margin-right: 20px !important;
- margin-bottom: 2px !important;
+ background: #e8e8e8;
+ margin-left: 20px !important;
+ margin-right: 20px !important;
+ margin-bottom: 2px !important;
- padding-top: 0; /* override */
+ padding-top: 0; /* override */
}
form .wizard-form {
- padding-left: 10px;
- padding-right: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
}
label.required:before {
- content: '*';
- position: relative;
- left: -2ex;
- float: left;
- width: 0;
+ content: '*';
+ position: relative;
+ left: -2ex;
+ float: left;
+ width: 0;
}
.btn {
- text-transform: capitalize;
+ text-transform: capitalize;
}
fieldset.fields-section-pf {
- border-color: #adaaaa;
+ border-color: #adaaaa;
}
.form-horizontal .form-group {
- margin-left: 10px;
- margin-right: 10px;
+ margin-left: 10px;
+ margin-right: 10px;
}
.wu-horizontal-nav-content {
-/* margin-top: 122px; */
- padding-top: 122px;
- margin-top: 0;
+ /* margin-top: 122px; */
+ padding-top: 122px;
+ margin-top: 0;
}
/*
@@ -164,38 +164,42 @@ fieldset.fields-section-pf {
}
*/
@media (max-width: 767px) {
- .wu-horizontal-nav-content, .layout-pf.layout-pf-fixed .container-pf-nav-pf-vertical {
- margin-left: 0;
- margin-top: initial;
- }
+ .wu-horizontal-nav-content, .layout-pf.layout-pf-fixed .container-pf-nav-pf-vertical {
+ margin-left: 0;
+ margin-top: initial;
+ }
- .container-fluid {
- padding-top: initial;
- }
+ .container-fluid {
+ padding-top: initial;
+ }
}
@media (min-width: 768px) and (max-width: 1599px) {
- .nav-pf-vertical .list-group-item > a {
- width: 240px;
- }
+ .nav-pf-vertical .list-group-item > a {
+ width: 240px;
+ }
- .wu-horizontal-nav-content, .layout-pf.layout-pf-fixed .container-pf-nav-pf-vertical {
- margin-left: 240px;
- }
+ .wu-horizontal-nav-content, .layout-pf.layout-pf-fixed .container-pf-nav-pf-vertical {
+ margin-left: 240px;
+ }
}
@media (min-width: 1599px) {
- .wu-horizontal-nav-content, .layout-pf.layout-pf-fixed .container-pf-nav-pf-vertical {
- margin-left: 240px;
- }
+ .wu-horizontal-nav-content, .layout-pf.layout-pf-fixed .container-pf-nav-pf-vertical {
+ margin-left: 240px;
+ }
}
/* Pushes notifications area a bit down from the horizontal navigation bar. */
.notifications-row {
- padding-top: 24px;
+ padding-top: 24px;
}
.alert {
- margin-top: 20px;
- margin-bottom: 0px;
+ margin-top: 20px;
+ margin-bottom: 0px;
}
+
+
+@import '~angular-tree-component/dist/angular-tree-component.css';
+
diff --git a/ui/src/main/webapp/package.json b/ui/src/main/webapp/package.json
index e1ffa4620..587723350 100644
--- a/ui/src/main/webapp/package.json
+++ b/ui/src/main/webapp/package.json
@@ -40,6 +40,7 @@
"@angular/router": "^4.1.2",
"@swimlane/ngx-charts": "^5.2.0",
"angular-router-loader": "^0.6.0",
+ "angular-tree-component": "^7.1.0",
"angular2-moment": "^1.3.3",
"bootstrap": "3.3.7",
"bootstrap-datepicker": "1.6.4",
diff --git a/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.ts b/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.ts
index 078643cc1..3b39c0c6a 100644
--- a/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.ts
+++ b/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.ts
@@ -263,6 +263,7 @@ export class AnalysisContextFormComponent extends FormComponent
*/
forkJoin(registeredPackagesObservables).subscribe((packageMetadataArray: PackageMetadata[]) => {
+ console.log("package metadata array: ", packageMetadataArray);
let arrayOfRoots = [].concat(...packageMetadataArray.map((singlePackageMetadata) => singlePackageMetadata.packageTree));
let mergedRoots = this._packageRegistryService.mergePackageRoots(arrayOfRoots);
mergedRoots.forEach(singleRoot => this._packageRegistryService.putHierarchy(singleRoot));
diff --git a/ui/src/main/webapp/src/app/analysis-context/package-registry.service.ts b/ui/src/main/webapp/src/app/analysis-context/package-registry.service.ts
index 56813ece9..9c16fabd0 100644
--- a/ui/src/main/webapp/src/app/analysis-context/package-registry.service.ts
+++ b/ui/src/main/webapp/src/app/analysis-context/package-registry.service.ts
@@ -24,8 +24,8 @@ export class PackageRegistryService {
public putHierarchy(aPackage: Package) {
this.put(aPackage);
- if (aPackage.childs) {
- aPackage.childs.forEach(child => this.putHierarchy(child));
+ if (aPackage.children) {
+ aPackage.children.forEach(child => this.putHierarchy(child));
}
}
@@ -60,17 +60,17 @@ export class PackageRegistryService {
protected mergePackageHierarchy(aPackage: Package, packageMap: Map, parentPackage: Package = null) {
let packageInMap: Package = null;
- let childPackages = aPackage.childs;
+ let childPackages = aPackage.children;
if (!packageMap.has(aPackage.fullName)) {
packageInMap = Object.assign({}, aPackage); // clone object
packageMap.set(aPackage.fullName, packageInMap);
if (parentPackage) {
- parentPackage.childs.push(packageInMap);
+ parentPackage.children.push(packageInMap);
}
- packageInMap.childs = [];
+ packageInMap.children = [];
} else {
// some magic
packageInMap = packageMap.get(aPackage.fullName);
diff --git a/ui/src/main/webapp/src/app/app.module.ts b/ui/src/main/webapp/src/app/app.module.ts
index ce8fff224..17fcd8f68 100644
--- a/ui/src/main/webapp/src/app/app.module.ts
+++ b/ui/src/main/webapp/src/app/app.module.ts
@@ -35,6 +35,7 @@ import {CoreModule} from "./core/core.module";
import {ExecutionsModule} from "./executions/executions.module";
import {FileUploaderWrapper} from "./shared/upload/file-uploader-wrapper.service";
import {KeycloakService} from "./core/authentication/keycloak.service";
+import {TreeModule} from "angular-tree-component";
/**
* Load all mapping data from the generated files.
@@ -53,6 +54,8 @@ initializeModelMappingData();
// Moment
MomentModule,
+ TreeModule,
+
CoreModule,
SharedModule,
ProjectModule,
diff --git a/ui/src/main/webapp/src/app/project/project.module.ts b/ui/src/main/webapp/src/app/project/project.module.ts
index a64ba86fd..967090769 100644
--- a/ui/src/main/webapp/src/app/project/project.module.ts
+++ b/ui/src/main/webapp/src/app/project/project.module.ts
@@ -7,7 +7,6 @@ import {ProjectListComponent} from "./project-list.component";
import {MigrationProjectService} from "./migration-project.service";
import {ProjectResolve} from "./project.resolve";
import {SharedModule} from "../shared/shared.module";
-import {ExecutionsModule} from "../executions/executions.module";
import {ProjectLayoutComponent} from "./project-layout.component";
@NgModule({
diff --git a/ui/src/main/webapp/src/app/reports/application-details/application-details.component.ts b/ui/src/main/webapp/src/app/reports/application-details/application-details.component.ts
index 89d7f48c9..507f338f7 100644
--- a/ui/src/main/webapp/src/app/reports/application-details/application-details.component.ts
+++ b/ui/src/main/webapp/src/app/reports/application-details/application-details.component.ts
@@ -101,13 +101,13 @@ export class ApplicationDetailsComponent extends FilterableReportComponent imple
let newTreeData:TreeData = {
id: traversal.id,
name: traversal.path,
- childs: [],
+ children: [],
opened: true,
data: traversal.canonicalID
};
if (parentTreeData) {
- parentTreeData.childs.push(newTreeData);
+ parentTreeData.children.push(newTreeData);
} else {
this.applicationTree = this.applicationTree.concat(newTreeData);
}
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
index 7c89b545c..0d4d1e8d0 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
@@ -1 +1 @@
-
+
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
index 8a3a16edb..33fe0a2f8 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
@@ -1,21 +1,16 @@
import {
- Component, OnInit, Input, ElementRef, SimpleChange, Output, EventEmitter, NgZone,
- OnChanges, OnDestroy
+ Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewEncapsulation
} from "@angular/core";
-import {Package} from "../generated/windup-services";
-import * as $ from "jquery";
-import 'jstree';
-import {SchedulerService} from "./scheduler.service";
/**
- * Wrapper for jstree from: https://www.jstree.com/
+ * Wrapper for angular tree from: https://angular2-tree.readme.io/
*/
@Component({
templateUrl: './js-tree-angular-wrapper.component.html',
selector: 'wu-js-tree-wrapper',
- host: { 'style': 'display: block; overflow: auto;' }
+ //host: { 'style': 'display: block; overflow: auto;' }
})
-export class JsTreeAngularWrapperComponent implements OnInit, OnChanges, OnDestroy {
+export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
@Input()
treeNodes: TreeData[];
@@ -24,8 +19,6 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnChanges, OnDestr
treeNodesMap: {[id: string]: TreeData} = {};
- jsTree = [];
-
@Input()
selectedNodes: TreeData[];
@@ -35,131 +28,30 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnChanges, OnDestr
@Output()
nodeClicked: EventEmitter = new EventEmitter();
- protected element;
-
- protected updateSelectionCallback: Function = () => {};
- protected static EMPTY_CALLBACK = () => {};
-
- protected treeRedrawTimeout: any;
-
- public constructor(element: ElementRef, private _zone: NgZone, private _schedulerService: SchedulerService) {
- this.element = element.nativeElement;
- }
-
- ngOnChanges(changes: {[treeNodes: string]: SimpleChange}): any {
- let jsTree = $(this.element).jstree(true);
-
- // This is ugly workaround to prevent recursively calling ngOnChanges from change handler
- this.updateSelectionCallback = JsTreeAngularWrapperComponent.EMPTY_CALLBACK;
-
- if (jsTree) {
- if (changes.hasOwnProperty('treeNodes')) {
- let newTreeNodes: Package[] = changes['treeNodes'].currentValue;
- this.jsTree = newTreeNodes.map((node) => this.transformTreeNode(node));
- (jsTree as any).settings.core.data = this.jsTree;
- jsTree.redraw(true);
- jsTree.refresh(true, false);
- }
-
- if (changes.hasOwnProperty('selectedNodes')) {
- // Another ugly workaround, now to give enough time to initialize jsTree first
- this._schedulerService.setTimeout(this._zone.run(() => this.redrawSelection()), 100);
- }
- }
-
- // This is ugly workaround to prevent recursively calling ngOnChanges from change handler
- this.updateSelectionCallback = this.updateSelectedNodes;
- }
-
- transformTreeNode(node: any): any {
- let transformed = {
- id: node.id,
- text: node.name,
- children: [],
- original: node,
- state: {}
- };
-
- if (node.opened) {
- transformed.state = {
- opened: node.opened
- }
- }
-
- let self = this;
+ options = {
+ displayField: 'name',
+ isExpandedField: 'expanded',
+ hasChildrenField: 'children',
+ animateExpand: true
+ };
- if (node.childs) {
- transformed.children = node.childs.map((mapNode) => self.transformTreeNode(mapNode));
- }
-
- this.treeNodesMap[node.id] = node;
-
- return transformed;
+ public constructor() {
+ setInterval(() => {
+ console.log("Tree data: ", this.treeNodes);
+ }, 10000);
}
ngOnInit() {
- let self = this;
-
- if (this.treeNodes) {
- this.jsTree = this.treeNodes.map((node) => self.transformTreeNode(node));
- }
-
- let plugins = this.hasCheckboxes ? ['checkbox'] : [];
- plugins.push('sort');
-
- $(this.element).jstree({
- 'plugins': plugins,
- 'core': {
- data: this.jsTree
- },
- 'checkbox': {
- 'tie_selection': false,
- 'cascade': 'undetermined+down',
- 'three_state': false
- }
- });
-
- $(this.element).on('check_node.jstree uncheck_node.jstree', (event, data) => this.updateSelectionCallback(event, data));
- $(this.element).on('select_node.jstree', (event, data) => this.fireNodeClicked(event, data));
- $(this.element).on('changed.jstree loaded.jstree', (event, data) => this.redrawSelection());
}
ngOnDestroy(): void {
- if (this.treeRedrawTimeout) {
- this._schedulerService.clearTimeout(this.treeRedrawTimeout);
- this.treeRedrawTimeout = null;
- }
- }
-
- fireNodeClicked(event, data) {
- this.nodeClicked.emit(this.treeNodesMap[data.node.id]);
- }
-
- updateSelectedNodes(event, data) {
- let jsTree = $(this.element).jstree(true);
-
- if (jsTree) {
- this._zone.run(() => {
- this.selectedNodes = jsTree.get_checked(false).map((id) => this.treeNodesMap[id]);
- this.selectedNodesChange.emit(this.selectedNodes);
- });
- }
- }
-
- redrawSelection() {
- let jsTree = $(this.element).jstree(true);
-
- if (jsTree && this.selectedNodes) {
- let selectionIds = this.selectedNodes.map(node => node.id);
- jsTree.check_node(selectionIds, null);
- }
}
}
export interface TreeData {
id: number,
name: string,
- childs: TreeData[],
+ children: TreeData[],
data: any,
- opened: boolean
+ opened: boolean,
}
diff --git a/ui/src/main/webapp/src/app/shared/shared.module.ts b/ui/src/main/webapp/src/app/shared/shared.module.ts
index 705804662..632ba1f73 100644
--- a/ui/src/main/webapp/src/app/shared/shared.module.ts
+++ b/ui/src/main/webapp/src/app/shared/shared.module.ts
@@ -62,6 +62,7 @@ import {FilterPipe} from "./filter/filter.pipe";
import {TableComponent} from "./table/table.component";
import {TableSortHeaderComponent} from "./table/table-sort-header.component";
import {TablePanelComponent} from "./table/table-panel.component";
+import {TreeModule} from "angular-tree-component";
@NgModule({
imports: [
@@ -72,6 +73,9 @@ import {TablePanelComponent} from "./table/table-panel.component";
ChosenModule,
FileUploadModule,
MomentModule,
+
+ // Angular Tree
+ TreeModule,
],
providers: [
BreadCrumbsService,
diff --git a/ui/src/main/webapp/tests/app/services/package-registry.service.spec.ts b/ui/src/main/webapp/tests/app/services/package-registry.service.spec.ts
index 3abec1403..d9a7a0c0a 100644
--- a/ui/src/main/webapp/tests/app/services/package-registry.service.spec.ts
+++ b/ui/src/main/webapp/tests/app/services/package-registry.service.spec.ts
@@ -16,7 +16,7 @@ describe("PackageRegistryService", () => {
name: name,
fullName: fullName,
countClasses: 1,
- childs: [],
+ children: [],
level: level
};
};
@@ -34,7 +34,7 @@ describe("PackageRegistryService", () => {
expect(result[0].name).toBe('root');
expect(result[0].fullName).toBe('org.jboss.root');
expect(result[0].level).toBe(0);
- expect(result[0].childs.length).toBe(0);
+ expect(result[0].children.length).toBe(0);
expect(result[0].countClasses).toBe(2);
});
@@ -58,7 +58,7 @@ describe("PackageRegistryService", () => {
let secondPackage: Package = createPackage('root', 'org.jboss.root');
let packages = [ firstPackage, secondPackage ];
- packages.forEach(aPackage => aPackage.childs = [commonChild]);
+ packages.forEach(aPackage => aPackage.children = [commonChild]);
let result = instance.mergePackageRoots(packages);
@@ -68,24 +68,24 @@ describe("PackageRegistryService", () => {
expect(result[0].level).toBe(0);
expect(result[0].countClasses).toBe(2);
- expect(result[0].childs.length).toBe(1);
+ expect(result[0].children.length).toBe(1);
- let child = result[0].childs[0];
+ let child = result[0].children[0];
expect(child.name).toBe(commonChild.name);
expect(child.fullName).toBe(commonChild.fullName);
expect(child.level).toBe(commonChild.level);
- expect(child.childs.length).toBe(0);
+ expect(child.children.length).toBe(0);
expect(child.countClasses).toBe(commonChild.countClasses * 2);
});
it('should add different children', () => {
let firstPackage: Package = createPackage('root', 'org.jboss.root');
- firstPackage.childs = [
+ firstPackage.children = [
createPackage('firstOneChild', 'org.jboss.root.firstOneChild', 1)
];
let secondPackage: Package = createPackage('root', 'org.jboss.root');
- secondPackage.childs = [
+ secondPackage.children = [
createPackage('secondChild', 'org.jboss.root.secondChild', 1)
];
@@ -99,9 +99,9 @@ describe("PackageRegistryService", () => {
expect(result[0].level).toBe(0);
expect(result[0].countClasses).toBe(2);
- expect(result[0].childs.length).toBe(2);
- expect(result[0].childs).toContain(firstPackage.childs[0]);
- expect(result[0].childs).toContain(secondPackage.childs[0]);
+ expect(result[0].children.length).toBe(2);
+ expect(result[0].children).toContain(firstPackage.children[0]);
+ expect(result[0].children).toContain(secondPackage.children[0]);
});
});
});
diff --git a/ui/src/main/webapp/yarn.lock b/ui/src/main/webapp/yarn.lock
index cc90f004a..fc13f8e11 100644
--- a/ui/src/main/webapp/yarn.lock
+++ b/ui/src/main/webapp/yarn.lock
@@ -401,6 +401,14 @@ angular-router-loader@^0.6.0:
dependencies:
loader-utils "^1.0.2"
+angular-tree-component@^7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/angular-tree-component/-/angular-tree-component-7.1.0.tgz#53674ea944f7147647c7e48931f5fad66237a632"
+ dependencies:
+ lodash "^4.17.5"
+ mobx "^3.6.2"
+ mobx-angular "2.1.1"
+
angular2-moment@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/angular2-moment/-/angular2-moment-1.3.3.tgz#569c433bbfa2448d5424f0e10dce6f8c8c9533eb"
@@ -3832,6 +3840,10 @@ lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lo
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+lodash@^4.17.5:
+ version "4.17.5"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
+
lodash@~4.16.4:
version "4.16.6"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777"
@@ -4050,6 +4062,14 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkd
dependencies:
minimist "0.0.8"
+mobx-angular@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/mobx-angular/-/mobx-angular-2.1.1.tgz#d5e36539acb200186dd5a1170806b4776b9a8b88"
+
+mobx@^3.6.2:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/mobx/-/mobx-3.6.2.tgz#fb9f5ff5090539a1ad54e75dc4c098b602693320"
+
moment@^2.16.0:
version "2.17.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82"
@@ -4109,10 +4129,6 @@ ng2-file-upload@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ng2-file-upload/-/ng2-file-upload-1.2.1.tgz#5563c5dfd6f43fbfbe815c206e343464a0a6a197"
-ng2-slim-loading-bar@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/ng2-slim-loading-bar/-/ng2-slim-loading-bar-4.0.0.tgz#7256fdde7c058f14955a3ef2e65afafb5b664603"
-
no-case@^2.2.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.1.tgz#7aeba1c73a52184265554b7dc03baf720df80081"
From 48f51460a81f1a7613dd4e2adc71c422abd8b269 Mon Sep 17 00:00:00 2001
From: Jess Sightler
Date: Mon, 9 Apr 2018 17:10:37 -0400
Subject: [PATCH 2/8] Commented out some debug code
---
.../src/app/shared/js-tree-angular-wrapper.component.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
index 33fe0a2f8..4d65ec59d 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
@@ -36,9 +36,9 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
};
public constructor() {
- setInterval(() => {
- console.log("Tree data: ", this.treeNodes);
- }, 10000);
+ // setInterval(() => {
+ // console.log("Tree data: ", this.treeNodes);
+ // }, 10000);
}
ngOnInit() {
From 1dd720753e67aff537b049821a04cad4aba77547 Mon Sep 17 00:00:00 2001
From: Jess Sightler
Date: Mon, 9 Apr 2018 18:02:25 -0400
Subject: [PATCH 3/8] Started working on selection code
---
.../js-tree-angular-wrapper.component.html | 7 +++-
.../js-tree-angular-wrapper.component.ts | 32 ++++++++++++++-----
2 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
index 0d4d1e8d0..540b0e669 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
@@ -1 +1,6 @@
-
+
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
index 4d65ec59d..21946d23a 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
@@ -8,17 +8,21 @@ import {
@Component({
templateUrl: './js-tree-angular-wrapper.component.html',
selector: 'wu-js-tree-wrapper',
- //host: { 'style': 'display: block; overflow: auto;' }
+ host: { 'style': 'display: block; overflow: auto;' }
})
export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
+
+ treeNodesFiltered: TreeData[];
+
@Input()
- treeNodes: TreeData[];
+ set treeNodes(inputData:TreeData[]) {
+ this.treeNodesFiltered = inputData.filter(value => value.name != null && value.name != "");
+ console.log("Tree nodes filtered: ", this.treeNodesFiltered);
+ };
@Input()
hasCheckboxes: boolean = true;
- treeNodesMap: {[id: string]: TreeData} = {};
-
@Input()
selectedNodes: TreeData[];
@@ -30,9 +34,10 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
options = {
displayField: 'name',
- isExpandedField: 'expanded',
- hasChildrenField: 'children',
- animateExpand: true
+ useCheckbox: true,
+ useTriState: false,
+ animateExpand: true,
+ nodeHeight: 22,
};
public constructor() {
@@ -44,7 +49,18 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
ngOnInit() {
}
- ngOnDestroy(): void {
+ ngOnDestroy() {
+ }
+
+ selected(event) {
+ this.selectedNodes.push(event.node.data);
+ console.log("Selected: ", this.selectedNodes);
+ }
+
+ deselected(event) {
+ console.log("Deselected event: ", event);
+ this.selectedNodes = this.selectedNodes.filter((item) => item.id != event.node.data.id);
+ console.log("De-Selected: ", this.selectedNodes);
}
}
From a19282da0ab42cd73656e969a7c47628e46c77ea Mon Sep 17 00:00:00 2001
From: Jess Sightler
Date: Tue, 10 Apr 2018 22:17:46 -0400
Subject: [PATCH 4/8] WINDUP-1895: Implemented basic sorting and selection
---
.../analysis-context-form.component.html | 4 +-
.../js-tree-angular-wrapper.component.html | 2 +
.../js-tree-angular-wrapper.component.ts | 69 ++++++++++++++++---
3 files changed, 63 insertions(+), 12 deletions(-)
diff --git a/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.html b/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.html
index 6541e2a88..5c949053b 100644
--- a/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.html
+++ b/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.html
@@ -104,8 +104,8 @@ Loading...
Identifying packages...
-
-
+
All classes in the selected packages will be ignored during analysis.
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
index 540b0e669..2e8c8907f 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
@@ -1,6 +1,8 @@
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
index 21946d23a..fad2c1f57 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
@@ -1,6 +1,8 @@
import {
- Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewEncapsulation
+ Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewEncapsulation, ViewChild, AfterViewInit, OnChanges,
+ SimpleChanges
} from "@angular/core";
+import {ITreeState, TreeComponent} from "angular-tree-component";
/**
* Wrapper for angular tree from: https://angular2-tree.readme.io/
@@ -10,21 +12,63 @@ import {
selector: 'wu-js-tree-wrapper',
host: { 'style': 'display: block; overflow: auto;' }
})
-export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
+export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnDestroy {
+
+ @ViewChild('tree')
+ treeComponent: TreeComponent;
+
+ treeState: ITreeState = {
+ selectedNodeIds: {},
+ expandedNodeIds: {},
+ hiddenNodeIds: {},
+ activeNodeIds: {}
+ };
treeNodesFiltered: TreeData[];
@Input()
set treeNodes(inputData:TreeData[]) {
- this.treeNodesFiltered = inputData.filter(value => value.name != null && value.name != "");
- console.log("Tree nodes filtered: ", this.treeNodesFiltered);
+ let sortFunc = (item1, item2) => {
+ return item1.name.localeCompare(item2.name);
+ };
+
+ let crawlAndSortChildren = (inputData:TreeData[]) => {
+ if (!inputData)
+ return inputData;
+
+ inputData.forEach(child => {
+ child.children = crawlAndSortChildren(child.children)
+ });
+
+ return inputData.sort(sortFunc);
+ };
+
+ this.treeNodesFiltered = crawlAndSortChildren(inputData.filter(value => value.name != null && value.name != "").sort(sortFunc));
};
@Input()
hasCheckboxes: boolean = true;
+ _selectedNodes: TreeData[];
+
@Input()
- selectedNodes: TreeData[];
+ set selectedNodes (newSelectedNodes: TreeData[]) {
+ this._selectedNodes = newSelectedNodes;
+
+ const selectedLeafNodeIds = {};
+
+ this._selectedNodes.forEach(selectedNode => {
+ selectedLeafNodeIds[selectedNode.id] = true;
+ });
+
+ this.treeState.selectedLeafNodeIds = selectedLeafNodeIds;
+ this.treeComponent.treeModel.setState(this.treeState);
+
+ }
+
+ get selectedNodes (): TreeData[] {
+ return this._selectedNodes;
+ }
@Output()
selectedNodesChange: EventEmitter = new EventEmitter();
@@ -35,7 +79,7 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
options = {
displayField: 'name',
useCheckbox: true,
- useTriState: false,
+ useTriState: true,
animateExpand: true,
nodeHeight: 22,
};
@@ -46,6 +90,9 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
// }, 10000);
}
+ ngAfterViewInit() {
+ }
+
ngOnInit() {
}
@@ -53,14 +100,16 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnDestroy {
}
selected(event) {
- this.selectedNodes.push(event.node.data);
- console.log("Selected: ", this.selectedNodes);
+ this._selectedNodes.push(event.node.data);
+ console.log("Selected: ", this._selectedNodes);
+ this.selectedNodesChange.emit(this._selectedNodes);
}
deselected(event) {
console.log("Deselected event: ", event);
- this.selectedNodes = this.selectedNodes.filter((item) => item.id != event.node.data.id);
- console.log("De-Selected: ", this.selectedNodes);
+ this._selectedNodes = this._selectedNodes.filter((item) => item.id != event.node.data.id);
+ this.selectedNodesChange.emit(this._selectedNodes);
+ console.log("De-Selected: ", this._selectedNodes);
}
}
From 10789a02a494fe2a1d3123623cc457fca9c1bd05 Mon Sep 17 00:00:00 2001
From: Jess Sightler
Date: Wed, 11 Apr 2018 17:52:26 -0400
Subject: [PATCH 5/8] Updated to handle large application more gracefully
---
.../analysis-context.service.ts | 9 +-
.../js-tree-angular-wrapper.component.html | 18 +--
.../js-tree-angular-wrapper.component.ts | 118 +++++++++++++++---
ui/src/main/webapp/yarn.lock | 6 +-
4 files changed, 122 insertions(+), 29 deletions(-)
diff --git a/ui/src/main/webapp/src/app/analysis-context/analysis-context.service.ts b/ui/src/main/webapp/src/app/analysis-context/analysis-context.service.ts
index cc9e021c4..7cb56c5c0 100644
--- a/ui/src/main/webapp/src/app/analysis-context/analysis-context.service.ts
+++ b/ui/src/main/webapp/src/app/analysis-context/analysis-context.service.ts
@@ -33,7 +33,14 @@ export class AnalysisContextService extends AbstractService {
* @returns {Observable}
*/
saveAsDefault(analysisContext: AnalysisContext, project: MigrationProject): Observable {
- let body = JSON.stringify(analysisContext);
+ let body = JSON.stringify(analysisContext, (key, value) => {
+ // This works around the cases where we store the parent as part of the value.
+ // It would be a circular reference without this.
+ if (key == "parent")
+ return undefined;
+
+ return value;
+ });
let url = Constants.REST_BASE + this.CREATE_URL.replace('{projectId}', project.id.toString());
return this._http.put(url, body, this.JSON_OPTIONS)
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
index 2e8c8907f..a2d1fd0bb 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
@@ -1,8 +1,10 @@
-
+
+
+
\ No newline at end of file
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
index fad2c1f57..184e11b0f 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
@@ -1,8 +1,8 @@
import {
- Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewEncapsulation, ViewChild, AfterViewInit, OnChanges,
+ Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewChild, AfterViewInit,
SimpleChanges
} from "@angular/core";
-import {ITreeState, TreeComponent} from "angular-tree-component";
+import {ITreeState, TreeComponent, TreeNode} from "angular-tree-component";
/**
* Wrapper for angular tree from: https://angular2-tree.readme.io/
@@ -24,45 +24,61 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
activeNodeIds: {}
};
- treeNodesFiltered: TreeData[];
+ treeNodesFiltered: TreeDataExtended[];
@Input()
set treeNodes(inputData:TreeData[]) {
+ console.log("Tree nodes set:", inputData);
+ // Sort alphabetically
let sortFunc = (item1, item2) => {
return item1.name.localeCompare(item2.name);
};
- let crawlAndSortChildren = (inputData:TreeData[]) => {
+ // Sort all children, and also attach the parent node
+ let crawlAndSortChildren = (parent:TreeDataExtended, inputData:TreeData[]):TreeDataExtended[] => {
if (!inputData)
- return inputData;
+ return inputData;
inputData.forEach(child => {
- child.children = crawlAndSortChildren(child.children)
+ let childExtended = child;
+ childExtended.parent = parent;
+ childExtended.hasChildren = !!(child.children && child.children.length);
+ child.children = crawlAndSortChildren(childExtended, child.children)
});
- return inputData.sort(sortFunc);
+ return inputData.sort(sortFunc).map(treeData => treeData);
};
- this.treeNodesFiltered = crawlAndSortChildren(inputData.filter(value => value.name != null && value.name != "").sort(sortFunc));
+ // Filter out any empty root nodes, sort, and convert for display purposes
+ this.treeNodesFiltered = crawlAndSortChildren(null, inputData.filter(value => value.name != null && value.name != "").sort(sortFunc));
+
+ // Make sure to reset selections so that parent and child relationships are right
+ this.selectedNodes = this._selectedNodes;
};
@Input()
hasCheckboxes: boolean = true;
- _selectedNodes: TreeData[];
+ _selectedNodes: TreeDataExtended[];
@Input()
set selectedNodes (newSelectedNodes: TreeData[]) {
- this._selectedNodes = newSelectedNodes;
+ this._selectedNodes = newSelectedNodes;
+ console.log("Reselecting nodes: ", this.treeState.selectedLeafNodeIds);
const selectedLeafNodeIds = {};
- this._selectedNodes.forEach(selectedNode => {
- selectedLeafNodeIds[selectedNode.id] = true;
- });
+ if (this._selectedNodes) {
+ this._selectedNodes.forEach(selectedNode => {
+ selectedLeafNodeIds[selectedNode.id] = true;
+
+ this.addParentSelections(selectedLeafNodeIds, selectedNode.id);
+ });
+ }
this.treeState.selectedLeafNodeIds = selectedLeafNodeIds;
this.treeComponent.treeModel.setState(this.treeState);
+ console.log("Reselected nodes: ", selectedLeafNodeIds);
}
@@ -79,9 +95,12 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
options = {
displayField: 'name',
useCheckbox: true,
- useTriState: true,
+ useTriState: false,
animateExpand: true,
nodeHeight: 22,
+ hasChildrenField: 'hasChildren',
+ childrenField: 'childNodes',
+ getChildren: (node:TreeNode) => node.data.children
};
public constructor() {
@@ -99,18 +118,87 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
ngOnDestroy() {
}
+ private addParentSelections(selectedLeafNodeIds:{}, nodeId:number) {
+ console.log("parent add searching for: " + nodeId);
+ // 1. Find node from the main set of nodes by id
+ let finder = (originalNodes:TreeDataExtended[]) => {
+ let result = null;
+
+ if (!originalNodes)
+ return null;
+
+ originalNodes.forEach(originalNode => {
+ if (result)
+ return;
+
+ if (originalNode.id == nodeId) {
+ result = originalNode;
+ return;
+ }
+
+ result = finder(originalNode.children);
+ });
+
+ return result;
+ };
+
+ let originalNode = finder(this.treeNodesFiltered);
+ console.log("Original node: ", originalNode);
+
+ while (originalNode) {
+ selectedLeafNodeIds[originalNode.id] = true;
+ originalNode = originalNode.parent;
+ }
+
+ console.log("Add parent set them to: ", selectedLeafNodeIds);
+ }
+
selected(event) {
this._selectedNodes.push(event.node.data);
+
+ // This just triggers the setter method to be called
+ this.selectedNodes = this._selectedNodes;
console.log("Selected: ", this._selectedNodes);
+ this.selectedNodes = this._selectedNodes;
this.selectedNodesChange.emit(this._selectedNodes);
}
deselected(event) {
console.log("Deselected event: ", event);
- this._selectedNodes = this._selectedNodes.filter((item) => item.id != event.node.data.id);
+ let nodesToDeselect = [];
+ let crawlNode = (data:TreeData) => {
+ if (!data)
+ return;
+
+ nodesToDeselect.push(data.id);
+
+ data.children.forEach((child) => {
+ crawlNode(child);
+ });
+ };
+ crawlNode(event.node.data);
+ console.log("Should deselect: ", nodesToDeselect);
+
+ console.log("Current: ", this._selectedNodes);
+ this._selectedNodes = this._selectedNodes.filter((item) => {
+ let index = nodesToDeselect.indexOf(item.id);
+ console.log("Item: ", item, index);
+ return index == -1;
+ });
+ console.log("Then: ", this._selectedNodes);
+
+ // This just triggers the setter method to be called
+ this.selectedNodes = this._selectedNodes;
this.selectedNodesChange.emit(this._selectedNodes);
console.log("De-Selected: ", this._selectedNodes);
}
+
+
+}
+
+export interface TreeDataExtended extends TreeData {
+ hasChildren: boolean,
+ parent: TreeDataExtended,
}
export interface TreeData {
diff --git a/ui/src/main/webapp/yarn.lock b/ui/src/main/webapp/yarn.lock
index fc13f8e11..b71fd9107 100644
--- a/ui/src/main/webapp/yarn.lock
+++ b/ui/src/main/webapp/yarn.lock
@@ -3836,11 +3836,7 @@ lodash@^3.8.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
-lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.0:
- version "4.17.4"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
-
-lodash@^4.17.5:
+lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0:
version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
From 45bf0210ea5df902677cbff5e928d574d6456f24 Mon Sep 17 00:00:00 2001
From: Jess Sightler
Date: Fri, 13 Apr 2018 12:36:10 -0400
Subject: [PATCH 6/8] Commented out excessive logging
---
.../js-tree-angular-wrapper.component.ts | 26 +++++++++----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
index 184e11b0f..898d2acb2 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
@@ -28,7 +28,7 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
@Input()
set treeNodes(inputData:TreeData[]) {
- console.log("Tree nodes set:", inputData);
+ //console.log("Tree nodes set:", inputData);
// Sort alphabetically
let sortFunc = (item1, item2) => {
return item1.name.localeCompare(item2.name);
@@ -64,7 +64,7 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
@Input()
set selectedNodes (newSelectedNodes: TreeData[]) {
this._selectedNodes = newSelectedNodes;
- console.log("Reselecting nodes: ", this.treeState.selectedLeafNodeIds);
+ //console.log("Reselecting nodes: ", this.treeState.selectedLeafNodeIds);
const selectedLeafNodeIds = {};
@@ -78,7 +78,7 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
this.treeState.selectedLeafNodeIds = selectedLeafNodeIds;
this.treeComponent.treeModel.setState(this.treeState);
- console.log("Reselected nodes: ", selectedLeafNodeIds);
+ //console.log("Reselected nodes: ", selectedLeafNodeIds);
}
@@ -119,7 +119,7 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
}
private addParentSelections(selectedLeafNodeIds:{}, nodeId:number) {
- console.log("parent add searching for: " + nodeId);
+ //console.log("parent add searching for: " + nodeId);
// 1. Find node from the main set of nodes by id
let finder = (originalNodes:TreeDataExtended[]) => {
let result = null;
@@ -143,14 +143,14 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
};
let originalNode = finder(this.treeNodesFiltered);
- console.log("Original node: ", originalNode);
+ //console.log("Original node: ", originalNode);
while (originalNode) {
selectedLeafNodeIds[originalNode.id] = true;
originalNode = originalNode.parent;
}
- console.log("Add parent set them to: ", selectedLeafNodeIds);
+ //console.log("Add parent set them to: ", selectedLeafNodeIds);
}
selected(event) {
@@ -158,13 +158,13 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
// This just triggers the setter method to be called
this.selectedNodes = this._selectedNodes;
- console.log("Selected: ", this._selectedNodes);
+ //console.log("Selected: ", this._selectedNodes);
this.selectedNodes = this._selectedNodes;
this.selectedNodesChange.emit(this._selectedNodes);
}
deselected(event) {
- console.log("Deselected event: ", event);
+ //console.log("Deselected event: ", event);
let nodesToDeselect = [];
let crawlNode = (data:TreeData) => {
if (!data)
@@ -177,20 +177,20 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
});
};
crawlNode(event.node.data);
- console.log("Should deselect: ", nodesToDeselect);
+ //console.log("Should deselect: ", nodesToDeselect);
- console.log("Current: ", this._selectedNodes);
+ //console.log("Current: ", this._selectedNodes);
this._selectedNodes = this._selectedNodes.filter((item) => {
let index = nodesToDeselect.indexOf(item.id);
- console.log("Item: ", item, index);
+ //console.log("Item: ", item, index);
return index == -1;
});
- console.log("Then: ", this._selectedNodes);
+ //console.log("Then: ", this._selectedNodes);
// This just triggers the setter method to be called
this.selectedNodes = this._selectedNodes;
this.selectedNodesChange.emit(this._selectedNodes);
- console.log("De-Selected: ", this._selectedNodes);
+ //console.log("De-Selected: ", this._selectedNodes);
}
From 3687ae2e16f121019727493dfdb35f9c4f5034b9 Mon Sep 17 00:00:00 2001
From: Jess Sightler
Date: Tue, 1 May 2018 21:27:56 -0400
Subject: [PATCH 7/8] Display a warning if the item cannot really be unselected
---
.../js-tree-angular-wrapper.component.html | 35 +++++++++-
.../js-tree-angular-wrapper.component.ts | 70 +++++++++++++------
2 files changed, 84 insertions(+), 21 deletions(-)
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
index a2d1fd0bb..26776894c 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
@@ -1,3 +1,12 @@
+
+
Already selected:
+
+
+ {{selected.name}}
+
+
+
End already selected
+
\ No newline at end of file
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
index 898d2acb2..72d336782 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.ts
@@ -1,6 +1,6 @@
import {
Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewChild, AfterViewInit,
- SimpleChanges
+ SimpleChanges, ApplicationRef
} from "@angular/core";
import {ITreeState, TreeComponent, TreeNode} from "angular-tree-component";
@@ -73,6 +73,7 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
selectedLeafNodeIds[selectedNode.id] = true;
this.addParentSelections(selectedLeafNodeIds, selectedNode.id);
+ this.addChildSelections(selectedLeafNodeIds, selectedNode.id);
});
}
@@ -103,7 +104,7 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
getChildren: (node:TreeNode) => node.data.children
};
- public constructor() {
+ public constructor(public applicationRef:ApplicationRef) {
// setInterval(() => {
// console.log("Tree data: ", this.treeNodes);
// }, 10000);
@@ -118,31 +119,48 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
ngOnDestroy() {
}
- private addParentSelections(selectedLeafNodeIds:{}, nodeId:number) {
- //console.log("parent add searching for: " + nodeId);
- // 1. Find node from the main set of nodes by id
- let finder = (originalNodes:TreeDataExtended[]) => {
- let result = null;
+ private findNode(originalNodes:TreeDataExtended[], nodeId:number):TreeDataExtended {
+ let result = null;
- if (!originalNodes)
- return null;
+ if (!originalNodes)
+ return null;
- originalNodes.forEach(originalNode => {
- if (result)
- return;
+ originalNodes.forEach(originalNode => {
+ if (result)
+ return;
- if (originalNode.id == nodeId) {
- result = originalNode;
- return;
- }
+ if (originalNode.id == nodeId) {
+ result = originalNode;
+ return;
+ }
- result = finder(originalNode.children);
- });
+ result = this.findNode(originalNode.children, nodeId);
+ });
+
+ return result;
+ }
+
+ private addChildSelections(selectedLeafNodeIds:{}, nodeId:number) {
+ let originalNode = this.findNode(this.treeNodesFiltered, nodeId);
+ if (!originalNode)
+ return;
+
+
+ let selectorFunction = (node:TreeDataExtended) => {
+ selectedLeafNodeIds[node.id] = true;
- return result;
+ if (!node.hasChildren)
+ return;
+
+ node.children.forEach(childNode => {
+ selectorFunction(childNode);
+ });
};
+ selectorFunction(originalNode);
+ }
- let originalNode = finder(this.treeNodesFiltered);
+ private addParentSelections(selectedLeafNodeIds:{}, nodeId:number) {
+ let originalNode = this.findNode(this.treeNodesFiltered, nodeId);
//console.log("Original node: ", originalNode);
while (originalNode) {
@@ -179,6 +197,17 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
crawlNode(event.node.data);
//console.log("Should deselect: ", nodesToDeselect);
+ let indexOfExistingNode = this._selectedNodes.findIndex(selectedNode => {
+ console.log("this selected node:", selectedNode, event);
+ return selectedNode.id == event.node.id;
+ });
+
+ if (indexOfExistingNode == -1)
+ {
+ window.alert("This cannot be unselected until all parent nodes are unselected!");
+ return;
+ }
+
//console.log("Current: ", this._selectedNodes);
this._selectedNodes = this._selectedNodes.filter((item) => {
let index = nodesToDeselect.indexOf(item.id);
@@ -190,6 +219,7 @@ export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnD
// This just triggers the setter method to be called
this.selectedNodes = this._selectedNodes;
this.selectedNodesChange.emit(this._selectedNodes);
+ this.applicationRef.tick();
//console.log("De-Selected: ", this._selectedNodes);
}
From 259fb36428d3ceae8819e7f8bd9e34645796f2ac Mon Sep 17 00:00:00 2001
From: Jess Sightler
Date: Wed, 2 May 2018 16:44:37 -0400
Subject: [PATCH 8/8] Removed some debugging code
---
.../js-tree-angular-wrapper.component.html | 9 ---------
.../js-tree-angular-wrapper.component.ts | 19 +++++++++----------
2 files changed, 9 insertions(+), 19 deletions(-)
diff --git a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
index 26776894c..0337e65de 100644
--- a/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
+++ b/ui/src/main/webapp/src/app/shared/js-tree-angular-wrapper.component.html
@@ -1,12 +1,3 @@
-
-
Already selected:
-
-
- {{selected.name}}
-
-
-
End already selected
-
{
+ let index = nodesToDeselect.indexOf(item.id);
+ //console.log("Item: ", item, index);
+ return index == -1;
+ });
+ //console.log("Then: ", this._selectedNodes);
}
- //console.log("Current: ", this._selectedNodes);
- this._selectedNodes = this._selectedNodes.filter((item) => {
- let index = nodesToDeselect.indexOf(item.id);
- //console.log("Item: ", item, index);
- return index == -1;
- });
- //console.log("Then: ", this._selectedNodes);
-
// This just triggers the setter method to be called
this.selectedNodes = this._selectedNodes;
this.selectedNodesChange.emit(this._selectedNodes);
- this.applicationRef.tick();
//console.log("De-Selected: ", this._selectedNodes);
}