Skip to content

Commit

Permalink
Merge pull request #78 from MarkLark86/SDESK-3535
Browse files Browse the repository at this point in the history
[SDESK-3535] Update Time Report
  • Loading branch information
Mayur Dhamanwala authored Jan 20, 2019
2 parents c8fcf80 + cbe42fd commit 32f8b96
Show file tree
Hide file tree
Showing 35 changed files with 1,596 additions and 260 deletions.
61 changes: 61 additions & 0 deletions client/charts/directives/Table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Table.$inject = ['lodash'];

/**
* @ngdoc directive
* @module superdesk.apps.analytics.charts
* @name sdaTable
* @requires lodash
* @description A directive that renders a sortable and clickable html table
*/
export function Table(_) {
return {
scope: {
title: '=',
subtitle: '=',
headers: '=',
rows: '=',
page: '=',
onCellClicked: '=',
},
replace: true,
template: require('../views/table.html'),
link: function(scope) {
/**
* @ngdoc method
* @name sdaTable#onHeaderClicked
* @param {Object} header - The header column that was clicked
* @description Determines the sort filter based on the header data
*/
scope.onHeaderClicked = (header) => {
// If the header entry does not have a field attribute
// then sorting by this column is disabled
if (!header.field) {
return;
}

let newOrder;

if (_.get(scope, 'page.sort.field') === header.field) {
// If the header.field is already sorted, then toggle the sort order
if (_.get(scope, 'page.sort.order') === 'asc') {
newOrder = 'desc';
} else {
newOrder = 'asc';
}
} else {
// Otherwise set order to descending by default on first click
newOrder = 'desc';
}

scope.page = {
...scope.page,
no: 1,
sort: {
field: header.field,
order: newOrder,
},
};
};
},
};
}
1 change: 1 addition & 0 deletions client/charts/directives/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export {Chart} from './Chart';
export {ChartContainer} from './ChartContainer';
export {Table} from './Table';
1 change: 1 addition & 0 deletions client/charts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ angular.module('superdesk.analytics.charts', [])

.directive('sdChart', directives.Chart)
.directive('sdChartContainer', directives.ChartContainer)
.directive('sdaTable', directives.Table)

.run(cacheIncludedTemplates);
29 changes: 26 additions & 3 deletions client/charts/styles/charts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ $colors: #7cb5ec #434348 #90ed7d #f7a35c #8085e9 #f15c80 #e4d354 #2b908f #f45b5b

&--margin-bottom {
margin-bottom: 3rem;
.sd-chart__table {
margin-bottom: 3rem;
}
}

&--multi-chart {
Expand All @@ -39,10 +42,10 @@ $colors: #7cb5ec #434348 #90ed7d #f7a35c #8085e9 #f15c80 #e4d354 #2b908f #f45b5b

.clickable {
cursor: pointer;
}

&:hover {
border: 1px solid #9bb3ff;
}
td.clickable:hover {
border: 1px solid #9bb3ff;
}

.sd-chart__table-header {
Expand All @@ -53,6 +56,21 @@ $colors: #7cb5ec #434348 #90ed7d #f7a35c #8085e9 #f15c80 #e4d354 #2b908f #f45b5b
position: sticky;
top: 0;
background-color: $white;

&--no-padding-bottom {
padding-bottom: 0;
}

.pagination-box {
display: block;
position: absolute;
right: 0;
bottom: 0;
}

.sd-pagination {
padding: 0;
}
}

.sd-chart__table-header-options {
Expand Down Expand Up @@ -106,6 +124,11 @@ $colors: #7cb5ec #434348 #90ed7d #f7a35c #8085e9 #f15c80 #e4d354 #2b908f #f45b5b
padding-top: 0;
padding-bottom: 0;
}

.panel-info {
border-top: 1px solid rgba(0, 0, 0, 0.15);
padding-bottom: 10rem;
}
}
}

