Skip to content
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
Expand Up @@ -41,7 +41,13 @@
<td class="col md-col">{{ entry.customer_name }}</td>
<td class="hidden-col">{{ entry.customer_id }}</td>
<td class="col md-col">{{ entry.activity_name }}</td>
<td class="col lg-col">{{ entry.uri }}</td>
<td class="col lg-col">
<ng-container *ngIf="entry.uri !== null">
<a [class.is-url]="isURL(entry.uri)" (click)="openURLInNewTab(entry.uri)">
{{ entry.uri }}
</a>
</ng-container>
</td>
<td class="col lg-col">{{ entry.description }}</td>
<td class="col lg-col">{{ entry.technologies }}</td>
</tr>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import '../../../../../styles/colors.scss';
.col{
white-space: nowrap;
overflow: hidden;
Expand Down Expand Up @@ -31,4 +32,26 @@
overflow-x: scroll;
width: 100%;
display: grid;
}
}

$url-base-color: $primary;
$url-hover-color: darken($url-base-color, 20);

.is-url {
cursor: pointer;
color: $url-base-color;
text-decoration: underline;

&:visited {
color: $dark;
}

&:hover {
color: $url-hover-color;
}

&:active {
color: $url-base-color;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Reports Page', () => {
description: 'any comment',
uri: 'custom uri',
project_id: '123',
project_name: 'Time-Tracker'
project_name: 'Time-Tracker',
};

const state: EntryState = {
Expand All @@ -33,38 +33,41 @@ describe('Reports Page', () => {
timeEntriesSummary: null,
timeEntriesDataSource: {
data: [timeEntry],
isLoading: false
isLoading: false,
},
reportDataSource: {
data: [timeEntry],
isLoading: false
}
isLoading: false,
},
};

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [],
declarations: [TimeEntriesTableComponent, SubstractDatePipe],
providers: [provideMockStore({ initialState: state })],
}).compileComponents();
store = TestBed.inject(MockStore);

}));
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
imports: [],
declarations: [TimeEntriesTableComponent, SubstractDatePipe],
providers: [provideMockStore({ initialState: state })],
}).compileComponents();
store = TestBed.inject(MockStore);
})
);

beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(TimeEntriesTableComponent);
component = fixture.componentInstance;
store.setState(state);
getReportDataSourceSelectorMock = store.overrideSelector(getReportDataSource, state.reportDataSource);
fixture.detectChanges();
}));
beforeEach(
waitForAsync(() => {
fixture = TestBed.createComponent(TimeEntriesTableComponent);
component = fixture.componentInstance;
store.setState(state);
getReportDataSourceSelectorMock = store.overrideSelector(getReportDataSource, state.reportDataSource);
fixture.detectChanges();
})
);

it('component should be created', async () => {
expect(component).toBeTruthy();
});

it('on success load time entries, the report should be populated', () => {
component.reportDataSource$.subscribe(ds => {
component.reportDataSource$.subscribe((ds) => {
expect(ds.data).toEqual(state.reportDataSource.data);
});
});
Expand All @@ -76,6 +79,34 @@ describe('Reports Page', () => {
expect(component.dtTrigger.next).toHaveBeenCalled();
});

it('when the uri starts with http or https it should return true and open the url in a new tab', () => {
const url = 'http://customuri.com';
spyOn(component, 'isURL').and.returnValue(true);
spyOn(window, 'open');

expect(component.openURLInNewTab(url)).not.toEqual('');
expect(window.open).toHaveBeenCalledWith(url, '_blank');
});

it('when the uri starts without http or https it should return false and not navigate or open a new tab', () => {
const url = timeEntry.uri;
spyOn(component, 'isURL').and.returnValue(false);

expect(component.openURLInNewTab(url)).toEqual('');
});

const params = [
{url: 'http://example.com', expected_value: true},
{url: 'https://example.com', expected_value: true},
{url: 'no-url-example', expected_value: false}
];
params.map((param) => {
it(`Given the url ${param.url}, the method isURL should return ${param.expected_value}`, () => {

expect(component.isURL(param.url)).toEqual(param.expected_value);
});
});

afterEach(() => {
fixture.destroy();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { formatDate } from '@angular/common';
import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from '@angular/core';
import { select, Store } from '@ngrx/store';
import { DataTableDirective } from 'angular-datatables';
import * as moment from 'moment';
import { Observable, Subject } from 'rxjs';
import { Entry } from 'src/app/modules/shared/models';
import { DataSource } from 'src/app/modules/shared/models/data-source.model';

import { EntryState } from '../../../time-clock/store/entry.reducer';
import { getReportDataSource } from '../../../time-clock/store/entry.selectors';

@Component({
selector: 'app-time-entries-table',
templateUrl: './time-entries-table.component.html',
styleUrls: ['./time-entries-table.component.scss']
styleUrls: ['./time-entries-table.component.scss'],
})
export class TimeEntriesTableComponent implements OnInit, OnDestroy, AfterViewInit {
dtOptions: any = {
Expand All @@ -24,7 +23,6 @@ export class TimeEntriesTableComponent implements OnInit, OnDestroy, AfterViewIn
{
extend: 'colvis',
columns: ':not(.hidden-col)',

},
'print',
{
Expand All @@ -33,29 +31,29 @@ export class TimeEntriesTableComponent implements OnInit, OnDestroy, AfterViewIn
format: {
body: (data, row, column, node) => {
return column === 3 ?
moment.duration(data).asHours().toFixed(4).slice(0, -1) :
data;
}
}
moment.duration(data).asHours().toFixed(4).slice(0, -1) :
data;
},
},
},
text: 'Excel',
filename: `time-entries-${formatDate(new Date(), 'MM_dd_yyyy-HH_mm', 'en')}`
filename: `time-entries-${formatDate(new Date(), 'MM_dd_yyyy-HH_mm', 'en')}`,
},
{
extend: 'csv',
exportOptions: {
format: {
body: (data, row, column, node) => {
return column === 3 ?
moment.duration(data).asHours().toFixed(4).slice(0, -1) :
data;
}
}
moment.duration(data).asHours().toFixed(4).slice(0, -1) :
data;
},
},
},
text: 'CSV',
filename: `time-entries-${formatDate(new Date(), 'MM_dd_yyyy-HH_mm', 'en')}`
}
]
filename: `time-entries-${formatDate(new Date(), 'MM_dd_yyyy-HH_mm', 'en')}`,
},
],
};
dtTrigger: Subject<any> = new Subject();
@ViewChild(DataTableDirective, { static: false })
Expand Down Expand Up @@ -91,4 +89,13 @@ export class TimeEntriesTableComponent implements OnInit, OnDestroy, AfterViewIn
this.dtTrigger.next();
}
}

openURLInNewTab(uri: string): WindowProxy | string {
return this.isURL(uri) ? window.open(uri, '_blank') : '';
}

isURL(uri: string): boolean {
const regex = new RegExp('http*', 'g');
return regex.test(uri);
}
}
2 changes: 2 additions & 0 deletions src/app/modules/time-entries/pages/time-entries.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,13 @@ export class TimeEntriesComponent implements OnInit, OnDestroy {
this.selectedMonthAsText = moment().month(event.monthIndex).format('MMMM');
this.store.dispatch(new entryActions.LoadEntries(this.selectedMonth, this.selectedYear));
}

openModal(item: any) {
this.idToDelete = item.id;
this.message = `Are you sure you want to delete ${item.activity_name}?`;
this.showModal = true;
}

resetDraggablePosition(event: any): void {
event.source._dragRef.reset();
}
Expand Down