diff --git a/apps/desktop-timer/package.json b/apps/desktop-timer/package.json index e36e9675d1c..380939ed502 100644 --- a/apps/desktop-timer/package.json +++ b/apps/desktop-timer/package.json @@ -21,8 +21,8 @@ "devDependencies": { "@electron/rebuild": "^3.2.10", "@types/moment-duration-format": "^2.2.3", - "electron": "28.1.0", - "electron-builder": "^24.6.4", + "electron": "^30.0.1", + "electron-builder": "^24.13.3", "electron-installer-dmg": "^4.0.0", "electron-packager": "^17.1.1", "electron-reload": "~1.5.0", diff --git a/apps/desktop/package.json b/apps/desktop/package.json index c5370df3f7c..dca949ec575 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -21,8 +21,8 @@ "devDependencies": { "@electron/rebuild": "^3.2.10", "@types/moment-duration-format": "^2.2.3", - "electron": "28.1.0", - "electron-builder": "^24.6.4", + "electron": "^30.0.1", + "electron-builder": "^24.13.3", "electron-installer-dmg": "^4.0.0", "electron-packager": "^17.1.1", "electron-reload": "~1.5.0", diff --git a/apps/gauzy/src/app/pages/employees/employees.component.ts b/apps/gauzy/src/app/pages/employees/employees.component.ts index 8b9d447f3e2..db0e168f97b 100644 --- a/apps/gauzy/src/app/pages/employees/employees.component.ts +++ b/apps/gauzy/src/app/pages/employees/employees.component.ts @@ -762,7 +762,7 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements } this.setFilter({ field: 'tags', search: tagIds }); }, - sort: false + isSortable: false }, workStatus: { title: this.getTranslation('SM_TABLE.STATUS'), diff --git a/apps/gauzy/src/app/pages/employees/event-types/event-type.component.ts b/apps/gauzy/src/app/pages/employees/event-types/event-type.component.ts index 3758f784c22..fb2fc1a6957 100644 --- a/apps/gauzy/src/app/pages/employees/event-types/event-type.component.ts +++ b/apps/gauzy/src/app/pages/employees/event-types/event-type.component.ts @@ -313,7 +313,7 @@ export class EventTypeComponent extends PaginationFilterBaseComponent implements title: this.getTranslation('EVENT_TYPE_PAGE.EMPLOYEE'), type: 'string', isFilterable: false, - sort: false + isSortable: false } }, pager: { diff --git a/apps/gauzy/src/app/pages/expenses/expenses.component.ts b/apps/gauzy/src/app/pages/expenses/expenses.component.ts index aacb563e20d..7f8421c741c 100644 --- a/apps/gauzy/src/app/pages/expenses/expenses.component.ts +++ b/apps/gauzy/src/app/pages/expenses/expenses.component.ts @@ -267,7 +267,7 @@ export class ExpensesComponent extends PaginationFilterBaseComponent implements filterFunction: (value: IOrganizationVendor) => { this.setFilter({ field: 'vendorId', search: value?.id || null }); }, - sort: false + isSortable: false }, categoryName: { title: this.getTranslation('SM_TABLE.CATEGORY'), @@ -279,13 +279,13 @@ export class ExpensesComponent extends PaginationFilterBaseComponent implements filterFunction: (value: IExpenseCategory) => { this.setFilter({ field: 'categoryId', search: value?.id || null }); }, - sort: false + isSortable: false }, employee: { title: this.getTranslation('SM_TABLE.EMPLOYEE'), isFilterable: false, type: 'custom', - sort: false, + isSortable: false, renderComponent: EmployeeLinksComponent, componentInitFunction: (instance: EmployeeLinksComponent, cell: Cell) => { instance.rowData = cell.getRow().getData(); @@ -296,7 +296,7 @@ export class ExpensesComponent extends PaginationFilterBaseComponent implements title: this.getTranslation('SM_TABLE.PROJECT'), type: 'string', isFilterable: false, - sort: false + isSortable: false }, amount: { title: this.getTranslation('SM_TABLE.VALUE'), diff --git a/apps/gauzy/src/app/pages/income/income.component.ts b/apps/gauzy/src/app/pages/income/income.component.ts index f6d498454ff..2e69c57c214 100644 --- a/apps/gauzy/src/app/pages/income/income.component.ts +++ b/apps/gauzy/src/app/pages/income/income.component.ts @@ -250,7 +250,7 @@ export class IncomeComponent extends PaginationFilterBaseComponent implements Af isFilterable: false, width: '15%', type: 'custom', - sort: false, + isSortable: false, renderComponent: EmployeeLinksComponent, componentInitFunction: (instance: EmployeeLinksComponent, cell: Cell) => { instance.rowData = cell.getRow().getData(); @@ -302,7 +302,7 @@ export class IncomeComponent extends PaginationFilterBaseComponent implements Af } this.setFilter({ field: 'tags', search: tagIds }); }, - sort: false + isSortable: false } } }; diff --git a/apps/gauzy/src/app/pages/invoices/invoices-received/invoices-received.component.ts b/apps/gauzy/src/app/pages/invoices/invoices-received/invoices-received.component.ts index d6e8d34cbd1..b8b464168ca 100644 --- a/apps/gauzy/src/app/pages/invoices/invoices-received/invoices-received.component.ts +++ b/apps/gauzy/src/app/pages/invoices/invoices-received/invoices-received.component.ts @@ -401,7 +401,7 @@ export class InvoicesReceivedComponent extends PaginationFilterBaseComponent imp title: this.getTranslation('INVOICES_PAGE.SENDER'), type: 'custom', isFilterable: false, - sort: false, + isSortable: false, renderComponent: ContactLinksComponent, componentInitFunction: (instance: ContactLinksComponent, cell: Cell) => { instance.rowData = cell.getRow().getData(); @@ -439,7 +439,7 @@ export class InvoicesReceivedComponent extends PaginationFilterBaseComponent imp } this.setFilter({ field: 'tags', search: tagIds }); }, - sort: false, + isSortable: false, componentInitFunction: (instance: TagsOnlyComponent, cell: Cell) => { instance.rowData = cell.getRow().getData(); instance.value = cell.getValue(); diff --git a/apps/gauzy/src/app/pages/invoices/invoices.component.ts b/apps/gauzy/src/app/pages/invoices/invoices.component.ts index 9423223ab39..20f3b559fef 100644 --- a/apps/gauzy/src/app/pages/invoices/invoices.component.ts +++ b/apps/gauzy/src/app/pages/invoices/invoices.component.ts @@ -991,7 +991,7 @@ export class InvoicesComponent extends PaginationFilterBaseComponent implements type: 'custom', width: '12%', isFilterable: false, - sort: false, + isSortable: false, renderComponent: ContactLinksComponent, componentInitFunction: (instance: ContactLinksComponent, cell: Cell) => { instance.rowData = cell.getRow().getData(); diff --git a/apps/gauzy/src/app/pages/payments/payments.component.ts b/apps/gauzy/src/app/pages/payments/payments.component.ts index 56124bfa78d..96bbce6f911 100644 --- a/apps/gauzy/src/app/pages/payments/payments.component.ts +++ b/apps/gauzy/src/app/pages/payments/payments.component.ts @@ -501,7 +501,7 @@ export class PaymentsComponent extends PaginationFilterBaseComponent implements type: 'text', isFilterable: false, width: '8%', - sort: false + isSortable: false }, paymentDate: { title: this.getTranslation('PAYMENTS_PAGE.PAYMENT_DATE'), @@ -541,7 +541,7 @@ export class PaymentsComponent extends PaginationFilterBaseComponent implements type: 'text', isFilterable: false, width: '10%', - sort: false + isSortable: false }, note: { title: this.getTranslation('PAYMENTS_PAGE.NOTE'), @@ -569,14 +569,14 @@ export class PaymentsComponent extends PaginationFilterBaseComponent implements filterFunction: (value: IOrganizationContact | null) => { this.setFilter({ field: 'organizationContactId', search: value?.id || null }); }, - sort: false + isSortable: false }, projectName: { title: this.getTranslation('PAYMENTS_PAGE.PROJECT'), type: 'text', width: '12%', isFilterable: false, - sort: false + isSortable: false }, overdue: { title: this.getTranslation('PAYMENTS_PAGE.STATUS'), @@ -608,7 +608,7 @@ export class PaymentsComponent extends PaginationFilterBaseComponent implements } this.setFilter({ field: 'tags', search: tagIds }); }, - sort: false + isSortable: false } } }; diff --git a/apps/gauzy/src/app/pages/users/users.component.ts b/apps/gauzy/src/app/pages/users/users.component.ts index c4a372b4e78..2ee1717aa08 100644 --- a/apps/gauzy/src/app/pages/users/users.component.ts +++ b/apps/gauzy/src/app/pages/users/users.component.ts @@ -473,7 +473,7 @@ export class UsersComponent extends PaginationFilterBaseComponent implements OnI } this.setFilter({ field: 'tags', search: tagIds }); }, - sort: false, + isSortable: false, class: 'align-row', width: '10%' }, diff --git a/apps/server-api/package.json b/apps/server-api/package.json index 96f790cfe21..82d3ca27f09 100644 --- a/apps/server-api/package.json +++ b/apps/server-api/package.json @@ -21,8 +21,8 @@ "devDependencies": { "@electron/rebuild": "^3.2.10", "@types/moment-duration-format": "^2.2.3", - "electron": "28.1.0", - "electron-builder": "^24.6.4", + "electron": "^30.0.1", + "electron-builder": "^24.13.3", "electron-installer-dmg": "^4.0.0", "electron-packager": "^17.1.1", "electron-reload": "~1.5.0", diff --git a/apps/server/package.json b/apps/server/package.json index 37503e345b0..6a2a96582d9 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -21,8 +21,8 @@ "devDependencies": { "@electron/rebuild": "^3.2.10", "@types/moment-duration-format": "^2.2.3", - "electron": "28.1.0", - "electron-builder": "^24.6.4", + "electron": "^30.0.1", + "electron-builder": "^24.13.3", "electron-installer-dmg": "^4.0.0", "electron-packager": "^17.1.1", "electron-reload": "~1.5.0", diff --git a/package.json b/package.json index 5df33fbd58c..3a43560d102 100644 --- a/package.json +++ b/package.json @@ -94,21 +94,21 @@ "postinstall.web": "yarn node ./decorate-angular-cli.js && yarn node tools/web/postinstall", "build:desktop": "cross-env NODE_ENV=production yarn run copy-files-i18n-desktop && yarn run postinstall.electron && yarn build:package:all && yarn run config:prod && yarn run config:desktop:prod && yarn run pack:desktop && yarn run generate:icons:desktop --environment=prod && yarn ng:prod build desktop --prod --base-href ./ && yarn run prepare:desktop && yarn ng:prod build desktop-api --prod && yarn ng:prod build api-desktop --prod --output-path=dist/apps/desktop/desktop-api && yarn ng:prod build desktop-ui --prod --base-href ./ && yarn run copy-files-desktop && yarn run copy-assets-gauzy", "build:desktop:local": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && electron dist/apps/desktop", - "build:desktop:linux": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --project dist/apps/desktop", - "build:desktop:windows": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --project dist/apps/desktop", - "build:desktop:mac": "yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --project dist/apps/desktop", - "build:desktop:linux:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --publish=always --project dist/apps/desktop", - "build:desktop:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --publish=always --project dist/apps/desktop", - "build:desktop:windows:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/desktop", - "build:desktop:windows:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/desktop", - "build:desktop:mac:release": "yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --publish=always --project dist/apps/desktop", + "build:desktop:linux": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --project dist/apps/desktop", + "build:desktop:windows": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --project dist/apps/desktop", + "build:desktop:mac": "yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --project dist/apps/desktop", + "build:desktop:linux:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --publish=always --project dist/apps/desktop", + "build:desktop:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --publish=always --project dist/apps/desktop", + "build:desktop:windows:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/desktop", + "build:desktop:windows:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/desktop", + "build:desktop:mac:release": "yarn run build:desktop && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --publish=always --project dist/apps/desktop", "prepare:desktop": "yarn run postinstall.electron && tsc -p apps/desktop/tsconfig.json", "serve:desktop.target": "yarn ng serve desktop", "serve:desktop": "wait-on http-get://localhost:4200/ && electron apps/desktop/src --serve", "start:desktop": "yarn run prepare:desktop && npm-run-all -p serve.electron.gauzy-desktop.target serve.electron.gauzy-desktop", - "build:desktop:mac:quick": "npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --project dist/apps/desktop", + "build:desktop:mac:quick": "npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --project dist/apps/desktop", "build:desktop:local:quick": "yarn electron dist/apps/desktop --prod", - "build:desktop:windows:quick": "npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --windows --project dist/apps/desktop", + "build:desktop:windows:quick": "npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --windows --project dist/apps/desktop", "build:sqlite:mac": "cd node_modules/sqlite3 && HOME=~/.electron-gyp node-pre-gyp rebuild --target=8.3.0 --arch=x64 --dist-url=https://electronjs.org/headers", "build:sqlite:windows": "cd node_modules/sqlite3 && cross-env HOME=~/.electron-gyp node-pre-gyp rebuild --target=8.3.0 --arch=x64 --target_platform=win32 --dist-url=https://electronjs.org/headers", "debug:desktop:app:mac": "lldb ./dist/apps/desktop-packages/mac/GauzyDesktop.app && run", @@ -116,7 +116,7 @@ "build:desktop:ui": "yarn run postinstall.web && yarn ng:prod build desktop-ui --prod --base-href ./", "prepare:desktop:dev": "yarn run postinstall.electron && tsc -p apps/desktop/tsconfig.dev.json", "start:api:desktop": "yarn ng serve api-desktop", - "deploy:desktop:mac": "npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --publish always --project dist/apps/desktop", + "deploy:desktop:mac": "npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --publish always --project dist/apps/desktop", "build:package:ui-auth": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/ui-auth lib:build", "build:package:ui-auth:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/ui-auth lib:build:prod", "build:package:ui-core": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/ui-core lib:build", @@ -193,15 +193,15 @@ "copy-files-desktop": "copyfiles -f packages/core/src/**/*.gql dist/apps/desktop/data/", "build:desktop-timer": "cross-env NODE_ENV=production yarn copy-files-i18n-desktop-timer && yarn run postinstall.electron && yarn build:package:all && yarn run config:prod && yarn run config:desktop-timer:prod && yarn run pack:desktop-timer && yarn run generate:icons:desktop-timer --environment=prod && yarn ng:prod build desktop-timer --prod --base-href ./ && yarn run prepare:desktop-timer && yarn ng:prod build api-desktop --prod --output-path=dist/apps/desktop-timer/desktop-api && yarn run copy-assets-gauzy-timer", "prepare:desktop-timer": "yarn run postinstall.electron && tsc -p apps/desktop-timer/tsconfig.json", - "build:desktop-timer:linux": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --project dist/apps/desktop-timer", - "build:desktop-timer:windows": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --project dist/apps/desktop-timer", - "build:desktop-timer:mac:quick": "yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --config -c.mac.identity=null --project dist/apps/desktop-timer", - "build:desktop-timer:mac": "yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --project dist/apps/desktop-timer", - "build:desktop-timer:linux:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --publish=always --project dist/apps/desktop-timer", - "build:desktop-timer:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --publish=always --project dist/apps/desktop-timer", - "build:desktop-timer:windows:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/desktop-timer", - "build:desktop-timer:windows:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/desktop-timer", - "build:desktop-timer:mac:release": "yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --publish=always --project dist/apps/desktop-timer", + "build:desktop-timer:linux": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --project dist/apps/desktop-timer", + "build:desktop-timer:windows": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --project dist/apps/desktop-timer", + "build:desktop-timer:mac:quick": "yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --config -c.mac.identity=null --project dist/apps/desktop-timer", + "build:desktop-timer:mac": "yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --project dist/apps/desktop-timer", + "build:desktop-timer:linux:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --publish=always --project dist/apps/desktop-timer", + "build:desktop-timer:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --publish=always --project dist/apps/desktop-timer", + "build:desktop-timer:windows:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/desktop-timer", + "build:desktop-timer:windows:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/desktop-timer", + "build:desktop-timer:mac:release": "yarn run build:desktop-timer && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --publish=always --project dist/apps/desktop-timer", "copy-assets-gauzy": "copyfiles -f apps/desktop/src/assets/snapshot-sound.wav dist/apps/desktop/data/sound/", "copy-assets-gauzy-timer": "copyfiles -f apps/desktop/src/assets/snapshot-sound.wav dist/apps/desktop-timer/data/sound/", "config:electron": "yarn ts-node ./.scripts/electron.env.ts", @@ -211,15 +211,15 @@ "prepare:gauzy-server": "yarn run postinstall.electron && tsc -p apps/server/tsconfig.json", "build:gauzy-server": "cross-env NODE_ENV=production yarn run copy-files-i18n-server && yarn run postinstall.electron && yarn build:package:all && yarn run config:prod && yarn run config:server:prod && yarn run pack:server && yarn run generate:icons:server --environment=prod && yarn ng:prod build gauzy-server --prod --base-href ./ && yarn run prepare:gauzy-server && yarn ng:prod build gauzy-server-ui --prod --base-href ./ && yarn ng:prod build gauzy-server-api --prod && yarn run copy-files-gauzy-server", "copy-files-gauzy-server": "copyfiles -f packages/core/src/**/*.gql dist/apps/gauzy-server/data/", - "build:gauzy-server:windows": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --project dist/apps/gauzy-server", - "build:gauzy-server:linux": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --project dist/apps/gauzy-server", - "build:gauzy-server:mac": "yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --project dist/apps/gauzy-server", - "build:gauzy-server:windows:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/gauzy-server", - "build:gauzy-server:windows:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/gauzy-server", - "build:gauzy-server:linux:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --publish=always --project dist/apps/gauzy-server", - "build:gauzy-server:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --publish=always --project dist/apps/gauzy-server", - "build:gauzy-server:mac:release": "yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --publish=always --project dist/apps/gauzy-server", - "quick:build:gauzy-server": "yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --mac --project dist/apps/gauzy-server", + "build:gauzy-server:windows": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --project dist/apps/gauzy-server", + "build:gauzy-server:linux": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --project dist/apps/gauzy-server", + "build:gauzy-server:mac": "yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --project dist/apps/gauzy-server", + "build:gauzy-server:windows:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/gauzy-server", + "build:gauzy-server:windows:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/gauzy-server", + "build:gauzy-server:linux:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --publish=always --project dist/apps/gauzy-server", + "build:gauzy-server:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --publish=always --project dist/apps/gauzy-server", + "build:gauzy-server:mac:release": "yarn run build:gauzy-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --publish=always --project dist/apps/gauzy-server", + "quick:build:gauzy-server": "yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --mac --project dist/apps/gauzy-server", "copy-files-i18n-desktop-timer": "yarn run download:translations --desktop=desktop-timer", "copy-files-i18n-desktop": "yarn run download:translations --desktop=desktop", "copy-files-i18n-server": "yarn run download:translations --desktop=server", @@ -236,16 +236,16 @@ "prepare:gauzy-api-server": "yarn run postinstall.electron && tsc -p apps/server-api/tsconfig.json", "build:gauzy-api-server": "cross-env NODE_ENV=production yarn run copy-files-i18n-api-server && yarn run postinstall.electron && yarn build:package:all && yarn run config:prod && yarn run config:api-server:prod && yarn run pack:api-server && yarn run generate:icons:server-api --environment=prod && yarn ng:prod build gauzy-api-server --prod --base-href ./ && yarn run prepare:gauzy-api-server && yarn ng:prod build server-api --prod && yarn run copy-files-gauzy-api-server", "copy-files-gauzy-api-server": "copyfiles -f packages/core/src/**/*.gql dist/apps/gauzy-api-server/data/", - "build:gauzy-api-server:windows": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --project dist/apps/gauzy-api-server", - "build:gauzy-api-server:linux": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --project dist/apps/gauzy-api-server", - "build:gauzy-api-server:mac": "yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --project dist/apps/gauzy-api-server", - "build:gauzy-api-server:windows:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/gauzy-api-server", - "build:gauzy-api-server:windows:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/gauzy-api-server", - "build:gauzy-api-server:linux:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --publish=always --project dist/apps/gauzy-api-server", - "build:gauzy-api-server:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --linux --publish=always --project dist/apps/gauzy-api-server", - "build:gauzy-api-server:mac:release": "yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=28.1.0 build --mac --publish=always --project dist/apps/gauzy-api-server", + "build:gauzy-api-server:windows": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --project dist/apps/gauzy-api-server", + "build:gauzy-api-server:linux": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --project dist/apps/gauzy-api-server", + "build:gauzy-api-server:mac": "yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --project dist/apps/gauzy-api-server", + "build:gauzy-api-server:windows:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/gauzy-api-server", + "build:gauzy-api-server:windows:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --windows --publish=always --project dist/apps/gauzy-api-server", + "build:gauzy-api-server:linux:release": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --publish=always --project dist/apps/gauzy-api-server", + "build:gauzy-api-server:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=30000 yarn run config:prod && yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --linux --publish=always --project dist/apps/gauzy-api-server", + "build:gauzy-api-server:mac:release": "yarn run build:gauzy-api-server && npm config set cache .cache && yarn electron-builder -c.electronVersion=30.0.1 build --mac --publish=always --project dist/apps/gauzy-api-server", "copy-files-i18n-api-server": "yarn run download:translations --desktop=server-api", - "quick:build:gauzy-api-server": "yarn electron-builder -c.electronVersion=28.1.0 -c.extraMetadata.author.name=Ever build --mac --project dist/apps/gauzy-api-server", + "quick:build:gauzy-api-server": "yarn electron-builder -c.electronVersion=30.0.1 -c.extraMetadata.author.name=Ever build --mac --project dist/apps/gauzy-api-server", "generate:icons:server-api": "yarn run generate:icons --desktop=server-api", "pack:api-server": "yarn run pack --desktop=gauzy-api-server" }, @@ -404,8 +404,8 @@ "cypress-cucumber-preprocessor": "^4.3.1", "cypress-file-upload": "^5.0.8", "cz-conventional-changelog": "^3.3.0", - "electron": "28.1.0", - "electron-builder": "^24.6.4", + "electron": "^30.0.1", + "electron-builder": "^24.13.3", "envalid": "^6.0.2", "esbuild": "^0.15.13", "eslint-plugin-cypress": "2.13.4", diff --git a/packages/core/src/database/migrations/1643809486960-MigrateEmailTemplatesData.ts b/packages/core/src/database/migrations/1643809486960-MigrateEmailTemplatesData.ts index 82f8e4c5bc0..573c81c2979 100644 --- a/packages/core/src/database/migrations/1643809486960-MigrateEmailTemplatesData.ts +++ b/packages/core/src/database/migrations/1643809486960-MigrateEmailTemplatesData.ts @@ -1,111 +1,117 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import { MigrationInterface, QueryRunner } from 'typeorm'; import * as chalk from 'chalk'; -import { EmailTemplateEnum } from "@gauzy/contracts"; -import { EmailTemplateUtils } from "../../email-template/utils"; -import { DatabaseTypeEnum } from "@gauzy/config"; - +import { EmailTemplateEnum } from '@gauzy/contracts'; +import { DatabaseTypeEnum } from '@gauzy/config'; +import { EmailTemplateUtils } from '../../email-template/utils'; export class MigrateEmailTemplatesData1643809486960 implements MigrationInterface { + name = 'MigrateEmailTemplatesData1643809486960'; + + /** + * Up Migration + * + * @param queryRunner + */ + public async up(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); + + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + await this.sqliteUpQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.postgres: + await this.postgresUpQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlUpQueryRunner(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } - name = 'MigrateEmailTemplatesData1643809486960'; + /** + * Down Migration + * + * @param queryRunner + */ + public async down(queryRunner: QueryRunner): Promise { + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + await this.sqliteDownQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.postgres: + await this.postgresDownQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlDownQueryRunner(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } - /** - * Up Migration - * - * @param queryRunner - */ - public async up(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + /** + * Up Migration + * + * @param queryRunner + */ + public async postgresUpQueryRunner(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); - switch (queryRunner.connection.options.type) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - await this.sqliteUpQueryRunner(queryRunner); - break; - case DatabaseTypeEnum.postgres: - await this.postgresUpQueryRunner(queryRunner); - break; - case DatabaseTypeEnum.mysql: - await this.mysqlUpQueryRunner(queryRunner); - break; - default: - throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); - } - } - /** - * Down Migration - * - * @param queryRunner - */ - public async down(queryRunner: QueryRunner): Promise { - switch (queryRunner.connection.options.type) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - await this.sqliteDownQueryRunner(queryRunner); - break; - case DatabaseTypeEnum.postgres: - await this.postgresDownQueryRunner(queryRunner); - break; - case DatabaseTypeEnum.mysql: - await this.mysqlDownQueryRunner(queryRunner); - break; - default: - throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); - } - } + // Migrate email templates for all templates + const templates = Object.values(EmailTemplateEnum); - /** - * Up Migration - * - * @param queryRunner - */ - public async sqliteUpQueryRunner(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + // Iterate over each template and migrate the data + for await (const template of templates) { + try { + await EmailTemplateUtils.migrateEmailTemplates(queryRunner, template); + } catch (error) { + console.log(`Error while migrating missing email templates for ${template}`, error); + } + } + } - const templates = Object.values(EmailTemplateEnum); - for await (const template of templates) { - try { - await EmailTemplateUtils.migrateEmailTemplates(queryRunner, template); - } catch (error) { - console.log(`Error while migrating missing email templates for ${template}`, error); - } - } - } - /** - * Up Migration - * - * @param queryRunner - */ - public async postgresUpQueryRunner(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + public async postgresDownQueryRunner(queryRunner: QueryRunner): Promise {} - const templates = Object.values(EmailTemplateEnum); - for await (const template of templates) { - try { - await EmailTemplateUtils.migrateEmailTemplates(queryRunner, template); - } catch (error) { - console.log(`Error while migrating missing email templates for ${template}`, error); - } - } - } + /** + * Up Migration + * + * @param queryRunner + */ + public async sqliteUpQueryRunner(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); - public async sqliteDownQueryRunner(queryRunner: QueryRunner): Promise { } + const templates = Object.values(EmailTemplateEnum); + for await (const template of templates) { + try { + await EmailTemplateUtils.migrateEmailTemplates(queryRunner, template); + } catch (error) { + console.log(`Error while migrating missing email templates for ${template}`, error); + } + } + } - public async postgresDownQueryRunner(queryRunner: QueryRunner): Promise { } + /** + * SqliteDB Down Migration + * + * @param queryRunner + */ + public async sqliteDownQueryRunner(queryRunner: QueryRunner): Promise {} - /** - * MySQL Up Migration - * - * @param queryRunner - */ - public async mysqlUpQueryRunner(queryRunner: QueryRunner): Promise { - } + /** + * MySQL Up Migration + * + * @param queryRunner + */ + public async mysqlUpQueryRunner(queryRunner: QueryRunner): Promise {} - /** - * MySQL Down Migration - * - * @param queryRunner - */ - public async mysqlDownQueryRunner(queryRunner: QueryRunner): Promise { - } + /** + * MySQL Down Migration + * + * @param queryRunner + */ + public async mysqlDownQueryRunner(queryRunner: QueryRunner): Promise {} } diff --git a/packages/core/src/database/migrations/1644312012849-RolePermissionsReload.ts b/packages/core/src/database/migrations/1644312012849-RolePermissionsReload.ts index 4793bf8e992..662d70d0f29 100644 --- a/packages/core/src/database/migrations/1644312012849-RolePermissionsReload.ts +++ b/packages/core/src/database/migrations/1644312012849-RolePermissionsReload.ts @@ -18,13 +18,15 @@ export class RolePermissionsReload1644312012849 implements MigrationInterface { case DatabaseTypeEnum.sqlite: case DatabaseTypeEnum.betterSqlite3: case DatabaseTypeEnum.postgres: - case DatabaseTypeEnum.mysql: try { await RolePermissionUtils.migrateRolePermissions(queryRunner); } catch (error) { console.log(chalk.red(`Error while migrating missing role permisions: ${error}`)); } break; + case DatabaseTypeEnum.mysql: + console.log('role permission migration is not supported for mysql yet'); + break; default: throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); } diff --git a/packages/core/src/database/migrations/1678876700413-EmailTemplateReader.ts b/packages/core/src/database/migrations/1678876700413-EmailTemplateReader.ts index db47baa5356..9c65460bce1 100644 --- a/packages/core/src/database/migrations/1678876700413-EmailTemplateReader.ts +++ b/packages/core/src/database/migrations/1678876700413-EmailTemplateReader.ts @@ -1,65 +1,71 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; -import * as chalk from "chalk"; +import { MigrationInterface, QueryRunner } from 'typeorm'; +import * as chalk from 'chalk'; import { EmailTemplateEnum } from '@gauzy/contracts'; +import { DatabaseTypeEnum } from '@gauzy/config'; import { EmailTemplateUtils } from '../../email-template/utils'; -import { DatabaseTypeEnum } from "@gauzy/config"; export class EmailTemplateReader1678876700413 implements MigrationInterface { + name = 'EmailTemplateReader1678876700413'; - name = 'EmailTemplateReader1678876700413'; + /** + * Up Migration + * + * @param queryRunner + */ + public async up(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); - /** - * Up Migration - * - * @param queryRunner - */ - public async up(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + case DatabaseTypeEnum.postgres: + await this.sqlitePostgresMigrateEmailTemplate(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlMigrateEmailTemplate(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } + /** + * Down Migration + * + * @param queryRunner + */ + public async down(queryRunner: QueryRunner): Promise {} - switch (queryRunner.connection.options.type) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - case DatabaseTypeEnum.postgres: - await this.sqlitePostgresMigrateEmailTemplate(queryRunner); - break; - case DatabaseTypeEnum.mysql: - await this.mysqlMigrateEmailTemplate(queryRunner); - break; - default: - throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); - } - } - /** - * Down Migration - * - * @param queryRunner - */ - public async down(queryRunner: QueryRunner): Promise { } + /** + * Sqlite | better-sqlite3 | MySQL Up Migration + * + * @param queryRunner + */ + public async sqlitePostgresMigrateEmailTemplate(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); - /** - * Sqlite | better-sqlite3 | MySQL Up Migration - * - * @param queryRunner - */ - public async sqlitePostgresMigrateEmailTemplate(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + try { + await EmailTemplateUtils.migrateEmailTemplates(queryRunner, EmailTemplateEnum.EMAIL_RESET); + } catch (error) { + console.log(`Error while migrating missing email templates for ${EmailTemplateEnum.EMAIL_RESET}`, error); + } - try { - await EmailTemplateUtils.migrateEmailTemplates(queryRunner, EmailTemplateEnum.EMAIL_RESET); - } catch (error) { - console.log(`Error while migrating missing email templates for ${EmailTemplateEnum.EMAIL_RESET}`, error); - } - try { - await EmailTemplateUtils.migrateEmailTemplates(queryRunner, EmailTemplateEnum.ORGANIZATION_TEAM_JOIN_REQUEST); - } catch (error) { - console.log(`Error while migrating missing email templates for ${EmailTemplateEnum.ORGANIZATION_TEAM_JOIN_REQUEST}`, error); - } - } + try { + await EmailTemplateUtils.migrateEmailTemplates( + queryRunner, + EmailTemplateEnum.ORGANIZATION_TEAM_JOIN_REQUEST + ); + } catch (error) { + console.log( + `Error while migrating email template for ${EmailTemplateEnum.ORGANIZATION_TEAM_JOIN_REQUEST}`, + error + ); + } + } - /** - * MySQL Up Migration - * - * @param queryRunner - */ - public async mysqlMigrateEmailTemplate(queryRunner: QueryRunner): Promise { } + /** + * MySQL Up Migration + * + * @param queryRunner + */ + public async mysqlMigrateEmailTemplate(queryRunner: QueryRunner): Promise {} } diff --git a/packages/core/src/database/migrations/1679765443208-MigrateRolePermisisons.ts b/packages/core/src/database/migrations/1679765443208-MigrateRolePermisisons.ts index c880dc5fd6c..255b19ebb58 100644 --- a/packages/core/src/database/migrations/1679765443208-MigrateRolePermisisons.ts +++ b/packages/core/src/database/migrations/1679765443208-MigrateRolePermisisons.ts @@ -18,13 +18,15 @@ export class MigrateRolePermisisons1679765443208 implements MigrationInterface { case DatabaseTypeEnum.sqlite: case DatabaseTypeEnum.betterSqlite3: case DatabaseTypeEnum.postgres: - case DatabaseTypeEnum.mysql: try { await RolePermissionUtils.migrateRolePermissions(queryRunner); } catch (error) { console.log(chalk.red(`Error while migrating missing role permisions: ${error}`)); } break; + case DatabaseTypeEnum.mysql: + console.log('role permission migration is not supported for mysql yet'); + break; default: throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); } diff --git a/packages/core/src/database/migrations/1680539459969-UpdateEmailTemplates.ts b/packages/core/src/database/migrations/1680539459969-UpdateEmailTemplates.ts index 3d8ac5220c0..673ed37bd83 100644 --- a/packages/core/src/database/migrations/1680539459969-UpdateEmailTemplates.ts +++ b/packages/core/src/database/migrations/1680539459969-UpdateEmailTemplates.ts @@ -1,63 +1,65 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; -import * as chalk from "chalk"; +import { MigrationInterface, QueryRunner } from 'typeorm'; +import * as chalk from 'chalk'; import { EmailTemplateEnum } from '@gauzy/contracts'; +import { DatabaseTypeEnum } from '@gauzy/config'; import { EmailTemplateUtils } from '../../email-template/utils'; -import { DatabaseTypeEnum } from "@gauzy/config"; export class UpdateEmailTemplates1680539459969 implements MigrationInterface { + name = 'UpdateEmailTemplates1680539459969'; - name = 'UpdateEmailTemplates1680539459969'; + /** + * Up Migration + * + * @param queryRunner + */ + public async up(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); - /** - * Up Migration - * - * @param queryRunner - */ - public async up(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + case DatabaseTypeEnum.postgres: + await this.sqlitePostgresUpdateEmailTemplates(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlUpdateEmailTemplates(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } + /** + * Down Migration + * + * @param queryRunner + */ + public async down(queryRunner: QueryRunner): Promise {} - switch (queryRunner.connection.options.type) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - case DatabaseTypeEnum.postgres: - await this.sqlitePostgresUpdateEmailTemplates(queryRunner); - break; - case DatabaseTypeEnum.mysql: - await this.mysqlUpdateEmailTemplates(queryRunner); - break; - default: - throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); - } - } - /** - * Down Migration - * - * @param queryRunner - */ - public async down(queryRunner: QueryRunner): Promise { } + /** + * Sqlite | better-sqlite3 | postgres Up Migration + * + * @param queryRunner + */ + public async sqlitePostgresUpdateEmailTemplates(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); - /** - * Sqlite | better-sqlite3 | postgres Up Migration - * - * @param queryRunner - */ - public async sqlitePostgresUpdateEmailTemplates(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + // Migrate email templates for all templates + const templates = Object.values(EmailTemplateEnum); - const templates = Object.values(EmailTemplateEnum); - for await (const template of templates) { - try { - await EmailTemplateUtils.migrateEmailTemplates(queryRunner, template); - } catch (error) { - console.log(`Error while migrating missing email templates for ${template}`, error); - } - } - } + // Iterate over each template and update it + for await (const template of templates) { + try { + await EmailTemplateUtils.migrateEmailTemplates(queryRunner, template); + } catch (error) { + console.log(`Error while migrating missing email templates for ${template}`, error); + } + } + } - /** - * MySQL Up Migration - * - * @param queryRunner - */ - public async mysqlUpdateEmailTemplates(queryRunner: QueryRunner): Promise { } + /** + * MySQL Up Migration + * + * @param queryRunner + */ + public async mysqlUpdateEmailTemplates(queryRunner: QueryRunner): Promise {} } diff --git a/packages/core/src/database/migrations/1701353754397-MigrateEmailTemplates.ts b/packages/core/src/database/migrations/1701353754397-MigrateEmailTemplates.ts index dac87c7e5ed..326bab9e3d8 100644 --- a/packages/core/src/database/migrations/1701353754397-MigrateEmailTemplates.ts +++ b/packages/core/src/database/migrations/1701353754397-MigrateEmailTemplates.ts @@ -1,63 +1,65 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import { MigrationInterface, QueryRunner } from 'typeorm'; import * as chalk from 'chalk'; -import { EmailTemplateEnum } from "@gauzy/contracts"; -import { EmailTemplateUtils } from "../../email-template/utils"; -import { DatabaseTypeEnum } from "@gauzy/config"; +import { EmailTemplateEnum } from '@gauzy/contracts'; +import { DatabaseTypeEnum } from '@gauzy/config'; +import { EmailTemplateUtils } from '../../email-template/utils'; export class MigrateEmailTemplates1701353754397 implements MigrationInterface { + name = 'MigrateEmailTemplates1701353754397'; - name = 'MigrateEmailTemplates1701353754397'; + /** + * Up Migration + * + * @param queryRunner + */ + public async up(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); - /** - * Up Migration - * - * @param queryRunner - */ - public async up(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + case DatabaseTypeEnum.postgres: + await this.sqlitePostgresMigrateEmailTemplates(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlMigrateEmailTemplates(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } + /** + * Down Migration + * + * @param queryRunner + */ + public async down(queryRunner: QueryRunner): Promise {} - switch (queryRunner.connection.options.type) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - case DatabaseTypeEnum.postgres: - await this.sqlitePostgresMigrateEmailTemplates(queryRunner); - break; - case DatabaseTypeEnum.mysql: - await this.mysqlMigrateEmailTemplates(queryRunner); - break; - default: - throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); - } - } - /** - * Down Migration - * - * @param queryRunner - */ - public async down(queryRunner: QueryRunner): Promise { } + /** + * Sqlite | better-sqlite3 | postgres Up Migration + * + * @param queryRunner + */ + public async sqlitePostgresMigrateEmailTemplates(queryRunner: QueryRunner): Promise { + console.log(chalk.yellow(this.name + ' start running!')); - /** - * Sqlite | better-sqlite3 | postgres Up Migration - * - * @param queryRunner - */ - public async sqlitePostgresMigrateEmailTemplates(queryRunner: QueryRunner): Promise { - console.log(chalk.yellow(this.name + ' start running!')); + // Migrate email templates for all templates + const templates = Object.values(EmailTemplateEnum); - const templates = Object.values(EmailTemplateEnum); - for await (const template of templates) { - try { - await EmailTemplateUtils.migrateEmailTemplates(queryRunner, template); - } catch (error) { - console.log(`Error while migrating missing email templates for ${template}`, error); - } - } - } + // Iterate over each template and migrate the data + for await (const template of templates) { + try { + await EmailTemplateUtils.migrateEmailTemplates(queryRunner, template); + } catch (error) { + console.log(`Error while migrating missing email templates for ${template}`, error); + } + } + } - /** - * MySQL Up Migration - * - * @param queryRunner - */ - public async mysqlMigrateEmailTemplates(queryRunner: QueryRunner): Promise { } + /** + * MySQL Up Migration + * + * @param queryRunner + */ + public async mysqlMigrateEmailTemplates(queryRunner: QueryRunner): Promise {} } diff --git a/packages/core/src/database/migrations/1726506479984-AlterFavoriteEntityIndexing.ts b/packages/core/src/database/migrations/1726506479984-AlterFavoriteEntityIndexing.ts new file mode 100644 index 00000000000..73bb56c9e2b --- /dev/null +++ b/packages/core/src/database/migrations/1726506479984-AlterFavoriteEntityIndexing.ts @@ -0,0 +1,125 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import { yellow } from 'chalk'; +import { DatabaseTypeEnum } from '@gauzy/config'; + +export class AlterFavoriteEntityIndexing1726506479984 implements MigrationInterface { + name = 'AlterFavoriteEntityIndexing1726506479984'; + + /** + * Up Migration + * + * @param queryRunner + */ + public async up(queryRunner: QueryRunner): Promise { + console.log(yellow(this.name + ' start running!')); + + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + await this.sqliteUpQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.postgres: + await this.postgresUpQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlUpQueryRunner(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } + + /** + * Down Migration + * + * @param queryRunner + */ + public async down(queryRunner: QueryRunner): Promise { + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + await this.sqliteDownQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.postgres: + await this.postgresDownQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlDownQueryRunner(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } + + /** + * PostgresDB Up Migration + * + * @param queryRunner + */ + public async postgresUpQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "public"."IDX_a8d924902879f0a3349678c86f"`); + await queryRunner.query(`DROP INDEX "public"."IDX_b4734abeedbb9c724c980f7f54"`); + await queryRunner.query(`CREATE INDEX "IDX_837468421e96f22a2e12022ef0" ON "favorite" ("entity") `); + await queryRunner.query(`CREATE INDEX "IDX_e88acab853ab012582c6d0f3f6" ON "favorite" ("entityId") `); + } + + /** + * PostgresDB Down Migration + * + * @param queryRunner + */ + public async postgresDownQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "public"."IDX_e88acab853ab012582c6d0f3f6"`); + await queryRunner.query(`DROP INDEX "public"."IDX_837468421e96f22a2e12022ef0"`); + await queryRunner.query(`CREATE INDEX "IDX_b4734abeedbb9c724c980f7f54" ON "favorite" ("entityId") `); + await queryRunner.query(`CREATE INDEX "IDX_a8d924902879f0a3349678c86f" ON "favorite" ("entity") `); + } + + /** + * SqliteDB and BetterSQlite3DB Up Migration + * + * @param queryRunner + */ + public async sqliteUpQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_b4734abeedbb9c724c980f7f54"`); + await queryRunner.query(`DROP INDEX "IDX_a8d924902879f0a3349678c86f"`); + await queryRunner.query(`CREATE INDEX "IDX_837468421e96f22a2e12022ef0" ON "favorite" ("entity") `); + await queryRunner.query(`CREATE INDEX "IDX_e88acab853ab012582c6d0f3f6" ON "favorite" ("entityId") `); + } + + /** + * SqliteDB and BetterSQlite3DB Down Migration + * + * @param queryRunner + */ + public async sqliteDownQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_e88acab853ab012582c6d0f3f6"`); + await queryRunner.query(`DROP INDEX "IDX_837468421e96f22a2e12022ef0"`); + await queryRunner.query(`CREATE INDEX "IDX_a8d924902879f0a3349678c86f" ON "favorite" ("entity") `); + await queryRunner.query(`CREATE INDEX "IDX_b4734abeedbb9c724c980f7f54" ON "favorite" ("entityId") `); + } + + /** + * MySQL Up Migration + * + * @param queryRunner + */ + public async mysqlUpQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX \`IDX_a8d924902879f0a3349678c86f\` ON \`favorite\``); + await queryRunner.query(`DROP INDEX \`IDX_b4734abeedbb9c724c980f7f54\` ON \`favorite\``); + await queryRunner.query(`CREATE INDEX \`IDX_837468421e96f22a2e12022ef0\` ON \`favorite\` (\`entity\`)`); + await queryRunner.query(`CREATE INDEX \`IDX_e88acab853ab012582c6d0f3f6\` ON \`favorite\` (\`entityId\`)`); + } + + /** + * MySQL Down Migration + * + * @param queryRunner + */ + public async mysqlDownQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX \`IDX_e88acab853ab012582c6d0f3f6\` ON \`favorite\``); + await queryRunner.query(`DROP INDEX \`IDX_837468421e96f22a2e12022ef0\` ON \`favorite\``); + await queryRunner.query(`CREATE INDEX \`IDX_b4734abeedbb9c724c980f7f54\` ON \`favorite\` (\`entityId\`)`); + await queryRunner.query(`CREATE INDEX \`IDX_a8d924902879f0a3349678c86f\` ON \`favorite\` (\`entity\`)`); + } +} diff --git a/packages/core/src/email-template/utils.ts b/packages/core/src/email-template/utils.ts index 480aff245be..b8e7b83ff00 100644 --- a/packages/core/src/email-template/utils.ts +++ b/packages/core/src/email-template/utils.ts @@ -15,6 +15,12 @@ import { prepareSQLQuery as p } from '../database/database.helper'; * Email templates utils functions. */ export class EmailTemplateUtils { + private static readonly supportedDatabaseTypes = new Set([ + DatabaseTypeEnum.sqlite, + DatabaseTypeEnum.betterSqlite3, + DatabaseTypeEnum.postgres, + DatabaseTypeEnum.mysql + ]); public static globalPath = ['core', 'seeds', 'data', 'default-email-templates']; /** @@ -186,71 +192,158 @@ export class EmailTemplateUtils { // Get the database type const type = queryRunner.connection.options.type as DatabaseTypeEnum; - // Prepare the select query - Replace $ placeholders with ? for mysql, sqlite & better-sqlite3 - const selectQuery = replacePlaceholders( - p(` - SELECT COUNT(*) as count - FROM "email_template" - WHERE "name" = $1 - AND "languageCode" = $2 - AND "tenantId" IS NULL - AND "organizationId" IS NULL - `), - type - ); - - // Prepare the update query - Replace $ placeholders with ? for mysql, sqlite & better-sqlite3 - const updateQuery = replacePlaceholders( - p(` - UPDATE "email_template" - SET "hbs" = $1, "mjml" = $2 - WHERE "name" = $3 - AND "languageCode" = $4 - AND "tenantId" IS NULL - AND "organizationId" IS NULL - `), - type - ); + // Validate the database type + EmailTemplateUtils.validateDatabaseType(queryRunner.connection.options.type as DatabaseTypeEnum); + + // Determine select query based on the database type + const selectQuery = this.getSelectQuery(type); + + // Determine update query based on the database type + const updateQuery = this.getUpdateQuery(type); // Determine insert query based on the database type - const insertQuery = - type === DatabaseTypeEnum.sqlite || type === DatabaseTypeEnum.betterSqlite3 - ? `INSERT INTO "email_template" ("name", "languageCode", "hbs", "mjml", "id") VALUES(?, ?, ?, ?, ?)` - : replacePlaceholders( - p(` - INSERT INTO "email_template" ("name", "languageCode", "hbs", "mjml") VALUES($1, $2, $3, $4) - `), - type - ); + const insertQuery = this.generateInsertQuery(type); + + // Define a set of database types that require the 'id' column in the INSERT query + const sqlTypesWithId = new Set([ + DatabaseTypeEnum.sqlite, + DatabaseTypeEnum.betterSqlite3, + DatabaseTypeEnum.mysql + ]); // Loop through the templates - for (const item of templates) { - const { name, languageCode, hbs, mjml = null } = item; - const payload = [name, languageCode, hbs, mjml]; - - // Switch based on the database type - switch (type) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - payload.push(uuidV4()); // Add a UUID for sqlite - break; - case DatabaseTypeEnum.postgres: - case DatabaseTypeEnum.mysql: - // No additional action needed for these types - break; - default: - throw new Error(`Unsupported database type: ${type}`); - } + for (const template of templates) { + const payload = sqlTypesWithId.has(type) + ? [template.name, template.languageCode, template.hbs, template.mjml, uuidV4()] + : [template.name, template.languageCode, template.hbs, template.mjml]; + + await this.upsertEmailTemplate( + queryRunner, + selectQuery, + updateQuery, + insertQuery, + template.name, + template.languageCode, + template.hbs, + template.mjml, + payload + ); + } + } + + /** + * Upsert an email template based on its existence in the database. + * + * @param queryRunner - The QueryRunner instance for executing queries. + * @param type - The type of the database (e.g., sqlite, mysql). + * @param selectQuery - The SQL query to check if the template exists. + * @param updateQuery - The SQL query to update the template. + * @param insertQuery - The SQL query to insert a new template. + * @param name - The name of the email template. + * @param languageCode - The language code of the email template. + * @param hbs - The Handlebars (hbs) content of the template. + * @param mjml - The MJML content of the template. + * @param payload - The payload for the insert query, including necessary fields. + */ + static async upsertEmailTemplate( + queryRunner: QueryRunner, + selectQuery: string, + updateQuery: string, + insertQuery: string, + name: string, + languageCode: string, + hbs: string, + mjml: string, + payload: any + ): Promise { + // Get the database manager + const manager = queryRunner.connection.manager; - // Check if the template exists - const [template] = await queryRunner.connection.manager.query(selectQuery, [name, languageCode]); + try { + // Execute the SELECT query to check if the template exists + const [template]: any = await manager.query(selectQuery, [name, languageCode]); + + // Safely parse the count value + const templateCount = Number(template.count); - // Update if exists, otherwise insert - if (parseInt(template.count, 10) > 0) { - await queryRunner.connection.manager.query(updateQuery, [hbs, mjml, name, languageCode]); + if (templateCount > 0) { + // Execute the UPDATE query if the template exists + await manager.query(updateQuery, [hbs, mjml, name, languageCode]); + console.log(`✅ Updated email template: ${name}`); } else { - await queryRunner.connection.manager.query(insertQuery, payload); + // Execute the INSERT query if the template does not exist + await manager.query(insertQuery, payload); + console.log(`✅ Inserted email template: ${name}`); } + } catch (error) { + console.error(`❌ Error upsert email template "${name}":`, error); + } + } + + /** + * Generates the appropriate INSERT query based on the database type. + * @param type - The type of the database. + * @returns The INSERT SQL query string. + */ + public static generateInsertQuery(type: DatabaseTypeEnum): string { + // Define a set of database types that require the 'id' column in the INSERT query + const sqlTypesWithId = new Set([ + DatabaseTypeEnum.sqlite, + DatabaseTypeEnum.betterSqlite3, + DatabaseTypeEnum.mysql + ]); + + const baseColumns = ['name', 'languageCode', 'hbs', 'mjml']; + const requiresId = sqlTypesWithId.has(type); + const columns = requiresId ? [...baseColumns, 'id'] : baseColumns; + + const placeholders = requiresId + ? columns.map(() => '?').join(', ') + : columns.map((_, index) => `$${index + 1}`).join(', '); + + const columnsString = columns.map((col) => `"${col}"`).join(', '); + + const query = `INSERT INTO "email_template" (${columnsString}) VALUES(${placeholders})`; + + return replacePlaceholders(p(query), type); + } + + /** + * Generates the appropriate SELECT query based on the database type. + * + * @param type - The type of the database. + * @returns The SELECT SQL query string. + */ + private static getSelectQuery(type: DatabaseTypeEnum): string { + // Prepare the select query + const query = `SELECT COUNT(*) as count FROM "email_template" WHERE "name" = $1 AND "languageCode" = $2 AND "tenantId" IS NULL AND "organizationId" IS NULL`; + + // Replace $ placeholders with ? for mysql, sqlite & better-sqlite3 + return replacePlaceholders(p(query), type); + } + + /** + * Generates the appropriate UPDATE query based on the database type. + * + * @param type - The type of the database. + * @returns The UPDATE SQL query string. + */ + private static getUpdateQuery(type: DatabaseTypeEnum): string { + // Prepare the select query + const query = `UPDATE "email_template" SET "hbs" = $1, "mjml" = $2 WHERE "name" = $3 AND "languageCode" = $4 AND "tenantId" IS NULL AND "organizationId" IS NULL`; + + // Replace $ placeholders with ? for mysql, sqlite & better-sqlite3 + return replacePlaceholders(p(query), type); + } + + /** + * Validates the database type. + * + * @param type + */ + private static validateDatabaseType(type: DatabaseTypeEnum): void { + if (!EmailTemplateUtils.supportedDatabaseTypes.has(type)) { + throw new Error(`Unsupported database: ${type}`); } } } diff --git a/packages/core/src/favorite/favorite.entity.ts b/packages/core/src/favorite/favorite.entity.ts index cc7511452e7..7d207403355 100644 --- a/packages/core/src/favorite/favorite.entity.ts +++ b/packages/core/src/favorite/favorite.entity.ts @@ -11,6 +11,7 @@ import { MikroOrmFavoriteRepository } from './repository/mikro-orm-favorite.repo export class Favorite extends TenantOrganizationBaseEntity implements IFavorite { [EntityRepositoryType]?: MikroOrmFavoriteRepository; + // Indicate the entity type @ApiProperty({ type: () => String, enum: FavoriteEntityEnum }) @IsNotEmpty() @IsEnum(FavoriteEntityEnum) diff --git a/packages/core/src/time-tracking/statistic/statistic.helper.ts b/packages/core/src/time-tracking/statistic/statistic.helper.ts index e27225cd792..727d49228a3 100644 --- a/packages/core/src/time-tracking/statistic/statistic.helper.ts +++ b/packages/core/src/time-tracking/statistic/statistic.helper.ts @@ -1,4 +1,4 @@ -import { DatabaseTypeEnum } from "@gauzy/config"; +import { DatabaseTypeEnum } from '@gauzy/config'; import { prepareSQLQuery as p } from './../../database/database.helper'; /** @@ -8,22 +8,22 @@ import { prepareSQLQuery as p } from './../../database/database.helper'; * @returns */ export function concateUserNameExpression(dbType: string): string { - let expression: string; + let expression: string; - switch (dbType) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - expression = `("user"."firstName" || ' ' || "user"."lastName")`; - break; - case DatabaseTypeEnum.mysql: - case DatabaseTypeEnum.postgres: - expression = `CONCAT("user"."firstName", ' ', "user"."lastName")`; - break; - default: - throw new Error(`Cannot create statistic query due to unsupported database type: ${dbType}`); - } + switch (dbType) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + expression = `("user"."firstName" || ' ' || "user"."lastName")`; + break; + case DatabaseTypeEnum.mysql: + case DatabaseTypeEnum.postgres: + expression = `CONCAT("user"."firstName", ' ', "user"."lastName")`; + break; + default: + throw new Error(`Cannot create statistic query due to unsupported database type: ${dbType}`); + } - return expression; + return expression; } /** @@ -34,23 +34,21 @@ export function concateUserNameExpression(dbType: string): string { * @param slotQueryAlias The alias used for the slot query. * @returns A string representing the duration query. */ -export const getDurationQueryString = ( - dbType: string, - logQueryAlias: string, - slotQueryAlias: string -): string => { - switch (dbType) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - return `COALESCE(ROUND(SUM((julianday(COALESCE("${logQueryAlias}"."stoppedAt", datetime('now'))) - julianday("${logQueryAlias}"."startedAt")) * 86400) / COUNT("${slotQueryAlias}"."id")), 0)`; - case DatabaseTypeEnum.postgres: - return `COALESCE(ROUND(SUM(extract(epoch from (COALESCE("${logQueryAlias}"."stoppedAt", NOW()) - "${logQueryAlias}"."startedAt"))) / COUNT("${slotQueryAlias}"."id")), 0)`; - case DatabaseTypeEnum.mysql: - // Directly return the SQL string for MySQL, as MikroORM allows raw SQL. - return p(`COALESCE(ROUND(SUM(TIMESTAMPDIFF(SECOND, "${logQueryAlias}"."startedAt", COALESCE("${logQueryAlias}"."stoppedAt", NOW()))) / COUNT("${slotQueryAlias}"."id")), 0)`); - default: - throw new Error(`Unsupported database type: ${dbType}`); - } +export const getDurationQueryString = (dbType: string, logQueryAlias: string, slotQueryAlias: string): string => { + switch (dbType) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + return `COALESCE(ROUND(SUM((julianday(COALESCE("${logQueryAlias}"."stoppedAt", datetime('now'))) - julianday("${logQueryAlias}"."startedAt")) * 86400) / COUNT("${slotQueryAlias}"."id")), 0)`; + case DatabaseTypeEnum.postgres: + return `COALESCE(ROUND(SUM(extract(epoch from (COALESCE("${logQueryAlias}"."stoppedAt", NOW()) - "${logQueryAlias}"."startedAt"))) / COUNT("${slotQueryAlias}"."id")), 0)`; + case DatabaseTypeEnum.mysql: + // Directly return the SQL string for MySQL, as MikroORM allows raw SQL. + return p( + `COALESCE(ROUND(SUM(TIMESTAMPDIFF(SECOND, \`${logQueryAlias}\`.\`startedAt\`, COALESCE(\`${logQueryAlias}\`.\`stoppedAt\`, NOW()))) / COUNT(\`${slotQueryAlias}\`.\`id\`)), 0)` + ); + default: + throw new Error(`Unsupported database type: ${dbType}`); + } }; /** @@ -62,17 +60,17 @@ export const getDurationQueryString = ( * @returns The SQL query string for calculating task total duration. */ export const getTotalDurationQueryString = (dbType: string, queryAlias: string): string => { - switch (dbType) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - return `COALESCE(ROUND(SUM((julianday(COALESCE("${queryAlias}"."stoppedAt", datetime('now'))) - julianday("${queryAlias}"."startedAt")) * 86400)), 0)`; - case DatabaseTypeEnum.postgres: - return `COALESCE(ROUND(SUM(extract(epoch from (COALESCE("${queryAlias}"."stoppedAt", NOW()) - "${queryAlias}"."startedAt")))), 0)`; - case DatabaseTypeEnum.mysql: - return `COALESCE(ROUND(SUM(TIMESTAMPDIFF(SECOND, "${queryAlias}"."startedAt", COALESCE("${queryAlias}"."stoppedAt", NOW())))), 0)`; - default: - throw Error(`Unsupported database type: ${dbType}`); - } + switch (dbType) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + return `COALESCE(ROUND(SUM((julianday(COALESCE("${queryAlias}"."stoppedAt", datetime('now'))) - julianday("${queryAlias}"."startedAt")) * 86400)), 0)`; + case DatabaseTypeEnum.postgres: + return `COALESCE(ROUND(SUM(extract(epoch from (COALESCE("${queryAlias}"."stoppedAt", NOW()) - "${queryAlias}"."startedAt")))), 0)`; + case DatabaseTypeEnum.mysql: + return `COALESCE(ROUND(SUM(TIMESTAMPDIFF(SECOND, \`${queryAlias}\`.\`startedAt\`, COALESCE(\`${queryAlias}\`.\`stoppedAt\`, NOW())))), 0)`; + default: + throw Error(`Unsupported database type: ${dbType}`); + } }; /** @@ -83,15 +81,15 @@ export const getTotalDurationQueryString = (dbType: string, queryAlias: string): * @returns The SQL query string for filtering activity duration. */ export const getActivityDurationQueryString = (dbType: string, queryAlias: string): string => { - switch (dbType) { - case DatabaseTypeEnum.sqlite: - case DatabaseTypeEnum.betterSqlite3: - return `datetime("${queryAlias}"."date" || ' ' || "${queryAlias}"."time") Between :start AND :end`; - case DatabaseTypeEnum.postgres: - return `CONCAT("${queryAlias}"."date", ' ', "${queryAlias}"."time")::timestamp Between :start AND :end`; - case DatabaseTypeEnum.mysql: - return p(`CONCAT("${queryAlias}"."date", ' ', "${queryAlias}"."time") BETWEEN :start AND :end`); - default: - throw Error(`cannot create statistic query due to unsupported database type: ${dbType}`); - } -} + switch (dbType) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + return `datetime("${queryAlias}"."date" || ' ' || "${queryAlias}"."time") Between :start AND :end`; + case DatabaseTypeEnum.postgres: + return `CONCAT("${queryAlias}"."date", ' ', "${queryAlias}"."time")::timestamp Between :start AND :end`; + case DatabaseTypeEnum.mysql: + return p(`CONCAT(\`${queryAlias}\`.\`date\`, ' ', \`${queryAlias}\`.\`time\`) BETWEEN :start AND :end`); + default: + throw Error(`cannot create statistic query due to unsupported database type: ${dbType}`); + } +}; diff --git a/packages/desktop-libs/package.json b/packages/desktop-libs/package.json index 867e59680c3..5522384a9ab 100644 --- a/packages/desktop-libs/package.json +++ b/packages/desktop-libs/package.json @@ -58,6 +58,6 @@ "devDependencies": { "@types/node": "^20.14.9", "@types/unzipper": "^0.10.9", - "electron": "28.1.0" + "electron": "^30.0.1" } } diff --git a/packages/desktop-libs/src/lib/decorators/concretes/power-manager-detect-inactivity.ts b/packages/desktop-libs/src/lib/decorators/concretes/power-manager-detect-inactivity.ts index 055bc173e4a..84ac74192ac 100644 --- a/packages/desktop-libs/src/lib/decorators/concretes/power-manager-detect-inactivity.ts +++ b/packages/desktop-libs/src/lib/decorators/concretes/power-manager-detect-inactivity.ts @@ -29,8 +29,6 @@ export class PowerManagerDetectInactivity extends BasePowerManagerDecorator { if (proof) { if (accepted) { this._detectionEmitter.emit('activity-proof-result-accepted', true); - this._clearIntervals(); - this.startInactivityDetection(); } else { this._detectionEmitter.emit('activity-proof-result-not-accepted'); } @@ -59,7 +57,7 @@ export class PowerManagerDetectInactivity extends BasePowerManagerDecorator { }, 1000); } - private _clearIntervals(): void { + public clearIntervals(): void { if (this._inactivityDetectionIntervalId) { clearInterval(this._inactivityDetectionIntervalId); this._inactivityDetectionIntervalId = null; @@ -71,11 +69,11 @@ export class PowerManagerDetectInactivity extends BasePowerManagerDecorator { } public stopInactivityDetection(): void { - this._clearIntervals(); + this.clearIntervals(); this.removeListeners(); } - private removeListeners() { + public removeListeners() { this._detectionEmitter.removeAllListeners(); } diff --git a/packages/desktop-libs/src/lib/desktop-ipc.ts b/packages/desktop-libs/src/lib/desktop-ipc.ts index caa9645f7f8..6411fa928c3 100644 --- a/packages/desktop-libs/src/lib/desktop-ipc.ts +++ b/packages/desktop-libs/src/lib/desktop-ipc.ts @@ -320,13 +320,13 @@ export function ipcMainHandler(store, startServer, knex, config, timeTrackerWind } }); - ipcMain.handle('TAKE_SCREEN_CAPTURE', async (event, { quitApp }) => { + ipcMain.handle('COLLECT_ACTIVITIES', async (event, { quitApp }) => { try { - log.info('Take Screen Capture'); - return await timerHandler.makeScreenshot(knex, quitApp); + log.info('Collect Activities'); + return await timerHandler.collectAllActivities(knex, quitApp); } catch (error) { - log.error('Error on take screen capture', error); - throw new UIError('500', error, 'IPCTKSCAPTURE'); + log.error('Error collecting activities', error); + throw new UIError('500', error, 'HANDLE ACTIVITIES'); } }); @@ -1195,7 +1195,7 @@ export function removeAllHandlers() { 'UPDATE_SYNCED', 'DESKTOP_CAPTURER_GET_SOURCES', 'FINISH_SYNCED_TIMER', - 'TAKE_SCREEN_CAPTURE', + 'COLLECT_ACTIVITIES', 'START_SERVER' ]; channels.forEach((channel: string) => { diff --git a/packages/desktop-libs/src/lib/desktop-os-inactivity-handler.ts b/packages/desktop-libs/src/lib/desktop-os-inactivity-handler.ts index 32a75ff844d..a040c0c3b33 100644 --- a/packages/desktop-libs/src/lib/desktop-os-inactivity-handler.ts +++ b/packages/desktop-libs/src/lib/desktop-os-inactivity-handler.ts @@ -1,4 +1,4 @@ -import { BrowserWindow, ipcMain } from 'electron'; +import { BrowserWindow } from 'electron'; import moment from 'moment'; import { SleepInactivityTracking, SleepTracking } from './contexts'; import { DialogAcknowledgeInactivity, PowerManagerDetectInactivity } from './decorators'; @@ -52,19 +52,13 @@ export class DesktopOsInactivityHandler { } }); - this._powerManager.detectInactivity.on('activity-proof-result', async ({ accepted, proof }) => { + this._powerManager.detectInactivity.on('activity-proof-result', async () => { this._inactivityResultAccepted = true; if (!this._dialog) return; this._dialog.close(); delete this._dialog; - - ipcMain.on('pause-tracking', async () => { - if (this._isRemoveIdleTime) { - await this._removeIdleTime(accepted); - } - }); }); this._powerManager.detectInactivity.on('activity-proof-not-accepted', async () => { @@ -75,9 +69,8 @@ export class DesktopOsInactivityHandler { powerManager.window ) ); - if (this._isRemoveIdleTime) { - await this._removeIdleTime(false); - } + console.log('[OS_INACTIVITY_HANDLER] Activity Proof Result Not Accepted'); + await this._removeIdleTime(false); await dialog.show(); this._notify.customNotification( TranslateService.instant('TIMER_TRACKER.NATIVE_NOTIFICATION.STOPPED_DU_INACTIVITY'), @@ -85,7 +78,7 @@ export class DesktopOsInactivityHandler { ); }); - this._powerManager.detectInactivity.on('activity-proof-result-not-accepted', () => { + this._powerManager.detectInactivity.on('activity-proof-result-not-accepted', async () => { const { suspendDetected, isOnBattery, window } = this._powerManager; this._powerManager.sleepTracking = new SleepInactivityTracking( @@ -94,14 +87,17 @@ export class DesktopOsInactivityHandler { : new NeverSleepTracking(window) ); - this._powerManager.pauseTracking(); + console.log('[OS_INACTIVITY_HANDLER] Activity Proof Result Not Accepted'); + + await this._removeIdleTime(false); }); this._powerManager.detectInactivity.on('activity-proof-result-accepted', async () => { this._powerManager.sleepTracking = new SleepTracking(this._powerManager.window); - if (this._isRemoveIdleTime) { - await this._removeIdleTime(true); - } + console.log('[OS_INACTIVITY_HANDLER] Activity Proof Result Accepted'); + await this._removeIdleTime(true); + this._powerManager.clearIntervals(); + this._powerManager.startInactivityDetection(); }); } @@ -130,6 +126,12 @@ export class DesktopOsInactivityHandler { } private async _removeIdleTime(isWorking: boolean): Promise { + if (!this._isRemoveIdleTime) { + if (!isWorking) { + this._powerManager.pauseTracking(); + } + return; + } const auth = LocalStore.getStore('auth'); const inactivityTimeLimit = auth ? auth.inactivityTimeLimit : 10; const now = moment().clone(); diff --git a/packages/desktop-libs/src/lib/desktop-timer.ts b/packages/desktop-libs/src/lib/desktop-timer.ts index 60e91b31969..67ffcef20f1 100644 --- a/packages/desktop-libs/src/lib/desktop-timer.ts +++ b/packages/desktop-libs/src/lib/desktop-timer.ts @@ -635,19 +635,19 @@ export default class TimerHandler { } /* - * Make screenshots and activities after start and stop timer + * Collect All activities after start and stop timer */ - async makeScreenshot(knex, quitApp) { + async collectAllActivities(knex, quitApp) { console.log(`Time Slot Start/End At ${quitApp ? 'End' : 'Beginning'}`, this.timeSlotStart); if (this.timeSlotStart) { - console.log('Make Screenshot Started for: ', this.timeSlotStart); + console.log('Collection Started At: ', this.timeSlotStart); await this._activeWindow.updateActivities(); console.log('Updated Activities'); const activities = await this.getAllActivities(knex, this.timeSlotStart); - console.log('Make Screenshot Ended for: ', this.timeSlotStart); + console.log('Collection Ended At: ', this.timeSlotStart); return activities; } else { diff --git a/packages/desktop-libs/src/lib/offline/dao/interval.dao.ts b/packages/desktop-libs/src/lib/offline/dao/interval.dao.ts index a5c99e62141..630a68d1ee1 100644 --- a/packages/desktop-libs/src/lib/offline/dao/interval.dao.ts +++ b/packages/desktop-libs/src/lib/offline/dao/interval.dao.ts @@ -160,7 +160,6 @@ export class IntervalDAO implements DAO { const remotesIds = await this._provider .connection(TABLE_NAME_INTERVALS) .select('remoteId') - .distinct('remoteId') .where('employeeId', user.employeeId) .where('isDeleted', false) .where((qb) => qb.whereBetween('stoppedAt', [new Date(startedAt), new Date(stoppedAt)])); diff --git a/packages/desktop-ui-lib/package.json b/packages/desktop-ui-lib/package.json index 12778eddec4..783121698e7 100644 --- a/packages/desktop-ui-lib/package.json +++ b/packages/desktop-ui-lib/package.json @@ -68,7 +68,7 @@ "@types/jest": "^29.4.4", "@types/moment-duration-format": "^2.2.3", "@types/node": "^20.14.9", - "electron": "28.1.0", + "electron": "^30.0.1", "jest-preset-angular": "^13.1.4", "tslint": "^6.1.3" } diff --git a/packages/desktop-ui-lib/src/lib/login/login.component.scss b/packages/desktop-ui-lib/src/lib/login/login.component.scss index 5b34bb7c326..32bf3510141 100644 --- a/packages/desktop-ui-lib/src/lib/login/login.component.scss +++ b/packages/desktop-ui-lib/src/lib/login/login.component.scss @@ -444,7 +444,7 @@ ::ng-deep { nb-card-body { - padding: .5rem; + padding: 36px 0.5rem 0.5rem; } nb-card-header { diff --git a/packages/desktop-ui-lib/src/lib/offline-sync/concretes/sequence-queue.ts b/packages/desktop-ui-lib/src/lib/offline-sync/concretes/sequence-queue.ts index 4b67ad29235..aeed4413150 100644 --- a/packages/desktop-ui-lib/src/lib/offline-sync/concretes/sequence-queue.ts +++ b/packages/desktop-ui-lib/src/lib/offline-sync/concretes/sequence-queue.ts @@ -92,7 +92,7 @@ export class SequenceQueue extends OfflineQueue { ? latest : { ...timer, - id: status.lastLog.id + id: status?.lastLog?.id }, ...timer }); diff --git a/packages/desktop-ui-lib/src/lib/recap/+state/request/request.store.ts b/packages/desktop-ui-lib/src/lib/recap/+state/request/request.store.ts index 9a8eceed71d..030aae00c29 100644 --- a/packages/desktop-ui-lib/src/lib/recap/+state/request/request.store.ts +++ b/packages/desktop-ui-lib/src/lib/recap/+state/request/request.store.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { Store, StoreConfig } from '@datorama/akita'; import { ITimeLogFilters, TimeLogSourceEnum } from '@gauzy/contracts'; +import { moment } from '../../shared/features/date-range-picker'; export type IRequestState = ITimeLogFilters; @@ -8,6 +9,7 @@ export function createInitialState(): IRequestState { return { source: [TimeLogSourceEnum.DESKTOP], logType: [], + timeZone: moment.tz.guess(), activityLevel: { start: 0, end: 100 diff --git a/packages/desktop-ui-lib/src/lib/recap/monthly/+state/monthly.service.ts b/packages/desktop-ui-lib/src/lib/recap/monthly/+state/monthly.service.ts index 304e652e1b1..ab00e980f76 100644 --- a/packages/desktop-ui-lib/src/lib/recap/monthly/+state/monthly.service.ts +++ b/packages/desktop-ui-lib/src/lib/recap/monthly/+state/monthly.service.ts @@ -4,6 +4,7 @@ import { Observable } from 'rxjs'; import { RequestQuery } from '../../+state/request/request.query'; import { Store, TimeTrackerDateManager, ToastrNotificationService } from '../../../services'; import { TimesheetService, TimesheetStatisticsService } from '../../services/timesheet'; +import { moment } from '../../shared/features/date-range-picker'; import { IDateRangePicker } from '../../shared/features/date-range-picker/date-picker.interface'; import { MonthlyRecapQuery } from './monthly.query'; import { IMonthlyRecapState, MonthlyRecapStore } from './monthly.store'; @@ -51,7 +52,7 @@ export class MonthlyRecapService { this.monthlyStore.setLoading(true); const { organizationId, tenantId, user } = this.store; const employeeIds = [user.employee.id]; - const timeZone = user.timeZone; + const timeZone = user.timeZone || moment.tz.guess(); const timeFormat = user.timeFormat; const request: IGetTimeLogInput = { ...this.requestQuery.request, diff --git a/packages/desktop-ui-lib/src/lib/recap/shared/features/activity-report/activity-report.component.scss b/packages/desktop-ui-lib/src/lib/recap/shared/features/activity-report/activity-report.component.scss index 1a0ac287f2d..c161f695528 100644 --- a/packages/desktop-ui-lib/src/lib/recap/shared/features/activity-report/activity-report.component.scss +++ b/packages/desktop-ui-lib/src/lib/recap/shared/features/activity-report/activity-report.component.scss @@ -6,7 +6,7 @@ padding-bottom: 10px; background-color: var(--gauzy-card-1); border-radius: var(--border-radius); - height: calc(100vh - 23.75rem); + height: calc(100vh - 22.625rem); overflow-y: auto; .table-row-custom { diff --git a/packages/desktop-ui-lib/src/lib/recap/weekly/+state/weekly.service.ts b/packages/desktop-ui-lib/src/lib/recap/weekly/+state/weekly.service.ts index 7f18365d219..527217ceaf9 100644 --- a/packages/desktop-ui-lib/src/lib/recap/weekly/+state/weekly.service.ts +++ b/packages/desktop-ui-lib/src/lib/recap/weekly/+state/weekly.service.ts @@ -4,6 +4,7 @@ import { Observable } from 'rxjs'; import { RequestQuery } from '../../+state/request/request.query'; import { Store, TimeTrackerDateManager, ToastrNotificationService } from '../../../services'; import { TimesheetService, TimesheetStatisticsService } from '../../services/timesheet'; +import { moment } from '../../shared/features/date-range-picker'; import { IDateRangePicker } from '../../shared/features/date-range-picker/date-picker.interface'; import { WeeklyRecapQuery } from './weekly.query'; import { IWeeklyRecapState, WeeklyRecapStore } from './weekly.store'; @@ -51,7 +52,7 @@ export class WeeklyRecapService { this.weeklyStore.setLoading(true); const { organizationId, tenantId, user } = this.store; const employeeIds = [user.employee.id]; - const timeZone = user.timeZone; + const timeZone = user.timeZone || moment.tz.guess(); const timeFormat = user.timeFormat; const request: IGetTimeLogInput = { ...this.requestQuery.request, diff --git a/packages/desktop-ui-lib/src/lib/settings/plugins/component/plugin-layout/plugin-layout.component.scss b/packages/desktop-ui-lib/src/lib/settings/plugins/component/plugin-layout/plugin-layout.component.scss index f3e91e6b42c..0acf7171c00 100644 --- a/packages/desktop-ui-lib/src/lib/settings/plugins/component/plugin-layout/plugin-layout.component.scss +++ b/packages/desktop-ui-lib/src/lib/settings/plugins/component/plugin-layout/plugin-layout.component.scss @@ -5,3 +5,7 @@ h4 { letter-spacing: 0em; color: var(--gauzy-text-color-1); } + +.titlebar-space { + margin-top: 15px; +} diff --git a/packages/desktop-ui-lib/src/lib/shared/utils/permission.util.ts b/packages/desktop-ui-lib/src/lib/shared/utils/permission.util.ts new file mode 100644 index 00000000000..9689dc62ccd --- /dev/null +++ b/packages/desktop-ui-lib/src/lib/shared/utils/permission.util.ts @@ -0,0 +1,21 @@ +/** + * Checks if the user has all the required permissions. + * + * @param permissions The list of permissions the user has. + * @param requires The permissions required to perform the action. + * @returns A boolean indicating whether the user has all the required permissions. + */ +export function hasAllPermissions(permissions: T[], ...requires: T[]) { + return requires.every((permission) => permissions.includes(permission)); +} + +/** + * Checks if the user has any of the required permissions. + * + * @param permissions The list of permissions the user has. + * @param requires The permissions required to perform the action. + * @returns A boolean indicating whether the user has any of the required permissions. + */ +export function hasAnyPermission(permissions: T[], ...requires: T[]) { + return requires.some((permission) => permissions.includes(permission)); +} diff --git a/packages/desktop-ui-lib/src/lib/theme-selector/switch-theme/switch-theme.component.html b/packages/desktop-ui-lib/src/lib/theme-selector/switch-theme/switch-theme.component.html index ee310c5cb21..afcb6c3e7bb 100644 --- a/packages/desktop-ui-lib/src/lib/theme-selector/switch-theme/switch-theme.component.html +++ b/packages/desktop-ui-lib/src/lib/theme-selector/switch-theme/switch-theme.component.html @@ -1,7 +1,10 @@
- {{ 'SETTINGS_MENU.LIGHT' | translate }}/{{ - 'SETTINGS_MENU.DARK' | translate - }} - + {{ 'SETTINGS_MENU.LIGHT' | translate }}/{{ 'SETTINGS_MENU.DARK' | translate }} +
diff --git a/packages/desktop-ui-lib/src/lib/theme-selector/switch-theme/switch-theme.component.ts b/packages/desktop-ui-lib/src/lib/theme-selector/switch-theme/switch-theme.component.ts index b0a33c89a2e..102e7e135f3 100644 --- a/packages/desktop-ui-lib/src/lib/theme-selector/switch-theme/switch-theme.component.ts +++ b/packages/desktop-ui-lib/src/lib/theme-selector/switch-theme/switch-theme.component.ts @@ -1,30 +1,45 @@ -import { Component, OnInit } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { BehaviorSubject, Observable, from, tap } from 'rxjs'; import { ElectronService } from '../../electron/services'; +@UntilDestroy({ checkProperties: true }) @Component({ selector: 'gauzy-switch-theme', templateUrl: './switch-theme.component.html', - styleUrls: ['./switch-theme.component.scss'] + styleUrls: ['./switch-theme.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class SwitchThemeComponent implements OnInit { - switch = true; // Default theme can be light + private _switch$ = new BehaviorSubject(true); hasText = false; - constructor( - private translate: TranslateService, - private electronService: ElectronService - ) { } + constructor(private electronService: ElectronService) {} ngOnInit(): void { - this.electronService.ipcRenderer.invoke('SAVED_THEME').then((theme) => { - this.switch = theme === 'dark'; - }); + from(this.electronService.ipcRenderer.invoke('PREFERRED_THEME')) + .pipe( + tap((theme) => (this.switch = theme === 'dark')), + untilDestroyed(this) + ) + .subscribe(); } - switchTheme(): void { + public switchTheme(): void { const currentTheme = this.switch; this.switch = !currentTheme; this.electronService.ipcRenderer.send('THEME_CHANGE', this.switch ? 'dark' : 'light'); } + + public get switch$(): Observable { + return this._switch$.asObservable(); + } + + public get switch(): boolean { + return this._switch$.getValue(); + } + + public set switch(value: boolean) { + this._switch$.next(value); + } } diff --git a/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.component.scss b/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.component.scss index a19862558cd..7e5eebcb0a2 100644 --- a/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.component.scss +++ b/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.component.scss @@ -17,7 +17,7 @@ } .timer-window-container { - margin-top: 20px; + margin-top: 28px; display: flex; flex-direction: row; align-items: flex-start; @@ -36,7 +36,7 @@ .timer { min-width: 360px !important; width: auto; - height: calc(100vh - 2.5rem); + height: calc(100vh - 2.5rem - 23px); overflow: hidden; &.expanded { @@ -633,14 +633,13 @@ img { flex-direction: column; padding: 8px 4px; border-radius: var(--border-radius); - height: calc(100vh - 15.75rem); + height: calc(100vh - 16.25rem); width: auto; .table-scroll-container { flex-grow: 10; max-height: unset; padding: 0 4px 0; - margin-bottom: 8px; overflow-x: hidden; } } diff --git a/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.component.ts b/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.component.ts index c423ab25111..99bfde90faa 100644 --- a/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.component.ts +++ b/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.component.ts @@ -19,6 +19,7 @@ import { ITaskStatus, ITaskUpdateInput, ITimeLog, + ITimeSlotTimeLogs, PermissionsEnum, TaskStatusEnum } from '@gauzy/contracts'; @@ -73,6 +74,7 @@ import { NoteService } from '../shared/features/note/+state/note.service'; import { ProjectSelectorService } from '../shared/features/project-selector/+state/project-selector.service'; import { TaskSelectorService } from '../shared/features/task-selector/+state/task-selector.service'; import { TeamSelectorService } from '../shared/features/team-selector/+state/team-selector.service'; +import { hasAllPermissions } from '../shared/utils/permission.util'; import { TasksComponent } from '../tasks/tasks.component'; import { TimeTrackerQuery } from './+state/time-tracker.query'; import { IgnitionState, TimeTrackerStore } from './+state/time-tracker.store'; @@ -118,6 +120,7 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { private _remoteSleepLock = false; private _isReady = false; private _session: moment.Moment = null; + private hasActiveTaskPermissions = false; @ViewChild('dialogOpenBtn') btnDialogOpen: ElementRef; public start$: BehaviorSubject = new BehaviorSubject(false); userData: any; @@ -204,9 +207,23 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { .pipe( filter((permissions: any[]) => permissions.length > 0), tap((permissions: any[]) => { - this.taskSelectorService.hasPermission = permissions.includes(PermissionsEnum.ORG_TASK_ADD); - this.clientSelectorService.hasPermission = permissions.includes(PermissionsEnum.ORG_CONTACT_EDIT); - this.projectSelectorService.hasPermission = permissions.includes(PermissionsEnum.ORG_PROJECT_ADD); + this.taskSelectorService.hasPermission = hasAllPermissions( + permissions, + PermissionsEnum.ORG_TASK_ADD + ); + this.clientSelectorService.hasPermission = hasAllPermissions( + permissions, + PermissionsEnum.ORG_CONTACT_EDIT + ); + this.projectSelectorService.hasPermission = hasAllPermissions( + permissions, + PermissionsEnum.ORG_PROJECT_ADD + ); + this.hasActiveTaskPermissions = hasAllPermissions( + permissions, + PermissionsEnum.ORG_TEAM_EDIT_ACTIVE_TASK, + PermissionsEnum.ALL_ORG_EDIT + ); }), untilDestroyed(this) ) @@ -1086,7 +1103,6 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { this._ngZone.run(async () => { if (this.start) { await this.toggleStart(false); - this.electronService.ipcRenderer.send('pause-tracking'); } }) ); @@ -1152,7 +1168,7 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { this.electronService.ipcRenderer.on('prepare_activities_screenshot', (event, arg) => this._ngZone.run(async () => { - await this.sendActivities(arg); + await this.takeCaptureAndSendActivities(arg); }) ); @@ -1283,6 +1299,8 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { title: this._environment.DESCRIPTION }; + console.log('remove_idle_time', arg); + const isReadyForDeletion = !this._isOffline && timeSlotPayload.timeslotIds.length > 0; if (isReadyForDeletion) { @@ -1341,9 +1359,14 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { }, (payload) => this.timeTrackerService.toggleApiStop(payload) ); - this._startMode = TimerStartMode.STOP; } catch (error) { await this.electronService.ipcRenderer.invoke('MARK_AS_STOPPED_OFFLINE'); + } finally { + this._startMode = TimerStartMode.STOP; + this.timeTrackerStore.ignition({ + state: IgnitionState.STOPPED, + mode: this._startMode + }); } } const isDeleted = await this.timeTrackerService.deleteTimeSlots(timeSlotPayload); @@ -1375,6 +1398,8 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { this._errorHandlerService.handleError(error); } }); + } else { + if (this.start && !arg.isWorking) await this.toggleStart(false); } if (this._isOffline || isReadyForDeletion) { @@ -1635,13 +1660,15 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { if (this._startMode === TimerStartMode.MANUAL) { console.log('Taking screen capture in startTimer'); - const activities = await this.electronService.ipcRenderer.invoke('TAKE_SCREEN_CAPTURE', { + const activities = await this.electronService.ipcRenderer.invoke('COLLECT_ACTIVITIES', { quitApp: this.quitApp }); - console.log('Sending activities', activities); - - await this.sendActivities(activities); + asyncScheduler.schedule(async () => { + this._loggerService.info('Capturing Screen and Sending Activities Start...', activities); + await this.takeCaptureAndSendActivities(activities); + this._loggerService.info('Capturing Screen and Sending Activities Done ✔️'); + }, 1000); } console.log('Updating Task Status'); @@ -1679,34 +1706,26 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { this.electronService.ipcRenderer.send('stop-capture-screen'); if (this._startMode === TimerStartMode.MANUAL) { - console.log('Stopping timer'); - const timer = await this.electronService.ipcRenderer.invoke('STOP_TIMER', config); + console.log('Taking screen capture'); - this.start$.next(false); - - this.loading = false; - - console.log('Toggling timer'); - await this._toggle(timer, onClick); + const activities = await this.electronService.ipcRenderer.invoke('COLLECT_ACTIVITIES', config); asyncScheduler.schedule(async () => { - console.log('Taking screen capture'); - const activities = await this.electronService.ipcRenderer.invoke('TAKE_SCREEN_CAPTURE', config); - - console.log('Sending activities'); - await this.sendActivities(activities); + this._loggerService.info('Capturing Screen and Sending Activities Start...', activities); + await this.takeCaptureAndSendActivities(activities); + this._loggerService.info('Capturing Screen and Sending Activities Done ✔️'); }, 1000); - } else { - console.log('Stopping timer'); - const timer = await this.electronService.ipcRenderer.invoke('STOP_TIMER', config); + } - this.start$.next(false); + console.log('Stopping timer'); + const timer = await this.electronService.ipcRenderer.invoke('STOP_TIMER', config); - this.loading = false; + console.log('Toggling timer'); + await this._toggle(timer, onClick); - console.log('Toggling timer'); - await this._toggle(timer, onClick); - } + this.start$.next(false); + + this.loading = false; console.log('Updating Tray stop'); @@ -2084,39 +2103,109 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { } } - public async sendActivities(arg): Promise { - console.log('sendActivities'); + public async takeScreenCapture(arg) { + let HighResolutionScreenshots = []; + let lowResolutionScreenshots = []; + + try { + this._loggerService.info('Take screen capture'); + if (!arg.displays) { + HighResolutionScreenshots = await this.getScreenshot(arg, false); + lowResolutionScreenshots = await this.getScreenshot(arg, true); + } else { + HighResolutionScreenshots = arg.displays; + } + + this._loggerService.info('Update timer last capture'); + this.handleLastCapture(HighResolutionScreenshots); + + // notify + this._loggerService.info('Notify screen capture to user'); + this.screenshotNotify(arg, lowResolutionScreenshots); + + return HighResolutionScreenshots; + } catch (error) { + this._loggerService.error('Error on screenshot', error); + } + } + + public checkSendActivitiesValidationFail(arg) { + this._loggerService.info('sendActivities'); if (this.isRemoteTimer) { - console.log('isRemoteTimer exit from sendActivities'); - return; + this._loggerService.info('isRemoteTimer exit from sendActivities'); + return true; } if (!arg) { this._loggerService.info('No data available to send from sendActivities'); - return; + return true; } - // screenshot process - let screenshotImg = []; + return false; + } - let thumbScreenshotImg = []; + public async handleLastCapture(screenshots: any[]) { + if (!this._isOffline && screenshots.length > 0) { + /* Converting the screenshot image to a base64 string. */ + const original = `data:image/png;base64, ${this.buffToB64(screenshots[0])}`; - try { - if (!arg.displays) { - screenshotImg = await this.getScreenshot(arg, false); - thumbScreenshotImg = await this.getScreenshot(arg, true); - } else { - screenshotImg = arg.displays; - } + /* Compressing the image to 320x200 */ + const compressed = await compressImage(original, 320, 200); - // notify - this.screenshotNotify(arg, thumbScreenshotImg); + /* Saving compressed image to the local storage. */ + await this.localImage(compressed, original); + + /* Update image waiting for server response*/ + this.updateImageUrl(null); + + /* Adding the last screen capture to the screenshots array. */ + this.screenshots$.next([...this.screenshots, this.lastScreenCapture]); + } + } + + public async uploadScreenshots(arg, timeSlotId: string, screenshots: any[]) { + this._loggerService.info('Upload screenshot to TimeSlot api'); + try { + await Promise.all( + screenshots.map(async (img) => { + return await this.uploadsScreenshot(arg, img, timeSlotId); + }) + ); } catch (error) { - this._loggerService.error('Error on screenshot', error); + console.log('ERROR', error); } - const paramActivity = { + this._loggerService.info('Get last time slot image'); + await this.getLastTimeSlotImage({ + ...arg, + token: this.token, + apiHost: this.apiHost, + timeSlotId + }); + } + + private handleCreateTimeSlotError(error: any, arg, screenshots) { + const paramActivity = this.buildParamActivity(arg); + this._loggerService.error('Error sending to API timeslot:', error); + + try { + this.electronService.ipcRenderer.send('failed_synced_timeslot', { + params: { + ...paramActivity, + b64Imgs: screenshots.map((img) => ({ + b64img: this.buffToB64(img), + fileName: this.fileNameFormat(img) + })) + } + }); + } catch (e) { + this._loggerService.error('Failed to send failed_synced_timeslot event', e); + } + } + + private buildParamActivity(arg) { + return { employeeId: arg.employeeId, projectId: arg.projectId, duration: arg.duration, @@ -2134,23 +2223,26 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { isAw: arg.isAw, isAwConnected: arg.isAwConnected }; + } + public async createTimeSlot(arg, screenshots: any[]) { try { - const resActivities: any = await this.timeTrackerService.pushToTimeSlot(paramActivity); - - console.log('Result of TimeSlot', resActivities); - - const timeLogs = resActivities.timeLogs; + this._loggerService.info('Build Param Activity'); + const paramActivity = this.buildParamActivity(arg); + this._loggerService.info('Create Time Slot'); + const { timeLogs, id: timeSlotId } = (await this.timeTrackerService.pushToTimeSlot( + paramActivity + )) as ITimeSlotTimeLogs; if (!timeLogs?.length) { // Stop process if there is no time logs associate to activity result. this._loggerService.error('[@SendActivities]', 'No time logs'); - return; + return null; } - + this._loggerService.info('Post Create activities'); this.electronService.ipcRenderer.send('return_time_slot', { timerId: arg.timerId, - timeSlotId: resActivities.id, + timeSlotId, quitApp: arg.quitApp, timeLogs: timeLogs }); @@ -2161,68 +2253,30 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { idsWakatime: arg.idsWakatime }); - if (!this._isOffline && screenshotImg.length > 0) { - /* Converting the screenshot image to a base64 string. */ - const original = `data:image/png;base64, ${this.buffToB64(screenshotImg[0])}`; - - /* Compressing the image to 320x200 */ - const compressed = await compressImage(original, 320, 200); - - /* Saving compressed image to the local storage. */ - await this.localImage(compressed, original); - - /* Update image waiting for server response*/ - this.updateImageUrl(null); - - /* Adding the last screen capture to the screenshots array. */ - this.screenshots$.next([...this.screenshots, this.lastScreenCapture]); - } - - // upload screenshot to TimeSlot api - try { - await Promise.all( - screenshotImg.map(async (img) => { - return await this.uploadsScreenshot(arg, img, resActivities.id); - }) - ); - } catch (error) { - console.log('ERROR', error); - } - - const timeSlotId = resActivities.id; - - console.log('Get last time slot image'); - await this.getLastTimeSlotImage({ - ...arg, - token: this.token, - apiHost: this.apiHost, - timeSlotId - }); - - console.log('Sending create-synced-interval event...'); + this._loggerService.info('Sending create-synced-interval event...'); this.electronService.ipcRenderer.send('create-synced-interval', { ...paramActivity, remoteId: timeSlotId, b64Imgs: [] }); + + return timeSlotId; } catch (error) { - this._loggerService.error('Error send to api timeslot::', error); - try { - console.log('Sending failed_synced_timeslot event...'); - this.electronService.ipcRenderer.send('failed_synced_timeslot', { - params: { - ...paramActivity, - b64Imgs: screenshotImg.map((img) => { - return { - b64img: this.buffToB64(img), - fileName: this.fileNameFormat(img) - }; - }) - } - }); - } catch (e) { - this._loggerService.error('Failed to send failed_synced_timeslot event', e); - } + this.handleCreateTimeSlotError(error, arg, screenshots); + return null; + } + } + + public async takeCaptureAndSendActivities(activities) { + // Check validations + if (this.checkSendActivitiesValidationFail(activities)) return; + // Take Screenshots + const screenshots = await this.takeScreenCapture(activities); + // Create time slot and return time slot ID + const timeslotId = await this.createTimeSlot(activities, screenshots); + // Upload screenshots if available + if (timeslotId && screenshots.length > 0) { + await this.uploadScreenshots(activities, timeslotId, screenshots); } } @@ -2418,7 +2472,7 @@ export class TimeTrackerComponent implements OnInit, AfterViewInit { public async updateOrganizationTeamEmployee(): Promise { try { - if (!this.selectedTask || !this.selectedTeam) { + if (!this.selectedTask || !this.selectedTeam || !this.hasActiveTaskPermissions) { return; } const organizationTeamId = this.teamSelectorService.selectedId; diff --git a/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.service.ts b/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.service.ts index 42286113f6b..c4138de2d2b 100644 --- a/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.service.ts +++ b/packages/desktop-ui-lib/src/lib/time-tracker/time-tracker.service.ts @@ -16,6 +16,7 @@ import { ITaskStatus, ITaskStatusFindInput, ITaskUpdateInput, + ITimeLog, TimeLogSourceEnum, TimeLogType } from '@gauzy/contracts'; @@ -325,27 +326,56 @@ export class TimeTrackerService { } toggleApiStop(values) { + const TIMEOUT = 15000; + const API_URL = `${API_PREFIX}/timesheet/timer/stop`; + + // Destructuring with defaults + const { + organizationContactId = null, + organizationTeamId = null, + manualTimeSlot = null, + description = null, + projectId = null, + version = null, + taskId = null, + organizationId, + tenantId, + startedAt, + stoppedAt + } = values; + const options = { - headers: new HttpHeaders({ timeout: `${15 * 1000}` }) + headers: new HttpHeaders({ timeout: TIMEOUT.toString() }) }; + const body = { - description: values.description, + description, isBillable: true, logType: TimeLogType.TRACKED, - projectId: values.projectId, - taskId: values.taskId, - manualTimeSlot: values.manualTimeSlot, - organizationId: values.organizationId, - tenantId: values.tenantId, - organizationContactId: values.organizationContactId, + source: TimeLogSourceEnum.DESKTOP, + projectId, + taskId, + manualTimeSlot, + organizationId, + tenantId, + organizationContactId, isRunning: false, - version: values.version, - startedAt: moment(values.startedAt).utc().toISOString(), - stoppedAt: moment(values.stoppedAt).utc().toISOString(), - organizationTeamId: values.organizationTeamId + version, + startedAt: moment(startedAt).utc().toISOString(), + stoppedAt: moment(stoppedAt).utc().toISOString(), + organizationTeamId }; - this._loggerService.log.info(`Toggle Stop Timer Request: ${moment().format()}`, body); - return firstValueFrom(this.http.post(`${API_PREFIX}/timesheet/timer/stop`, { ...body }, options)); + + // Log request details + this._loggerService.info(`Toggle Stop Timer Request: ${moment().format()}`, body); + + // Perform the API call + try { + return firstValueFrom(this.http.post(API_URL, body, options)); + } catch (error) { + this._loggerService.error(`Error stopping timer: ${moment().format()}`, { error, requestBody: body }); + throw error; + } } deleteTimeSlot(values) { @@ -448,6 +478,7 @@ export class TimeTrackerService { } uploadImages(values, img: any) { + const TIMEOUT = 60 * 1000; // Max 60 sec to upload images const formData = new FormData(); const contentType = 'image/png'; const b64Data = img.b64Img; @@ -457,8 +488,13 @@ export class TimeTrackerService { formData.append('tenantId', values.tenantId); formData.append('organizationId', values.organizationId); formData.append('recordedAt', moment(values.recordedAt).utc().toISOString()); + + const options = { + headers: new HttpHeaders({ timeout: TIMEOUT.toString() }) + }; + return firstValueFrom( - this.http.post(`${API_PREFIX}/timesheet/screenshot`, formData).pipe( + this.http.post(`${API_PREFIX}/timesheet/screenshot`, formData, options).pipe( catchError((error) => { error.error = { ...error.error, @@ -593,7 +629,9 @@ export class TimeTrackerService { organizationTeamId: values.organizationTeamId, tenantId: values.tenantId }; - return firstValueFrom(this.http.put(`${API_PREFIX}/organization-team-employee/${employeeId}`, params)); + return firstValueFrom( + this.http.put(`${API_PREFIX}/organization-team-employee/${employeeId}/active-task`, params) + ); } public async getTeams(values?: any): Promise { diff --git a/packages/desktop-window/package.json b/packages/desktop-window/package.json index c1a357a2f1f..de750b39f42 100644 --- a/packages/desktop-window/package.json +++ b/packages/desktop-window/package.json @@ -33,6 +33,6 @@ }, "devDependencies": { "@types/node": "^20.14.9", - "electron": "28.1.0" + "electron": "^30.0.1" } } diff --git a/packages/plugins/job-proposal-ui/src/lib/proposal-template/components/proposal-template/proposal-template.component.ts b/packages/plugins/job-proposal-ui/src/lib/proposal-template/components/proposal-template/proposal-template.component.ts index 51e12c758a0..56bd71672f6 100644 --- a/packages/plugins/job-proposal-ui/src/lib/proposal-template/components/proposal-template/proposal-template.component.ts +++ b/packages/plugins/job-proposal-ui/src/lib/proposal-template/components/proposal-template/proposal-template.component.ts @@ -311,7 +311,7 @@ export class ProposalTemplateComponent extends PaginationFilterBaseComponent imp isFilterable: false, width: '20%', type: 'custom', - sort: false, + isSortable: false, renderComponent: EmployeeLinksComponent, valuePrepareFunction: (value: IEmployee) => ({ id: value?.id, @@ -328,7 +328,7 @@ export class ProposalTemplateComponent extends PaginationFilterBaseComponent imp type: 'text', width: '30%', isFilterable: false, - sort: false, + isSortable: false, valuePrepareFunction: (value: string) => value.slice(0, 150) }, content: { @@ -336,7 +336,7 @@ export class ProposalTemplateComponent extends PaginationFilterBaseComponent imp type: 'html', width: '40%', isFilterable: false, - sort: false, + isSortable: false, valuePrepareFunction: (value: string) => { return value ? this._truncatePipe.transform(this._nl2BrPipe.transform(value), 500) : ''; } @@ -346,7 +346,7 @@ export class ProposalTemplateComponent extends PaginationFilterBaseComponent imp type: 'text', width: '10%', isFilterable: false, - sort: false, + isSortable: false, valuePrepareFunction: (value: boolean) => { return value ? this.getTranslation('PROPOSAL_TEMPLATE.YES') diff --git a/packages/plugins/job-proposal-ui/src/lib/proposal/components/proposal/proposal.component.ts b/packages/plugins/job-proposal-ui/src/lib/proposal/components/proposal/proposal.component.ts index b83d942ee8b..9256f22eda5 100644 --- a/packages/plugins/job-proposal-ui/src/lib/proposal/components/proposal/proposal.component.ts +++ b/packages/plugins/job-proposal-ui/src/lib/proposal/components/proposal/proposal.component.ts @@ -529,7 +529,7 @@ export class ProposalComponent extends PaginationFilterBaseComponent implements } this.setFilter({ field: 'tags', search: tagIds }); }, - sort: false + isSortable: false }; } } diff --git a/packages/plugins/job-search-ui/src/lib/components/job-search/job-search.component.ts b/packages/plugins/job-search-ui/src/lib/components/job-search/job-search.component.ts index 0e3c761f144..c86dc0ce8f2 100644 --- a/packages/plugins/job-search-ui/src/lib/components/job-search/job-search.component.ts +++ b/packages/plugins/job-search-ui/src/lib/components/job-search/job-search.component.ts @@ -650,7 +650,7 @@ export class JobSearchComponent extends PaginationFilterBaseComponent implements isFilterable: false, width: '15%', type: 'custom', - sort: false, + isSortable: false, renderComponent: EmployeeLinksComponent, componentInitFunction: (instance: EmployeeLinksComponent, cell: Cell) => { // Get row data @@ -671,7 +671,7 @@ export class JobSearchComponent extends PaginationFilterBaseComponent implements width: '85%', type: 'custom', isFilterable: false, - sort: false, + isSortable: false, renderComponent: JobTitleDescriptionDetailsComponent, componentInitFunction(instance: JobTitleDescriptionDetailsComponent, cell: Cell) { // Get row data diff --git a/yarn.lock b/yarn.lock index c702bbf5989..374850e196f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11970,13 +11970,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190" integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== -"@types/node@^18.11.18": - version "18.19.28" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.28.tgz#c64a2c992c8ebbf61100a4570e4eebc1934ae030" - integrity sha512-J5cOGD9n4x3YGgVuaND6khm5x07MMdAKkRyXnjVR6KFhLMNh2yONGiP7Z+4+tBOt5mK+GvDTiacTOVGGpqiecw== - dependencies: - undici-types "~5.26.4" - "@types/node@^20.14.9": version "20.14.9" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.9.tgz#12e8e765ab27f8c421a1820c99f5f313a933b420" @@ -18823,7 +18816,7 @@ ejs@^3.1.7, ejs@^3.1.8: dependencies: jake "^10.8.5" -electron-builder@^24.6.4: +electron-builder@^24.13.3: version "24.13.3" resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-24.13.3.tgz#c506dfebd36d9a50a83ee8aa32d803d83dbe4616" integrity sha512-yZSgVHft5dNVlo31qmJAe4BVKQfFdwpRw7sFp1iQglDRCDD6r22zfRJuZlhtB5gp9FHUxCMEoWGq10SkCnMAIg== @@ -18962,13 +18955,13 @@ electron@*: "@types/node" "^20.9.0" extract-zip "^2.0.1" -electron@28.1.0: - version "28.1.0" - resolved "https://registry.yarnpkg.com/electron/-/electron-28.1.0.tgz#9de1ecdaafcb0ec5753827f14dfb199e6c84545e" - integrity sha512-82Y7o4PSWPn1o/aVwYPsgmBw6Gyf2lVHpaBu3Ef8LrLWXxytg7ZRZr/RtDqEMOzQp3+mcuy3huH84MyjdmP50Q== +electron@^30.0.1: + version "30.5.1" + resolved "https://registry.yarnpkg.com/electron/-/electron-30.5.1.tgz#9f6060ce5b869c3803cbf8064305e9c3056c0744" + integrity sha512-AhL7+mZ8Lg14iaNfoYTkXQ2qee8mmsQyllKdqxlpv/zrKgfxz6jNVtcRRbQtLxtF8yzcImWdfTQROpYiPumdbw== dependencies: "@electron/get" "^2.0.0" - "@types/node" "^18.11.18" + "@types/node" "^20.9.0" extract-zip "^2.0.1" elliptic@^6.5.3, elliptic@^6.5.5: