Skip to content

Commit 984815b

Browse files
TTL-910 Custom filters (#1001)
* feat: TTL-910 add project dropdown * feat: TTL-910 add activity and project filters * refactor: TTL-910 if statements * test: TTL-910 add test * test: TTL-910 update tests * feat: TTL-910 update ui * test: TTL-910 update tests * test: TTL-910 fix tests * test: TTL-910 fix tests * test: TTL-910 fix tests * test: TTL-910 fix tests * test: TTL-910 fix tests * test: TTL-910 fix tests * test: TTL-910 fix tests * test: TTL-910 fix tests * test: TTL-910 fix tests * refactor: TTL-910 modify ngOnchange feature * refactor: TTL-910 modify ngOnChange feature * feat: TTL-925 update overlap message (#1002) --------- Co-authored-by: mmaquina <[email protected]>
1 parent 1595a9e commit 984815b

24 files changed

+485
-220
lines changed

src/app/app.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ import { TimeRangeOptionsComponent } from './modules/reports/components/time-ran
9999
import { V2RedirectComponent } from './modules/v2-redirect/v2-redirect.component';
100100
import { SpinnerOverlayComponent } from './modules/shared/components/spinner-overlay/spinner-overlay.component';
101101
import { SpinnerInterceptor } from './modules/shared/interceptors/spinner.interceptor';
102+
import { SearchProjectComponent } from './modules/shared/components/search-project/search-project.component';
103+
import { SearchActivityComponent } from './modules/shared/components/search-activity/search-activity.component';
102104

103105
const maskConfig: Partial<IConfig> = {
104106
validation: false,
@@ -140,6 +142,8 @@ const maskConfig: Partial<IConfig> = {
140142
SubstractDatePipeDisplayAsFloat,
141143
TechnologiesComponent,
142144
SearchUserComponent,
145+
SearchProjectComponent,
146+
SearchActivityComponent,
143147
TimeEntriesSummaryComponent,
144148
TimeDetailsPipe,
145149
InputLabelComponent,

src/app/modules/reports/components/time-entries-table/time-entries-table.component.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
<div class="row scroll-table mt-5 ml-0">
1+
<div class="flex flex-row justify-center mt-14">
22
<app-search-user [users]="users" (selectedUserId)="user($event)"></app-search-user>
3-
3+
<app-search-activity [activities]="activities" (selectedActivityId)="activity($event)"></app-search-activity>
4+
</div>
5+
<div class="flex justify-center">
6+
<app-search-project class="" [projects]="listProjects" (selectedProjectId)="project($event)"></app-search-project>
7+
</div>
8+
<div class="row scroll-table mt-5 ml-0">
9+
410
<table
511
class="table table-striped mb-0"
612
datatable

src/app/modules/reports/components/time-entries-table/time-entries-table.component.spec.ts

Lines changed: 89 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
22
import { MockStore, provideMockStore } from '@ngrx/store/testing';
33
import { DataTablesModule } from 'angular-datatables';
44
import { NgxPaginationModule } from 'ngx-pagination';
5-
import { Entry } from 'src/app/modules/shared/models';
5+
import { Activity, Entry, Customer, Project } from 'src/app/modules/shared/models';
66
import { SubstractDatePipe } from 'src/app/modules/shared/pipes/substract-date/substract-date.pipe';
77
import { SubstractDatePipeDisplayAsFloat } from 'src/app/modules/shared/pipes/substract-date-return-float/substract-date-return-float.pipe';
88
import { getReportDataSource, getResultSumEntriesSelected } from 'src/app/modules/time-clock/store/entry.selectors';
@@ -11,6 +11,14 @@ import { TimeEntriesTableComponent } from './time-entries-table.component';
1111
import { TotalHours } from '../../models/total-hours-report';
1212
import { ActionsSubject } from '@ngrx/store';
1313
import { UserActionTypes } from 'src/app/modules/users/store';
14+
import { ProjectActionTypes } from 'src/app/modules/customer-management/components/projects/components/store/project.actions';
15+
import { SearchUserComponent } from 'src/app/modules/shared/components/search-user/search-user.component';
16+
import { SearchProjectComponent } from 'src/app/modules/shared/components/search-project/search-project.component';
17+
import { SearchActivityComponent } from 'src/app/modules/shared/components/search-activity/search-activity.component';
18+
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
19+
import { MatCheckboxModule } from '@angular/material/checkbox';
20+
import { NgSelectModule } from '@ng-select/ng-select';
21+
import { ActivityManagementActionTypes } from 'src/app/modules/activities-management/store';
1422

1523
describe('Reports Page', () => {
1624
describe('TimeEntriesTableComponent', () => {
@@ -55,13 +63,13 @@ describe('Reports Page', () => {
5563
uri: 'custom uri',
5664
project_id: '123',
5765
project_name: 'Time-Tracker',
58-
}
66+
},
5967
];
6068

6169
const state: EntryState = {
6270
active: timeEntry,
6371
isLoading: false,
64-
resultSumEntriesSelected: new TotalHours(),
72+
resultSumEntriesSelected: new TotalHours(),
6573
message: '',
6674
createError: false,
6775
updateError: false,
@@ -81,25 +89,37 @@ describe('Reports Page', () => {
8189
beforeEach(
8290
waitForAsync(() => {
8391
TestBed.configureTestingModule({
84-
imports: [NgxPaginationModule, DataTablesModule],
85-
declarations: [TimeEntriesTableComponent, SubstractDatePipe, SubstractDatePipeDisplayAsFloat],
92+
imports: [
93+
NgxPaginationModule,
94+
DataTablesModule,
95+
MatCheckboxModule,
96+
NgSelectModule,
97+
FormsModule,
98+
ReactiveFormsModule,
99+
],
100+
declarations: [
101+
TimeEntriesTableComponent,
102+
SubstractDatePipe,
103+
SubstractDatePipeDisplayAsFloat,
104+
SearchUserComponent,
105+
SearchProjectComponent,
106+
SearchActivityComponent,
107+
],
86108
providers: [provideMockStore({ initialState: state }), { provide: ActionsSubject, useValue: actionSub }],
87109
}).compileComponents();
88-
89110
})
90111
);
91112

92-
beforeEach(
93-
() => {
94-
fixture = TestBed.createComponent(TimeEntriesTableComponent);
95-
component = fixture.componentInstance;
96-
store = TestBed.inject(MockStore);
97-
store.setState(state);
98-
getReportDataSourceSelectorMock = (store.overrideSelector(getReportDataSource, state.reportDataSource),
113+
beforeEach(() => {
114+
fixture = TestBed.createComponent(TimeEntriesTableComponent);
115+
component = fixture.componentInstance;
116+
store = TestBed.inject(MockStore);
117+
store.setState(state);
118+
getReportDataSourceSelectorMock =
119+
(store.overrideSelector(getReportDataSource, state.reportDataSource),
99120
store.overrideSelector(getResultSumEntriesSelected, state.resultSumEntriesSelected));
100-
fixture.detectChanges();
101-
}
102-
);
121+
fixture.detectChanges();
122+
});
103123

104124
beforeEach(() => {
105125
row = 0;
@@ -144,11 +164,10 @@ describe('Reports Page', () => {
144164
const params = [
145165
{ url: 'http://example.com', expected_value: true },
146166
{ url: 'https://example.com', expected_value: true },
147-
{ url: 'no-url-example', expected_value: false }
167+
{ url: 'no-url-example', expected_value: false },
148168
];
149169
params.map((param) => {
150170
it(`Given the url ${param.url}, the method isURL should return ${param.expected_value}`, () => {
151-
152171
expect(component.isURL(param.url)).toEqual(param.expected_value);
153172
});
154173
});
@@ -160,50 +179,47 @@ describe('Reports Page', () => {
160179
});
161180

162181
it('when the rerenderDataTable method is called and dtElement and dtInstance are defined, the destroy and next methods are called ',
163-
() => {
164-
spyOn(component.dtTrigger, 'next');
182+
() => {
183+
spyOn(component.dtTrigger, 'next');
165184

166-
component.ngAfterViewInit();
185+
component.ngAfterViewInit();
167186

168-
component.dtElement.dtInstance.then((dtInstance) => {
169-
expect(component.dtTrigger.next).toHaveBeenCalled();
170-
});
187+
component.dtElement.dtInstance.then((dtInstance) => {
188+
expect(component.dtTrigger.next).toHaveBeenCalled();
171189
});
190+
});
172191

173192
it(`When the user method is called, the emit method is called`, () => {
174193
const userId = 'abc123';
175194
spyOn(component.selectedUserId, 'emit');
176195
component.user(userId);
177196
expect(component.selectedUserId.emit).toHaveBeenCalled();
178-
179197
});
180198

181199
it('Should populate the users with the payload from the action executed', () => {
182200
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
183201
const usersArray = [];
184202
const action = {
185203
type: UserActionTypes.LOAD_USERS_SUCCESS,
186-
payload: usersArray
204+
payload: usersArray,
187205
};
188206

189207
actionSubject.next(action);
190208

191-
192209
expect(component.users).toEqual(usersArray);
193210
});
194211

195212
it('The sum of the data dates is equal to {"hours": 3, "minutes":20,"seconds":0}', () => {
196213
const { hours, minutes, seconds }: TotalHours = component.sumDates(timeEntryList);
197214
expect({ hours, minutes, seconds }).toEqual({ hours: 3, minutes: 20, seconds: 0 });
198-
199215
});
200216

201217
it('the sume of hours of entries selected is equal to {hours:0, minutes:0, seconds:0}', () => {
202218
let checked = true;
203-
let {hours, minutes, seconds}: TotalHours = component.sumHoursEntriesSelected(timeEntryList[0], checked);
219+
let { hours, minutes, seconds }: TotalHours = component.sumHoursEntriesSelected(timeEntryList[0], checked);
204220
checked = false;
205-
({hours, minutes, seconds} = component.sumHoursEntriesSelected(timeEntryList[0], checked));
206-
expect({hours, minutes, seconds}).toEqual({hours: 0, minutes: 0, seconds: 0});
221+
({ hours, minutes, seconds } = component.sumHoursEntriesSelected(timeEntryList[0], checked));
222+
expect({ hours, minutes, seconds }).toEqual({ hours: 0, minutes: 0, seconds: 0 });
207223
});
208224

209225
it('should export data with the correct format', () => {
@@ -228,7 +244,7 @@ describe('Reports Page', () => {
228244
"ng-reflect-ng-for-of": "git"
229245
}--><!--ng-container--><!--bindings={
230246
"ng-reflect-ng-if": "true"
231-
}-->`
247+
}-->`,
232248
];
233249
const dataFormat = [
234250
'<span matripple="" class="mat-ripple mat-checkbox-ripple mat-focus-indicator" ng-reflect-trigger="[object HTMLLabelElement]" ng-reflect-disabled="false" ng-reflect-radius="20" ng-reflect-centered="true" ng-reflect-animation="[object Object]">&nbsp;',
@@ -245,7 +261,7 @@ describe('Reports Page', () => {
245261
'Activity_Name',
246262
' https://ioetec.atlassian.net/browse/CB-115 ',
247263
'',
248-
' git '
264+
' git ',
249265
];
250266

251267
data.forEach((value: any, index) => {
@@ -257,7 +273,7 @@ describe('Reports Page', () => {
257273
it('Should render column header called Time Zone', () => {
258274
const table = document.querySelector('table#time-entries-table');
259275
const tableHeaderElements = Array.from(table.getElementsByTagName('th'));
260-
const tableHeaderTitles = tableHeaderElements.map(element => (element.textContent));
276+
const tableHeaderTitles = tableHeaderElements.map((element) => element.textContent);
261277
expect(tableHeaderTitles).toContain('Time zone');
262278
});
263279

@@ -272,6 +288,45 @@ describe('Reports Page', () => {
272288
expect(cell).toContain('UTC-5');
273289
});
274290

291+
it('Should populate the projects with the payload from the action executed', () => {
292+
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
293+
const customerObj: Customer = { name: 'name' };
294+
const projectsArray: Project[] = [
295+
{
296+
id: 'projectId',
297+
customer_id: 'customer_id',
298+
customer: customerObj,
299+
name: 'name',
300+
description: 'proejectDescription',
301+
project_type_id: 'project_type_id',
302+
status: 'active',
303+
},
304+
];
305+
const action = {
306+
type: ProjectActionTypes.LOAD_PROJECTS_SUCCESS,
307+
payload: projectsArray,
308+
};
309+
actionSubject.next(action);
310+
expect(component.projects).toEqual(projectsArray);
311+
});
312+
313+
it('Should populate the activities with the payload from the action executed', () => {
314+
const Subject = TestBed.inject(ActionsSubject) as ActionsSubject;
315+
const activitiesArray: Activity[] = [
316+
{
317+
id: 'activityId',
318+
name: 'activityName',
319+
description: 'activityDescription',
320+
status: 'string'
321+
},
322+
];
323+
const action = {
324+
type: ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS,
325+
payload: activitiesArray,
326+
};
327+
Subject.next(action);
328+
expect(component.activities).toEqual(activitiesArray);
329+
});
275330

276331
afterEach(() => {
277332
fixture.destroy();

0 commit comments

Comments
 (0)