Skip to content

Commit 0cb1516

Browse files
571 ui list trending technologies (#577)
* feat: #571 technology report * feat: #571 technology report - move componente TimeTange to shared * feat: #571 technology report - test create component * feat: #571 mock data * fix: #571 update async for waitForAsync * fix: #571 test coverage * TT-52 feat: add toggle flag * TT-52 feat: update previous test * TT-52 feat: remove print * TT-52 feat: unit tests for feature flag ui-list-technologies * TT-52 feat: include route in the feature toggle * TT-52 feat: consider global toggle state * TT-52 feat: update aync methods in user components * TT-52 feat: remove errors due to rebase * TT-52 feat: CI test * ci: update workflow Co-authored-by: roberto <[email protected]>
1 parent 79fadf5 commit 0cb1516

28 files changed

+422
-37
lines changed

.github/workflows/CI-time-tracker-ui.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ jobs:
4747
STACK_EXCHANGE_ID: ${{ secrets.STACK_EXCHANGE_ID }}
4848
STACK_EXCHANGE_ACCESS_TOKEN: ${{ secrets.STACK_EXCHANGE_ACCESS_TOKEN }}
4949
AZURE_APP_CONFIGURATION_CONNECTION_STRING: ${{ secrets.AZURE_APP_CONFIGURATION_CONNECTION_STRING }}
50-
run: sudo sh scripts/populate-keys.sh
50+
run: |
51+
chmod +x ./scripts/populate-keys.sh
52+
sh ./scripts/populate-keys.sh
5153
5254
- name: Running tests
5355
run: npm run ci-test --if-present

angular.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
],
2626
"styles": [
2727
"node_modules/datatables.net-dt/css/jquery.dataTables.css",
28+
"node_modules/datatables.net-responsive-dt/css/responsive.dataTables.css",
2829
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
2930
"src/styles.scss",
3031
"node_modules/ngx-toastr/toastr.css",
@@ -39,7 +40,8 @@
3940
"node_modules/datatables.net-buttons/js/buttons.colVis.js",
4041
"node_modules/datatables.net-buttons/js/buttons.flash.js",
4142
"node_modules/datatables.net-buttons/js/buttons.html5.js",
42-
"node_modules/datatables.net-buttons/js/buttons.print.js"
43+
"node_modules/datatables.net-buttons/js/buttons.print.js",
44+
"node_modules/datatables.net-responsive/js/dataTables.responsive.js"
4345
]
4446
},
4547
"configurations": {

package-lock.json

Lines changed: 0 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,20 @@
2121
"@angular/platform-browser": "~10.2.2",
2222
"@angular/platform-browser-dynamic": "~10.2.2",
2323
"@angular/router": "~10.2.2",
24-
"@azure/app-configuration": "^1.1.0",
25-
"@azure/identity": "^1.1.0",
2624
"@ngrx/effects": "^10.0.1",
2725
"@ngrx/store": "^10.0.1",
2826
"@ngrx/store-devtools": "^10.0.1",
2927
"@types/datatables.net-buttons": "^1.4.3",
3028
"angular-datatables": "^9.0.2",
29+
"@azure/app-configuration": "^1.1.0",
30+
"@azure/identity": "^1.1.0",
3131
"bootstrap": "^4.4.1",
3232
"datatables.net": "^1.10.21",
3333
"datatables.net-buttons": "^1.6.2",
3434
"datatables.net-buttons-dt": "^1.6.2",
3535
"datatables.net-dt": "^1.10.21",
36+
"datatables.net-responsive": "^2.2.6",
37+
"datatables.net-responsive-dt": "^2.2.6",
3638
"jquery": "^3.5.1",
3739
"jszip": "^3.4.0",
3840
"minimist": "^1.2.5",

src/app/app-routing.module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { HomeComponent } from './modules/home/home.component';
1111
import { LoginComponent } from './modules/login/login.component';
1212
import { CustomerComponent } from './modules/customer-management/pages/customer.component';
1313
import { UsersComponent } from './modules/users/pages/users.component';
14+
import { TechnologyReportComponent } from './modules/technology-report/pages/technology-report.component';
15+
import { TechnologiesReportGuard } from './guards/technologies-report-guard/technologies-report.guard';
1416

1517
const routes: Routes = [
1618
{
@@ -24,6 +26,7 @@ const routes: Routes = [
2426
{ path: 'activities-management', component: ActivitiesManagementComponent },
2527
{ path: 'customers-management', canActivate: [AdminGuard], component: CustomerComponent },
2628
{ path: 'users', canActivate: [AdminGuard], component: UsersComponent },
29+
{ path: 'technology-report', canActivate: [AdminGuard, TechnologiesReportGuard], component: TechnologyReportComponent},
2730
{ path: '', pathMatch: 'full', redirectTo: 'time-clock' },
2831
],
2932
},

src/app/app.module.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
33
import { ToastrModule } from 'ngx-toastr';
44
import { CommonModule, DatePipe } from '@angular/common';
55
import { BrowserModule } from '@angular/platform-browser';
6-
import { NgModule } from '@angular/core';
6+
import { NgModule, Component } from '@angular/core';
77
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
88
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
99
import { DataTablesModule } from 'angular-datatables';
@@ -73,6 +73,9 @@ import { LoadingBarComponent } from './modules/shared/components/loading-bar/loa
7373
import { UsersComponent } from './modules/users/pages/users.component';
7474
import { UsersListComponent } from './modules/users/components/users-list/users-list.component';
7575
import {NgxMaterialTimepickerModule} from 'ngx-material-timepicker';
76+
// tslint:disable-next-line: max-line-length
77+
import { TechnologyReportTableComponent } from './modules/technology-report/components/technology-report-table/technology-report-table.component';
78+
import { TechnologyReportComponent } from './modules/technology-report/pages/technology-report.component';
7679

7780
const maskConfig: Partial<IConfig> = {
7881
validation: false,
@@ -122,7 +125,9 @@ const maskConfig: Partial<IConfig> = {
122125
DialogComponent,
123126
LoadingBarComponent,
124127
UsersComponent,
125-
UsersListComponent
128+
UsersListComponent,
129+
TechnologyReportComponent,
130+
TechnologyReportTableComponent,
126131
],
127132
imports: [
128133
NgxMaskModule.forRoot(maskConfig),
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { inject, TestBed } from '@angular/core/testing';
2+
import { Router } from '@angular/router';
3+
import { RouterTestingModule } from '@angular/router/testing';
4+
import { Observable, of } from 'rxjs';
5+
import { FeatureManagerService } from 'src/app/modules/shared/feature-toggles/feature-toggle-manager.service';
6+
import { TechnologiesReportGuard } from './technologies-report.guard';
7+
8+
describe('TechnologiesReportGuard', () => {
9+
10+
let technologiesReportGuard: TechnologiesReportGuard;
11+
let featureManagerService: FeatureManagerService;
12+
13+
beforeEach(() => {
14+
TestBed.configureTestingModule({
15+
imports: [ RouterTestingModule ]
16+
});
17+
technologiesReportGuard = TestBed.inject(TechnologiesReportGuard);
18+
featureManagerService = TestBed.inject(FeatureManagerService);
19+
});
20+
21+
it('should be created', () => {
22+
expect(technologiesReportGuard).toBeTruthy();
23+
});
24+
25+
it('can activate the route when feature is enabled for user', () => {
26+
spyOn(featureManagerService, 'isToggleEnabledForUser').and.returnValue(of(true));
27+
28+
const canActivate: Observable<boolean> = technologiesReportGuard.canActivate();
29+
30+
expect(featureManagerService.isToggleEnabledForUser).toHaveBeenCalled();
31+
canActivate.subscribe(value => expect(value).toEqual(true));
32+
});
33+
34+
it('can not active the route and is redirected to home if feature is not enabled for user', inject([Router], (router: Router) => {
35+
spyOn(featureManagerService, 'isToggleEnabledForUser').and.returnValue(of(false));
36+
spyOn(router, 'navigate').and.stub();
37+
38+
const canActivate: Observable<boolean> = technologiesReportGuard.canActivate();
39+
40+
expect(featureManagerService.isToggleEnabledForUser).toHaveBeenCalled();
41+
canActivate.subscribe(value => expect(value).toEqual(false));
42+
expect(router.navigate).toHaveBeenCalledWith(['']);
43+
}));
44+
45+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Injectable } from '@angular/core';
2+
import { Router, CanActivate } from '@angular/router';
3+
import { map } from 'rxjs/operators';
4+
import { FeatureManagerService } from 'src/app/modules/shared/feature-toggles/feature-toggle-manager.service';
5+
6+
@Injectable({
7+
providedIn: 'root'
8+
})
9+
export class TechnologiesReportGuard implements CanActivate {
10+
11+
constructor(
12+
private featureManagerService: FeatureManagerService,
13+
private router: Router
14+
) { }
15+
16+
canActivate() {
17+
return this.featureManagerService
18+
.isToggleEnabledForUser('ui-list-technologies')
19+
.pipe(map((enabled) => {
20+
if (enabled === true) {
21+
return true;
22+
} else {
23+
this.router.navigate(['']);
24+
return false;
25+
}
26+
}));
27+
}
28+
}

src/app/modules/reports/components/time-range-form/time-range-form.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ToastrService } from 'ngx-toastr';
22
import { formatDate } from '@angular/common';
33
import { Component, OnInit } from '@angular/core';
44
import { FormControl, FormGroup } from '@angular/forms';
5+
import { DATE_FORMAT } from 'src/environments/environment';
56
import * as entryActions from '../../../time-clock/store/entry.actions';
67
import {Store} from '@ngrx/store';
78
import {EntryState} from '../../../time-clock/store/entry.reducer';
@@ -28,8 +29,8 @@ export class TimeRangeFormComponent implements OnInit {
2829

2930
setInitialDataOnScreen() {
3031
this.reportForm.setValue({
31-
startDate: formatDate(moment().startOf('week').toString(), 'yyyy-MM-dd', 'en'),
32-
endDate: formatDate(moment().endOf('week').toString(), 'yyyy-MM-dd', 'en')
32+
startDate: formatDate(moment().startOf('week').toString(), DATE_FORMAT, 'en'),
33+
endDate: formatDate(moment().endOf('week').toString(), DATE_FORMAT, 'en')
3334
});
3435
this.onSubmit();
3536
}

src/app/modules/shared/components/details-fields/details-fields.component.spec.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import { ProjectSelectedEvent } from './project-selected-event';
2020
import { SaveEntryEvent } from './save-entry-event';
2121
import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker';
2222

23+
import { DATE_FORMAT } from 'src/environments/environment';
24+
import { DATE_FORMAT_YEAR } from 'src/environments/environment';
2325

2426
describe('DetailsFieldsComponent', () => {
2527
type Merged = TechnologyState & ProjectState & EntryState;
@@ -67,8 +69,8 @@ describe('DetailsFieldsComponent', () => {
6769
project_name: '',
6870
activity_id: '',
6971
uri: '',
70-
start_date: formatDate(new Date(), 'yyyy-MM-dd', 'en'),
71-
end_date: formatDate(new Date(), 'yyyy-MM-dd', 'en'),
72+
start_date: formatDate(new Date(), DATE_FORMAT, 'en'),
73+
end_date: formatDate(new Date(), DATE_FORMAT, 'en'),
7274
start_hour: '00:00',
7375
end_hour: '00:00',
7476
description: '',
@@ -179,8 +181,8 @@ describe('DetailsFieldsComponent', () => {
179181
project_name: '',
180182
activity_id: '',
181183
uri: '',
182-
start_date: formatDate(new Date(), 'yyyy-MM-dd', 'en'),
183-
end_date: formatDate(new Date(), 'yyyy-MM-dd', 'en'),
184+
start_date: formatDate(new Date(), DATE_FORMAT, 'en'),
185+
end_date: formatDate(new Date(), DATE_FORMAT, 'en'),
184186
start_hour: '00:00',
185187
end_hour: '00:00',
186188
description: '',
@@ -315,7 +317,7 @@ describe('DetailsFieldsComponent', () => {
315317
it('displays error message when the date selected is in the future', () => {
316318
spyOn(toastrServiceStub, 'error');
317319

318-
const futureDate = moment().add(1, 'days').format('YYYY-MM-DD');
320+
const futureDate = moment().add(1, 'days').format(DATE_FORMAT_YEAR);
319321
component.entryForm.setValue({ ...formValues, start_date: futureDate, end_date: futureDate });
320322
component.onSubmit();
321323

@@ -325,8 +327,8 @@ describe('DetailsFieldsComponent', () => {
325327
it('when start_date is in the future and end_date is OK then throws an error', () => {
326328
spyOn(toastrServiceStub, 'error');
327329

328-
const futureDate = moment().add(1, 'days').format('YYYY-MM-DD');
329-
const currentDate = moment().format('YYYY-MM-DD');
330+
const futureDate = moment().add(1, 'days').format(DATE_FORMAT_YEAR);
331+
const currentDate = moment().format(DATE_FORMAT_YEAR);
330332
component.entryForm.setValue({ ...formValues, start_date: futureDate, end_date: currentDate });
331333
component.onSubmit();
332334

@@ -336,8 +338,8 @@ describe('DetailsFieldsComponent', () => {
336338
it('when start_date is OK and end_date is in the future then throws an error future', () => {
337339
spyOn(toastrServiceStub, 'error');
338340

339-
const futureDate = moment().add(1, 'days').format('YYYY-MM-DD');
340-
const currentDate = moment().format('YYYY-MM-DD');
341+
const futureDate = moment().add(1, 'days').format(DATE_FORMAT_YEAR);
342+
const currentDate = moment().format(DATE_FORMAT_YEAR);
341343
component.entryForm.setValue({ ...formValues, start_date: currentDate, end_date: futureDate });
342344
component.onSubmit();
343345

0 commit comments

Comments
 (0)