Expand Down
213 changes: 213 additions & 0 deletions client/charts/tests/sda-table.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
describe('sda-table', () => {
let $compile;
let scope;
let $rootScope;
let data;
let element;

beforeEach(window.module('superdesk.core.notify'));
beforeEach(window.module('superdesk.analytics.charts'));

beforeEach(inject((_$compile_, _$rootScope_) => {
$compile = _$compile_;
$rootScope = _$rootScope_;

element = null;

data = {
title: 'Test Table',
subtitle: 'Fake Data',
headers: [
{title: 'one', field: 'one'},
{title: 'two'},
{title: 'three', field: 'three'},
],
rows: [
[{label: 1}, {label: 2}, {label: 3, clickable: true, tooltip: 'View data', custom: {data: [3]}}],
[{label: 4}, {label: 5}, {label: 6, clickable: true, tooltip: 'View data'}],
[{label: 7}, {label: 8}, {label: 9, clickable: true, tooltip: 'View data'}],
],
page: {
no: 1,
max: 5,
sort: {
field: 'one',
order: 'desc',
},
},
onCellClicked: jasmine.createSpy(),
};
}));

const setElement = () => {
scope = $rootScope.$new();
Object.keys(data).forEach((key) => {
scope[key] = data[key];
});

const template = angular.element(`<div><div
sda-table
data-title="title"
data-subtitle="subtitle"
data-headers="headers"
data-rows="rows"
data-page="page"
data-on-cell-clicked="onCellClicked"
</div>`);

element = $compile(template)(scope);

$rootScope.$digest();
};

const getHeader = (index) => $(
element.find('thead')
.first()
.find('tr')
.first()
.find('th')
.get(index)
);

const getBodyRow = (index) => $(
element.find('tbody')
.first()
.find('tr')
.get(index)
);

const getCell = (row, column) => $(
getBodyRow(row)
.find('td')
.get(column)
);

const stripWhitespace = (elem) => (
elem.text().replace(/\s+/g, '')
);

const trim = (elem) => (
elem.text().trim()
);

it('renders the table', () => {
setElement();

// Test titles
expect(trim(element.find('.sd-chart__table-header-title'))).toBe('Test Table');
expect(trim(element.find('.sd-chart__table-header-subtitle'))).toBe('Fake Data');

// Test header
expect(trim(getHeader(0))).toBe('one');
expect(trim(getHeader(1))).toBe('two');
expect(trim(getHeader(2))).toBe('three');

// Test size of the table
expect(element.find('table').length).toBe(1);
expect(element.find('tbody')
.first()
.find('tr')
.length
).toBe(3);

// Test data of each row
expect(getBodyRow(0).find('td').length).toBe(3);
expect(stripWhitespace(getBodyRow(0))).toBe('123');
expect(stripWhitespace(getBodyRow(1))).toBe('456');
expect(stripWhitespace(getBodyRow(2))).toBe('789');

// Renders the pagination directive if page.max > 1
scope.page = {...data.page, max: 1};
scope.$digest();
expect(element.find('.pagination-box').length).toBe(0);

scope.page = {...data.page, max: 5};
scope.$digest();
expect(element.find('.pagination-box').length).toBe(1);

// Renders panel-info when no rows are to be rendered
expect(element.find('.panel-info').length).toBe(0);
scope.rows = [];
scope.$digest();
expect(element.find('.panel-info').length).toBe(1);
});

it('executes callback on cell clicked', () => {
setElement();

// Test onCellClicked on cells with clickable=true
getCell(0, 0).click();
getCell(0, 1).click();
getCell(0, 2).click();
expect(data.onCellClicked.calls.count()).toBe(1);
expect(data.onCellClicked.calls.mostRecent().args).toEqual(
[{label: 3, clickable: true, tooltip: 'View data', custom: {data: [3]}}]
);

getCell(1, 2).click();
expect(data.onCellClicked.calls.count()).toBe(2);
expect(data.onCellClicked.calls.mostRecent().args).toEqual(
[{label: 6, clickable: true, tooltip: 'View data'}]
);

getCell(2, 2).click();
expect(data.onCellClicked.calls.count()).toBe(3);
expect(data.onCellClicked.calls.mostRecent().args).toEqual(
[{label: 9, clickable: true, tooltip: 'View data'}]
);
});

it('sorts on header click', () => {
setElement();

// Test initial values
expect(scope.page.sort).toEqual({field: 'one', order: 'desc'});
expect(getHeader(0).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(0).find('.icon-chevron-down-thin').length).toBe(1);
expect(getHeader(1).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-down-thin').length).toBe(0);

// Clicking on already selected header toggles the order
getHeader(0).click();
expect(scope.page.sort).toEqual({field: 'one', order: 'asc'});
expect(getHeader(0).find('.icon-chevron-up-thin').length).toBe(1);
expect(getHeader(0).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-down-thin').length).toBe(0);

// Test clicking on non-sortable header field
// page value stays the same
getHeader(1).click();
expect(scope.page.sort).toEqual({field: 'one', order: 'asc'});
expect(getHeader(0).find('.icon-chevron-up-thin').length).toBe(1);
expect(getHeader(0).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-down-thin').length).toBe(0);

// Clicking on a non-selected header defaults to descending order
getHeader(2).click();
expect(scope.page.sort).toEqual({field: 'three', order: 'desc'});
expect(getHeader(0).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(0).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-down-thin').length).toBe(1);

// Again clicking on already selected header toggles the order
getHeader(2).click();
expect(scope.page.sort).toEqual({field: 'three', order: 'asc'});
expect(getHeader(0).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(0).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-up-thin').length).toBe(0);
expect(getHeader(1).find('.icon-chevron-down-thin').length).toBe(0);
expect(getHeader(2).find('.icon-chevron-up-thin').length).toBe(1);
expect(getHeader(2).find('.icon-chevron-down-thin').length).toBe(0);
});
});
13 changes: 12 additions & 1 deletion client/charts/views/chart-form-options.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</div>
</div>

<div class="form__row">
<div class="form__row" ng-if="currentParams.params.chart.sort_order">
<div class="sd-line-input sd-line-input--is-select">
<label class="sd-line-input__label" translate>Order Categories In:</label>
<select class="sd-line-input__select"
Expand All @@ -51,3 +51,14 @@
</select>
</div>
</div>

<div class="form__row" ng-if="currentParams.params.chart.type === 'table'">
<div class="sd-line-input">
<label class="sd-line-input__label" translate>Page Size</label>
<input type="number"
min="1"
class="sd-line-input__input"
ng-model="currentParams.params.size"
/>
</div>
</div>
Loading

0 comments on commit 32f8b96

Please sign in to comment.