diff --git a/static/css/core-ui.css b/static/css/core-ui.css
index d894b95b4..d28c74129 100644
--- a/static/css/core-ui.css
+++ b/static/css/core-ui.css
@@ -973,13 +973,18 @@ a:focus {
table-layout: fixed;
}
-.co-fixed-table .co-flowing-col{
+.co-fixed-table .co-flowing-col {
overflow: hidden;
text-overflow: ellipsis;
padding-left: 16px;
vertical-align: middle;
}
+.co-fixed-table .nowrap-col {
+ white-space: nowrap;
+ overflow: hidden;
+}
+
.co-table td {
border-bottom: 1px solid #eee;
padding: 10px;
diff --git a/static/js/directives/ui/app-public-view/app-public-view.component.html b/static/js/directives/ui/app-public-view/app-public-view.component.html
index e47f7ae74..1430247a1 100644
--- a/static/js/directives/ui/app-public-view/app-public-view.component.html
+++ b/static/js/directives/ui/app-public-view/app-public-view.component.html
@@ -75,13 +75,16 @@
-
+
-
diff --git a/static/js/directives/ui/app-public-view/channels-list.html b/static/js/directives/ui/app-public-view/channels-list.html
index 2c5bd38dc..8fa843a2f 100644
--- a/static/js/directives/ui/app-public-view/channels-list.html
+++ b/static/js/directives/ui/app-public-view/channels-list.html
@@ -1,4 +1,18 @@
-
-
-
-(None)
\ No newline at end of file
+
diff --git a/static/js/directives/ui/cor-table/cor-table-col.component.ts b/static/js/directives/ui/cor-table/cor-table-col.component.ts
index 9a53141bd..ec4523257 100644
--- a/static/js/directives/ui/cor-table/cor-table-col.component.ts
+++ b/static/js/directives/ui/cor-table/cor-table-col.component.ts
@@ -10,6 +10,7 @@ import { CorTableComponent } from './cor-table.component';
template: '',
})
export class CorTableColumn implements OnInit {
+
@Input('@') public title: string;
@Input('@') public templateurl: string;
@Input('@') public datafield: string;
@@ -19,6 +20,7 @@ export class CorTableColumn implements OnInit {
@Input('@') public style: string;
@Input('@') public class: string;
@Input('@') public kindof: string;
+ @Input('<') public itemLimit: number = 5;
constructor(@Host() @Inject(CorTableComponent) private parent: CorTableComponent,
@Inject('TableService') private tableService: any) {
diff --git a/static/js/directives/ui/cor-table/cor-table.component.css b/static/js/directives/ui/cor-table/cor-table.component.css
new file mode 100644
index 000000000..cd128e1fd
--- /dev/null
+++ b/static/js/directives/ui/cor-table/cor-table.component.css
@@ -0,0 +1,5 @@
+.cor-table-element .co-top-bar {
+ display: flex;
+ justify-content: flex-end;
+ align-items: baseline;
+}
diff --git a/static/js/directives/ui/cor-table/cor-table.component.html b/static/js/directives/ui/cor-table/cor-table.component.html
index f6d18048c..6e17d0574 100644
--- a/static/js/directives/ui/cor-table/cor-table.component.html
+++ b/static/js/directives/ui/cor-table/cor-table.component.html
@@ -1,8 +1,8 @@
-
+
-
+
+
+
+
@@ -24,20 +38,20 @@
-
+
{{ ::col.title }}
|
-
-
+ style="{{ ::col.style }}" class="{{ ::col.class }}">
+
{{ item[col.datafield] }}
|
@@ -49,4 +63,4 @@
No matching {{ ::$ctrl.tableItemTitle }} found.
Try adjusting your filter above.
-
\ No newline at end of file
+
diff --git a/static/js/directives/ui/cor-table/cor-table.component.spec.ts b/static/js/directives/ui/cor-table/cor-table.component.spec.ts
new file mode 100644
index 000000000..eb7a1c597
--- /dev/null
+++ b/static/js/directives/ui/cor-table/cor-table.component.spec.ts
@@ -0,0 +1,126 @@
+import { Mock } from 'ts-mocks';
+import { CorTableComponent, CorTableOptions } from './cor-table.component';
+import { CorTableColumn } from './cor-table-col.component';
+import { SimpleChanges } from 'ng-metadata/core';
+import { ViewArray } from '../../../services/view-array/view-array';
+import Spy = jasmine.Spy;
+
+
+describe("CorTableComponent", () => {
+ var component: CorTableComponent;
+ var tableServiceMock: Mock;
+ var tableData: any[];
+ var columnMocks: Mock[];
+ var orderedDataMock: Mock;
+
+ beforeEach(() => {
+ orderedDataMock = new Mock();
+ orderedDataMock.setup(mock => mock.visibleEntries).is([]);
+ tableServiceMock = new Mock();
+ tableServiceMock.setup(mock => mock.buildOrderedItems)
+ .is((items, options, filterFields, numericFields, extrafilter?) => orderedDataMock.Object);
+
+ tableData = [
+ {name: "apple", last_modified: 1496068383000, version: "1.0.0"},
+ {name: "pear", last_modified: 1496068383001, version: "1.1.0"},
+ {name: "orange", last_modified: 1496068383002, version: "1.0.0"},
+ {name: "banana", last_modified: 1496068383000, version: "2.0.0"},
+ ];
+
+ columnMocks = Object.keys(tableData[0])
+ .map((key, index) => {
+ const col = new Mock();
+ col.setup(mock => mock.isNumeric).is(() => index == 1 ? true : false);
+ col.setup(mock => mock.processColumnForOrdered).is((value) => "dummy");
+ col.setup(mock => mock.datafield).is(key);
+
+ return col;
+ });
+
+ component = new CorTableComponent(tableServiceMock.Object);
+ component.tableData = tableData;
+ component.filterFields = ['name', 'version'];
+ component.compact = false;
+ component.tableItemTitle = "fruits";
+ component.maxDisplayCount = 10;
+ // Add columns
+ columnMocks.forEach(colMock => component.addColumn(colMock.Object));
+ (tableServiceMock.Object.buildOrderedItems).calls.reset();
+ });
+
+ describe("constructor", () => {
+
+ it("sets table options", () => {
+ expect(component.options.filter).toEqual('');
+ expect(component.options.reverse).toBe(false);
+ expect(component.options.predicate).toEqual('');
+ expect(component.options.page).toEqual(0);
+ });
+ });
+
+ describe("ngOnChanges", () => {
+ var changes: SimpleChanges;
+
+ it("calls table service to build ordered items if table data is changed", () => {
+ changes = {tableData: {currentValue: [], previousValue: [], isFirstChange: () => false}};
+ component.ngOnChanges(changes);
+
+ expect((tableServiceMock.Object.buildOrderedItems)).toHaveBeenCalled();
+ });
+
+ it("passes processed table data to table service", () => {
+ changes = {tableData: {currentValue: [], previousValue: [], isFirstChange: () => false}};
+ component.tableData = changes['tableData'].currentValue;
+ component.ngOnChanges(changes);
+
+ expect((tableServiceMock.Object.buildOrderedItems).calls.argsFor(0)[0]).not.toEqual(tableData);
+ });
+
+ it("passes options to table service", () => {
+ changes = {tableData: {currentValue: [], previousValue: [], isFirstChange: () => false}};
+ component.ngOnChanges(changes);
+
+ expect((tableServiceMock.Object.buildOrderedItems).calls.argsFor(0)[1]).toEqual(component.options);
+ });
+
+ it("passes filter fields to table service", () => {
+ changes = {tableData: {currentValue: [], previousValue: [], isFirstChange: () => false}};
+ component.ngOnChanges(changes);
+
+ expect((tableServiceMock.Object.buildOrderedItems).calls.argsFor(0)[2]).toEqual(component.filterFields);
+ });
+
+ it("passes numeric fields to table service", () => {
+ changes = {tableData: {currentValue: [], previousValue: [], isFirstChange: () => false}};
+ component.ngOnChanges(changes);
+
+ const expectedNumericCols: string[] = columnMocks.filter(colMock => colMock.Object.isNumeric())
+ .map(colMock => colMock.Object.datafield);
+
+ expect((tableServiceMock.Object.buildOrderedItems).calls.argsFor(0)[3]).toEqual(expectedNumericCols);
+ });
+
+ it("resets to first page if table data is changed", () => {
+ component.options.page = 1;
+ changes = {tableData: {currentValue: [], previousValue: [], isFirstChange: () => false}};
+ component.ngOnChanges(changes);
+
+ expect(component.options.page).toEqual(0);
+ });
+ });
+
+ describe("addColumn", () => {
+ var columnMock: Mock;
+
+ beforeEach(() => {
+ columnMock = new Mock();
+ columnMock.setup(mock => mock.isNumeric).is(() => false);
+ });
+
+ it("calls table service to build ordered items with new column", () => {
+ component.addColumn(columnMock.Object);
+
+ expect((tableServiceMock.Object.buildOrderedItems)).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/static/js/directives/ui/cor-table/cor-table.component.ts b/static/js/directives/ui/cor-table/cor-table.component.ts
index 30c08baf8..d858d11b2 100644
--- a/static/js/directives/ui/cor-table/cor-table.component.ts
+++ b/static/js/directives/ui/cor-table/cor-table.component.ts
@@ -1,5 +1,7 @@
import { Input, Component, OnChanges, SimpleChanges, Inject } from 'ng-metadata/core';
import { CorTableColumn } from './cor-table-col.component';
+import { ViewArray } from '../../../services/view-array/view-array';
+import './cor-table.component.css';
/**
@@ -13,23 +15,28 @@ import { CorTableColumn } from './cor-table-col.component';
}
})
export class CorTableComponent implements OnChanges {
+
@Input('<') public tableData: any[] = [];
@Input('@') public tableItemTitle: string;
@Input('<') public filterFields: string[];
- @Input('@') public compact: string;
+ @Input('<') public compact: boolean = false;
@Input('<') public maxDisplayCount: number = 10;
- private columns: CorTableColumn[];
- private orderedData: any;
- private options: any;
+ @Input('<') public canExpand: boolean = false;
+ @Input('<') public expandRows: boolean = false;
+
+ public orderedData: ViewArray;
+ public options: CorTableOptions = {
+ filter: '',
+ reverse: false,
+ predicate: '',
+ page: 0,
+ };
+
+ private rows: CorTableRow[] = [];
+ private columns: CorTableColumn[] = [];
constructor(@Inject('TableService') private tableService: any) {
- this.columns = [];
- this.options = {
- 'filter': '',
- 'reverse': false,
- 'predicate': '',
- 'page': 0,
- };
+
}
public ngOnChanges(changes: SimpleChanges): void {
@@ -53,6 +60,11 @@ export class CorTableComponent implements OnChanges {
this.refreshOrder();
}
+ private setExpanded(isExpanded: boolean): void {
+ this.expandRows = isExpanded;
+ this.rows.forEach((row) => row.expanded = isExpanded);
+ }
+
private tablePredicateClass(col: CorTableColumn, options: any) {
return this.tableService.tablePredicateClass(col.datafield, this.options.predicate, this.options.reverse);
}
@@ -60,15 +72,15 @@ export class CorTableComponent implements OnChanges {
private refreshOrder(): void {
this.options.page = 0;
- var columnMap = {};
+ var columnMap: {[name: string]: CorTableColumn} = {};
this.columns.forEach(function(col) {
columnMap[col.datafield] = col;
});
- const numericCols = this.columns.filter(col => col.isNumeric())
+ const numericCols: string[] = this.columns.filter(col => col.isNumeric())
.map(col => col.datafield);
- const processed = this.tableData.map((item) => {
+ const processed: any[] = this.tableData.map((item) => {
Object.keys(item).forEach((key) => {
if (columnMap[key]) {
item[key] = columnMap[key].processColumnForOrdered(item[key]);
@@ -79,5 +91,20 @@ export class CorTableComponent implements OnChanges {
});
this.orderedData = this.tableService.buildOrderedItems(processed, this.options, this.filterFields, numericCols);
+ this.rows = this.orderedData.visibleEntries.map((item) => Object.assign({}, {expanded: false, rowData: item}));
}
}
+
+
+export type CorTableOptions = {
+ filter: string;
+ reverse: boolean;
+ predicate: string;
+ page: number;
+};
+
+
+export type CorTableRow = {
+ expanded: boolean;
+ rowData: any;
+};
diff --git a/static/js/directives/ui/manage-trigger/manage-trigger.component.html b/static/js/directives/ui/manage-trigger/manage-trigger.component.html
index aa0979b6b..517dc15fd 100644
--- a/static/js/directives/ui/manage-trigger/manage-trigger.component.html
+++ b/static/js/directives/ui/manage-trigger/manage-trigger.component.html
@@ -17,7 +17,7 @@
max-display-count="$ctrl.namespacesPerPage"
filter-fields="::['title', 'id']">
@@ -100,7 +100,8 @@
max-display-count="$ctrl.repositoriesPerPage"
filter-fields="['name', 'description']">
+ templateurl="/static/js/directives/ui/manage-trigger-githost/repository-radio-input.html"
+ style="width: 30px;">
@@ -376,7 +380,7 @@
max-display-count="$ctrl.robotsPerPage">