Thursday, July 14, 2016

ng2-admin + ag-grid

This blog will show how to add ag-grid to ng2-admin.
ag-grid is a JavaScript Data Grid for Building Enterprise Web Applications.
ng2-admin is a admin template made by Akveo team.

Install required tools (do it as administrator)
npm install --global webpack
npm install --global webpack-dev-server
npm install --global typings
npm install --global typescript
npm install --global bower

Clone ng2-admin git repository
git clone https://github.com/akveo/ng2-admin.git
cd ng2-admin 

Install dependencies
npm install

Finally run local dev server
npm start

Open browser at http://localhost:3000


Let's add ag-grid

Install ag-grid dependencies
npm install ag-grid ag-grid-ng2 --save


Open vs code 
code .

Edit index.html and add links to ag-grid css files
  <link href="assets/ag-grid/styles/ag-grid.css" rel="stylesheet"></link>
  <link href="assets/ag-grid/styles/theme-blue.css" rel="stylesheet"></link>



Copy ag-grid.css and theme-blue.css to assets/ag-grid/styles folder

Let's add sample gird to Basic Tables page. Grid is based on sample https://github.com/ceolter/ag-grid-ng2-example
Copy content of images folder to src/assets/img
Create folder agTable in src\app\pages\tables\components\basicTables\components directory.
Create agTable.html file
<div class="horizontal-scroll">
<div style="width: 100%;">

    <div style="padding: 4px;">
        <div style="float: right;">
            <input (keyup)="onQuickFilterChanged($event)" type="text" id="quickFilterInput" placeholder="Type text to filter..."/>

            <button [disabled]="!showGrid" (click)="showGrid=false" class="btn btn-primary btn-xs">Destroy Grid</button>
            
            <button [disabled]="showGrid" (click)="showGrid=true" class="btn btn-primary btn-xs">Create Grid</button>
        </div>
        <div>
            <b>Employees Skills and Contact Details</b>
            {{rowCount}}
        </div>
    </div>
    <div style="clear: both;"></div>

    <div *ngIf="showGrid">

        <!-- Because we are using the Angular ID (ie #ag-grid marker), we have to have all the items that use
             that marker inside the same ng-if as the grid -->

        <div style="padding: 4px;" class="toolbar">
            <span>
                Grid API:
                <button (click)="agGrid.api.selectAll()" class="btn btn-primary btn-xs">Select All</button>
                <button (click)="agGrid.api.deselectAll()" class="btn btn-primary btn-xs">Clear Selection</button>
            </span>
            <span style="margin-left: 20px;">
                Column API:
                <button (click)="agGrid.columnApi.setColumnVisible('country', false)" class="btn btn-primary btn-xs">Hide Country Column</button>
                <button (click)="agGrid.columnApi.setColumnVisible('country', true)" class="btn btn-primary btn-xs">Show Country Column</button>
            </span>
        </div>
        <div style="clear: both;"></div>
        <div style="padding: 4px;" class="toolbar">
            <label>
                <input type="checkbox" (change)="showToolPanel=$event.target.checked"/>
                Show Tool Panel
            </label>
            <button (click)="createRowData()" class="btn btn-primary btn-xs">Refresh Data</button>
        </div>
        <div style="clear: both;"></div>

        <ag-grid-ng2 #agGrid style="width: 100%; height: 350px;" class="ag-blue"

                     [gridOptions]="gridOptions"
                     [columnDefs]="columnDefs"
                     [showToolPanel]="showToolPanel"
                     [rowData]="rowData"

                     enableColResize
                     enableSorting
                     enableFilter
                     groupHeaders
                     suppressRowClickSelection
                     toolPanelSuppressGroups
                     toolPanelSuppressValues
                     debug
                     rowHeight="22"
                     rowSelection="multiple"

                     (modelUpdated)="onModelUpdated()"
                     (cellClicked)="onCellClicked($event)"
                     (cellDoubleClicked)="onCellDoubleClicked($event)"
                     (cellContextMenu)="onCellContextMenu($event)"
                     (cellValueChanged)="onCellValueChanged($event)"
                     (cellFocused)="onCellFocused($event)"
                     (rowSelected)="onRowSelected($event)"
                     (selectionChanged)="onSelectionChanged()"
                     (beforeFilterChanged)="onBeforeFilterChanged()"
                     (afterFilterChanged)="onAfterFilterChanged()"
                     (filterModified)="onFilterModified()"
                     (beforeSortChanged)="onBeforeSortChanged()"
                     (afterSortChanged)="onAfterSortChanged()"
                     (virtualRowRemoved)="onVirtualRowRemoved($event)"
                     (rowClicked)="onRowClicked($event)"
                     (ready)="onReady($event)"

                     (columnEverythingChanged)="onColumnEvent($event)"
                     (columnRowGroupChanged)="onColumnEvent($event)"
                     (columnValueChanged)="onColumnEvent($event)"
                     (columnMoved)="onColumnEvent($event)"
                     (columnVisible)="onColumnEvent($event)"
                     (columnGroupOpened)="onColumnEvent($event)"
                     (columnResized)="onColumnEvent($event)"
                     (columnPinnedCountChanged)="onColumnEvent($event)">
        </ag-grid-ng2>
    </div>

</div>
</div>

Create agTable.components.ts file 
import {Component} from '@angular/core';

import {BaAppPicturePipe} from '../../../../../../theme/pipes';
import {BasicTablesService} from '../../basicTables.service';
import {AgGridNg2} from 'ag-grid-ng2/main';
import {GridOptions} from 'ag-grid/main';
import ProficiencyFilter from './proficiencyFilter';
import SkillFilter from './skillFilter';
import RefData from './refData';


@Component({
     selector: 'ag-table',
  template: require('./agTable.html'),
    directives: [AgGridNg2],
    styles: ['.toolbar button {margin: 2px; padding: 0px;}'],
})
export class AgTable {

    private gridOptions: GridOptions;
    private showGrid: boolean;
    private rowData: any[];
    private columnDefs: any[];
    private rowCount: string;

    constructor() {
        // we pass an empty gridOptions in, so we can grab the api out
        this.gridOptions = <GridOptions>{};
        this.createRowData();
        this.createColumnDefs();
        this.showGrid = true;
    }

    private createRowData() {
        var rowData: any[] = [];

        for (var i = 0; i < 10000; i++) {
            var countryData = RefData.countries[i % RefData.countries.length];
            rowData.push({
                name: RefData.firstNames[i % RefData.firstNames.length] + ' ' + RefData.lastNames[i % RefData.lastNames.length],
                skills: {
                    android: Math.random() < 0.4,
                    html5: Math.random() < 0.4,
                    mac: Math.random() < 0.4,
                    windows: Math.random() < 0.4,
                    css: Math.random() < 0.4
                },
                address: RefData.addresses[i % RefData.addresses.length],
                years: Math.round(Math.random() * 100),
                proficiency: Math.round(Math.random() * 100),
                country: countryData.country,
                continent: countryData.continent,
                language: countryData.language,
                mobile: createRandomPhoneNumber(),
                landline: createRandomPhoneNumber()
            });
        }

        this.rowData = rowData;
    }

    private createColumnDefs() {
        this.columnDefs = [
            {headerName: '#', width: 30, checkboxSelection: true, suppressSorting: true,
                suppressMenu: true, pinned: true},
            {
                headerName: 'Employee',
                children: [
                    {headerName: "Name", field: "name",
                        width: 150, pinned: true},
                    {headerName: "Country", field: "country", width: 150,
                        cellRenderer: countryCellRenderer, pinned: true,
                        filterParams: {cellRenderer: countryCellRenderer, cellHeight: 20}},
                ]
            },
            {
                headerName: 'IT Skills',
                children: [
                    {headerName: "Skills", width: 125, suppressSorting: true, cellRenderer: skillsCellRenderer, filter: SkillFilter},
                    {headerName: "Proficiency", field: "proficiency", width: 120, cellRenderer: percentCellRenderer, filter: ProficiencyFilter},
                ]
            },
            {
                headerName: 'Contact',
                children: [
                    {headerName: "Mobile", field: "mobile", width: 150, filter: 'text'},
                    {headerName: "Land-line", field: "landline", width: 150, filter: 'text'},
                    {headerName: "Address", field: "address", width: 500, filter: 'text'}
                ]
            }
        ];
    }

    private calculateRowCount() {
        if (this.gridOptions.api && this.rowData) {
            var model = this.gridOptions.api.getModel();
            var totalRows = this.rowData.length;
            var processedRows = model.getRowCount();
            this.rowCount = processedRows.toLocaleString() + ' / ' + totalRows.toLocaleString();
        }
    }

    private onModelUpdated() {
        console.log('onModelUpdated');
        this.calculateRowCount();
    }

    private onReady() {
        console.log('onReady');
        this.calculateRowCount();
    }

    private onCellClicked($event) {
        console.log('onCellClicked: ' + $event.rowIndex + ' ' + $event.colDef.field);
    }

    private onCellValueChanged($event) {
        console.log('onCellValueChanged: ' + $event.oldValue + ' to ' + $event.newValue);
    }

    private onCellDoubleClicked($event) {
        console.log('onCellDoubleClicked: ' + $event.rowIndex + ' ' + $event.colDef.field);
    }

    private onCellContextMenu($event) {
        console.log('onCellContextMenu: ' + $event.rowIndex + ' ' + $event.colDef.field);
    }

    private onCellFocused($event) {
        console.log('onCellFocused: (' + $event.rowIndex + ',' + $event.colIndex + ')');
    }

    private onRowSelected($event) {
        // taking out, as when we 'select all', it prints to much to the console!!
        // console.log('onRowSelected: ' + $event.node.data.name);
    }

    private onSelectionChanged() {
        console.log('selectionChanged');
    }

    private onBeforeFilterChanged() {
        console.log('beforeFilterChanged');
    }

    private onAfterFilterChanged() {
        console.log('afterFilterChanged');
    }

    private onFilterModified() {
        console.log('onFilterModified');
    }

    private onBeforeSortChanged() {
        console.log('onBeforeSortChanged');
    }

    private onAfterSortChanged() {
        console.log('onAfterSortChanged');
    }

    private onVirtualRowRemoved($event) {
        // because this event gets fired LOTS of times, we don't print it to the
        // console. if you want to see it, just uncomment out this line
        // console.log('onVirtualRowRemoved: ' + $event.rowIndex);
    }

    private onRowClicked($event) {
        console.log('onRowClicked: ' + $event.node.data.name);
    }

    private onQuickFilterChanged($event) {
        this.gridOptions.api.setQuickFilter($event.target.value);
    }

    // here we use one generic event to handle all the column type events.
    // the method just prints the event name
    private onColumnEvent($event) {
        console.log('onColumnEvent: ' + $event);
    }

}

function skillsCellRenderer(params) {
    var data = params.data;
    var skills = [];
    RefData.IT_SKILLS.forEach(function (skill) {
        if (data && data.skills && data.skills[skill]) {
            skills.push('<img src="assets/img/skills/' + skill + '.png" width="16px" title="' + skill + '" />');
        }
    });
    return skills.join(' ');
}

function countryCellRenderer(params) {
    var flag = "<img border='0' width='15' height='10' style='margin-bottom: 2px' src='assets/img/flags/" + RefData.COUNTRY_CODES[params.value] + ".png'>";
    return flag + " " + params.value;
}

function createRandomPhoneNumber() {
    var result = '+';
    for (var i = 0; i < 12; i++) {
        result += Math.round(Math.random() * 10);
        if (i === 2 || i === 5 || i === 8) {
            result += ' ';
        }
    }
    return result;
}

function percentCellRenderer(params) {
    var value = params.value;

    var eDivPercentBar = document.createElement('div');
    eDivPercentBar.className = 'div-percent-bar';
    eDivPercentBar.style.width = value + '%';
    if (value < 20) {
        eDivPercentBar.style.backgroundColor = 'red';
    } else if (value < 60) {
        eDivPercentBar.style.backgroundColor = '#ff9900';
    } else {
        eDivPercentBar.style.backgroundColor = '#00A000';
    }

    var eValue = document.createElement('div');
    eValue.className = 'div-percent-value';
    eValue.innerHTML = value + '%';

    var eOuterDiv = document.createElement('div');
    eOuterDiv.className = 'div-outer-div';
    eOuterDiv.appendChild(eValue);
    eOuterDiv.appendChild(eDivPercentBar);

    return eOuterDiv;
}

Create index.ts file
export * from './agTable.component';

Create proficiencyFilter.ts file
var FILTER_TITLE =
    '<div style="text-align: center; background: lightgray; width: 100%; display: block; border-bottom: 1px solid grey;">' +
    '<b>TITLE_NAME</b>' +
    '</div>';

var PROFICIENCY_TEMPLATE =
    '<label style="padding-left: 4px;">' +
    '<input type="radio" name="RANDOM"/>' +
    'PROFICIENCY_NAME' +
    '</label>';

var PROFICIENCY_NONE = 'none';
var PROFICIENCY_ABOVE40 = 'above40';
var PROFICIENCY_ABOVE60 = 'above60';
var PROFICIENCY_ABOVE80 = 'above80';

var PROFICIENCY_NAMES = ['No Filter', 'Above 40%', 'Above 60%', 'Above 80%'];
var PROFICIENCY_VALUES = [PROFICIENCY_NONE, PROFICIENCY_ABOVE40, PROFICIENCY_ABOVE60, PROFICIENCY_ABOVE80];

export default class ProficiencyFilter {

    private filterChangedCallback: Function;
    private selected: string;
    private valueGetter: Function;

    private init(params) {
        this.filterChangedCallback = params.filterChangedCallback;
        this.selected = PROFICIENCY_NONE;
        this.valueGetter = params.valueGetter;
    }

    private getGui() {
        var eGui = document.createElement('div');
        var eInstructions = document.createElement('div');
        eInstructions.innerHTML = FILTER_TITLE.replace('TITLE_NAME', 'Custom Proficiency Filter');
        eGui.appendChild(eInstructions);

        var random = '' + Math.random();

        var that = this;
        PROFICIENCY_NAMES.forEach( function (name, index) {
            var eFilter = document.createElement('div');
            var html = PROFICIENCY_TEMPLATE.replace('PROFICIENCY_NAME', name).replace('RANDOM', random);
            eFilter.innerHTML = html;
            var eRadio = <HTMLInputElement> eFilter.querySelector('input');
            if (index === 0) {
                eRadio.checked = true;
            }
            eGui.appendChild(eFilter);

            eRadio.addEventListener('click', function () {
                that.selected = PROFICIENCY_VALUES[index];
                that.filterChangedCallback();
            });
        });

        return eGui;
    }

    private doesFilterPass(params) {

        var value = this.valueGetter(params);
        var valueAsNumber = parseFloat(value);

        switch (this.selected) {
            case PROFICIENCY_ABOVE40 : return valueAsNumber >= 40;
            case PROFICIENCY_ABOVE60 : return valueAsNumber >= 60;
            case PROFICIENCY_ABOVE80 : return valueAsNumber >= 80;
            default : return true;
        }

    }

    private isFilterActive() {
        return this.selected !== PROFICIENCY_NONE;
    }

}

Create refData.ts file
export default class RefData {

    static IT_SKILLS = ['android', 'css', 'html5', 'mac', 'windows'];
    static IT_SKILLS_NAMES = ['Android', 'CSS', 'HTML 5', 'Mac', 'Windows'];


    static firstNames = ["Sophie", "Isabelle", "Emily", "Olivia", "Lily", "Chloe", "Isabella",
        "Amelia", "Jessica", "Sophia", "Ava", "Charlotte", "Mia", "Lucy", "Grace", "Ruby",
        "Ella", "Evie", "Freya", "Isla", "Poppy", "Daisy", "Layla"];
    static lastNames = ["Beckham", "Black", "Braxton", "Brennan", "Brock", "Bryson", "Cadwell",
        "Cage", "Carson", "Chandler", "Cohen", "Cole", "Corbin", "Dallas", "Dalton", "Dane",
        "Donovan", "Easton", "Fisher", "Fletcher", "Grady", "Greyson", "Griffin", "Gunner",
        "Hayden", "Hudson", "Hunter", "Jacoby", "Jagger", "Jaxon", "Jett", "Kade", "Kane",
        "Keating", "Keegan", "Kingston", "Kobe"];

    static COUNTRY_CODES = {
        Ireland: "ie",
        Spain: "es",
        "United Kingdom": "gb",
        France: "fr",
        Germany: "de",
        Sweden: "se",
        Italy: "it",
        Greece: "gr",
        Iceland: "is",
        Portugal: "pt",
        Malta: "mt",
        Norway: "no",
        Brazil: "br",
        Argentina: "ar",
        Colombia: "co",
        Peru: "pe",
        Venezuela: "ve",
        Uruguay: "uy"
    };

    static countries = [
        {country: "Ireland", continent: "Europe", language: "English"},
        {country: "Spain", continent: "Europe", language: "Spanish"},
        {country: "United Kingdom", continent: "Europe", language: "English"},
        {country: "France", continent: "Europe", language: "French"},
        {country: "Germany", continent: "Europe", language: "(other)"},
        {country: "Sweden", continent: "Europe", language: "(other)"},
        {country: "Norway", continent: "Europe", language: "(other)"},
        {country: "Italy", continent: "Europe", language: "(other)"},
        {country: "Greece", continent: "Europe", language: "(other)"},
        {country: "Iceland", continent: "Europe", language: "(other)"},
        {country: "Portugal", continent: "Europe", language: "Portuguese"},
        {country: "Malta", continent: "Europe", language: "(other)"},
        {country: "Brazil", continent: "South America", language: "Portuguese"},
        {country: "Argentina", continent: "South America", language: "Spanish"},
        {country: "Colombia", continent: "South America", language: "Spanish"},
        {country: "Peru", continent: "South America", language: "Spanish"},
        {country: "Venezuela", continent: "South America", language: "Spanish"},
        {country: "Uruguay", continent: "South America", language: "Spanish"}
    ];

    static addresses = [
        '1197 Thunder Wagon Common, Cataract, RI, 02987-1016, US, (401) 747-0763',
        '3685 Rocky Glade, Showtucket, NU, X1E-9I0, CA, (867) 371-4215',
        '3235 High Forest, Glen Campbell, MS, 39035-6845, US, (601) 638-8186',
        '2234 Sleepy Pony Mall , Drain, DC, 20078-4243, US, (202) 948-3634',
        '2722 Hazy Turnabout, Burnt Cabins, NY, 14120-5642, US, (917) 604-6597',
        '6686 Lazy Ledge, Two Rock, CA, 92639-3020, US, (619) 901-9911',
        '2000 Dewy Limits, Wacahoota, NF, A4L-2V9, CA, (709) 065-3959',
        '7710 Noble Pond Avenue, Bolivia, RI, 02931-1842, US, (401) 865-2160',
        '3452 Sunny Vale, Pyro, ON, M8V-4Z0, CA, (519) 072-8609',
        '4402 Dusty Cove, Many Farms, UT, 84853-8223, US, (435) 518-0673',
        '5198 Silent Parade, Round Bottom, MD, 21542-9798, US, (301) 060-7245',
        '8550 Shady Moor, Kitty Fork, CO, 80941-6207, US, (303) 502-3767',
        '2131 Old Dell, Merry Midnight, AK, 99906-8842, US, (907) 369-2206',
        '7390 Harvest Crest, Mosquito Crossing, RI, 02957-6116, US, (401) 463-6348',
        '874 Little Point, Hot Coffee, BC, V3U-2P6, CA, (250) 706-9207',
        '8834 Stony Pioneer Heights, Newlove, OR, 97419-8670, US, (541) 408-2213',
        '9829 Grand Beach, Flint, UT, 84965-9900, US, (435) 700-5161',
        '3799 Cozy Blossom Ramp, Ptarmigan, MS, 38715-0313, US, (769) 740-1526',
        '3254 Silver Island Loop, Maunaloa, DE, 19869-3169, US, (302) 667-7671',
        '1081 Middle Wood, Taylors Gut Landing, OR, 97266-2873, US, (541) 357-6310',
        '1137 Umber Trail, Shacktown, NW, X3U-5Y8, CA, (867) 702-6883',
        '9914 Hidden Bank, Wyoming, MO, 64635-9665, US, (636) 280-4192',
        '7080 Misty Nectar Townline, Coward, AB, T9U-3N4, CA, (403) 623-2838',
        '1184 Wishing Grounds, Vibank, NW, X7D-0V9, CA, (867) 531-2730',
        '126 Easy Pointe, Grandview Beach, KY, 40928-9539, US, (502) 548-0956',
        '6683 Colonial Street, Swan River, BC, V1A-9I8, CA, (778) 014-4257',
        '960 Gentle Oak Lane, Shakopee, ND, 58618-6277, US, (701) 327-1219',
        '6918 Cotton Pine Corner, Kenaston, IA, 52165-3975, US, (515) 906-7427',
        '2368 Burning Woods, Ernfold, NY, 11879-9186, US, (646) 819-0355',
        '5646 Quiet Shadow Chase, Tiger Tail, IA, 52283-5537, US, (712) 375-9225',
        '5466 Foggy Mountain Dale, Sweet Home, MT, 59738-0251, US, (406) 881-1706',
        '5313 Clear Willow Route, Amazon, BC, V0S-2S6, CA, (604) 340-7596',
        '7000 Pleasant Autoroute, Spaceport City, UT, 84749-2448, US, (435) 154-3360',
        '8359 Quaking Anchor Road, Gross, BC, V9O-0H5, CA, (250) 985-3859',
        '5143 Amber Deer Hollow, New Deal, ND, 58446-0853, US, (701) 927-0322',
        '6230 Jagged Bear Key, Young, AR, 72337-3811, US, (501) 805-7239',
        '7207 Heather Vista, Devon, WY, 82520-1771, US, (307) 358-7092',
        '9416 Red Rise Place, Spraytown, OK, 73809-4766, US, (580) 867-1973',
        '3770 Golden Horse Diversion, Yelland, IL, 60471-1487, US, (224) 717-9349',
        '4819 Honey Treasure Park, Alaska, NB, E1U-3I0, CA, (506) 656-9138',
        '6187 Round Front, Land O Lakes, AK, 99873-6403, US, (907) 853-9063',
        '9218 Crystal Highway, Pickelville, MT, 59847-9299, US, (406) 076-0024',
        '6737 Bright Quay, Lazy Mountain, KY, 42390-4772, US, (606) 256-7288',
        '237 Merry Campus, Twentysix, SC, 29330-4909, US, (864) 945-0157',
        '446 Fallen Gate Rise, Petrolia, SC, 29959-9527, US, (864) 826-0553',
        '2347 Indian Boulevard, Frisbee, VA, 23797-6458, US, (703) 656-8445',
        '365 Emerald Grove Line, Level, NC, 28381-1514, US, (919) 976-7958',
        '1207 Iron Extension, Klickitat, SC, 29197-8571, US, (803) 535-7888',
        '6770 Cinder Glen, Caronport, OH, 45053-5002, US, (440) 369-4018',
        '7619 Tawny Carrefour, Senlac, NV, 89529-9876, US, (775) 901-6433'];
}

Create skillFilter.ts file
import RefData from './refData';

var SKILL_TEMPLATE =
    '<label style="border: 1px solid lightgrey; margin: 4px; padding: 4px; display: inline-block;">' +
    '  <span>' +
    '    <div style="text-align: center;">SKILL_NAME</div>' +
    '    <div>' +
    '      <input type="checkbox"/>' +
    '      <img src="assets/img/skills/SKILL.png" width="30px"/>' +
    '    </div>' +
    '  </span>' +
    '</label>';

var FILTER_TITLE =
    '<div style="text-align: center; background: lightgray; width: 100%; display: block; border-bottom: 1px solid grey;">' +
    '<b>TITLE_NAME</b>' +
    '</div>';

export default class SkillFilter {

    private filterChangedCallback: Function;
    private model: any;

    private init(params) {
        this.filterChangedCallback = params.filterChangedCallback;
        this.model = {
            android: false,
            css: false,
            html5: false,
            mac: false,
            windows: false
        };
    };

    private getGui() {
        var eGui = document.createElement('div');
        eGui.style.width = '380px';
        var eInstructions = document.createElement('div');
        eInstructions.innerHTML = FILTER_TITLE.replace('TITLE_NAME', 'Custom Skills Filter');
        eGui.appendChild(eInstructions);

        var that = this;

        RefData.IT_SKILLS.forEach(function (skill, index) {
            var skillName = RefData.IT_SKILLS_NAMES[index];
            var eSpan = document.createElement('span');
            var html = SKILL_TEMPLATE.replace("SKILL_NAME", skillName).replace("SKILL", skill);
            eSpan.innerHTML = html;

            var eCheckbox = <HTMLInputElement> eSpan.querySelector('input');
            eCheckbox.addEventListener('click', function () {
                that.model[skill] = eCheckbox.checked;
                that.filterChangedCallback();
            });

            eGui.appendChild(eSpan);
        });

        return eGui;
    };

    private doesFilterPass(params) {

        var rowSkills = params.data.skills;
        var model = this.model;
        var passed = true;

        RefData.IT_SKILLS.forEach(function (skill) {
            if (model[skill]) {
                if (!rowSkills[skill]) {
                    passed = false;
                }
            }
        });

        return passed;
    };

    private isFilterActive() {
        var model = this.model;
        var somethingSelected = model.android || model.css || model.html5 || model.mac || model.windows;
        return somethingSelected;
    };


}

Edit basicTables.html file and add new row with ag-grid
 <div class="row">
    <div class="col-lg-12">
      <ba-card title="Ag Table" baCardClass="with-scroll table-panel">
        <ag-table></ag-table>
      </ba-card>
    </div>    
</div>

Edit basicTables.component.ts file and add new directive
import {Component, ViewEncapsulation} from '@angular/core';

import {BasicTablesService} from './basicTables.service';
import {BaCard} from '../../../../theme/components';
import {HoverTable} from './components/hoverTable';
import {BorderedTable} from './components/borderedTable';
import {CondensedTable} from './components/condensedTable';
import {StripedTable} from './components/stripedTable';
import {ContextualTable} from './components/contextualTable';
import {ResponsiveTable} from './components/responsiveTable';
import {AgTable} from './components/agTable';

@Component({
  selector: 'basic-tables',
  encapsulation: ViewEncapsulation.None,
  directives: [AgTable, BaCard, HoverTable, BorderedTable, CondensedTable, StripedTable, ContextualTable, ResponsiveTable],
  styles: [require('./basicTables.scss')],
  template: require('./basicTables.html'),
  providers: [BasicTablesService]
})
export class BasicTables {

  constructor() {
  }
}

Run npm start open Basic tables menu. Result should look like this


Sources of this example are available on github https://github.com/andrzejszywala/ng2-admin

Sunday, July 3, 2016

Angular 2, Wildfly, Eclipse and VS Code

This blog will show how to create application using Angular 2 and JEE. I decided to use eclipse and vs code because TypeScript support is much better in vs code.

Let's start with the eclipse configuration.

Download eclipse neon.
In workspace preferences check "Refresh using native hooks or pooling"

Open Eclipse Marketplace and find jbosstools

We need only JBoss AS, Wildfly & EAP Server Tools

Create New Maven Project

Add new remote archetype catalog

Select javaee-bce-archetype

Specify Archetype parameters

This archetype will create simple JEE application with sample entity and REST endpoint.

In pom.xml add maven-war-plugin and set path to directory where npm will copy javascript files


In META-INF create file load-script.sql

Add some sample data
Add load script to persistence.xml

Add new WildFly server to eclipse and run the application







Now it's time to configure client part of the application.

Install VS Code and node.js. Go to project folder and run 
Generate angular 2 appliaction
Go to client folder and open vs code

Create file .ember-cli










In .embel-cli set path where npm will copy transpiled JavaScript files.


run npm install command to build application
e:\ws\ng2\ng2-pom\client>npm install

> client@0.0.0 postinstall e:\ws\ng2\ng2-pom\client
> typings install


├── es6-shim (ambient)
├── angular-protractor (ambient dev)
├── jasmine (ambient dev)
└── selenium-webdriver (ambient dev)

balanced-match@0.4.1 node_modules\angular-cli\node_modules\ember-cli\node_modules\tree-sync\node_modules\walk-sync\node_modules\matcher-collection\node_modules\minimatch\node_modules\brace-expansion\node_modules\balanced-match -> node_modules\balanced-match
concat-map@0.0.1 node_modules\angular-cli\node_modules\ember-cli\node_modules\tree-sync\node_modules\walk-sync\node_modules\matcher-collection\node_modules\minimatch\node_modules\brace-expansion\node_modules\concat-map -> node_modules\concat-map
brace-expansion@1.1.5 node_modules\angular-cli\node_modules\ember-cli\node_modules\tree-sync\node_modules\walk-sync\node_modules\matcher-collection\node_modules\minimatch\node_modules\brace-expansion -> node_modules\brace-expansion
minimatch@3.0.2 node_modules\angular-cli\node_modules\ember-cli\node_modules\tree-sync\node_modules\walk-sync\node_modules\matcher-collection\node_modules\minimatch -> node_modules\minimatch
matcher-collection@1.0.2 node_modules\angular-cli\node_modules\ember-cli\node_modules\tree-sync\node_modules\walk-sync\node_modules\matcher-collection -> node_modules\matcher-collection
object-assign@4.1.0 node_modules\angular-cli\node_modules\ember-cli\node_modules\inquirer\node_modules\figures\node_modules\object-assign -> node_modules\object-assign
walk-sync@0.2.6 node_modules\angular-cli\node_modules\ember-cli\node_modules\tree-sync\node_modules\walk-sync -> node_modules\walk-sync
client@0.0.0 e:\ws\ng2\ng2-pom\client
+-- angular-cli@1.0.0-beta.8
| +-- ember-cli@2.5.0
| | +-- exists-sync@0.0.3
| | `-- through@2.3.8
| +-- typescript@1.8.10
| `-- typings@0.8.1
|   +-- any-promise@1.3.0
|   +-- archy@1.0.0
|   +-- bluebird@3.4.1
|   +-- columnify@1.5.4
|   | +-- strip-ansi@3.0.1
|   | | `-- ansi-regex@2.0.0
|   | `-- wcwidth@1.0.1
|   |   `-- defaults@1.0.3
|   |     `-- clone@1.0.2
|   +-- listify@1.0.0
|   +-- minimist@1.2.0
|   +-- typings-core@0.3.1
|   | +-- array-uniq@1.0.3
|   | +-- configstore@2.0.0
|   | | +-- dot-prop@2.4.0
|   | | | `-- is-obj@1.0.1
|   | | +-- os-tmpdir@1.0.1
|   | | +-- osenv@0.1.3
|   | | | `-- os-homedir@1.0.1
|   | | +-- uuid@2.0.2
|   | | +-- write-file-atomic@1.1.4
|   | | | +-- imurmurhash@0.1.4
|   | | | `-- slide@1.1.6
|   | | `-- xdg-basedir@2.0.0
|   | |   `-- os-homedir@1.0.1
|   | +-- debug@2.2.0
|   | | `-- ms@0.7.1
|   | +-- detect-indent@4.0.0
|   | | `-- repeating@2.0.1
|   | |   `-- is-finite@1.0.1
|   | |     `-- number-is-nan@1.0.0
|   | +-- graceful-fs@4.1.4
|   | +-- has@1.0.1
|   | | `-- function-bind@1.1.0
|   | +-- invariant@2.2.1
|   | | `-- loose-envify@1.2.0
|   | |   `-- js-tokens@1.0.3
|   | +-- is-absolute@0.2.5
|   | | +-- is-relative@0.2.1
|   | | | `-- is-unc-path@0.1.1
|   | | |   `-- unc-path-regex@0.1.2
|   | | `-- is-windows@0.1.1
|   | +-- lockfile@1.0.1
|   | +-- make-error-cause@1.1.1
|   | | `-- make-error@1.1.1
|   | +-- mkdirp@0.5.1
|   | | `-- minimist@0.0.8
|   | +-- object.pick@1.1.2
|   | | `-- isobject@2.1.0
|   | |   `-- isarray@1.0.0
|   | +-- parse-json@2.2.0
|   | | `-- error-ex@1.3.0
|   | |   `-- is-arrayish@0.2.1
|   | +-- popsicle@5.0.1
|   | | +-- arrify@1.0.1
|   | | +-- concat-stream@1.5.1
|   | | | +-- inherits@2.0.1
|   | | | +-- readable-stream@2.0.6
|   | | | | +-- core-util-is@1.0.2
|   | | | | +-- isarray@1.0.0
|   | | | | +-- process-nextick-args@1.0.7
|   | | | | +-- string_decoder@0.10.31
|   | | | | `-- util-deprecate@1.0.2
|   | | | `-- typedarray@0.0.6
|   | | +-- form-data@0.2.0
|   | | | +-- async@0.9.2
|   | | | +-- combined-stream@0.0.7
|   | | | | `-- delayed-stream@0.0.5
|   | | | `-- mime-types@2.0.14
|   | | |   `-- mime-db@1.12.0
|   | | +-- methods@1.1.2
|   | | `-- tough-cookie@2.2.2
|   | +-- popsicle-proxy-agent@1.0.0
|   | | +-- http-proxy-agent@1.0.0
|   | | | +-- agent-base@2.0.1
|   | | | | `-- semver@5.0.3
|   | | | `-- extend@3.0.0
|   | | `-- https-proxy-agent@1.0.0
|   | |   +-- agent-base@2.0.1
|   | |   | `-- semver@5.0.3
|   | |   `-- extend@3.0.0
|   | +-- popsicle-retry@2.0.0
|   | +-- popsicle-status@1.0.2
|   | +-- promise-finally@2.2.1
|   | +-- rc@1.1.6
|   | | +-- deep-extend@0.4.1
|   | | +-- ini@1.3.4
|   | | `-- strip-json-comments@1.0.4
|   | +-- rimraf@2.5.2
|   | +-- sort-keys@1.1.2
|   | | `-- is-plain-obj@1.1.0
|   | +-- string-template@1.0.0
|   | +-- strip-bom@2.0.0
|   | | `-- is-utf8@0.2.1
|   | +-- thenify@3.2.0
|   | +-- throat@2.0.2
|   | +-- touch@1.0.0
|   | | `-- nopt@1.0.10
|   | |   `-- abbrev@1.0.9
|   | `-- zip-object@0.1.0
|   +-- update-notifier@0.6.3
|   | +-- boxen@0.3.1
|   | | +-- filled-array@1.1.0
|   | | +-- repeating@2.0.1
|   | | | `-- is-finite@1.0.1
|   | | |   `-- number-is-nan@1.0.0
|   | | +-- string-width@1.0.1
|   | | | +-- code-point-at@1.0.0
|   | | | | `-- number-is-nan@1.0.0
|   | | | +-- is-fullwidth-code-point@1.0.0
|   | | | | `-- number-is-nan@1.0.0
|   | | | `-- strip-ansi@3.0.1
|   | | |   `-- ansi-regex@2.0.0
|   | | `-- widest-line@1.0.0
|   | +-- configstore@2.0.0
|   | | +-- dot-prop@2.4.0
|   | | | `-- is-obj@1.0.1
|   | | +-- graceful-fs@4.1.4
|   | | +-- mkdirp@0.5.1
|   | | | `-- minimist@0.0.8
|   | | +-- os-tmpdir@1.0.1
|   | | +-- osenv@0.1.3
|   | | | `-- os-homedir@1.0.1
|   | | +-- uuid@2.0.2
|   | | +-- write-file-atomic@1.1.4
|   | | | +-- imurmurhash@0.1.4
|   | | | `-- slide@1.1.6
|   | | `-- xdg-basedir@2.0.0
|   | |   `-- os-homedir@1.0.1
|   | +-- is-npm@1.0.0
|   | +-- latest-version@2.0.0
|   | | `-- package-json@2.3.2
|   | |   +-- got@5.6.0
|   | |   | +-- create-error-class@3.0.2
|   | |   | | `-- capture-stack-trace@1.0.0
|   | |   | +-- duplexer2@0.1.4
|   | |   | +-- is-plain-obj@1.1.0
|   | |   | +-- is-redirect@1.0.0
|   | |   | +-- is-retry-allowed@1.0.0
|   | |   | +-- is-stream@1.1.0
|   | |   | +-- lowercase-keys@1.0.0
|   | |   | +-- node-status-codes@1.0.0
|   | |   | +-- parse-json@2.2.0
|   | |   | | `-- error-ex@1.3.0
|   | |   | |   `-- is-arrayish@0.2.1
|   | |   | +-- pinkie-promise@2.0.1
|   | |   | | `-- pinkie@2.0.4
|   | |   | +-- read-all-stream@3.1.0
|   | |   | +-- readable-stream@2.1.4
|   | |   | | +-- buffer-shims@1.0.0
|   | |   | | +-- core-util-is@1.0.2
|   | |   | | +-- inherits@2.0.1
|   | |   | | +-- isarray@1.0.0
|   | |   | | +-- process-nextick-args@1.0.7
|   | |   | | +-- string_decoder@0.10.31
|   | |   | | `-- util-deprecate@1.0.2
|   | |   | +-- timed-out@2.0.0
|   | |   | +-- unzip-response@1.0.0
|   | |   | `-- url-parse-lax@1.0.0
|   | |   |   `-- prepend-http@1.0.4
|   | |   +-- rc@1.1.6
|   | |   | +-- deep-extend@0.4.1
|   | |   | +-- ini@1.3.4
|   | |   | `-- strip-json-comments@1.0.4
|   | |   +-- registry-url@3.1.0
|   | |   `-- semver@5.1.0
|   | `-- semver-diff@2.1.0
|   |   `-- semver@5.1.0
|   +-- wordwrap@1.0.0
|   `-- xtend@4.0.1
`-- protractor@3.3.0
  `-- request@2.67.0
    `-- http-signature@1.1.1
      `-- sshpk@1.8.3
        +-- ecc-jsbn@0.1.1
        +-- jodid25519@1.0.2
        +-- jsbn@0.1.0
        `-- tweetnacl@0.13.3

npm WARN optional Skipping failed optional dependency /karma/chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: fsevents@1.0.12

Run ng serve command

e:\ws\ng2\ng2-pom\client>ng serve
(node:9580) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version.
Livereload server on http://localhost:49152
Serving on http://localhost:4200/


Application is available at url http://localhost:4200/ but not at http://localhost:8080/workshops/index.html so let's fix this. Open index.html file in vs code change base tag and remove ember-cli-live-reload.js

Edit app.component.html file

{{title}}:
<table border="1">
  <tr>
    <th>Id</th>
    <th>Price</th>
  </tr>
  <tr *ngFor="let item of items">
    <td>{{item['confirmation-id']}}</td>
    <td>{{item.price}}</td>
  </tr>
</table>

Edit app.component.ts file
import { Component, OnInit } from '@angular/core';
import { HTTP_PROVIDERS, Response, Http } from '@angular/http';
import { Observable }     from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css'],
  providers: [HTTP_PROVIDERS]
})
export class AppComponent implements OnInit {
  title = 'Prices';
  items;

  constructor (private http: Http) {}

  ngOnInit() {
    this.getItems();
  }

  getItems() {
    this.http.get('resources/registrations/')
      .map(response => {
        return response.json();
      })
      .subscribe(items => this.items = items)
      ;
  }

  private extractData(res: Response) {
    let body = res.json();
    return body.data || { };
  }
  private handleError (error: any) {
    // In a real world app, we might use a remote logging infrastructure
    // We'd also dig deeper into the error to get a better message
    let errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';
    console.error(errMsg); // log to console instead
    return Observable.throw(errMsg);
  }
}

Final result should look like this



Let's configure maven to build angular appliaction
Create pom.xml in client folder
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>org.jdn</groupId>
 <artifactId>client</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>pom</packaging>

 <build>
  <plugins>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.1.1</version>
    <executions>
     <execution>
      <id>some-execution</id>
      <phase>compile</phase>
      <goals>
       <goal>exec</goal>
      </goals>
     </execution>
    </executions>
    <configuration>
     <executable>ng</executable>
     <arguments>
      <argument>build</argument>
      <argument>-prod</argument>
     </arguments>
    </configuration>
   </plugin>
  </plugins>
 </build>
</project>

Add new module to main pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.jdn</groupId>
    <artifactId>ng2-pom</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
     <module>client</module>
        <module>workshops</module>
        <module>workshops-st</module>
    </modules>
</project>

Run maven to build project

e:\ws\ng2\ng2-pom>e:\programowanie\maven\bin\mvn install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] client
[INFO] ng2
[INFO] ng2-st
[INFO] ng2-pom
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building client 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-install-plugin/2.4/maven-install-plugin-2.4.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-install-plugin/2.4/maven-install-plugin-2.4.pom (7 KB at 8.5 KB/sec)
[INFO]
[INFO] --- exec-maven-plugin:1.1.1:exec (some-execution) @ client ---
[INFO] '"ng build -prod"' is not recognized as an internal or external command,
[INFO] operable program or batch file.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] client ............................................. FAILURE [  1.696 s]
[INFO] ng2 ................................................ SKIPPED
[INFO] ng2-st ............................................. SKIPPED
[INFO] ng2-pom ............................................ SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.918 s
[INFO] Finished at: 2016-07-03T17:42:10+02:00
[INFO] Final Memory: 7M/104M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.1.1:exec (some-execution) on project client: Result of cmd.exe /X /C ""ng build -prod"" execution is: '1'. -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

e:\ws\ng2\ng2-pom>e:\programowanie\maven\bin\mvn install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] client
[INFO] ng2
[INFO] ng2-st
[INFO] ng2-pom
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building client 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.1.1:exec (some-execution) @ client ---
[INFO] (node:4748) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version.
[INFO]
[INFO] Running without elevated rights. Running Ember CLI "as Administrator" increases performance significantly.
[INFO] See ember-cli.com/user-guide/#windows for details.
[INFO]
[INFO] Built project successfully. Stored in "../workshops/src/main/angular".
[INFO] File sizes:
[INFO]  - app.component.css: 0 B
[INFO]  - main.js: 844.99 KB (179.68 KB gzipped)
[INFO]  - system-config.js: 1.66 KB (538 B gzipped)
[INFO]  - es6-shim.js: 131.74 KB (30.4 KB gzipped)
[INFO]  - Reflect.js: 36.91 KB (5.29 KB gzipped)
[INFO]  - system.src.js: 159.57 KB (38.99 KB gzipped)
[INFO]  - zone.js: 52.72 KB (11.37 KB gzipped)
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ client ---
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.pom
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.pom (3 KB at 3.7 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-digest/1.0/plexus-digest-1.0.pom
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-digest/1.0/plexus-digest-1.0.pom (2 KB at 15.0 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-components/1.1.7/plexus-components-1.1.7.pom
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-components/1.1.7/plexus-components-1.1.7.pom (5 KB at 68.4 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom (8 KB at 98.1 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-container-default/1.0-alpha-8/plexus-container-default-1.0-alpha-8.pom
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-container-default/1.0-alpha-8/plexus-container-default-1.0-alpha-8.pom (8 KB at 81.5 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.jar
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-digest/1.0/plexus-digest-1.0.jar
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-digest/1.0/plexus-digest-1.0.jar (12 KB at 84.5 KB/sec)
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.jar (226 KB at 1000.2 KB/sec)
[INFO] Installing E:\ws\ng2\ng2-pom\client\pom.xml to C:\Users\Andrzej\.m2\repository\org\jdn\client\0.0.1-SNAPSHOT\client-0.0.1-SNAPSHOT.pom
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building ng2 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ ng2 ---
[WARNING] Using platform encoding (Cp1250 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ ng2 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. build is platform dependent!
[INFO] Compiling 6 source files to E:\ws\ng2\ng2-pom\workshops\target\classes
[WARNING] /E:/ws/ng2/ng2-pom/workshops/src/main/java/com/airhacks/workshops/business/registrations/boundary/Registrations.java: E:\ws\ng2\ng2-pom\workshops\src\main\java\com\airhacks\workshops\busines
s\registrations\boundary\Registrations.java uses unchecked or unsafe operations.
[WARNING] /E:/ws/ng2/ng2-pom/workshops/src/main/java/com/airhacks/workshops/business/registrations/boundary/Registrations.java: Recompile with -Xlint:unchecked for details.
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ ng2 ---
[WARNING] Using platform encoding (Cp1250 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ ng2 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1250, i.e. build is platform dependent!
[INFO] Compiling 6 source files to E:\ws\ng2\ng2-pom\workshops\target\test-classes
[WARNING] /E:/ws/ng2/ng2-pom/workshops/src/test/java/com/airhacks/workshops/business/registrations/entity/RegistrationTest.java: Some input files use unchecked or unsafe operations.
[WARNING] /E:/ws/ng2/ng2-pom/workshops/src/test/java/com/airhacks/workshops/business/registrations/entity/RegistrationTest.java: Recompile with -Xlint:unchecked for details.
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ ng2 ---
[INFO] Surefire report directory: E:\ws\ng2\ng2-pom\workshops\target\surefire-reports
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit4/2.12.4/surefire-junit4-2.12.4.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit4/2.12.4/surefire-junit4-2.12.4.pom (3 KB at 28.7 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-providers/2.12.4/surefire-providers-2.12.4.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-providers/2.12.4/surefire-providers-2.12.4.pom (3 KB at 31.4 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit4/2.12.4/surefire-junit4-2.12.4.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit4/2.12.4/surefire-junit4-2.12.4.jar (37 KB at 424.2 KB/sec)

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.airhacks.workshops.business.registrations.boundary.RegistrationsTest
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.577 sec
Running com.airhacks.workshops.business.registrations.control.VatCalculatorTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 sec
Running com.airhacks.workshops.business.registrations.entity.RegistrationTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.004 sec

Results :

Tests run: 7, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- maven-war-plugin:2.6:war (default-war) @ ng2 ---
[INFO] Packaging webapp
[INFO] Assembling webapp [ng2] in [E:\ws\ng2\ng2-pom\workshops\target\workshops]
[INFO] Processing war project
[INFO] Copying webapp webResources [E:\ws\ng2\ng2-pom\workshops\src/main/angular] to [E:\ws\ng2\ng2-pom\workshops\target\workshops]
[INFO] Copying webapp resources [E:\ws\ng2\ng2-pom\workshops\src\main\webapp]
[INFO] Webapp assembled in [147 msecs]
[INFO] Building war: E:\ws\ng2\ng2-pom\workshops\target\workshops.war
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ ng2 ---
[INFO] Installing E:\ws\ng2\ng2-pom\workshops\target\workshops.war to C:\Users\Andrzej\.m2\repository\org\jdn\ng2\0.0.1-SNAPSHOT\ng2-0.0.1-SNAPSHOT.war
[INFO] Installing E:\ws\ng2\ng2-pom\workshops\pom.xml to C:\Users\Andrzej\.m2\repository\org\jdn\ng2\0.0.1-SNAPSHOT\ng2-0.0.1-SNAPSHOT.pom
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building ng2-st 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ ng2-st ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\ws\ng2\ng2-pom\workshops-st\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ ng2-st ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ ng2-st ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\ws\ng2\ng2-pom\workshops-st\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ ng2-st ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to E:\ws\ng2\ng2-pom\workshops-st\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ ng2-st ---
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ ng2-st ---
[INFO] Building jar: E:\ws\ng2\ng2-pom\workshops-st\target\ng2-st-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ ng2-st ---
[INFO] Installing E:\ws\ng2\ng2-pom\workshops-st\target\ng2-st-0.0.1-SNAPSHOT.jar to C:\Users\Andrzej\.m2\repository\org\jdn\ng2-st\0.0.1-SNAPSHOT\ng2-st-0.0.1-SNAPSHOT.jar
[INFO] Installing E:\ws\ng2\ng2-pom\workshops-st\pom.xml to C:\Users\Andrzej\.m2\repository\org\jdn\ng2-st\0.0.1-SNAPSHOT\ng2-st-0.0.1-SNAPSHOT.pom
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building ng2-pom 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ ng2-pom ---
[INFO] Installing e:\ws\ng2\ng2-pom\pom.xml to C:\Users\Andrzej\.m2\repository\org\jdn\ng2-pom\0.0.1-SNAPSHOT\ng2-pom-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] client ............................................. SUCCESS [ 27.767 s]
[INFO] ng2 ................................................ SUCCESS [  6.487 s]
[INFO] ng2-st ............................................. SUCCESS [  0.911 s]
[INFO] ng2-pom ............................................ SUCCESS [  0.050 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 35.345 s
[INFO] Finished at: 2016-07-03T17:44:25+02:00
[INFO] Final Memory: 29M/163M
[INFO] ------------------------------------------------------------------------