diff --git a/.github/workflows/CD-time-tracker-ui.yml b/.github/workflows/CD-time-tracker-ui.yml index db0ed3d19..5934939b6 100644 --- a/.github/workflows/CD-time-tracker-ui.yml +++ b/.github/workflows/CD-time-tracker-ui.yml @@ -35,8 +35,8 @@ jobs: STACK_EXCHANGE_ACCESS_TOKEN: ${{ secrets.stack_exchange_access_token }} AZURE_APP_CONFIGURATION_CONNECTION_STRING: ${{ secrets.azure_app_configuration_connection_string }} run: | - chmod +x ./scripts/populate-keys.sh - sh ./scripts/populate-keys.sh + chmod +x ./scripts/populate-var-file.sh + sh ./scripts/populate-var-file.sh - name: 'run: npm install and build' run: | diff --git a/.github/workflows/CI-time-tracker-ui.yml b/.github/workflows/CI-time-tracker-ui.yml index da410589a..f63625e00 100644 --- a/.github/workflows/CI-time-tracker-ui.yml +++ b/.github/workflows/CI-time-tracker-ui.yml @@ -48,8 +48,8 @@ jobs: STACK_EXCHANGE_ACCESS_TOKEN: ${{ secrets.STACK_EXCHANGE_ACCESS_TOKEN }} AZURE_APP_CONFIGURATION_CONNECTION_STRING: ${{ secrets.AZURE_APP_CONFIGURATION_CONNECTION_STRING }} run: | - chmod +x ./scripts/populate-keys.sh - sh ./scripts/populate-keys.sh + chmod +x ./scripts/populate-var-file.sh + sh ./scripts/populate-var-file.sh - name: Running tests run: npm run ci-test --if-present diff --git a/Makefile b/Makefile index f465cfed1..98d231b11 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ cleanup: ## Delete image timetracker_ui .PHONY: run run: ## Execute timetracker_ui docker containe. - docker-compose --env-file ./.env up -d + docker-compose up -d .PHONY: logs logs: ## Show logs of timetracker_ui. @@ -40,12 +40,12 @@ remove: ## Delete container timetracker_ui. .PHONY: test test: ## Run all tests on docker container timetracker_ui at the CLI. - docker-compose -f docker-compose.yml --env-file ./.env up -d + docker-compose -f docker-compose.yml up -d docker exec timetracker_ui bash -c "npm run ci-test" .PHONY: testdev testdev: ## Run all tests on docker container timetracker_ui at the Dev - docker-compose -f docker-compose.yml -f docker-compose.dev.yml --env-file ./.env up -d + docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d docker exec timetracker_ui bash -c "npm run ci-test" .PHONY: publish diff --git a/package-lock.json b/package-lock.json index 3d2ad4cbb..f67310f61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "time-tracker", - "version": "1.72.1", + "version": "1.72.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6472,15 +6472,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", @@ -11939,9 +11930,9 @@ "dev": true }, "moment": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.25.3.tgz", - "integrity": "sha512-PuYv0PHxZvzc15Sp8ybUCoQ+xpyPWvjOuK72a5ovzp2LI32rJXOiIfyoFoYvG3s6EwwrdkMyWuRiEHSZRLJNdg==" + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", + "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==" }, "move-concurrently": { "version": "1.0.1", @@ -20539,7 +20530,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -21773,6 +21763,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", @@ -23603,9 +23602,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" @@ -24796,6 +24795,14 @@ "ajv-keywords": "^3.1.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==", + "requires": { + "randombytes": "^2.1.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -24831,9 +24838,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" diff --git a/package.json b/package.json index 396d1b3fe..8b4bc822c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "time-tracker", - "version": "1.72.1", + "version": "1.72.4", "scripts": { "config": "ts-node ./scripts/setenv.ts", "preinstall": "npx npm-force-resolutions", @@ -49,7 +49,7 @@ "jquery": "3.5.1", "jszip": "3.7.0", "minimist": "1.2.5", - "moment": "2.25.3", + "moment": "2.29.2", "msal": "1.2.1", "ngrx-store-localstorage": "11.0.0", "ngx-cookie-service": "11.0.2", diff --git a/scripts/populate-var-file.sh b/scripts/populate-var-file.sh new file mode 100644 index 000000000..f395689af --- /dev/null +++ b/scripts/populate-var-file.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +> src/environments/keys.ts +echo 'export const AUTHORITY = "'$AUTHORITY'";' >> src/environments/keys.ts +echo 'export const CLIENT_ID = "'$CLIENT_ID'";' >> src/environments/keys.ts +echo 'export const SCOPES = ["'$SCOPES'"];' >> src/environments/keys.ts +echo 'export const STACK_EXCHANGE_ID = "'$STACK_EXCHANGE_ID'";' >> src/environments/keys.ts +echo 'export const STACK_EXCHANGE_ACCESS_TOKEN = "'$STACK_EXCHANGE_ACCESS_TOKEN'";' >> src/environments/keys.ts +echo 'export const AZURE_APP_CONFIGURATION_CONNECTION_STRING = "'$AZURE_APP_CONFIGURATION_CONNECTION_STRING'";' >> src/environments/keys.ts +cat src/environments/keys.ts diff --git a/scripts/setenv.ts b/scripts/setenv.ts index 0c07a1b30..659a587b2 100644 --- a/scripts/setenv.ts +++ b/scripts/setenv.ts @@ -1,14 +1,13 @@ const { writeFile } = require('fs'); -require('dotenv').config(); const pathJs = `./src/environments/keys.ts` -const contentKeys = -`export const AUTHORITY = '${process.env.AUTHORITY}'; -export const CLIENT_ID = '${process.env.CLIENT_ID}'; -export const SCOPES = ['${process.env.SCOPES}']; -export const STACK_EXCHANGE_ID = '${process.env.STACK_EXCHANGE_ID}'; -export const STACK_EXCHANGE_ACCESS_TOKEN = '${process.env.STACK_EXCHANGE_ACCESS_TOKEN}'; -export const AZURE_APP_CONFIGURATION_CONNECTION_STRING = '${process.env.AZURE_APP_CONFIGURATION_CONNECTION_STRING}'; +const contentKeys = +`export const AUTHORITY = '${process.env["AUTHORITY"]}'; +export const CLIENT_ID = '${process.env["CLIENT_ID"]}'; +export const SCOPES = ['${process.env["SCOPES"]}']; +export const STACK_EXCHANGE_ID = '${process.env["STACK_EXCHANGE_ID"]}'; +export const STACK_EXCHANGE_ACCESS_TOKEN = '${process.env["STACK_EXCHANGE_ACCESS_TOKEN"]}'; +export const AZURE_APP_CONFIGURATION_CONNECTION_STRING = '${process.env["AZURE_APP_CONFIGURATION_CONNECTION_STRING"]}'; `; writeFile(pathJs, contentKeys, function (err) { @@ -19,7 +18,7 @@ writeFile(pathJs, contentKeys, function (err) { }); const pathJson = `./src/environments/.keys.json` -const contentKeysJson = +const contentKeysJson = `{ "authority": "${process.env.AUTHORITY_JSON}", "client_id": "${process.env.CLIENT_ID_JSON}", diff --git a/src/app/modules/reports/components/time-entries-table/time-entries-table.component.html b/src/app/modules/reports/components/time-entries-table/time-entries-table.component.html index 9b4880904..d3d548016 100644 --- a/src/app/modules/reports/components/time-entries-table/time-entries-table.component.html +++ b/src/app/modules/reports/components/time-entries-table/time-entries-table.component.html @@ -1,62 +1,57 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + +
IDUser emailDateDurationTime inTime outProjectProject IDCustomerCustomer IDActivityTicketDescriptionTechnologies
{{ entry.id }}{{ entry.owner_email }} - {{ entry.start_date | date: 'MM/dd/yyyy' }} - - {{ entry.end_date | substractDate: entry.start_date }} - {{ entry.start_date | date: 'HH:mm' }}{{ entry.end_date | date: 'HH:mm' }}{{ entry.project_name }}{{ entry.project_id }}{{ entry.customer_name }}{{ entry.customer_id }}{{ entry.activity_name }} - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - -
IDUser emailDateDurationTime inTime outProjectProject IDCustomerCustomer IDActivityTicketDescriptionTechnologies
{{ entry.id }}{{ entry.owner_email }} + {{ entry.start_date | date: 'MM/dd/yyyy' }} + + {{ entry.end_date | substractDate: entry.start_date }} + {{ dateTimeOffset.parseDateTimeOffset(entry.start_date,entry.timezone_offset) }}{{ dateTimeOffset.parseDateTimeOffset(entry.end_date , entry.timezone_offset) }}{{ entry.project_name }}{{ entry.project_id }}{{ entry.customer_name }}{{ entry.customer_id }}{{ entry.activity_name }} + + {{ entry.uri }} - - {{ entry.description }} - -
- {{ technology }} -
-
-
- +
+
{{ entry.description }} + +
+ {{ technology }} +
+
+
+
\ No newline at end of file diff --git a/src/app/modules/reports/components/time-entries-table/time-entries-table.component.ts b/src/app/modules/reports/components/time-entries-table/time-entries-table.component.ts index 5cb6f4988..04af82799 100644 --- a/src/app/modules/reports/components/time-entries-table/time-entries-table.component.ts +++ b/src/app/modules/reports/components/time-entries-table/time-entries-table.component.ts @@ -8,6 +8,7 @@ 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'; +import { ParseDateTimeOffset } from '../../../shared/formatters/parse-date-time-offset/parse-date-time-offset'; @Component({ selector: 'app-time-entries-table', @@ -60,9 +61,11 @@ export class TimeEntriesTableComponent implements OnInit, OnDestroy, AfterViewIn isLoading$: Observable; reportDataSource$: Observable>; rerenderTableSubscription: Subscription; + dateTimeOffset: ParseDateTimeOffset; constructor(private store: Store) { this.reportDataSource$ = this.store.pipe(select(getReportDataSource)); + this.dateTimeOffset = new ParseDateTimeOffset(); } ngOnInit(): void { diff --git a/src/app/modules/shared/formatters/parse-date-time-offset/parse-date-time-offset.spec.ts b/src/app/modules/shared/formatters/parse-date-time-offset/parse-date-time-offset.spec.ts new file mode 100644 index 000000000..93c567e64 --- /dev/null +++ b/src/app/modules/shared/formatters/parse-date-time-offset/parse-date-time-offset.spec.ts @@ -0,0 +1,23 @@ +import { ParseDateTimeOffset } from './parse-date-time-offset'; + +describe('ParseDateToUtcComponent', () => { + + it('returns converted date when his offset is 300', () => { + let parseTimeOffset = new ParseDateTimeOffset(); + const date = '2022-03-30T13:00:00Z'; + const timezone_offset = 300; + const dateOffset:string = '08:00'; + + expect(parseTimeOffset.parseDateTimeOffset(date, timezone_offset)).toEqual(dateOffset); + }); + + it('returns converted date when his offset is 420', () => { + let parseTimeOffset = new ParseDateTimeOffset(); + const date = '2022-03-30T16:30:00Z'; + const timezone_offset = 420; + const dateOffset:string = '09:30'; + + expect(parseTimeOffset.parseDateTimeOffset(date, timezone_offset)).toEqual(dateOffset); + }); + +}); diff --git a/src/app/modules/shared/formatters/parse-date-time-offset/parse-date-time-offset.ts b/src/app/modules/shared/formatters/parse-date-time-offset/parse-date-time-offset.ts new file mode 100644 index 000000000..b0f090a68 --- /dev/null +++ b/src/app/modules/shared/formatters/parse-date-time-offset/parse-date-time-offset.ts @@ -0,0 +1,8 @@ +import * as moment from 'moment'; + +export class ParseDateTimeOffset { + + parseDateTimeOffset(date:string, offset): string{ + return moment.utc(date).utcOffset(-1*offset).format("HH:mm"); + } +} diff --git a/src/app/modules/time-entries/pages/time-entries.component.html b/src/app/modules/time-entries/pages/time-entries.component.html index 5e44df0be..87f2da3c6 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.html +++ b/src/app/modules/time-entries/pages/time-entries.component.html @@ -1,135 +1,85 @@
-
- - -
-
- -
+
+
+ +
-
-
- - - +
+
+ + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - + + +
DateTime in - outDurationCustomerProjectActivity
{{ entry.start_date | date: 'MM/dd/yyyy' }}{{ entry.start_date | date: 'HH:mm' }} - {{ entry.end_date | date: 'HH:mm' }}{{ entry.end_date | substractDate: entry.start_date }}{{ entry.customer_name }}{{ entry.project_name }}{{ entry.activity_name }} -
+
- - + \ No newline at end of file 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 7bbbb794e..7c6e9d993 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.ts @@ -16,6 +16,8 @@ import { getActiveTimeEntry, getTimeEntriesDataSource } from './../../time-clock import { CookieService } from 'ngx-cookie-service'; import { FeatureToggle } from './../../../../environments/enum'; import { CalendarView } from 'angular-calendar'; +import { ParseDateTimeOffset } from '../../shared/formatters/parse-date-time-offset/parse-date-time-offset'; + @Component({ selector: 'app-time-entries', templateUrl: './time-entries.component.html', @@ -51,6 +53,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy, AfterViewInit { isActiveEntryOverlapping = false; calendarView: CalendarView = CalendarView.Month; actualDate: Date; + dateTimeOffset : ParseDateTimeOffset; constructor( private store: Store, private toastrService: ToastrService, @@ -60,6 +63,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy, AfterViewInit { this.selectedDate = moment(new Date()); this.actualDate = new Date(); this.timeEntriesDataSource$ = this.store.pipe(delay(0), select(getTimeEntriesDataSource)); + this.dateTimeOffset = new ParseDateTimeOffset(); } ngOnInit(): void {