This commit is contained in:
crusader 2018-05-19 22:06:59 +09:00
parent b3dd0bcaab
commit 962c116bb2
36 changed files with 277 additions and 333 deletions

View File

@ -26,14 +26,14 @@
"@loafer/decorator": "^0.0.1",
"@loafer/ng-logger": "^0.0.1",
"@loafer/ng-rest": "^0.0.1",
"@loafer/ng-rpc": "^0.0.1",
"@loafer/ng-rpc": "^0.0.3",
"@ngrx/core": "^1.2.0",
"@ngrx/effects": "^5.2.0",
"@ngrx/entity": "^5.2.0",
"@ngrx/router-store": "^5.2.0",
"@ngrx/store": "^5.2.0",
"@ngrx/store-devtools": "^5.2.0",
"@overflow/commons-typescript": "^0.0.3",
"@overflow/commons-typescript": "^0.0.5",
"angular-l10n": "^4.1.5",
"angularx-qrcode": "^1.1.0",
"chart.js": "^2.7.2",
@ -69,9 +69,12 @@
"karma-jasmine": "^1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-coverage-istanbul-reporter": "^1.4.2",
"prettier": "^1.12.1",
"protractor": "~5.3.1",
"ts-node": "~4.0.1",
"tslint": "~5.9.1",
"tslint-config-prettier": "^1.12.0",
"tslint-config-standard": "^7.0.0",
"typescript": "~2.5.3"
},
"description": "This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.3.0.",

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core';
import { RPCModule } from '@loafer/ng-rpc';
import { RPCModule } from '@loafer/ng-rpc/ng-rpc.module';
import {
RPC_CODEC,
@ -13,6 +13,13 @@ import {
import { environment } from '../environments/environment';
export function getRPCClientCodec() {
return new JSONRPCClientCodec();
}
export function getRPCClientWebsocketRWC(config: RxWebsocketSubjectConfig) {
return new RPCClientWebsocketRWC(config);
}
@NgModule({
exports: [
@ -24,10 +31,10 @@ import { environment } from '../environments/environment';
providers: [
{provide: 'WEBAPP_RPC_CONFIG', useValue: environment.webappRPCConfig},
{provide: RPC_CODEC, useFactory: () => new JSONRPCClientCodec()},
{provide: RPC_CODEC, useFactory: getRPCClientCodec},
{
provide: RPC_RWC,
useFactory: (config: RxWebsocketSubjectConfig) => new RPCClientWebsocketRWC(config),
useFactory: getRPCClientWebsocketRWC,
deps: ['WEBAPP_RPC_CONFIG']
},

View File

@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { NoAuthProbePageComponent } from './noauth-probe-page.component';
import { ListComponent as ProbeListComponent } from 'packages/probe/component/list/list.component';
import { ListComponent as NoauthListComponent } from 'packages/noauth/component/list/list.component';
import { NoAuthProbeListComponent } from 'packages/noauth-probe/component/noauth-probe-list.component';
import { DownloadComponent } from 'packages/probe/component/download/download.component';
const routes: Routes = [

View File

@ -1,2 +1 @@
container로 교체
<!-- <of-noauth-list></of-noauth-list> -->
<of-noauth-list-container></of-noauth-list-container>

View File

@ -1,6 +1,6 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NoauthModule } from 'packages/noauth/noauth.module';
import { NoauthModule } from 'packages/noauth-probe/noauth.module';
import { NoAuthProbePageComponent } from './noauth-probe-page.component';
import { NoAuthProbePageRoutingModule } from './noauth-probe-page-routing.module';
import { TabbarModule } from 'app/commons/component/layout/tabbar/app.tabbar.module';

View File

@ -0,0 +1,5 @@
import { NoAuthProbeListComponent } from './noauth-probe-list.component';
export const COMPONENTS = [
NoAuthProbeListComponent,
];

View File

@ -11,16 +11,16 @@
</tr>
</ng-template>
<ng-template pTemplate="body" let-rowData let-expanded="expanded" let-columns="columns">
<tr [pSelectableRow]="rowData.data" [pRowToggler]="rowData">
<tr [pSelectableRow]="rowData" [pRowToggler]="rowData">
<td>
<a href="#">
<i [ngClass]="expanded ? 'fa fa-fw fa-chevron-circle-down' : 'fa fa-fw fa-chevron-circle-right'"></i>
</a>
</td>
<td>{{rowData.data.tempProbeKey}}</td>
<td>{{rowData.meta.host.name}}</td>
<td>{{rowData.meta.host.os}}</td>
<td>{{rowData.data.createDate | date: 'dd/MM/yyyy'}}</td>
<td>{{rowData.tempProbeKey}}</td>
<td>{{rowData.descriptions.host.name}}</td>
<td>{{rowData.descriptions.host.os}}</td>
<td>{{rowData.createDate | date: 'dd/MM/yyyy'}}</td>
</tr>
</ng-template>
<ng-template pTemplate="rowexpansion" let-rowData let-columns="columns">
@ -30,39 +30,39 @@
<div class="ui-g-12 ui-md-6">
<div class="ui-g-12">
<b>Platform:</b> {{rowData.meta.host.platform}}
<b>Platform:</b> {{rowData.descriptions.host.platform}}
</div>
<div class="ui-g-12">
<b>Platform family:</b> {{rowData.meta.host.platformFamily}}
<b>Platform family:</b> {{rowData.descriptions.host.platformFamily}}
</div>
<div class="ui-g-12">
<b>Kernel:</b> {{rowData.meta.host.kernelVersion}}
<b>Kernel:</b> {{rowData.descriptions.host.kernelVersion}}
</div>
<div class="ui-g-12">
<b>HostID:</b> {{rowData.meta.host.hostID}}
<b>HostID:</b> {{rowData.descriptions.host.hostID}}
</div>
</div>
<div class="ui-g-12 ui-md-6">
<div class="ui-g">
<div class="ui-g-12">
<b>NIC:</b> {{rowData.meta.network.name}}
<b>NIC:</b> {{rowData.descriptions.network.name}}
</div>
<div class="ui-g-12">
<b>Network Address:</b> {{rowData.meta.network.address}}
<b>Network Address:</b> {{rowData.descriptions.network.address}}
</div>
<div class="ui-g-12">
<b>Gateway:</b> {{rowData.meta.network.gateway}}
<b>Gateway:</b> {{rowData.descriptions.network.gateway}}
</div>
<div class="ui-g-12">
<b>Mac Address:</b> {{rowData.meta.network.macAddress}}
<b>Mac Address:</b> {{rowData.descriptions.network.macAddress}}
</div>
</div>
</div>
<div class="ui-g-12" dir="rtl">
<button class="ui-button-danger ui-button-width-fit" type="button" label="Deny" icon="ui-icon-close" pButton (click)="onAcceptOrDeny(false, rowData.data)"></button>
<button class=" ui-button-width-fit" type="button" label="Accept" icon="fa-check" pButton (click)="onAcceptOrDeny(true, rowData.data)"></button>
<button class="ui-button-danger ui-button-width-fit" type="button" label="Deny" icon="ui-icon-close" pButton (click)="onAcceptOrDeny(false, rowData)"></button>
<button class=" ui-button-width-fit" type="button" label="Accept" icon="fa-check" pButton (click)="onAcceptOrDeny(true, rowData)"></button>
</div>
</div>
</td>

View File

@ -1,20 +1,20 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ListComponent } from './list.component';
import { NoAuthProbeListComponent } from './noauth-probe-list.component';
describe('ListComponent', () => {
let component: ListComponent;
let fixture: ComponentFixture<ListComponent>;
describe('NoAuthProbeListComponent', () => {
let component: NoAuthProbeListComponent;
let fixture: ComponentFixture<NoAuthProbeListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ListComponent ]
declarations: [ NoAuthProbeListComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ListComponent);
fixture = TestBed.createComponent(NoAuthProbeListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@ -0,0 +1,42 @@
import { Component, Input, Output, EventEmitter, AfterContentInit } from '@angular/core';
import { NoAuthProbe } from '@overflow/commons-typescript/model/noauth';
import { ConfirmationService, Message } from 'primeng/primeng';
import { MessageService } from 'primeng/components/common/messageservice';
@Component({
selector: 'of-noauth-list',
templateUrl: './noauth-probe-list.component.html',
providers: [ConfirmationService, MessageService]
})
export class NoAuthProbeListComponent {
@Input() noauthProbes: NoAuthProbe[];
@Output() accept = new EventEmitter<NoAuthProbe>();
@Output() deny = new EventEmitter<NoAuthProbe>();
msgs: Message[];
constructor(
private confirmationService: ConfirmationService,
private messageService: MessageService
) {
}
onAcceptOrDeny(isAccept: boolean, selected: NoAuthProbe) {
console.log(selected);
this.msgs = [];
const title = isAccept ?
'Are you sure to accept this Probe?' : 'Are you sure to deny this Probe';
const message = isAccept ?
'Start collecting data as a Probe.' : 'It will be permanently deleted.';
this.confirmationService.confirm({
header: title,
message: message,
icon: isAccept ? 'fa-check' : 'fa fa-trash',
accept: () => {
isAccept ? this.accept.emit(selected) : this.deny.emit(selected);
},
reject: () => {
}
});
}
}

View File

@ -0,0 +1,5 @@
import { NoAuthProbeListContainerComponent } from './noauth-probe-list-container.component';
export const CONTAINER_COMPONENTS = [
NoAuthProbeListContainerComponent,
];

View File

@ -0,0 +1 @@
<of-noauth-list [noauthProbes]="noauthProbes$ | async" (accept)="accept($event)" (deny)="deny($event)"></of-noauth-list>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NoAuthProbeListContainerComponent } from './noauth-probe-list-container.component';
describe('NoAuthProbeListContainerComponent', () => {
let component: NoAuthProbeListContainerComponent;
let fixture: ComponentFixture<NoAuthProbeListContainerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NoAuthProbeListContainerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NoAuthProbeListContainerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,60 @@
import { Component, OnInit } from '@angular/core';
import { AfterContentInit, OnDestroy } from '@angular/core/src/metadata/lifecycle_hooks';
import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { AuthSelector } from 'packages/member/store';
import { Domain } from '@overflow/commons-typescript/model/domain';
import * as ListStore from '../store/noauth-probe';
import { NoAuthProbeSelector } from '../store';
import { NoAuthProbe } from '@overflow/commons-typescript/model/noauth';
import { ConfirmationService } from 'primeng/primeng';
import { MessageService } from 'primeng/components/common/messageservice';
@Component({
selector: 'of-noauth-list-container',
templateUrl: './noauth-probe-list-container.component.html',
providers: [ConfirmationService, MessageService]
})
export class NoAuthProbeListContainerComponent implements OnInit, AfterContentInit, OnDestroy {
noauthProbes$: Observable<NoAuthProbe[]>;
constructor(
private store: Store<ListStore.State>,
) {
}
ngOnInit() {
// this.noauthProbes$ = this.store.pipe(select(NoAuthProbeSelector.select('noAuthProbes'))).map((_noauthProbes: NoAuthProbe[]) => {
this.noauthProbes$ = this.store.pipe(select(NoAuthProbeSelector.selectAll)).map((_noauthProbes: NoAuthProbe[]) => {
if (null === _noauthProbes) {
return null;
}
_noauthProbes.forEach(_noauthProbe => {
_noauthProbe.descriptions = JSON.parse(_noauthProbe.description);
});
return _noauthProbes;
});
}
ngAfterContentInit() {
this.store.select(AuthSelector.select('domain')).subscribe(
(domain: Domain) => {
this.store.dispatch(new ListStore.ReadAllByDomain(domain));
}
);
}
ngOnDestroy() {
}
accept(selected) {
this.store.dispatch(new ListStore.Accept(selected));
}
deny(selected) {
this.store.dispatch(new ListStore.Deny(selected));
}
}

View File

@ -1,11 +1,14 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { PrimeNGModules } from 'packages/commons/prime-ng/prime-ng.module';
import { NoAuthProbeStoreModule } from './noauth-probe-store.module';
import { NoAuthProbeRPCModule } from './noauth-probe-rpc.module';
import { NoAuthProbeLoggerModule } from './noauth-probe-logger.module';
import { COMPONENTS } from './component';
import { CONTAINER_COMPONENTS } from './container';
import { SERVICES } from './service';
import { PrimeNGModules } from '../commons/prime-ng/prime-ng.module';
@NgModule({
imports: [
@ -17,9 +20,11 @@ import { PrimeNGModules } from '../commons/prime-ng/prime-ng.module';
],
declarations: [
COMPONENTS,
CONTAINER_COMPONENTS,
],
exports: [
COMPONENTS,
CONTAINER_COMPONENTS,
],
providers: [
SERVICES,

View File

@ -21,9 +21,17 @@ export const EFFECTS = [
NoAuthProbeStore.Effects,
];
export const selectNoAuthProbeState = createFeatureSelector<State>(MODULE.name);
export const selectFeatureState = createFeatureSelector<State>(MODULE.name);
export const NoAuthProbeSelector = new StateSelector<NoAuthProbeStore.State>(createSelector(
selectNoAuthProbeState,
export const selectNoAuthProbeState = createSelector(
selectFeatureState,
(state: State) => state.noAuthProbe
));
);
// export const NoAuthProbeSelector = new StateSelector<NoAuthProbeStore.State>(createSelector(
// selectNoAuthProbeState,
// (state: State) => state.noAuthProbe
// ));
export const NoAuthProbeSelector = NoAuthProbeStore.adapter.getSelectors(selectNoAuthProbeState);

View File

@ -15,6 +15,7 @@ import {
import {
State,
initialState,
adapter,
} from './noauth-probe.state';
import { NoAuthProbe } from '@overflow/commons-typescript/model/noauth';
@ -30,21 +31,19 @@ export function reducer(state = initialState, action: Actions): State {
}
case ActionType.ReadAllByDomainSuccess: {
return {
return adapter.addAll(action.payload, {
...state,
error: null,
pending: false,
noAuthProbes: action.payload,
};
});
}
case ActionType.ReadAllByDomainFailure: {
return {
return adapter.removeAll({
...state,
error: action.payload,
pending: false,
noAuthProbes: null,
};
});
}
case ActionType.Accept: {
@ -56,12 +55,12 @@ export function reducer(state = initialState, action: Actions): State {
}
case ActionType.AcceptSuccess: {
return {
...state,
const s = adapter.removeAll(state);
return adapter.addAll(action.payload, {
...s,
error: null,
pending: false,
noAuthProbes: action.payload,
};
});
}
case ActionType.AcceptFailure: {
@ -81,12 +80,12 @@ export function reducer(state = initialState, action: Actions): State {
}
case ActionType.DenySuccess: {
return {
...state,
const s = adapter.removeAll(state);
return adapter.addAll(action.payload, {
...s,
error: null,
pending: false,
noAuthProbes: action.payload,
};
});
}
case ActionType.DenyFailure: {
@ -97,7 +96,6 @@ export function reducer(state = initialState, action: Actions): State {
};
}
case ActionType.OnConnect: {
return {
...state,
};

View File

@ -0,0 +1,29 @@
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { RPCClientError } from '@loafer/ng-rpc/protocol';
import { NoAuthProbe } from '@overflow/commons-typescript/model/noauth';
export interface State extends EntityState<NoAuthProbe> {
error: RPCClientError | null;
pending: boolean;
}
export const adapter: EntityAdapter<NoAuthProbe> = createEntityAdapter<NoAuthProbe>();
// export interface State {
// error: RPCClientError | null;
// pending: boolean;
// noAuthProbes: NoAuthProbe[] | null;
// }
// export const initialState: State = {
// error: null,
// pending: false,
// noAuthProbes: null,
// };
export const initialState: State = adapter.getInitialState({
error: null,
pending: false,
});

View File

@ -1,5 +0,0 @@
import { ListComponent } from './list/list.component';
export const COMPONENTS = [
ListComponent,
];

View File

@ -1,128 +0,0 @@
import { Component, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { AfterContentInit, OnDestroy } from '@angular/core/src/metadata/lifecycle_hooks';
import { Router } from '@angular/router';
import { Store, select } from '@ngrx/store';
import { AuthSelector } from 'packages/member/store';
import { RPCClientError } from '@loafer/ng-rpc/protocol';
import { Domain } from '@overflow/commons-typescript/model/domain';
import * as ListStore from '../../store/noauth-probe';
import { NoAuthProbeSelector } from '../../store';
import { NoAuthProbe } from '@overflow/commons-typescript/model/noauth';
import { ConfirmationService, Message } from 'primeng/primeng';
import { MessageService } from 'primeng/components/common/messageservice';
import { Subscription } from 'rxjs/Subscription';
class NoauthProbeDesc {
host: {
name: string;
os: string;
platform: string;
platformFamily: string;
platformVersion: string;
kernelVersion: string;
hostID: string;
};
network: {
name: string;
address: string;
gateway: string;
macAddress: string;
};
}
class NoauthProbeResult {
id: number;
data: NoAuthProbe;
meta: NoauthProbeDesc;
}
@Component({
selector: 'of-noauth-list',
templateUrl: './list.component.html',
providers: [ConfirmationService, MessageService]
})
export class ListComponent implements OnInit, AfterContentInit, OnDestroy {
noAuthProbesSubscription$: Subscription;
noAuthProbes$ = this.store.pipe(select(NoAuthProbeSelector.select('noAuthProbes')));
noauthProbes: NoauthProbeResult[];
msgs: Message[];
constructor(
private router: Router,
private store: Store<ListStore.State>,
private confirmationService: ConfirmationService,
private messageService: MessageService
) {
}
ngOnInit() {
this.noAuthProbesSubscription$ = this.noAuthProbes$.subscribe(
(result: NoAuthProbe[]) => {
if (result) {
this.arrangeData(result);
}
},
(error: RPCClientError) => {
console.log(error.response.message);
}
);
}
ngAfterContentInit() {
this.store.select(AuthSelector.select('domain')).subscribe(
(domain: Domain) => {
this.store.dispatch(new ListStore.ReadAllByDomain(domain));
}
);
}
ngOnDestroy() {
this.noAuthProbesSubscription$.unsubscribe();
}
arrangeData(list) {
if (!list || list.length === 0) {
return;
}
this.noauthProbes = [];
for (const np of list) {
const desc: NoauthProbeDesc = JSON.parse(np.description);
const result: NoauthProbeResult = {
id: np.id,
data: np,
meta: desc
};
this.noauthProbes.push(result);
}
}
onAcceptOrDeny(isAccept: boolean, selected: NoAuthProbe) {
console.log(selected);
this.msgs = [];
const title = isAccept ?
'Are you sure to accept this Probe?' : 'Are you sure to deny this Probe';
const message = isAccept ?
'Start collecting data as a Probe.' : 'It will be permanently deleted.';
this.confirmationService.confirm({
header: title,
message: message,
icon: isAccept ? 'fa-check' : 'fa fa-trash',
accept: () => {
isAccept ? this.handleAccept(selected) : this.handleDeny(selected);
},
reject: () => {
}
});
}
handleAccept(selected) {
this.store.dispatch(new ListStore.Accept(selected));
}
handleDeny(selected) {
this.store.dispatch(new ListStore.Deny(selected));
}
}

View File

@ -1,15 +0,0 @@
import { RPCClientError } from '@loafer/ng-rpc/protocol';
import { NoAuthProbe } from '@overflow/commons-typescript/model/noauth';
export interface State {
error: RPCClientError | null;
pending: boolean;
noAuthProbes: NoAuthProbe[] | null;
}
export const initialState: State = {
error: null,
pending: false,
noAuthProbes: null,
};

View File

@ -4,8 +4,7 @@ import { Router } from '@angular/router';
@Component({
selector: 'of-target-filter',
templateUrl: './filter.component.html',
styleUrls: ['./filter.component.scss']
templateUrl: './filter.component.html'
})
export class FilterComponent implements OnInit {

View File

@ -19,6 +19,17 @@
"lib": [
"es2017",
"dom"
]
],
// /* Additional Checks */
// "noUnusedLocals": true /* Report errors on unused locals. */,
// "noUnusedParameters": true /* Report errors on unused parameters. */,
// "noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
// "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
// /* Debugging Options */
// "traceResolution": false /* Report module resolution log messages. */,
// "listEmittedFiles": false /* Print names of generated files part of the compilation. */,
// "listFiles": false /* Print names of files part of the compilation. */,
// "pretty": true /* Stylize errors and messages using color and context. */,
}
}

View File

@ -1,139 +1,34 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"extends": ["tslint:latest", "tslint-config-prettier", "tslint-immutable"],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-define": ["error", { "functions": true, "classes": true }],
"interface-name": [true, "never-prefix"],
// TODO: allow devDependencies only in **/*.spec.ts files:
// waiting on https://github.com/palantir/tslint/pull/3708
"no-implicit-dependencies": [true, "dev"],
/* tslint-immutable rules */
// Recommended built-in rules
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
"no-parameter-reassignment": true,
"typedef": [true, "call-signature"],
// Immutability rules
"readonly-keyword": true,
"readonly-array": true,
"no-let": true,
"no-object-mutation": true,
"no-delete": true,
"no-method-signature": true,
// Functional style rules
"no-this": true,
"no-class": true,
"no-mixed-interface": true,
"no-expression-statement": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
{ "ignore-prefix": ["console.", "process.exit"] }
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"of",
"camelCase"
],
"component-selector": [
true,
"element",
"of",
"kebab-case"
],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
"no-if-statement": true
/* end tslint-immutable rules */
}
}