diff --git a/karma.conf.js b/karma.conf.js index c2c379965..5760f0a99 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -5,21 +5,21 @@ module.exports = function (config) { config.set({ basePath: '', frameworks: ['jasmine', '@angular-devkit/build-angular'], - files: [ - 'node_modules/jquery/dist/jquery.js', - 'node_modules/datatables.net/js/jquery.dataTables.js', - ], + files: ['node_modules/jquery/dist/jquery.js', 'node_modules/datatables.net/js/jquery.dataTables.js'], plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), require('@angular-devkit/build-angular/plugins/karma'), require('karma-jasmine-html-reporter'), require('karma-spec-reporter'), - require('karma-coverage-istanbul-reporter') - + require('karma-coverage-istanbul-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, + jasmine: { + random: true, + seed: '90967', + }, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, './coverage/time-tracker'), @@ -29,8 +29,8 @@ module.exports = function (config) { statements: 80, lines: 80, branches: 80, - functions: 80 - } + functions: 80, + }, }, reporters: ['spec', 'kjhtml'], specReporter: { @@ -39,7 +39,7 @@ module.exports = function (config) { suppressFailed: false, suppressPassed: false, suppressSkipped: true, - showSpecTiming: false + showSpecTiming: false, }, port: 9876, @@ -48,6 +48,6 @@ module.exports = function (config) { autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + restartOnFileChange: true, }); }; diff --git a/package-lock.json b/package-lock.json index c92c5caf6..a533ce88d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "time-tracker", - "version": "1.45.1", + "version": "1.45.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6063,15 +6063,6 @@ "p-try": "^2.0.0" } }, - "serialize-javascript": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", - "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", @@ -7150,9 +7141,9 @@ } }, "ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", "dev": true } } @@ -18437,6 +18428,15 @@ } } }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -19858,9 +19858,9 @@ } }, "serialize-javascript": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", - "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -21088,9 +21088,9 @@ }, "dependencies": { "serialize-javascript": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", - "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -21725,9 +21725,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", "dev": true, "requires": { "async-limiter": "~1.0.0" diff --git a/package.json b/package.json index bb4c011e9..bfcdb1d05 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "time-tracker", - "version": "1.45.1", + "version": "1.45.3", "scripts": { "preinstall": "npx npm-force-resolutions", "ng": "ng", diff --git a/src/app/modules/shared/feature-toggles/filters/feature-filter-provider.service.ts b/src/app/modules/shared/feature-toggles/filters/feature-filter-provider.service.ts index 9b4f57bf6..0bebd97fb 100644 --- a/src/app/modules/shared/feature-toggles/filters/feature-filter-provider.service.ts +++ b/src/app/modules/shared/feature-toggles/filters/feature-filter-provider.service.ts @@ -6,23 +6,36 @@ import { FeatureFilterModel } from './feature-filter.model'; import { TargetingFilterParameters } from './targeting/targeting-feature-filter-parameters'; import { TargetingFeatureFilterModel } from './targeting/targeting-feature-filter.model'; - @Injectable({ providedIn: 'root', }) export class FeatureFilterProvider { - - constructor(private userService: AzureAdB2CService) { } + constructor(private userService: AzureAdB2CService) {} getFilterFromConfiguration(featureFilterConfiguration: FeatureFilterConfiguration): FeatureFilterModel { const featureName = featureFilterConfiguration.name; switch (featureName) { case FeatureFilterTypes.TARGETING: { + let username: string; + let group: string; + if (this.userService) { + try { + username = this.userService.getUserEmail(); + group = this.userService.getUserGroup(); + } catch (error) { + username = 'fakeuser@ioet.com'; + group = 'fake-group'; + } + } + const appContext = { - username: this.userService.getUserEmail(), - group: this.userService.getUserGroup() + username, + group, }; - const filter = new TargetingFeatureFilterModel(featureFilterConfiguration.parameters as TargetingFilterParameters, appContext); + const filter = new TargetingFeatureFilterModel( + featureFilterConfiguration.parameters as TargetingFilterParameters, + appContext + ); return filter; } default: { diff --git a/src/app/modules/time-entries/pages/time-entries.component.spec.ts b/src/app/modules/time-entries/pages/time-entries.component.spec.ts index 298db6cb5..c4cf0b699 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.spec.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.spec.ts @@ -455,4 +455,30 @@ describe('TimeEntriesComponent', () => { component.resetDraggablePosition(dragEndEventStub); expect(dragEndEventStub.source._dragRef.reset).toHaveBeenCalled(); }); + + it('component.doSave shouldn´t be called when saving the runningEntry with start_date overlapped', () => { + const startDate = new Date(2021, 6, 1, 10, 0); + const endDate = new Date(2021, 6, 1, 10, 55); + const newRunningEntry = { start_date: endDate, id: '1234', technologies: [], project_name: 'time-tracker', running: true }; + const newEntry = { start_date: startDate, end_date: endDate, id: '4321', technologies: [], project_name: 'time-tracker'}; + + state.timeEntriesDataSource.data = [newRunningEntry, newEntry]; + component.activeTimeEntry = newRunningEntry; + component.entryId = newRunningEntry.id; + spyOn(component, 'doSave'); + + const startDateModified = new Date(2021, 6, 1, 10, 50); + const RunningEntryModified = { + entry: { + start_date: startDateModified, + id: '1234', + technologies: ['py'], + project_name: 'time-tracker', + running: true + }, shouldRestartEntry: false + }; + component.saveEntry(RunningEntryModified); + + expect(component.doSave).toHaveBeenCalledTimes(0); + }); }); diff --git a/src/app/modules/time-entries/pages/time-entries.component.ts b/src/app/modules/time-entries/pages/time-entries.component.ts index b6799b99c..7c06b05fe 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.ts @@ -32,6 +32,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { selectedMonth: number; selectedYear: number; selectedMonthAsText: string; + isActiveEntryOverlapping = false; constructor(private store: Store, private toastrService: ToastrService, private actionsSubject$: ActionsSubject) { this.timeEntriesDataSource$ = this.store.pipe(delay(0), select(getTimeEntriesDataSource)); } @@ -104,8 +105,11 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { const isStartDateGreaterThanActiveEntry = startDateAsLocalDate > activeEntryAsLocalDate; const isEndDateGreaterThanActiveEntry = endDateAsLocalDate > activeEntryAsLocalDate; const isTimeEntryOverlapping = isStartDateGreaterThanActiveEntry || isEndDateGreaterThanActiveEntry; - if (!isEditingEntryEqualToActiveEntry && isTimeEntryOverlapping) { - this.toastrService.error('You are on the clock and this entry overlaps it, try with earlier times.'); + this.checkIfActiveEntryOverlapping(isEditingEntryEqualToActiveEntry, startDateAsLocalDate); + if (!isEditingEntryEqualToActiveEntry && isTimeEntryOverlapping || this.isActiveEntryOverlapping ) { + const message = this.isActiveEntryOverlapping ? 'try another "Time in"' : 'try with earlier times'; + this.toastrService.error(`You are on the clock and this entry overlaps it, ${message}.`); + this.isActiveEntryOverlapping = false; } else { this.doSave(event); } @@ -170,4 +174,16 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { resetDraggablePosition(event: any): void { event.source._dragRef.reset(); } + + checkIfActiveEntryOverlapping(isEditingEntryEqualToActiveEntry: boolean, startDateAsLocalDate: Date) { + if (isEditingEntryEqualToActiveEntry) { + this.store.pipe(select(getTimeEntriesDataSource)).subscribe(ds => { + const overlappingEntry = ds.data.find((item) => { + const itemEndDate = new Date(item.end_date); + return startDateAsLocalDate < itemEndDate; + }); + this.isActiveEntryOverlapping = overlappingEntry ? true : false; + }); + } + } }