Refactor implementation into correct builders

This bugged me for a while, so fixing it now before addressing more
issues in the hierarchy builder
pull/5432/head
Oliver Günther 8 years ago
parent 1c2c5eecf8
commit ac2ded3f04
No known key found for this signature in database
GPG Key ID: 88872239EB414F99
  1. 15
      frontend/app/components/angular/angular-injector-bridge.functions.ts
  2. 25
      frontend/app/components/wp-fast-table/builders/modes/grouped/grouped-rows-builder.ts
  3. 126
      frontend/app/components/wp-fast-table/builders/modes/hierarchy/hierarchy-rows-builder.ts
  4. 265
      frontend/app/components/wp-fast-table/builders/modes/hierarchy/single-hierarchy-row-builder.ts
  5. 10
      frontend/app/components/wp-fast-table/builders/modes/plain/plain-rows-builder.ts
  6. 17
      frontend/app/components/wp-fast-table/builders/modes/rows-builder.ts
  7. 9
      frontend/app/components/wp-fast-table/builders/rows/single-row-builder.ts
  8. 5
      frontend/app/components/wp-fast-table/handlers/row/group-row-handler.ts
  9. 2
      frontend/app/components/wp-fast-table/handlers/state/hierarchy-transformer.ts
  10. 8
      frontend/app/components/wp-fast-table/wp-fast-table.ts

