Merge branch 'develop' into add-rectangle-change-border-position

This commit is contained in:
PiotrP 2018-11-28 04:29:15 -08:00
commit 42d1ce522e
42 changed files with 736 additions and 165 deletions

View File

@ -1,4 +1,4 @@
# Editor configuration, see http://editorconfig.org # Editor configuration, see https://editorconfig.org
root = true root = true
[*] [*]

View File

@ -46,7 +46,7 @@ before_script:
- greenkeeper-lockfile-update - greenkeeper-lockfile-update
- npm install -g codecov - npm install -g codecov
script: yarn ng test --watch=false --code-coverage script: yarn coverage
after_success: after_success:
- codecov - codecov

16
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch localhost",
"type": "firefox",
"request": "launch",
"reAttach": true,
"url": "http://localhost:4200",
"webRoot": "${workspaceFolder}"
}
]
}

View File

@ -133,6 +133,9 @@
"assets": [ "assets": [
"src/assets", "src/assets",
"src/favicon.ico" "src/favicon.ico"
],
"codeCoverageExclude": [
"src/app/cartography/components/experimental-map/**/*"
] ]
} }
}, },

View File

@ -22,7 +22,8 @@
"distlinux": "yarn buildforelectron && electron-builder --linux --x64", "distlinux": "yarn buildforelectron && electron-builder --linux --x64",
"distwin": "yarn buildforelectron && electron-builder --win --x64", "distwin": "yarn buildforelectron && electron-builder --win --x64",
"distmac": "yarn buildforelectron && electron-builder --mac --x64", "distmac": "yarn buildforelectron && electron-builder --mac --x64",
"release": "build" "release": "build",
"coverage": "ng test --watch=false --code-coverage"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {

View File

@ -74,6 +74,7 @@ import { DrawingService } from './services/drawing.service';
import { ProjectNameValidator } from './components/projects/models/projectNameValidator'; import { ProjectNameValidator } from './components/projects/models/projectNameValidator';
import { MatSidenavModule } from '@angular/material'; import { MatSidenavModule } from '@angular/material';
import { NodeSelectInterfaceComponent } from './components/project-map/node-select-interface/node-select-interface.component'; import { NodeSelectInterfaceComponent } from './components/project-map/node-select-interface/node-select-interface.component';
import { DrawLinkToolComponent } from './components/project-map/draw-link-tool/draw-link-tool.component';
if (environment.production) { if (environment.production) {
@ -115,7 +116,8 @@ if (environment.production) {
LocalServerComponent, LocalServerComponent,
ProgressComponent, ProgressComponent,
ServerDiscoveryComponent, ServerDiscoveryComponent,
NodeSelectInterfaceComponent NodeSelectInterfaceComponent,
DrawLinkToolComponent
], ],
imports: [ imports: [
NgbModule.forRoot(), NgbModule.forRoot(),

View File

@ -1,5 +1,3 @@
import { DraggableComponent } from './components/draggable/draggable.component';
import { SelectionComponent } from './components/selection/selection.component';
import { NodeComponent } from './components/experimental-map/node/node.component'; import { NodeComponent } from './components/experimental-map/node/node.component';
import { LinkComponent } from './components/experimental-map/link/link.component'; import { LinkComponent } from './components/experimental-map/link/link.component';
import { StatusComponent } from './components/experimental-map/status/status.component'; import { StatusComponent } from './components/experimental-map/status/status.component';
@ -10,6 +8,8 @@ import { LineComponent } from './components/experimental-map/drawing/drawings/li
import { RectComponent } from './components/experimental-map/drawing/drawings/rect/rect.component'; import { RectComponent } from './components/experimental-map/drawing/drawings/rect/rect.component';
import { TextComponent } from './components/experimental-map/drawing/drawings/text/text.component'; import { TextComponent } from './components/experimental-map/drawing/drawings/text/text.component';
import { InterfaceLabelComponent } from './components/experimental-map/interface-label/interface-label.component'; import { InterfaceLabelComponent } from './components/experimental-map/interface-label/interface-label.component';
import { DraggableComponent } from './components/experimental-map/draggable/draggable.component';
import { SelectionComponent } from './components/experimental-map/selection/selection.component';
export const ANGULAR_MAP_DECLARATIONS = [ export const ANGULAR_MAP_DECLARATIONS = [

View File

@ -2,9 +2,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { MatMenuModule, MatIconModule } from '@angular/material'; import { MatMenuModule, MatIconModule } from '@angular/material';
import { DrawLinkToolComponent } from './components/draw-link-tool/draw-link-tool.component';
import { DrawingResizingComponent } from './components/drawing-resizing/drawing-resizing.component'; import { DrawingResizingComponent } from './components/drawing-resizing/drawing-resizing.component';
import { CssFixer } from './helpers/css-fixer'; import { CssFixer } from './helpers/css-fixer';
import { FontFixer } from './helpers/font-fixer'; import { FontFixer } from './helpers/font-fixer';
import { MultiLinkCalculatorHelper } from './helpers/multi-link-calculator-helper'; import { MultiLinkCalculatorHelper } from './helpers/multi-link-calculator-helper';
@ -54,7 +52,6 @@ import { MapSettingsManager } from './managers/map-settings-manager';
declarations: [ declarations: [
D3MapComponent, D3MapComponent,
ExperimentalMapComponent, ExperimentalMapComponent,
DrawLinkToolComponent,
DrawingResizingComponent, DrawingResizingComponent,
...ANGULAR_MAP_DECLARATIONS, ...ANGULAR_MAP_DECLARATIONS,
SelectionControlComponent, SelectionControlComponent,

View File

@ -8,7 +8,6 @@
</filter> </filter>
</svg> </svg>
<app-draw-link-tool *ngIf="drawLinkTool"></app-draw-link-tool>
<app-drawing-resizing></app-drawing-resizing> <app-drawing-resizing></app-drawing-resizing>
<app-selection-control></app-selection-control> <app-selection-control></app-selection-control>
<app-selection-select></app-selection-select> <app-selection-select></app-selection-select>

Before

Width:  |  Height:  |  Size: 435 B

After

Width:  |  Height:  |  Size: 372 B

View File

@ -1,13 +1,129 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { DraggableSelectionComponent } from './draggable-selection.component'; import { DraggableSelectionComponent } from './draggable-selection.component';
import { NodesWidget } from '../../widgets/nodes';
import { DrawingsWidget } from '../../widgets/drawings';
import { LinksWidget } from '../../widgets/links';
import { LabelWidget } from '../../widgets/label';
import { InterfaceLabelWidget } from '../../widgets/interface-label';
import { SelectionManager } from '../../managers/selection-manager';
import { SelectionManagerMock } from '../../managers/selection-manager.spec';
import { NodesEventSource } from '../../events/nodes-event-source';
import { DrawingsEventSource } from '../../events/drawings-event-source';
import { GraphDataManager } from '../../managers/graph-data-manager';
import { MockedGraphDataManager } from '../../managers/graph-data-manager.spec';
import { LinksEventSource } from '../../events/links-event-source';
import { DraggableStart, DraggableDrag, DraggableEnd } from '../../events/draggable';
import { MapNode } from '../../models/map/map-node';
import { EventEmitter } from '@angular/core';
import { MapDrawing } from '../../models/map/map-drawing';
import { MapLabel } from '../../models/map/map-label';
import { MapLinkNode } from '../../models/map/map-link-node';
import { select } from 'd3-selection';
import { MapLink } from '../../models/map/map-link';
describe('DraggableSelectionComponent', () => { describe('DraggableSelectionComponent', () => {
let component: DraggableSelectionComponent; let component: DraggableSelectionComponent;
let fixture: ComponentFixture<DraggableSelectionComponent>; let fixture: ComponentFixture<DraggableSelectionComponent>;
let mockedGraphDataManager: MockedGraphDataManager;
let nodesStartEventEmitter: EventEmitter<DraggableStart<MapNode>>;
let nodesDragEventEmitter: EventEmitter<DraggableDrag<MapNode>>;
let nodesEndEventEmitter: EventEmitter<DraggableEnd<MapNode>>;
let drawingsStartEventEmitter: EventEmitter<DraggableStart<MapDrawing>>;
let drawingsDragEventEmitter: EventEmitter<DraggableDrag<MapDrawing>>;
let drawingsEndEventEmitter: EventEmitter<DraggableEnd<MapDrawing>>;
let labelStartEventEmitter: EventEmitter<DraggableStart<MapLabel>>;
let labelDragEventEmitter: EventEmitter<DraggableDrag<MapLabel>>;
let labelEndEventEmitter: EventEmitter<DraggableEnd<MapLabel>>;
let interfaceLabelStartEventEmitter: EventEmitter<DraggableStart<MapLinkNode>>;
let interfaceLabelDragEventEmitter: EventEmitter<DraggableDrag<MapLinkNode>>;
let interfaceLabelEndEventEmitter: EventEmitter<DraggableEnd<MapLinkNode>>;
beforeEach(async(() => { beforeEach(async(() => {
mockedGraphDataManager = new MockedGraphDataManager();
nodesStartEventEmitter = new EventEmitter<DraggableStart<MapNode>>();
nodesDragEventEmitter = new EventEmitter<DraggableDrag<MapNode>>();
nodesEndEventEmitter = new EventEmitter<DraggableEnd<MapNode>>();
drawingsStartEventEmitter = new EventEmitter<DraggableStart<MapDrawing>>();
drawingsDragEventEmitter = new EventEmitter<DraggableDrag<MapDrawing>>();
drawingsEndEventEmitter = new EventEmitter<DraggableEnd<MapDrawing>>();
labelStartEventEmitter = new EventEmitter<DraggableStart<MapLabel>>();
labelDragEventEmitter = new EventEmitter<DraggableDrag<MapLabel>>();
labelEndEventEmitter = new EventEmitter<DraggableEnd<MapLabel>>();
interfaceLabelStartEventEmitter = new EventEmitter<DraggableStart<MapLinkNode>>();
interfaceLabelDragEventEmitter = new EventEmitter<DraggableDrag<MapLinkNode>>();
interfaceLabelEndEventEmitter = new EventEmitter<DraggableEnd<MapLinkNode>>();
const nodesWidgetStub = {
redrawNode: () => {},
draggable: {
start: nodesStartEventEmitter,
drag: nodesDragEventEmitter,
end: nodesEndEventEmitter
}
};
const drawingsWidgetStub = {
redrawDrawing: () => {},
draggable: {
start: drawingsStartEventEmitter,
drag: drawingsDragEventEmitter,
end: drawingsEndEventEmitter
}
};
const linksWidgetStub = {
redrawLink: () => {},
};
const labelWidgetStub = {
redrawLabel: () => {},
draggable: {
start: labelStartEventEmitter,
drag: labelDragEventEmitter,
end: labelEndEventEmitter
}
};
const interfaceLabelWidgetStub = {
draggable: {
start: interfaceLabelStartEventEmitter,
drag: interfaceLabelDragEventEmitter,
end: interfaceLabelEndEventEmitter
}
};
const nodesEventSourceStub = {
dragged: { emit: () => {}},
labelDragged: { emit: () => {}}
};
const drawingsEventSourceStub = {
dragged: { emit: () => {}}
};
const linksEventSourceStub = {
interfaceDragged: { emit: () => {}}
};
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [
{ provide: NodesWidget, useValue: nodesWidgetStub },
{ provide: DrawingsWidget, useValue: drawingsWidgetStub },
{ provide: LinksWidget, useValue: linksWidgetStub },
{ provide: LabelWidget, useValue: labelWidgetStub },
{ provide: InterfaceLabelWidget, useValue: interfaceLabelWidgetStub },
{ provide: SelectionManager, useValue: new SelectionManagerMock() },
{ provide: NodesEventSource, useValue: nodesEventSourceStub },
{ provide: DrawingsEventSource, useValue: drawingsEventSourceStub },
{ provide: GraphDataManager, useValue: mockedGraphDataManager },
{ provide: LinksEventSource, useValue: linksEventSourceStub },
],
declarations: [ DraggableSelectionComponent ] declarations: [ DraggableSelectionComponent ]
}) })
.compileComponents(); .compileComponents();
@ -16,10 +132,418 @@ describe('DraggableSelectionComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(DraggableSelectionComponent); fixture = TestBed.createComponent(DraggableSelectionComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
fixture.detectChanges(); fixture.detectChanges();
}); });
// it('should create', () => { it('should create', () => {
// expect(component).toBeTruthy(); expect(component).toBeTruthy();
// }); });
describe('nodes dragging', () => {
let nodesWidgetStub: NodesWidget;
let linksWidgetStub: LinksWidget;
let selectionManagerStub: SelectionManager;
let node: MapNode;
beforeEach(() => {
nodesWidgetStub = fixture.debugElement.injector.get(NodesWidget);
linksWidgetStub = fixture.debugElement.injector.get(LinksWidget);
selectionManagerStub = fixture.debugElement.injector.get(SelectionManager);
node = new MapNode();
node.id = "nodeid";
node.x = 1;
node.y = 2;
});
it('should select node when started dragging', fakeAsync(() => {
nodesWidgetStub.draggable.start.emit(new DraggableStart<MapNode>(node));
tick();
expect(selectionManagerStub.getSelected().length).toEqual(1);
}));
it('should ignore node when started dragging and node is in selection', fakeAsync(() => {
selectionManagerStub.setSelected([node]);
nodesWidgetStub.draggable.start.emit(new DraggableStart<MapNode>(node));
tick();
expect(selectionManagerStub.getSelected().length).toEqual(1);
}));
it('should update node position when dragging', fakeAsync(() => {
spyOn(nodesWidgetStub, 'redrawNode');
selectionManagerStub.setSelected([node]);
const dragEvent = new DraggableDrag<MapNode>(node);
dragEvent.dx = 10;
dragEvent.dy = 20;
nodesWidgetStub.draggable.drag.emit(dragEvent);
tick();
expect(nodesWidgetStub.redrawNode).toHaveBeenCalledWith(select(fixture.componentInstance.svg), node);
expect(node.x).toEqual(11);
expect(node.y).toEqual(22);
}));
it('should redraw related links target when dragging node', fakeAsync(() => {
spyOn(nodesWidgetStub, 'redrawNode');
spyOn(linksWidgetStub, 'redrawLink');
const link = new MapLink();
link.target = node;
mockedGraphDataManager.setLinks([link]);
selectionManagerStub.setSelected([node]);
nodesWidgetStub.draggable.drag.emit(new DraggableDrag<MapNode>(node));
tick();
expect(linksWidgetStub.redrawLink).toHaveBeenCalledWith(select(fixture.componentInstance.svg), link);
}));
it('should redraw related links source when dragging node', fakeAsync(() => {
spyOn(nodesWidgetStub, 'redrawNode');
spyOn(linksWidgetStub, 'redrawLink');
const link = new MapLink();
link.source = node;
mockedGraphDataManager.setLinks([link]);
selectionManagerStub.setSelected([node]);
nodesWidgetStub.draggable.drag.emit(new DraggableDrag<MapNode>(node));
tick();
expect(linksWidgetStub.redrawLink).toHaveBeenCalledWith(select(fixture.componentInstance.svg), link);
}));
it('should emit event when node stopped dragging', fakeAsync(() => {
const nodesEventSourceStub = fixture.debugElement.injector.get(NodesEventSource);
const spyDragged = spyOn(nodesEventSourceStub.dragged, 'emit');
selectionManagerStub.setSelected([node]);
const dragEvent = new DraggableEnd<MapNode>(node);
dragEvent.dx = 10;
dragEvent.dy = 20;
nodesWidgetStub.draggable.end.emit(dragEvent);
tick();
expect(nodesEventSourceStub.dragged.emit).toHaveBeenCalled();
expect(spyDragged.calls.mostRecent().args[0].datum).toEqual(node);
expect(spyDragged.calls.mostRecent().args[0].dx).toEqual(10);
expect(spyDragged.calls.mostRecent().args[0].dy).toEqual(20);
}));
});
describe('drawings dragging', () => {
let drawingsWidgetStub: DrawingsWidget;
let selectionManagerStub: SelectionManager;
let drawing: MapDrawing;
beforeEach(() => {
drawingsWidgetStub = fixture.debugElement.injector.get(DrawingsWidget);
selectionManagerStub = fixture.debugElement.injector.get(SelectionManager);
drawing = new MapDrawing();
drawing.id = "drawingid";
drawing.x = 1;
drawing.y = 2;
});
it('should select drawing when started dragging', fakeAsync(() => {
drawingsWidgetStub.draggable.start.emit(new DraggableStart<MapDrawing>(drawing));
tick();
expect(selectionManagerStub.getSelected().length).toEqual(1);
}));
it('should ignore drawing when started dragging and node is in selection', fakeAsync(() => {
selectionManagerStub.setSelected([drawing]);
drawingsWidgetStub.draggable.start.emit(new DraggableStart<MapDrawing>(drawing));
tick();
expect(selectionManagerStub.getSelected().length).toEqual(1);
}));
it('should update drawing position when dragging', fakeAsync(() => {
spyOn(drawingsWidgetStub, 'redrawDrawing');
selectionManagerStub.setSelected([drawing]);
const dragEvent = new DraggableDrag<MapDrawing>(drawing);
dragEvent.dx = 10;
dragEvent.dy = 20;
drawingsWidgetStub.draggable.drag.emit(dragEvent);
tick();
expect(drawingsWidgetStub.redrawDrawing).toHaveBeenCalledWith(select(fixture.componentInstance.svg), drawing);
expect(drawing.x).toEqual(11);
expect(drawing.y).toEqual(22);
}));
it('should emit event when drawing stopped dragging', fakeAsync(() => {
const drawingsEventSourceStub = fixture.debugElement.injector.get(DrawingsEventSource);
const spyDragged = spyOn(drawingsEventSourceStub.dragged, 'emit');
selectionManagerStub.setSelected([drawing]);
const dragEvent = new DraggableEnd<MapDrawing>(drawing);
dragEvent.dx = 10;
dragEvent.dy = 20;
drawingsWidgetStub.draggable.end.emit(dragEvent);
tick();
expect(drawingsEventSourceStub.dragged.emit).toHaveBeenCalled();
expect(spyDragged.calls.mostRecent().args[0].datum).toEqual(drawing);
expect(spyDragged.calls.mostRecent().args[0].dx).toEqual(10);
expect(spyDragged.calls.mostRecent().args[0].dy).toEqual(20);
}));
});
describe('labels dragging', () => {
let labelWidgetStub: LabelWidget;
let selectionManagerStub: SelectionManager;
let label: MapLabel;
beforeEach(() => {
labelWidgetStub = fixture.debugElement.injector.get(LabelWidget);
selectionManagerStub = fixture.debugElement.injector.get(SelectionManager);
label = new MapLabel();
label.id = "labelid";
label.x = 1;
label.y = 2;
});
it('should select label when started dragging', fakeAsync(() => {
labelWidgetStub.draggable.start.emit(new DraggableStart<MapLabel>(label));
tick();
expect(selectionManagerStub.getSelected().length).toEqual(1);
}));
it('should ignore label when started dragging and node is in selection', fakeAsync(() => {
selectionManagerStub.setSelected([label]);
labelWidgetStub.draggable.start.emit(new DraggableStart<MapLabel>(label));
tick();
expect(selectionManagerStub.getSelected().length).toEqual(1);
}));
it('should update label position when dragging', fakeAsync(() => {
spyOn(labelWidgetStub, 'redrawLabel');
selectionManagerStub.setSelected([label]);
const node = new MapNode();
node.id = "nodeid";
node.label = label;
label.nodeId = node.id;
mockedGraphDataManager.setNodes([node]);
const dragEvent = new DraggableDrag<MapLabel>(label);
dragEvent.dx = 10;
dragEvent.dy = 20;
labelWidgetStub.draggable.drag.emit(dragEvent);
tick();
expect(labelWidgetStub.redrawLabel).toHaveBeenCalledWith(select(fixture.componentInstance.svg), label);
expect(label.x).toEqual(11);
expect(label.y).toEqual(22);
}));
it('should not update label position when dragging and parent is selected', fakeAsync(() => {
spyOn(labelWidgetStub, 'redrawLabel');
const node = new MapNode();
node.id = "nodeid";
node.label = label;
label.nodeId = node.id;
selectionManagerStub.setSelected([label, node]);
mockedGraphDataManager.setNodes([node]);
const dragEvent = new DraggableDrag<MapLabel>(label);
dragEvent.dx = 10;
dragEvent.dy = 20;
labelWidgetStub.draggable.drag.emit(dragEvent);
tick();
expect(labelWidgetStub.redrawLabel).not.toHaveBeenCalled();
expect(label.x).toEqual(1);
expect(label.y).toEqual(2);
}));
it('should emit event when label stopped dragging', fakeAsync(() => {
const nodesEventSourceStub = fixture.debugElement.injector.get(NodesEventSource);
const spyDragged = spyOn(nodesEventSourceStub.labelDragged, 'emit');
selectionManagerStub.setSelected([label]);
const dragEvent = new DraggableEnd<MapLabel>(label);
dragEvent.dx = 10;
dragEvent.dy = 20;
labelWidgetStub.draggable.end.emit(dragEvent);
tick();
expect(nodesEventSourceStub.labelDragged.emit).toHaveBeenCalled();
expect(spyDragged.calls.mostRecent().args[0].datum).toEqual(label);
expect(spyDragged.calls.mostRecent().args[0].dx).toEqual(10);
expect(spyDragged.calls.mostRecent().args[0].dy).toEqual(20);
}));
it('should not emit event when label stopped dragging and parent node is selected', fakeAsync(() => {
const nodesEventSourceStub = fixture.debugElement.injector.get(NodesEventSource);
spyOn(nodesEventSourceStub.labelDragged, 'emit');
const node = new MapNode();
node.id = "nodeid";
label.nodeId = node.id;
selectionManagerStub.setSelected([label, node]);
const dragEvent = new DraggableEnd<MapLabel>(label);
dragEvent.dx = 10;
dragEvent.dy = 20;
labelWidgetStub.draggable.end.emit(dragEvent);
tick();
expect(nodesEventSourceStub.labelDragged.emit).not.toHaveBeenCalled();
}));
});
describe('interfaces labels dragging', () => {
let linksWidgetStub: LinksWidget;
let interfaceLabelWidgetStub: InterfaceLabelWidget;
let selectionManagerStub: SelectionManager;
let linkNode: MapLinkNode;
beforeEach(() => {
interfaceLabelWidgetStub = fixture.debugElement.injector.get(InterfaceLabelWidget);
linksWidgetStub = fixture.debugElement.injector.get(LinksWidget);
selectionManagerStub = fixture.debugElement.injector.get(SelectionManager);
linkNode = new MapLinkNode();
linkNode.label = new MapLabel();
linkNode.label.x = 1;
linkNode.label.y = 2;
linkNode.id = "linknodeid";
});
it('should select interface label when started dragging', fakeAsync(() => {
interfaceLabelWidgetStub.draggable.start.emit(new DraggableStart<MapLinkNode>(linkNode));
tick();
expect(selectionManagerStub.getSelected().length).toEqual(1);
}));
it('should ignore interface label when started dragging and node is in selection', fakeAsync(() => {
selectionManagerStub.setSelected([linkNode]);
interfaceLabelWidgetStub.draggable.start.emit(new DraggableStart<MapLinkNode>(linkNode));
tick();
expect(selectionManagerStub.getSelected().length).toEqual(1);
}));
it('should update interface label position when dragging first node', fakeAsync(() => {
spyOn(linksWidgetStub, 'redrawLink');
selectionManagerStub.setSelected([linkNode]);
const node = new MapNode();
node.id = "nodeid";
linkNode.nodeId = node.id;
const secondLinkNode = new MapLinkNode();
secondLinkNode.label = new MapLabel();
secondLinkNode.label.x = 1;
secondLinkNode.label.y = 2;
secondLinkNode.id = "secondlinknodeid";
const link = new MapLink();
link.nodes = [linkNode, secondLinkNode];
mockedGraphDataManager.setLinks([link]);
const dragEvent = new DraggableDrag<MapLinkNode>(linkNode);
dragEvent.dx = 10;
dragEvent.dy = 20;
interfaceLabelWidgetStub.draggable.drag.emit(dragEvent);
tick();
expect(linksWidgetStub.redrawLink).toHaveBeenCalledWith(select(fixture.componentInstance.svg), link);
expect(linkNode.label.x).toEqual(11);
expect(linkNode.label.y).toEqual(22);
}));
it('should update interface label position when dragging second node', fakeAsync(() => {
spyOn(linksWidgetStub, 'redrawLink');
selectionManagerStub.setSelected([linkNode]);
const node = new MapNode();
node.id = "nodeid";
linkNode.nodeId = node.id;
const secondLinkNode = new MapLinkNode();
secondLinkNode.label = new MapLabel();
secondLinkNode.label.x = 1;
secondLinkNode.label.y = 2;
secondLinkNode.id = "secondlinknodeid";
const link = new MapLink();
link.nodes = [secondLinkNode, linkNode];
mockedGraphDataManager.setLinks([link]);
const dragEvent = new DraggableDrag<MapLinkNode>(linkNode);
dragEvent.dx = 10;
dragEvent.dy = 20;
interfaceLabelWidgetStub.draggable.drag.emit(dragEvent);
tick();
expect(linksWidgetStub.redrawLink).toHaveBeenCalledWith(select(fixture.componentInstance.svg), link);
expect(linkNode.label.x).toEqual(11);
expect(linkNode.label.y).toEqual(22);
}));
it('should not update interface label position when dragging and parent node is selected', fakeAsync(() => {
spyOn(linksWidgetStub, 'redrawLink');
const node = new MapNode();
node.id = "nodeid";
linkNode.nodeId = node.id;
selectionManagerStub.setSelected([linkNode, node]);
const secondLinkNode = new MapLinkNode();
secondLinkNode.label = new MapLabel();
secondLinkNode.label.x = 1;
secondLinkNode.label.y = 2;
secondLinkNode.id = "secondlinknodeid";
const link = new MapLink();
link.nodes = [linkNode, secondLinkNode];
mockedGraphDataManager.setLinks([link]);
const dragEvent = new DraggableDrag<MapLinkNode>(linkNode);
dragEvent.dx = 10;
dragEvent.dy = 20;
interfaceLabelWidgetStub.draggable.drag.emit(dragEvent);
tick();
expect(linksWidgetStub.redrawLink).not.toHaveBeenCalled();
expect(linkNode.label.x).toEqual(1);
expect(linkNode.label.y).toEqual(2);
}));
it('should emit event when interface label stopped dragging', fakeAsync(() => {
const linksEventSourceStub = fixture.debugElement.injector.get(LinksEventSource);
const spyDragged = spyOn(linksEventSourceStub.interfaceDragged, 'emit');
selectionManagerStub.setSelected([linkNode]);
const dragEvent = new DraggableEnd<MapLinkNode>(linkNode);
dragEvent.dx = 10;
dragEvent.dy = 20;
interfaceLabelWidgetStub.draggable.end.emit(dragEvent);
tick();
expect(linksEventSourceStub.interfaceDragged.emit).toHaveBeenCalled();
expect(spyDragged.calls.mostRecent().args[0].datum).toEqual(linkNode);
expect(spyDragged.calls.mostRecent().args[0].dx).toEqual(10);
expect(spyDragged.calls.mostRecent().args[0].dy).toEqual(20);
}));
it('should not emit event when interface label stopped dragging and parent node is selected', fakeAsync(() => {
const linksEventSourceStub = fixture.debugElement.injector.get(LinksEventSource);
spyOn(linksEventSourceStub.interfaceDragged, 'emit');
const node = new MapNode();
node.id = "nodeid";
linkNode.nodeId = node.id;
selectionManagerStub.setSelected([linkNode, node]);
const dragEvent = new DraggableEnd<MapLinkNode>(linkNode);
dragEvent.dx = 10;
dragEvent.dy = 20;
interfaceLabelWidgetStub.draggable.end.emit(dragEvent);
tick();
expect(linksEventSourceStub.interfaceDragged.emit).not.toHaveBeenCalled();
}));
});
}); });

View File

@ -94,7 +94,8 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
this.nodesWidget.redrawNode(svg, node); this.nodesWidget.redrawNode(svg, node);
const links = this.graphDataManager.getLinks().filter( const links = this.graphDataManager.getLinks().filter(
(link) => link.target.id === node.id || link.source.id === node.id); (link) => (link.target !== undefined && link.target.id === node.id) || (link.source !== undefined && link.source.id === node.id));
links.forEach((link) => { links.forEach((link) => {
this.linksWidget.redrawLink(svg, link); this.linksWidget.redrawLink(svg, link);
}); });

View File

@ -1 +0,0 @@
<!-- <app-node-select-interface (onChooseInterface)="onChooseInterface($event)"></app-node-select-interface> -->

View File

@ -1,61 +0,0 @@
import { Component, OnInit, Output, EventEmitter, OnDestroy, ViewChild } from '@angular/core';
import { DrawingLineWidget } from '../../widgets/drawing-line';
import { Subscription } from 'rxjs';
// import { NodeSelectInterfaceComponent } from '../node-select-interface/node-select-interface.component';
import { MapLinkCreated } from '../../events/links';
import { NodeClicked } from '../../events/nodes';
import { NodeWidget } from '../../widgets/node';
import { MapNode } from '../../models/map/map-node';
import { MapPort } from '../../models/map/map-port';
import { LinksEventSource } from '../../events/links-event-source';
@Component({
selector: 'app-draw-link-tool',
templateUrl: './draw-link-tool.component.html',
styleUrls: ['./draw-link-tool.component.scss']
})
export class DrawLinkToolComponent implements OnInit, OnDestroy {
// @ViewChild(NodeSelectInterfaceComponent) nodeSelectInterfaceMenu: NodeSelectInterfaceComponent;
// @Output('linkCreated') linkCreated = new EventEmitter<MapLinkCreated>();
private onNodeClicked: Subscription;
constructor(
private drawingLineTool: DrawingLineWidget,
private nodeWidget: NodeWidget,
private linksEventSource: LinksEventSource
) { }
ngOnInit() {
// this.onNodeClicked = this.nodeWidget.onNodeClicked.subscribe((eventNode: NodeClicked) => {
// this.nodeSelectInterfaceMenu.open(
// eventNode.node,
// eventNode.event.clientY,
// eventNode.event.clientX
// );
// });
}
ngOnDestroy() {
if (this.drawingLineTool.isDrawing()) {
this.drawingLineTool.stop();
}
// this.onNodeClicked.unsubscribe();
}
public onChooseInterface(event) {
const node: MapNode = event.node;
const port: MapPort = event.port;
if (this.drawingLineTool.isDrawing()) {
const data = this.drawingLineTool.stop();
this.linksEventSource.created.emit(new MapLinkCreated(data['node'], data['port'], node, port));
} else {
this.drawingLineTool.start(node.x + node.width / 2., node.y + node.height / 2., {
'node': node,
'port': port
});
}
}
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit, ElementRef, AfterViewInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, ElementRef, AfterViewInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
import { Point } from '../../models/point'; import { Point } from '../../../models/point';
export class DraggableDraggedEvent { export class DraggableDraggedEvent {

View File

@ -1,6 +1,6 @@
import { Component, OnInit, Input, AfterViewInit, ChangeDetectorRef, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, Input, AfterViewInit, ChangeDetectorRef, Output, EventEmitter } from '@angular/core';
import { Observable, Subscription, Subject } from 'rxjs'; import { Observable, Subscription, Subject } from 'rxjs';
import { Rectangle } from '../../models/rectangle'; import { Rectangle } from '../../../models/rectangle';
@Component({ @Component({
selector: '[app-selection]', selector: '[app-selection]',

View File

@ -17,3 +17,11 @@ export class ResizedDataEvent<T> {
public height: number) { public height: number) {
} }
} }
export class ClickedDataEvent<T> {
constructor(
public datum: T,
public x: number,
public y: number
) {}
}

View File

@ -1,5 +1,5 @@
import { Injectable, EventEmitter } from "@angular/core"; import { Injectable, EventEmitter } from "@angular/core";
import { DraggedDataEvent } from "./event-source"; import { DraggedDataEvent, ClickedDataEvent } from "./event-source";
import { MapNode } from "../models/map/map-node"; import { MapNode } from "../models/map/map-node";
import { MapLabel } from "../models/map/map-label"; import { MapLabel } from "../models/map/map-label";
@ -8,4 +8,5 @@ import { MapLabel } from "../models/map/map-label";
export class NodesEventSource { export class NodesEventSource {
public dragged = new EventEmitter<DraggedDataEvent<MapNode>>(); public dragged = new EventEmitter<DraggedDataEvent<MapNode>>();
public labelDragged = new EventEmitter<DraggedDataEvent<MapLabel>>(); public labelDragged = new EventEmitter<DraggedDataEvent<MapLabel>>();
public clicked = new EventEmitter<ClickedDataEvent<MapNode>>();
} }

View File

@ -1,6 +1,15 @@
import { MapNode } from "../models/map/map-node"; import { MapNode } from "../models/map/map-node";
import { SelectionManager } from "./selection-manager"; import { SelectionManager } from "./selection-manager";
export class SelectionManagerMock {
public items = [];
setSelected(items: any) {
this.items = items;
}
getSelected() {
return this.items;
}
}
describe('SelectionManager', () => { describe('SelectionManager', () => {
let manager: SelectionManager; let manager: SelectionManager;

View File

@ -25,5 +25,4 @@ export class MapNode implements Indexed {
x: number; x: number;
y: number; y: number;
z: number; z: number;
isSelected = false;
} }

View File

@ -9,6 +9,8 @@ import { MapNode } from "../models/map/map-node";
import { GraphDataManager } from "../managers/graph-data-manager"; import { GraphDataManager } from "../managers/graph-data-manager";
import { SelectionManager } from "../managers/selection-manager"; import { SelectionManager } from "../managers/selection-manager";
import { LabelWidget } from "./label"; import { LabelWidget } from "./label";
import { NodesEventSource } from '../events/nodes-event-source';
import { ClickedDataEvent } from '../events/event-source';
@Injectable() @Injectable()
@ -19,7 +21,8 @@ export class NodeWidget implements Widget {
constructor( constructor(
private graphDataManager: GraphDataManager, private graphDataManager: GraphDataManager,
private selectionManager: SelectionManager, private selectionManager: SelectionManager,
private labelWidget: LabelWidget private labelWidget: LabelWidget,
private nodesEventSource: NodesEventSource,
) {} ) {}
public draw(view: SVGSelection) { public draw(view: SVGSelection) {
@ -42,8 +45,9 @@ export class NodeWidget implements Widget {
event.preventDefault(); event.preventDefault();
self.onContextMenu.emit(new NodeContextMenu(event, n)); self.onContextMenu.emit(new NodeContextMenu(event, n));
}) })
.on('click', (n: MapNode) => { .on('click', (node: MapNode) => {
this.onNodeClicked.emit(new NodeClicked(event, n)); this.nodesEventSource.clicked.emit(new ClickedDataEvent<MapNode>(node, event.clientX, event.clientY))
// this.onNodeClicked.emit(new NodeClicked(event, n));
}); });
// update image of node // update image of node

View File

@ -0,0 +1 @@
<app-node-select-interface (onChooseInterface)="onChooseInterface($event)"></app-node-select-interface>

View File

@ -0,0 +1,58 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Subscription } from 'rxjs';
import { NodeSelectInterfaceComponent } from '../../../components/project-map/node-select-interface/node-select-interface.component';
import { DrawingLineWidget } from '../../../cartography/widgets/drawing-line';
import { NodesEventSource } from '../../../cartography/events/nodes-event-source';
import { LinksEventSource } from '../../../cartography/events/links-event-source';
import { MapNode } from '../../../cartography/models/map/map-node';
import { MapPort } from '../../../cartography/models/map/map-port';
import { MapLinkCreated } from '../../../cartography/events/links';
@Component({
selector: 'app-draw-link-tool',
templateUrl: './draw-link-tool.component.html',
styleUrls: ['./draw-link-tool.component.scss']
})
export class DrawLinkToolComponent implements OnInit, OnDestroy {
@ViewChild(NodeSelectInterfaceComponent) nodeSelectInterfaceMenu: NodeSelectInterfaceComponent;
private nodeClicked$: Subscription;
constructor(
private drawingLineTool: DrawingLineWidget,
private nodesEventSource: NodesEventSource,
private linksEventSource: LinksEventSource
) { }
ngOnInit() {
this.nodeClicked$ = this.nodesEventSource.clicked.subscribe((clickedEvent) => {
this.nodeSelectInterfaceMenu.open(
clickedEvent.datum,
clickedEvent.y,
clickedEvent.x
);
});
}
ngOnDestroy() {
if (this.drawingLineTool.isDrawing()) {
this.drawingLineTool.stop();
}
this.nodeClicked$.unsubscribe();
}
public onChooseInterface(event) {
const node: MapNode = event.node;
const port: MapPort = event.port;
if (this.drawingLineTool.isDrawing()) {
const data = this.drawingLineTool.stop();
this.linksEventSource.created.emit(new MapLinkCreated(data['node'], data['port'], node, port));
} else {
this.drawingLineTool.start(node.x + node.width / 2., node.y + node.height / 2., {
'node': node,
'port': port
});
}
}
}

View File

@ -18,9 +18,9 @@ export class NodeContextMenuComponent implements OnInit {
@ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger; @ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger;
protected topPosition; topPosition;
protected leftPosition; leftPosition;
public node: Node; node: Node;
constructor( constructor(
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,

View File

@ -1,6 +1,6 @@
<div class="context-menu" [style.left]="leftPosition" [style.top]="topPosition" *ngIf="node"> <div class="context-menu" [style.left]="leftPosition" [style.top]="topPosition" *ngIf="node">
<span [matMenuTriggerFor]="selectInterfaceMenu"></span> <span [matMenuTriggerFor]="selectInterfaceMenu"></span>
<mat-menu #selectInterfaceMenu="matMenu"> <mat-menu #selectInterfaceMenu="matMenu" class="context-menu-items">
<button mat-menu-item *ngFor="let port of node.ports" (click)="chooseInterface(port)"> <button mat-menu-item *ngFor="let port of node.ports" (click)="chooseInterface(port)">
<mat-icon>add_circle_outline</mat-icon> <mat-icon>add_circle_outline</mat-icon>
<span>{{ port.name }}</span> <span>{{ port.name }}</span>

View File

@ -15,8 +15,8 @@ export class NodeSelectInterfaceComponent implements OnInit {
@ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger; @ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger;
private topPosition; protected topPosition;
private leftPosition; protected leftPosition;
public node: Node; public node: Node;
constructor( constructor(

View File

@ -140,3 +140,5 @@
[project]="project" [project]="project"
[server]="server"> [server]="server">
</app-project-map-shortcuts> </app-project-map-shortcuts>
<app-draw-link-tool *ngIf="tools.draw_link"></app-draw-link-tool>

View File

@ -64,7 +64,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
private drawListener: Function; private drawListener: Function;
private ws: Subject<any>; private ws: Subject<any>;
protected tools = { tools = {
'selection': true, 'selection': true,
'moving': false, 'moving': false,
'draw_link': false 'draw_link': false

View File

@ -1,10 +1,18 @@
// The file contents for the current environment will overwrite these during build. // This file can be replaced during build by using the `fileReplacements` array.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// `ng build --env=prod` then `environment.prod.ts` will be used instead. // The list of file replacements can be found in `angular.json`.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = { export const environment = {
production: false, production: false,
electron: false, electron: false,
githubio: false githubio: false
}; };
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.

View File

@ -8,4 +8,5 @@ if (environment.production) {
enableProdMode(); enableProdMode();
} }
platformBrowserDynamic().bootstrapModule(AppModule); platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));

View File

@ -11,7 +11,7 @@
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
* *
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html * Learn more in https://angular.io/guide/browser-support
*/ */
/*************************************************************************************************** /***************************************************************************************************
@ -34,29 +34,47 @@
// import 'core-js/es6/weak-map'; // import 'core-js/es6/weak-map';
// import 'core-js/es6/set'; // import 'core-js/es6/set';
/**
* If the application will be indexed by Google Search, the following is required.
* Googlebot uses a renderer based on Chrome 41.
* https://developers.google.com/search/docs/guides/rendering
**/
// import 'core-js/es6/array';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */ /** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`. // import 'classlist.js'; // Run `npm install --save classlist.js`.
/** Evergreen browsers require these. **/ /** IE10 and IE11 requires the following for the Reflect API. */
import 'core-js/es6/reflect'; // import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
/** /**
* Required to support Web Animations `@angular/animation`. * Web Animations `@angular/platform-browser/animations`
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
**/ **/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`. // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
*/
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
/*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*/
// (window as any).__Zone_enable_cross_context_check = true;
/*************************************************************************************************** /***************************************************************************************************
* Zone JS is required by Angular itself. * Zone JS is required by default for Angular itself.
*/ */
import 'zone.js/dist/zone'; // Included with Angular CLI. import 'zone.js/dist/zone'; // Included with Angular CLI.
/*************************************************************************************************** /***************************************************************************************************
* APPLICATION IMPORTS * APPLICATION IMPORTS
*/ */

View File

@ -1,24 +1,14 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files // This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/long-stack-trace-zone'; import 'zone.js/dist/zone-testing';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import { getTestBed } from '@angular/core/testing'; import { getTestBed } from '@angular/core/testing';
import { import {
BrowserDynamicTestingModule, BrowserDynamicTestingModule,
platformBrowserDynamicTesting platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing'; } from '@angular/platform-browser-dynamic/testing';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare const __karma__: any;
declare const require: any; declare const require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// First, initialize the Angular testing environment. // First, initialize the Angular testing environment.
getTestBed().initTestEnvironment( getTestBed().initTestEnvironment(
BrowserDynamicTestingModule, BrowserDynamicTestingModule,
@ -28,5 +18,3 @@ getTestBed().initTestEnvironment(
const context = require.context('./', true, /\.spec\.ts$/); const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules. // And load the modules.
context.keys().map(context); context.keys().map(context);
// Finally, start Karma to run the tests.
__karma__.start();

View File

@ -1,18 +1,21 @@
{ {
"compileOnSave": false, "compileOnSave": false,
"compilerOptions": { "compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc", "outDir": "./dist/out-tsc",
"sourceMap": true, "sourceMap": true,
"declaration": false, "declaration": false,
"module": "es2015",
"moduleResolution": "node", "moduleResolution": "node",
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"importHelpers": true,
"target": "es5", "target": "es5",
"typeRoots": [ "typeRoots": [
"node_modules/@types" "node_modules/@types"
], ],
"lib": [ "lib": [
"es2016", "es2018",
"dom" "dom"
], ],
}, },

View File

@ -11,10 +11,14 @@
"check-space" "check-space"
], ],
"curly": true, "curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true, "eofline": true,
"forin": true, "forin": true,
"import-blacklist": [ "import-blacklist": [
true true,
"rxjs/Rx"
], ],
"import-spacing": true, "import-spacing": true,
"indent": [ "indent": [
@ -61,11 +65,12 @@
], ],
"no-misused-new": true, "no-misused-new": true,
"no-non-null-assertion": true, "no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-shadowed-variable": true, "no-shadowed-variable": true,
"no-string-literal": false, "no-string-literal": false,
"no-string-throw": true, "no-string-throw": true,
"no-switch-case-fall-through": true, "no-switch-case-fall-through": true,
"no-trailing-whitespace": false, "no-trailing-whitespace": true,
"no-unnecessary-initializer": true, "no-unnecessary-initializer": true,
"no-unused-expression": true, "no-unused-expression": true,
"no-use-before-declare": true, "no-use-before-declare": true,
@ -80,7 +85,7 @@
], ],
"prefer-const": true, "prefer-const": true,
"quotemark": [ "quotemark": [
false, true,
"single" "single"
], ],
"radix": true, "radix": true,
@ -102,7 +107,6 @@
"variable-declaration": "nospace" "variable-declaration": "nospace"
} }
], ],
"typeof-compare": true,
"unified-signatures": true, "unified-signatures": true,
"variable-name": false, "variable-name": false,
"whitespace": [ "whitespace": [
@ -113,18 +117,7 @@
"check-separator", "check-separator",
"check-type" "check-type"
], ],
"directive-selector": [ "no-output-on-prefix": true,
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"use-input-property-decorator": true, "use-input-property-decorator": true,
"use-output-property-decorator": true, "use-output-property-decorator": true,
"use-host-property-decorator": true, "use-host-property-decorator": true,
@ -133,9 +126,6 @@
"use-life-cycle-interface": true, "use-life-cycle-interface": true,
"use-pipe-transform-interface": true, "use-pipe-transform-interface": true,
"component-class-suffix": true, "component-class-suffix": true,
"directive-class-suffix": true, "directive-class-suffix": true
"no-access-missing-member": true,
"templates-use-public": true,
"invoke-injectable": true
} }
} }