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.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/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/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/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..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 +1,34 @@
-
+
\ 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 8a3a16edb..4ba15bb79 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,33 +1,91 @@
import {
- Component, OnInit, Input, ElementRef, SimpleChange, Output, EventEmitter, NgZone,
- OnChanges, OnDestroy
+ Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewChild, AfterViewInit,
+ SimpleChanges, ApplicationRef
} from "@angular/core";
-import {Package} from "../generated/windup-services";
-import * as $ from "jquery";
-import 'jstree';
-import {SchedulerService} from "./scheduler.service";
+import {ITreeState, TreeComponent, TreeNode} from "angular-tree-component";
/**
- * 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;' }
})
-export class JsTreeAngularWrapperComponent implements OnInit, OnChanges, OnDestroy {
+export class JsTreeAngularWrapperComponent implements AfterViewInit, OnInit, OnDestroy {
+
+ @ViewChild('tree')
+ treeComponent: TreeComponent;
+
+ treeState: ITreeState = {
+ selectedNodeIds: {},
+ expandedNodeIds: {},
+ hiddenNodeIds: {},
+ activeNodeIds: {}
+ };
+
+ treeNodesFiltered: TreeDataExtended[];
+
@Input()
- treeNodes: TreeData[];
+ set treeNodes(inputData:TreeData[]) {
+ //console.log("Tree nodes set:", inputData);
+ // Sort alphabetically
+ let sortFunc = (item1, item2) => {
+ return item1.name.localeCompare(item2.name);
+ };
+
+ // Sort all children, and also attach the parent node
+ let crawlAndSortChildren = (parent:TreeDataExtended, inputData:TreeData[]):TreeDataExtended[] => {
+ if (!inputData)
+ return inputData;
+
+ inputData.forEach(child => {
+ let childExtended = child;
+ childExtended.parent = parent;
+ childExtended.hasChildren = !!(child.children && child.children.length);
+ child.children = crawlAndSortChildren(childExtended, child.children)
+ });
+
+ return inputData.sort(sortFunc).map(treeData => treeData);
+ };
+
+ // 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;
- treeNodesMap: {[id: string]: TreeData} = {};
-
- jsTree = [];
+ _selectedNodes: TreeDataExtended[];
@Input()
- selectedNodes: TreeData[];
+ set selectedNodes (newSelectedNodes: TreeData[]) {
+ this._selectedNodes = newSelectedNodes;
+ //console.log("Reselecting nodes: ", this.treeState.selectedLeafNodeIds);
+
+ const selectedLeafNodeIds = {};
+
+ if (this._selectedNodes) {
+ this._selectedNodes.forEach(selectedNode => {
+ selectedLeafNodeIds[selectedNode.id] = true;
+
+ this.addParentSelections(selectedLeafNodeIds, selectedNode.id);
+ this.addChildSelections(selectedLeafNodeIds, selectedNode.id);
+ });
+ }
+
+ this.treeState.selectedLeafNodeIds = selectedLeafNodeIds;
+ this.treeComponent.treeModel.setState(this.treeState);
+ //console.log("Reselected nodes: ", selectedLeafNodeIds);
+
+ }
+
+ get selectedNodes (): TreeData[] {
+ return this._selectedNodes;
+ }
@Output()
selectedNodesChange: EventEmitter = new EventEmitter();
@@ -35,131 +93,147 @@ export class JsTreeAngularWrapperComponent implements OnInit, OnChanges, OnDestr
@Output()
nodeClicked: EventEmitter = new EventEmitter();
- protected element;
+ options = {
+ displayField: 'name',
+ useCheckbox: true,
+ useTriState: false,
+ animateExpand: true,
+ nodeHeight: 22,
+ hasChildrenField: 'hasChildren',
+ childrenField: 'childNodes',
+ getChildren: (node:TreeNode) => node.data.children
+ };
+
+ public constructor(public applicationRef:ApplicationRef) {
+ // setInterval(() => {
+ // console.log("Tree data: ", this.treeNodes);
+ // }, 10000);
+ }
- protected updateSelectionCallback: Function = () => {};
- protected static EMPTY_CALLBACK = () => {};
+ ngAfterViewInit() {
+ }
- protected treeRedrawTimeout: any;
+ ngOnInit() {
+ }
- public constructor(element: ElementRef, private _zone: NgZone, private _schedulerService: SchedulerService) {
- this.element = element.nativeElement;
+ ngOnDestroy() {
}
- ngOnChanges(changes: {[treeNodes: string]: SimpleChange}): any {
- let jsTree = $(this.element).jstree(true);
+ private findNode(originalNodes:TreeDataExtended[], nodeId:number):TreeDataExtended {
+ let result = null;
- // This is ugly workaround to prevent recursively calling ngOnChanges from change handler
- this.updateSelectionCallback = JsTreeAngularWrapperComponent.EMPTY_CALLBACK;
+ if (!originalNodes)
+ return null;
- 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);
- }
+ originalNodes.forEach(originalNode => {
+ if (result)
+ return;
- 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);
+ if (originalNode.id == nodeId) {
+ result = originalNode;
+ return;
}
- }
- // This is ugly workaround to prevent recursively calling ngOnChanges from change handler
- this.updateSelectionCallback = this.updateSelectedNodes;
- }
+ result = this.findNode(originalNode.children, nodeId);
+ });
- transformTreeNode(node: any): any {
- let transformed = {
- id: node.id,
- text: node.name,
- children: [],
- original: node,
- state: {}
- };
+ return result;
+ }
- if (node.opened) {
- transformed.state = {
- opened: node.opened
- }
- }
+ private addChildSelections(selectedLeafNodeIds:{}, nodeId:number) {
+ let originalNode = this.findNode(this.treeNodesFiltered, nodeId);
+ if (!originalNode)
+ return;
- let self = this;
- if (node.childs) {
- transformed.children = node.childs.map((mapNode) => self.transformTreeNode(mapNode));
- }
+ let selectorFunction = (node:TreeDataExtended) => {
+ selectedLeafNodeIds[node.id] = true;
- this.treeNodesMap[node.id] = node;
+ if (!node.hasChildren)
+ return;
- return transformed;
+ node.children.forEach(childNode => {
+ selectorFunction(childNode);
+ });
+ };
+ selectorFunction(originalNode);
}
- ngOnInit() {
- let self = this;
+ private addParentSelections(selectedLeafNodeIds:{}, nodeId:number) {
+ let originalNode = this.findNode(this.treeNodesFiltered, nodeId);
+ //console.log("Original node: ", originalNode);
- if (this.treeNodes) {
- this.jsTree = this.treeNodes.map((node) => self.transformTreeNode(node));
+ while (originalNode) {
+ selectedLeafNodeIds[originalNode.id] = true;
+ originalNode = originalNode.parent;
}
- 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());
+ //console.log("Add parent set them to: ", selectedLeafNodeIds);
}
- ngOnDestroy(): void {
- if (this.treeRedrawTimeout) {
- this._schedulerService.clearTimeout(this.treeRedrawTimeout);
- this.treeRedrawTimeout = null;
- }
- }
+ selected(event) {
+ this._selectedNodes.push(event.node.data);
- fireNodeClicked(event, data) {
- this.nodeClicked.emit(this.treeNodesMap[data.node.id]);
+ // 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);
}
- updateSelectedNodes(event, data) {
- let jsTree = $(this.element).jstree(true);
+ deselected(event) {
+ //console.log("Deselected event: ", event);
+ let nodesToDeselect = [];
+ let crawlNode = (data:TreeData) => {
+ if (!data)
+ return;
- if (jsTree) {
- this._zone.run(() => {
- this.selectedNodes = jsTree.get_checked(false).map((id) => this.treeNodesMap[id]);
- this.selectedNodesChange.emit(this.selectedNodes);
+ nodesToDeselect.push(data.id);
+
+ data.children.forEach((child) => {
+ crawlNode(child);
});
- }
- }
+ };
+ crawlNode(event.node.data);
+ //console.log("Should deselect: ", nodesToDeselect);
- redrawSelection() {
- let jsTree = $(this.element).jstree(true);
+ let indexOfExistingNode = this._selectedNodes.findIndex(selectedNode => {
+ console.log("this selected node:", selectedNode, event);
+ return selectedNode.id == event.node.id;
+ });
- if (jsTree && this.selectedNodes) {
- let selectionIds = this.selectedNodes.map(node => node.id);
- jsTree.check_node(selectionIds, null);
+ if (indexOfExistingNode == -1)
+ {
+ window.alert("This cannot be unselected until all parent nodes are unselected!");
+ } else
+ {
+ //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 {
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..b71fd9107 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"
@@ -3828,9 +3836,9 @@ 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.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"
lodash@~4.16.4:
version "4.16.6"
@@ -4050,6 +4058,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 +4125,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"