@ -20,7 +20,18 @@
*/
export function injectorBridge(injectable:any) {
let $injector = $currentInjector();
$injector.annotate(injectable.constructor).forEach((dep:string) => {
injectable[dep] = $injector.get(dep);
$injectFields(injectable, ...$injector.annotate(injectable.constructor));
}
/**
* Inject specified field into the target.
* Use when `Constructor.$inject` isn't an option, e.g., due to class inerheritance.
*
* @param target The target to inject into
* @param dependencies A set of dependencies to inject
*/
export function $injectFields(target:any, ...dependencies:string[]) {
let $injector = $currentInjector();
dependencies.forEach((dep:string) => {
target[dep] = $injector.get(dep);
});
}

@ -1,18 +1,13 @@
import {HalResource} from '../../../api/api-v3/hal-resources/hal-resource.service';
import {RowsBuilder} from './rows-builder';
import {States} from '../../../states.service';
import {injectorBridge} from '../../../angular/angular-injector-bridge.functions';
import {groupedRowClassName} from '../../helpers/wp-table-row-helpers';
import {WorkPackageTableColumnsService} from '../../state/wp-table-columns.service';
import {WorkPackageTableGroupByService} from '../../state/wp-table-group-by.service';
import {WorkPackageTable} from '../../wp-fast-table';
import {WorkPackageResource} from '../../../api/api-v3/hal-resources/work-package-resource.service';
import {QueryResource} from '../../../api/api-v3/hal-resources/query-resource.service';
import {QueryGroupByResource} from '../../../api/api-v3/hal-resources/query-group-by-resource.service';
import {WorkPackageCollectionResource} from '../../../api/api-v3/hal-resources/wp-collection-resource.service';
import {WorkPackageTableRow} from '../../wp-table.interfaces';
import {GroupObject} from '../../../api/api-v3/hal-resources/wp-collection-resource.service';
import {RowsBuilder} from "../rows-builder";
import {States} from "../../../../states.service";
import {WorkPackageTableColumnsService} from "../../../state/wp-table-columns.service";
import {WorkPackageTable} from "../../../wp-fast-table";
import {injectorBridge} from "../../../../angular/angular-injector-bridge.functions";
import {GroupObject} from "../../../../api/api-v3/hal-resources/wp-collection-resource.service";
import {WorkPackageResource} from "../../../../api/api-v3/hal-resources/work-package-resource.service";
import {HalResource} from "../../../../api/api-v3/hal-resources/hal-resource.service";
import {groupedRowClassName} from "../../../helpers/wp-table-row-helpers";
import {WorkPackageTableRow} from "../../../wp-table.interfaces";
export const rowGroupClassName = 'wp-table--group-header';
export const collapsedRowClass = '-collapsed';

@ -0,0 +1,126 @@
import {PlainRowsBuilder} from "../plain/plain-rows-builder";
import {WorkPackageTableColumnsService} from "../../../state/wp-table-columns.service";
import {States} from "../../../../states.service";
import {WorkPackageTableHierarchiesService} from "../../../state/wp-table-hierarchy.service";
import {WorkPackageTable} from "../../../wp-fast-table";
import {injectorBridge} from "../../../../angular/angular-injector-bridge.functions";
import {WorkPackageResourceInterface} from "../../../../api/api-v3/hal-resources/work-package-resource.service";
import {WorkPackageTableRow} from "../../../wp-table.interfaces";
import {SingleHierarchyRowBuilder} from "./single-hierarchy-row-builder";
import {hierarchyGroupClass} from "../../../helpers/wp-table-hierarchy-helpers";
export class HierarchyRowsBuilder extends PlainRowsBuilder {
// Injections
public states:States;
public wpTableColumns:WorkPackageTableColumnsService;
public wpTableHierarchies:WorkPackageTableHierarchiesService;
public I18n:op.I18n;
// Row builders
protected rowBuilder:SingleHierarchyRowBuilder;
protected refreshBuilder:SingleHierarchyRowBuilder;
// The group expansion state
constructor(public workPackageTable: WorkPackageTable) {
super(workPackageTable);
injectorBridge(this);
}
/**
* The hierarchy builder is only applicable if the hierachy mode is active
*/
public isApplicable(_table:WorkPackageTable) {
return this.wpTableHierarchies.isEnabled;
}
/**
* Rebuild the entire grouped tbody from the given table
* @param table
*/
public internalBuildRows(table:WorkPackageTable):DocumentFragment {
// Remember all additional rows drawn for hierarchy
const additional:{[workPackageId:string]: WorkPackageResourceInterface} = {};
const tbodyContent = document.createDocumentFragment();
table.rows.forEach((wpId:string) => {
let row:WorkPackageTableRow = table.rowIndex[wpId];
// If this row was already rendered in a hierarchy, ignore it here
if (additional[row.workPackageId]) {
return;
}
// If we have ancestors
if (row.object.ancestors.length) {
this.buildWithHierarchy(table, tbodyContent, row, additional);
} else {
let tr = this.buildEmptyRow(row);
row.element = tr;
tbodyContent.appendChild(tr);
}
additional[row.object.id] = row.object;
});
return tbodyContent;
}
protected setupRowBuilders() {
this.rowBuilder = new SingleHierarchyRowBuilder(this.stopExisting$, this.workPackageTable);
this.refreshBuilder = this.rowBuilder;
}
private buildWithHierarchy(
table:WorkPackageTable,
tbody:DocumentFragment,
row:WorkPackageTableRow,
additional:{[workPackageId:string]: WorkPackageResourceInterface}) {
// Ancestor data [root, med, thisrow]
const ancestors = row.object.ancestors;
const ancestorGroups:string[] = [];
ancestors.forEach((ancestor:WorkPackageResourceInterface, index:number) => {
if (!additional[ancestor.id]) {
let ancestorRow = this.rowBuilder.buildAncestorRow(table, ancestor, ancestorGroups, index);
// special case, root without parent
if (index === 0) {
// Simply append the root here
tbody.appendChild(ancestorRow);
} else {
// This ancestor must be inserted in the last position of its root
const parent = ancestors[index-1];
this.insertIntoHierarchy(tbody, ancestorRow, parent.id);
}
additional[ancestor.id] = ancestor;
ancestorGroups.push(hierarchyGroupClass(ancestor.id));
}
});
// Insert this row to parent
const parent = _.last(ancestors);
const tr = this.buildEmptyRow(row);
row.element = tr;
this.insertIntoHierarchy(tbody, tr, parent.id);
}
/**
* Append a row to the given parent hierarchy group.
*/
private insertIntoHierarchy(tbody:DocumentFragment, tr:HTMLElement, parentId:string) {
// Either append to the hierarchy group root (= the parentID row itself)
const hierarchyRoot = `.__hierarchy-root-${parentId}`;
// Or, if it has descendants, append to the LATEST of that set
const hierarchyGroup = `.__hierarchy-group-${parentId}`;
jQuery(tbody).find(`${hierarchyRoot},${hierarchyGroup}`).last().after(tr);
}
}
HierarchyRowsBuilder.$inject = ['wpTableColumns', 'wpTableHierarchies', 'states', 'I18n'];

@ -1,24 +1,21 @@
import {collapsedGroupClass, hierarchyGroupClass, hierarchyRootClass} from '../../helpers/wp-table-hierarchy-helpers';
import {WorkPackageTableHierarchiesService} from '../../state/wp-table-hierarchy.service';
import {UiStateLinkBuilder} from '../ui-state-link-builder';
import {WorkPackageResourceInterface} from '../../../api/api-v3/hal-resources/work-package-resource.service';
import {QueryColumn} from '../../../api/api-v3/hal-resources/query-resource.service';
import {WorkPackageTableRow} from '../../wp-table.interfaces';
import {PlainRowsBuilder} from './plain-rows-builder';
import {States} from '../../../states.service';
import {injectorBridge} from '../../../angular/angular-injector-bridge.functions';
import {WorkPackageTableColumnsService} from '../../state/wp-table-columns.service';
import {WorkPackageTable} from '../../wp-fast-table';
import {WorkPackageTable} from "../../../wp-fast-table";
import {WorkPackageTableRow} from "../../../wp-table.interfaces";
import {WorkPackageResourceInterface} from "../../../../api/api-v3/hal-resources/work-package-resource.service";
import {WorkPackageTableHierarchiesService} from "../../../state/wp-table-hierarchy.service";
import {$injectFields} from "../../../../angular/angular-injector-bridge.functions";
import {Observable} from 'rxjs';
import {RowRefreshBuilder} from "../../rows/row-refresh-builder";
import {WorkPackageEditForm} from "../../../../wp-edit-form/work-package-edit-form";
import {collapsedGroupClass, hierarchyRootClass} from "../../../helpers/wp-table-hierarchy-helpers";
import {QueryColumn} from "../../../../api/api-v3/hal-resources/query-resource.service";
import {UiStateLinkBuilder} from "../../ui-state-link-builder";
export const indicatorCollapsedClass = '-hierarchy-collapsed';
export const hierarchyCellClassName = 'wp-table--hierarchy-span';
export class HierarchyRowsBuilder extends PlainRowsBuilder {
// Injections
public states:States;
public wpTableColumns:WorkPackageTableColumnsService;
export class SingleHierarchyRowBuilder extends RowRefreshBuilder {
// Injected
public wpTableHierarchies:WorkPackageTableHierarchiesService;
public I18n:op.I18n;
public uiStateBuilder = new UiStateLinkBuilder();
public text:{
@ -27,10 +24,9 @@ export class HierarchyRowsBuilder extends PlainRowsBuilder {
collapsed:(level:number) => string;
};
// The group expansion state
constructor(workPackageTable: WorkPackageTable) {
super(workPackageTable);
injectorBridge(this);
constructor(protected stopExisting$: Observable<any>, protected workPackageTable: WorkPackageTable) {
super(stopExisting$, workPackageTable);
$injectFields(this, 'wpTableHierarchies');
this.text = {
leaf: (level:number) => this.I18n.t('js.work_packages.hierarchy.leaf', { level: level }),
@ -39,57 +35,13 @@ export class HierarchyRowsBuilder extends PlainRowsBuilder {
};
}
/**
* The hierarchy builder is only applicable if the hierachy mode is active
*/
public isApplicable(table:WorkPackageTable) {
return this.wpTableHierarchies.isEnabled;
}
/**
* Rebuild the entire grouped tbody from the given table
* @param table
*/
public internalBuildRows(table:WorkPackageTable):DocumentFragment {
// Remember all additional rows drawn for hierarchy
const additional:{[workPackageId:string]: WorkPackageResourceInterface} = {};
const tbodyContent = document.createDocumentFragment();
table.rows.forEach((wpId:string) => {
let row:WorkPackageTableRow = table.rowIndex[wpId];
// If this row was already rendered in a hierarchy, ignore it here
if (additional[row.workPackageId]) {
return;
}
// If we have ancestors
if (row.object.ancestors.length) {
this.buildWithHierarchy(table, tbodyContent, row, additional);
} else {
let tr = this.buildEmptyRow(row);
row.element = tr;
tbodyContent.appendChild(tr);
}
additional[row.object.id] = row.object;
});
return tbodyContent;
}
public get colspan():number {
return this.wpTableColumns.columnCount + 1;
}
/**
* Refresh a single row after structural changes.
* Remembers and re-adds the hierarchy indicator if neccessary.
*/
public refreshRow(row:WorkPackageTableRow, table:WorkPackageTable):HTMLElement|null {
public refreshRow(row: WorkPackageTableRow, editForm: WorkPackageEditForm | undefined): HTMLElement | null {
// Remove any old hierarchy
const newRow = super.refreshRow(row, table);
const newRow = super.refreshRow(row, editForm);
if (newRow) {
jQuery(newRow).find(`.wp-table--hierarchy-span`).remove();
@ -99,11 +51,14 @@ export class HierarchyRowsBuilder extends PlainRowsBuilder {
return newRow;
}
public buildEmptyRow(row:WorkPackageTableRow, table?:WorkPackageTable, level?:number) {
const element = this.rowBuilder.buildEmpty(row.object);
/**
* Build the columns on the given empty row
*/
public buildEmpty(workPackage:WorkPackageResourceInterface) {
const element = super.buildEmpty(workPackage);
const state = this.wpTableHierarchies.currentState;
row.object.ancestors.forEach((ancestor:WorkPackageResourceInterface) => {
workPackage.ancestors.forEach((ancestor:WorkPackageResourceInterface) => {
element.classList.add(`__hierarchy-group-${ancestor.id}`);
if (state.collapsed[ancestor.id]) {
@ -111,17 +66,78 @@ export class HierarchyRowsBuilder extends PlainRowsBuilder {
}
});
element.classList.add(`__hierarchy-root-${row.object.id}`);
this.appendHierarchyIndicator(row.object, element);
element.classList.add(`__hierarchy-root-${workPackage.id}`);
this.appendHierarchyIndicator(workPackage, element);
return element;
}
/**
* Append an additional ancestor row that is not yet loaded
*/
public buildAncestorRow(
table:WorkPackageTable,
ancestor:WorkPackageResourceInterface,
ancestorGroups:string[],
index:number):HTMLElement {
const loadedRow = table.rowIndex[ancestor.id];
if (loadedRow) {
const tr = this.buildEmpty(loadedRow.object);
tr.classList.add('wp-table--hierarchy-aditional-row');
return tr;
}
const tr = this.createEmptyRow(ancestor);
const columns = this.wpTableColumns.getColumns();
tr.classList.add(`wp-table--hierarchy-aditional-row`, hierarchyRootClass(ancestor.id), ...ancestorGroups);
// Set available information for ID and subject column
// and print hierarchy indicator at subject field.
columns.forEach((column:QueryColumn) => {
const td = document.createElement('td');
if (column.id === 'subject') {
const textNode = document.createTextNode(ancestor.name);
td.appendChild(this.buildHierarchyIndicator(ancestor, index));
td.appendChild(textNode);
}
if (column.id === 'id') {
const link = this.uiStateBuilder.linkToShow(
ancestor.id,
ancestor.subject,
ancestor.id
);
td.appendChild(link);
td.classList.add('hierarchy-row--id-cell');
}
tr.appendChild(td);
});
// Append details icon
const td = document.createElement('td');
tr.appendChild(td);
return tr;
}
/**
* Append to the row of hierarchy level <level> a hierarchy indicator.
* @param workPackage
* @param row
* @param level
*/
private appendHierarchyIndicator(workPackage:WorkPackageResourceInterface, row:HTMLElement, level?:number):void {
const jRow = jQuery(row);
const hierarchyElement = this.buildHierarchyIndicator(workPackage, level);
jRow.find('td.subject')
.addClass('-with-hierarchy')
.prepend(hierarchyElement);
.addClass('-with-hierarchy')
.prepend(hierarchyElement);
}
/**
@ -179,107 +195,6 @@ export class HierarchyRowsBuilder extends PlainRowsBuilder {
return false;
}
private buildWithHierarchy(
table:WorkPackageTable,
tbody:DocumentFragment,
row:WorkPackageTableRow,
additional:{[workPackageId:string]: WorkPackageResourceInterface}) {
// Ancestor data [root, med, thisrow]
const ancestors = row.object.ancestors;
const ancestorGroups:string[] = [];
ancestors.forEach((ancestor:WorkPackageResourceInterface, index:number) => {
if (!additional[ancestor.id]) {
let ancestorRow = this.buildAncestorRow(table, ancestor, ancestorGroups, index);
// special case, root without parent
if (index === 0) {
// Simply append the root here
tbody.appendChild(ancestorRow);
} else {
// This ancestor must be inserted in the last position of its root
const parent = ancestors[index-1];
this.insertIntoHierarchy(tbody, ancestorRow, parent.id);
}
additional[ancestor.id] = ancestor;
ancestorGroups.push(hierarchyGroupClass(ancestor.id));
}
});
// Insert this row to parent
const parent = _.last(ancestors);
const tr = this.buildEmptyRow(row);
row.element = tr;
this.insertIntoHierarchy(tbody, tr, parent.id);
}
/**
* Append a row to the given parent hierarchy group.
*/
private insertIntoHierarchy(tbody:DocumentFragment, tr:HTMLElement, parentId:string) {
// Either append to the hierarchy group root (= the parentID row itself)
const hierarchyRoot = `.__hierarchy-root-${parentId}`;
// Or, if it has descendants, append to the LATEST of that set
const hierarchyGroup = `.__hierarchy-group-${parentId}`;
jQuery(tbody).find(`${hierarchyRoot},${hierarchyGroup}`).last().after(tr);
}
/**
* Append an additional ancestor row that is not yet loaded
*/
private buildAncestorRow(
table:WorkPackageTable,
ancestor:WorkPackageResourceInterface,
ancestorGroups:string[],
index:number):HTMLElement {
const loadedRow = table.rowIndex[ancestor.id];
if (loadedRow) {
const tr = this.buildEmptyRow(loadedRow, table, index);
tr.classList.add('wp-table--hierarchy-aditional-row');
return tr;
}
const tr = this.rowBuilder.createEmptyRow(ancestor);
const columns = this.wpTableColumns.getColumns();
tr.classList.add(`wp-table--hierarchy-aditional-row`, hierarchyRootClass(ancestor.id), ...ancestorGroups);
// Set available information for ID and subject column
// and print hierarchy indicator at subject field.
columns.forEach((column:QueryColumn, i:number) => {
const td = document.createElement('td');
if (column.id === 'subject') {
const textNode = document.createTextNode(ancestor.name);
td.appendChild(this.buildHierarchyIndicator(ancestor, index));
td.appendChild(textNode);
}
if (column.id === 'id') {
const link = this.uiStateBuilder.linkToShow(
ancestor.id,
ancestor.subject,
ancestor.id
);
td.appendChild(link);
td.classList.add('hierarchy-row--id-cell');
}
tr.appendChild(td);
});
// Append details icon
const td = document.createElement('td');
tr.appendChild(td);
return tr;
}
}
HierarchyRowsBuilder.$inject = ['wpTableColumns', 'wpTableHierarchies', 'states', 'I18n'];
SingleHierarchyRowBuilder.$inject = ['states', 'I18n'];

@ -1,9 +1,7 @@
import {WorkPackageTableRow} from "../../wp-table.interfaces";
import {RowsBuilder} from "./rows-builder";
import {States} from "../../../states.service";
import {injectorBridge} from "../../../angular/angular-injector-bridge.functions";
import {WorkPackageTableColumnsService} from "../../state/wp-table-columns.service";
import {WorkPackageTable} from "../../wp-fast-table";
import {RowsBuilder} from "../rows-builder";
import {WorkPackageTable} from "../../../wp-fast-table";
import {injectorBridge} from "../../../../angular/angular-injector-bridge.functions";
import {WorkPackageTableRow} from "../../../wp-table.interfaces";
export class PlainRowsBuilder extends RowsBuilder {
// Injections

@ -2,8 +2,8 @@ import {Subject} from "rxjs";
import {States} from "../../../states.service";
import {WorkPackageTable} from "../../wp-fast-table";
import {WorkPackageTableRow} from "../../wp-table.interfaces";
import {RowRefreshBuilder} from "./row-refresh-builder";
import {SingleRowBuilder} from "./single-row-builder";
import {SingleRowBuilder} from "../rows/single-row-builder";
import {RowRefreshBuilder} from "../rows/row-refresh-builder";
export abstract class RowsBuilder {
public states:States;
@ -11,11 +11,10 @@ export abstract class RowsBuilder {
protected rowBuilder:SingleRowBuilder;
protected refreshBuilder:RowRefreshBuilder;
private stopExisting$ = new Subject();
protected stopExisting$ = new Subject();
constructor(public workPackageTable: WorkPackageTable) {
this.rowBuilder = new SingleRowBuilder(this.stopExisting$, workPackageTable);
this.refreshBuilder = new RowRefreshBuilder(this.stopExisting$, workPackageTable);
this.setupRowBuilders();
}
/**
@ -45,6 +44,14 @@ export abstract class RowsBuilder {
return this.refreshBuilder.refreshRow(row, editing);
}
/**
* Construct the single and refresh row builders for this instance
*/
protected setupRowBuilders() {
this.rowBuilder = new SingleRowBuilder(this.stopExisting$, this.workPackageTable);
this.refreshBuilder = new RowRefreshBuilder(this.stopExisting$, this.workPackageTable);
}
/**
* Build an empty row for the given work package.
*/

@ -3,7 +3,7 @@ import {States} from "../../../states.service";
import {WorkPackageTableSelection} from "../../state/wp-table-selection.service";
import {CellBuilder} from "../cell-builder";
import {DetailsLinkBuilder} from "../details-link-builder";
import {injectorBridge} from "../../../angular/angular-injector-bridge.functions";
import {$injectFields, injectorBridge} from "../../../angular/angular-injector-bridge.functions";
import {WorkPackageResource} from "../../../api/api-v3/hal-resources/work-package-resource.service";
import {WorkPackageTableColumnsService} from '../../state/wp-table-columns.service';
import {QueryColumn} from '../../../api/api-v3/hal-resources/query-resource.service';
@ -38,8 +38,8 @@ export class SingleRowBuilder {
// Timeline builder
protected timelineCellBuilder = new TimelineCellBuilder(this.stopExisting$, this.workPackageTable);
constructor(private stopExisting$: Observable<any>, private workPackageTable: WorkPackageTable) {
injectorBridge(this);
constructor(protected stopExisting$: Observable<any>, protected workPackageTable: WorkPackageTable) {
$injectFields(this, 'wpTableSelection', 'wpTableColumns', 'I18n');
}
/**
@ -102,6 +102,3 @@ export class SingleRowBuilder {
return tr;
}
}
SingleRowBuilder.$inject = ['wpTableSelection', 'wpTableColumns', 'I18n'];

@ -3,7 +3,10 @@ import {injectorBridge} from "../../../angular/angular-injector-bridge.functions
import {WorkPackageTable} from "../../wp-fast-table";
import {States} from "../../../states.service";
import {TableEventHandler} from "../table-handler-registry";
import {GroupedRowsBuilder, rowGroupClassName} from "../../builders/rows/grouped-rows-builder";
import {
GroupedRowsBuilder,
rowGroupClassName
} from "../../builders/modes/grouped/grouped-rows-builder";
export class GroupRowHandler implements TableEventHandler {
// Injections

@ -1,10 +1,10 @@
import {injectorBridge} from "../../../angular/angular-injector-bridge.functions";
import {States} from "../../../states.service";
import {indicatorCollapsedClass} from "../../builders/rows/hierarchy-rows-builder";
import {collapsedGroupClass, hierarchyGroupClass, hierarchyRootClass} from "../../helpers/wp-table-hierarchy-helpers";
import {WorkPackageTable} from "../../wp-fast-table";
import {WorkPackageTableHierarchiesService} from './../../state/wp-table-hierarchy.service';
import {WorkPackageTableHierarchies} from "../../wp-table-hierarchies";
import {indicatorCollapsedClass} from "../../builders/modes/hierarchy/single-hierarchy-row-builder";
export class HierarchyTransformer {
public wpTableHierarchies:WorkPackageTableHierarchiesService;

@ -1,5 +1,3 @@
import {HierarchyRowsBuilder} from './builders/rows/hierarchy-rows-builder';
import {RowsBuilder} from './builders/rows/rows-builder';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {WorkPackageResource} from '../api/api-v3/hal-resources/work-package-resource.service';
@ -9,9 +7,11 @@ import {injectorBridge} from '../angular/angular-injector-bridge.functions';
import {WorkPackageTableRow} from './wp-table.interfaces';
import {TableHandlerRegistry} from './handlers/table-handler-registry';
import {locateRow} from './helpers/wp-table-row-helpers';
import {GroupedRowsBuilder} from './builders/rows/grouped-rows-builder';
import {PlainRowsBuilder} from './builders/rows/plain-rows-builder';
import {WorkPackageTimelineTableController} from "../wp-table/timeline/wp-timeline-container.directive";
import {PlainRowsBuilder} from "./builders/modes/plain/plain-rows-builder";
import {GroupedRowsBuilder} from "./builders/modes/grouped/grouped-rows-builder";
import {HierarchyRowsBuilder} from "./builders/modes/hierarchy/hierarchy-rows-builder";
import {RowsBuilder} from "./builders/modes/rows-builder";
export class WorkPackageTable {
public wpCacheService:WorkPackageCacheService;

Loading…
Cancel
Save