Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: dbx-table #23

Merged
merged 6 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { filterMaybe } from '@dereekb/rxjs';
import { ChangeDetectionStrategy, Component, OnInit, OnDestroy, Input } from '@angular/core';
import { AbstractDbxInjectionDirective } from '@dereekb/dbx-core';
import { map, distinctUntilChanged, BehaviorSubject, switchMap } from 'rxjs';
import { Maybe } from '@dereekb/util';

@Component({
template: `
<div class="doc-example-table-action-cell">
<button mat-icon-button><mat-icon>thumb_up</mat-icon></button>
<dbx-button-spacer></dbx-button-spacer>
<button mat-icon-button><mat-icon>thumb_down</mat-icon></button>
</div>
`,
styleUrls: ['./table.item.action.example.scss']
})
export class DocExtensionTableItemActionExampleComponent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.doc-example-table-action-cell {
min-width: 110px;
display: flex;
align-items: center;
justify-content: center;
padding: 4px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { filterMaybe } from '@dereekb/rxjs';
import { ChangeDetectionStrategy, Component, OnInit, OnDestroy, Input } from '@angular/core';
import { AbstractDbxInjectionDirective } from '@dereekb/dbx-core';
import { map, distinctUntilChanged, BehaviorSubject, switchMap } from 'rxjs';
import { Maybe } from '@dereekb/util';
import { DbxTableColumn } from '@dereekb/dbx-web/table';
import { ExampleTableData } from './table.item';

@Component({
template: `
<div style="text-align: center">
<div class="dbx-small">{{ name }}</div>
<div class="dbx-small dbx-hint">{{ columnName }}</div>
</div>
`
})
export class DocExtensionTableItemCellExampleComponent {
item!: ExampleTableData;
column!: DbxTableColumn<Date>;

get name() {
return this.item.name;
}

get columnName() {
return this.column.columnName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { filterMaybe } from '@dereekb/rxjs';
import { ChangeDetectionStrategy, Component, OnInit, OnDestroy, Input } from '@angular/core';
import { AbstractDbxInjectionDirective } from '@dereekb/dbx-core';
import { map, distinctUntilChanged, BehaviorSubject, switchMap } from 'rxjs';
import { Maybe } from '@dereekb/util';
import { ExampleTableData } from './table.item';

@Component({
template: `
<div>{{ name }}</div>
`
})
export class DocExtensionTableItemHeaderExampleComponent {
item!: ExampleTableData;

get name() {
return this.item.name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ModelKeyRef } from '@dereekb/util';

export interface ExampleTableData extends ModelKeyRef {
name: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<dbx-content-container>
<doc-feature-layout header="Table Extension" hint="">
<!-- Examples -->
<doc-feature-example header="dbx-table-view" hint="The base-level component that renders the state of a dbxTableStore.">
<dbx-table-view dbxTable [dbxTableInput]="exampleInput" [dbxTableViewDelegate]="exampleViewDelegate" [dbxTableDataDelegate]="exampleDataDelegate"></dbx-table-view>
<h3>Context Loading</h3>
<p class="dbx-hint">While the context is loading the table shows a spinning loader.</p>
<dbx-table-view dbxTable [dbxTableInput]="exampleInput" [dbxTableViewDelegate]="exampleViewDelegate" [dbxTableDataDelegate]="exampleLoadingContextDelegate"></dbx-table-view>
<h3>Data Loading</h3>
<p class="dbx-hint">This example shows how loading the data is handled. The delegate also provides a loadMore() functionality, allowing more items to load as the table is scrolled.</p>
<button *ngIf="isLoading$ | async" mat-raised-button (click)="loadMoreItems()">Finish Loading Items</button>
<p></p>
<dbx-table-view dbxTable [dbxTableInput]="exampleInput" [dbxTableViewDelegate]="exampleViewDelegate" [dbxTableDataDelegate]="exampleLoadingDataDelegate"></dbx-table-view>
</doc-feature-example>
</doc-feature-layout>
</dbx-content-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { DocExtensionTableItemCellExampleComponent } from './../component/table.item.cell.example.component';
import { startOfDay } from 'date-fns/esm';
import { Component, OnDestroy } from '@angular/core';
import { DateRangeDayDistanceInput, expandDaysForDateRange, dateRange, formatToISO8601DayString, DateRangeType } from '@dereekb/date';
import { DbxInjectionComponentConfig } from '@dereekb/dbx-core';
import { DbxWidgetDataPair } from '@dereekb/dbx-web';
import { DbxTableColumn, DbxTableContextData, DbxTableContextDataDelegate, dbxTableDateHeaderInjectionFactory, dbxTableDateRangeDayDistanceInputCellInput, DbxTableViewDelegate } from '@dereekb/dbx-web/table';
import { beginLoading, beginLoadingPage, ListLoadingState, PageListLoadingState, successPageResult, successResult } from '@dereekb/rxjs';
import { Maybe, ModelKeyRef, range } from '@dereekb/util';
import { delay, map, Observable, of, startWith, BehaviorSubject, skip, shareReplay, distinctUntilChanged, switchMap } from 'rxjs';
import { DocExtensionTableItemActionExampleComponent } from '../component/table.item.action.example.component';
import { DocExtensionTableItemHeaderExampleComponent } from '../component/table.item.header.example.component';
import { ExampleTableData } from '../component/table.item';

@Component({
templateUrl: './table.component.html'
})
export class DocExtensionTableComponent implements OnDestroy {
readonly exampleInput: DateRangeDayDistanceInput = {
date: startOfDay(new Date()),
distance: 6
};

readonly exampleTableData: ExampleTableData[] = range(0, 15).map((x) => ({ name: `Example ${x}`, key: String(x) }));
readonly exampleTableDataItems = new BehaviorSubject<ExampleTableData[]>(this.exampleTableData);

readonly isLoading$ = this.exampleTableDataItems.pipe(
skip(1),
map((x) => false),
startWith(true),
distinctUntilChanged(),
shareReplay(1)
);

readonly exampleViewDelegate: DbxTableViewDelegate<DateRangeDayDistanceInput, Date, ExampleTableData> = {
inputHeader: dbxTableDateRangeDayDistanceInputCellInput(),
columnHeader: dbxTableDateHeaderInjectionFactory(),
itemHeader: function (item: ExampleTableData) {
return {
componentClass: DocExtensionTableItemHeaderExampleComponent,
init: (x) => {
x.item = item;
}
};
},
itemCell: function (column: DbxTableColumn<Date>, item: ExampleTableData) {
return {
componentClass: DocExtensionTableItemCellExampleComponent,
init: (x) => {
x.item = item;
x.column = column;
}
};
},
itemAction: function (item: ExampleTableData) {
return {
componentClass: DocExtensionTableItemActionExampleComponent
};
}
};

readonly exampleDataDelegate: DbxTableContextDataDelegate<DateRangeDayDistanceInput, Date, ExampleTableData> = {
loadData: (input) => {
const allDays = expandDaysForDateRange(dateRange({ ...input }));
const columns: DbxTableColumn<Date>[] = allDays.map((x) => ({ columnName: formatToISO8601DayString(x), meta: x }));
const items: ExampleTableData[] = [...this.exampleTableData];
const items$: Observable<PageListLoadingState<ExampleTableData>> = of(successPageResult(0, items));

const result: DbxTableContextData<DateRangeDayDistanceInput, Date, ExampleTableData> = {
input,
columns,
items$
};

return of(successResult(result)); // .pipe(delay(1000), startWith(beginLoadingPage<typeof result>(0)));
}
};

readonly exampleLoadingContextDelegate: DbxTableContextDataDelegate<DateRangeDayDistanceInput, Date, ExampleTableData> = {
loadData: (input) => {
return of(beginLoadingPage<DbxTableContextData<DateRangeDayDistanceInput, Date, ExampleTableData>>(0));
}
};

readonly exampleLoadingDataDelegate: DbxTableContextDataDelegate<DateRangeDayDistanceInput, Date, ExampleTableData> = {
loadData: (input) => {
const allDays = expandDaysForDateRange(dateRange({ ...input }));
const columns: DbxTableColumn<Date>[] = allDays.map((x) => ({ columnName: formatToISO8601DayString(x), meta: x }));
const items$: Observable<PageListLoadingState<ExampleTableData>> = this.exampleTableDataItems
.pipe(
skip(1),
switchMap((x) => of(successPageResult(0, x)).pipe(delay(1000), startWith(beginLoadingPage<ExampleTableData[]>(0))))
)
.pipe(startWith(beginLoadingPage<ExampleTableData[]>(0)));

const result: DbxTableContextData<DateRangeDayDistanceInput, Date, ExampleTableData> = {
input,
columns,
items$,
loadMore: () => this.loadMoreItems()
};

return of(successResult(result));
}
};

loadMoreItems() {
const currentItems = this.exampleTableDataItems.value;
const itemsCount = currentItems.length;
const newItems = range(itemsCount + 1, itemsCount + 15).map((x) => ({ name: `Example ${x}`, key: String(x) }));
this.exampleTableDataItems.next([...currentItems, ...newItems]);
}

ngOnDestroy(): void {
this.exampleTableDataItems.complete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@ import { DocFormComponentsModule } from '../form/doc.form.module';
import { DocExtensionMapboxComponent } from './container/mapbox.component';
import { DbxFormMapboxModule } from '@dereekb/dbx-form/mapbox';
import { DbxMapboxModule } from '@dereekb/dbx-web/mapbox';
import { DbxTableDateModule, DbxTableModule } from '@dereekb/dbx-web/table';
import { NgxMapboxGLModule } from 'ngx-mapbox-gl';
import { DocExtensionMapboxContentExampleComponent } from './component/mapbox.content.example.component';
import { DocExtensionMapboxMarkersExampleComponent } from './component/mapbox.markers.example.component';
import { DbxCalendarRootModule } from '@dereekb/dbx-web/calendar';
import { DocExtensionCalendarScheduleSelectionComponent } from './component/selection.calendar.component';
import { DbxFormCalendarModule, DbxFormDateScheduleRangeFieldModule } from '@dereekb/dbx-form/calendar';
import { DocExtensionCalendarScheduleSelectionWithFilterComponent } from './component/selection.filter.calendar.component';
import { DocExtensionTableComponent } from './container/table.component';
import { DocExtensionTableItemActionExampleComponent } from './component/table.item.action.example.component';
import { DocExtensionTableItemCellExampleComponent } from './component/table.item.cell.example.component';
import { DocExtensionTableItemHeaderExampleComponent } from './component/table.item.header.example.component';

@NgModule({
imports: [
Expand All @@ -32,6 +37,8 @@ import { DocExtensionCalendarScheduleSelectionWithFilterComponent } from './comp
DbxMapboxModule,
NgxMapboxGLModule,
DbxFormMapboxModule,
DbxTableModule,
DbxTableDateModule,
UIRouterModule.forChild({
states: STATES
})
Expand All @@ -44,10 +51,14 @@ import { DocExtensionCalendarScheduleSelectionWithFilterComponent } from './comp
DocExtensionMapboxMarkersExampleComponent,
DocExtensionCalendarScheduleSelectionComponent,
DocExtensionCalendarScheduleSelectionWithFilterComponent,
DocExtensionTableItemHeaderExampleComponent,
DocExtensionTableItemCellExampleComponent,
DocExtensionTableItemActionExampleComponent,
// container
DocExtensionLayoutComponent,
DocExtensionHomeComponent,
DocExtensionCalendarComponent,
DocExtensionTableComponent,
DocExtensionWidgetComponent,
DocExtensionMapboxComponent
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DocExtensionCalendarComponent } from './container/calendar.component';
import { DocExtensionHomeComponent } from './container/home.component';
import { DocExtensionWidgetComponent } from './container/widget.component';
import { DocExtensionMapboxComponent } from './container/mapbox.component';
import { DocExtensionTableComponent } from './container/table.component';

export const layoutState: Ng2StateDeclaration = {
url: '/extension',
Expand Down Expand Up @@ -36,11 +37,18 @@ export const docExtensionMapboxState: Ng2StateDeclaration = {
component: DocExtensionMapboxComponent
};

export const docExtensionTableState: Ng2StateDeclaration = {
url: '/table',
name: 'doc.extension.table',
component: DocExtensionTableComponent
};

export const STATES: Ng2StateDeclaration[] = [
//
layoutState,
homeState,
docExtensionCalendarState,
docExtensionWidgetState,
docExtensionMapboxState
docExtensionMapboxState,
docExtensionTableState
];
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ export const DOC_EXTENSION_ROUTES = [
title: 'Mapbox',
detail: 'mapbox extension',
ref: 'doc.extension.mapbox'
},
{
icon: 'table_view',
title: 'Table',
detail: 'table extension',
ref: 'doc.extension.table'
}
];

Expand Down
2 changes: 1 addition & 1 deletion packages/date/src/lib/date/date.block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ export function dateBlockTiming(durationInput: DateDurationSpan, inputRange: Dat
} else {
inputDate = startsAt; // TODO: May not be needed?
numberOfBlockedDays = inputRange.distance - 1;
range = dateRange({ date: inputDate, distance: inputRange.distance }, true);
range = dateRange({ type: DateRangeType.DAY, date: inputDate, distance: inputRange.distance }, true);
}

if (inputDate != null) {
Expand Down
37 changes: 35 additions & 2 deletions packages/date/src/lib/date/date.range.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
import { addDays, addHours } from 'date-fns';
import { dateRangeOverlapsDateRangeFunction, isDateInDateRangeFunction, isDateRangeInDateRangeFunction } from './date.range';
import { startOfDay, addDays, addHours } from 'date-fns';
import { dateRange, dateRangeOverlapsDateRangeFunction, DateRangeType, expandDaysForDateRangeFunction, isDateInDateRangeFunction, isDateRangeInDateRangeFunction } from './date.range';

describe('expandDaysForDateRangeFunction()', () => {
describe('function', () => {
const expandFn = expandDaysForDateRangeFunction({});

it('should expand the range to an array of days', () => {
const days = 3;
const start = startOfDay(new Date());
const end = addDays(start, days - 1);

const result = expandFn({ start, end });
expect(result.length).toBe(days);

expect(result[0]).toBeSameSecondAs(start);
expect(result[1]).toBeSameSecondAs(addDays(start, 1));
expect(result[2]).toBeSameSecondAs(addDays(addDays(start, 1), 1));
expect(result[2]).toBeSameSecondAs(end);
});

it('should expand the dateRange', () => {
const distance = 3;
const { start, end } = dateRange({ date: new Date(), distance, type: DateRangeType.DAYS_RANGE });

const result = expandFn({ start, end });
expect(result.length).toBe(distance + 1);

expect(result[0]).toBeSameSecondAs(start);
expect(result[1]).toBeSameSecondAs(addDays(start, 1));
expect(result[2]).toBeSameSecondAs(addDays(addDays(start, 1), 1));
expect(result[3]).toBeSameSecondAs(addDays(addDays(addDays(start, 1), 1), 1));
});
});
});

describe('isDateInDateRangeFunction()', () => {
describe('function', () => {
Expand Down
Loading