diff --git a/.gitignore b/.gitignore index 3d690aa4397..a64233bb5b4 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ ormlogs.log /packages/**/dist /.deploy/nginx/log + /apps/gauzy/src/environments/environment.prod.ts /apps/gauzy/src/environments/environment.ts @@ -76,6 +77,9 @@ ormlogs.log /apps/server/src/environments/environment.prod.ts /apps/server/src/environments/environment.ts +/apps/server-api/src/environments/environment.prod.ts +/apps/server-api/src/environments/environment.ts + /export /import /apps/api/*.tsbuildinfo diff --git a/apps/desktop-timer/src/assets/styles/material/_material-dark.scss b/apps/desktop-timer/src/assets/styles/material/_material-dark.scss index 5f10928010c..64fd08c0d5c 100644 --- a/apps/desktop-timer/src/assets/styles/material/_material-dark.scss +++ b/apps/desktop-timer/src/assets/styles/material/_material-dark.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #fff2f7, color-primary-200: #ffd4e3, color-primary-300: #fc9abc, @@ -358,13 +359,13 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote( + shadow: string.unquote( '0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12)' ), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12)' ), diff --git a/apps/desktop-timer/src/assets/styles/material/_material-light.scss b/apps/desktop-timer/src/assets/styles/material/_material-light.scss index 3058c9da301..81b23ab5ef8 100644 --- a/apps/desktop-timer/src/assets/styles/material/_material-light.scss +++ b/apps/desktop-timer/src/assets/styles/material/_material-light.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #e8cbfe, color-primary-200: #ce97fd, color-primary-300: #ae63f9, @@ -358,11 +359,11 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), + shadow: string.unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12)' ), diff --git a/apps/desktop/src/assets/styles/material/_material-dark.scss b/apps/desktop/src/assets/styles/material/_material-dark.scss index 5f10928010c..64fd08c0d5c 100644 --- a/apps/desktop/src/assets/styles/material/_material-dark.scss +++ b/apps/desktop/src/assets/styles/material/_material-dark.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #fff2f7, color-primary-200: #ffd4e3, color-primary-300: #fc9abc, @@ -358,13 +359,13 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote( + shadow: string.unquote( '0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12)' ), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12)' ), diff --git a/apps/desktop/src/assets/styles/material/_material-light.scss b/apps/desktop/src/assets/styles/material/_material-light.scss index 3058c9da301..81b23ab5ef8 100644 --- a/apps/desktop/src/assets/styles/material/_material-light.scss +++ b/apps/desktop/src/assets/styles/material/_material-light.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #e8cbfe, color-primary-200: #ce97fd, color-primary-300: #ae63f9, @@ -358,11 +359,11 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), + shadow: string.unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12)' ), diff --git a/apps/desktop/src/assets/styles/themes.scss b/apps/desktop/src/assets/styles/themes.scss index 749a9cb095b..e1c9b33373d 100644 --- a/apps/desktop/src/assets/styles/themes.scss +++ b/apps/desktop/src/assets/styles/themes.scss @@ -1,3 +1,4 @@ +@use "sass:string"; // @nebular theming framework @import '@nebular/theme/styles/theming'; // @nebular out of the box themes @@ -8,6 +9,7 @@ // Google Inter font @import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap'); + $nb-themes: nb-register-theme( ( font-family-secondary: font-family-primary, @@ -307,8 +309,8 @@ $nb-themes: nb-register-theme( tabset-tab-focus-underline-color: none, tabset-tab-text-transform: capitalize, button-filled-text-transform: none, - font-family-primary: unquote('Inter, sans-serif'), - font-family-secondary: unquote('Inter, sans-serif'), + font-family-primary: string.unquote('Inter, sans-serif'), + font-family-secondary: string.unquote('Inter, sans-serif'), button-outline-text-transform: none, gauzy-text-contact: #323232, button-filled-medium-padding: 0.4375rem 0.875rem, @@ -391,8 +393,8 @@ $nb-themes: nb-register-theme( tabset-tab-focus-underline-color: none, tabset-tab-text-transform: capitalize, button-filled-text-transform: none, - font-family-primary: unquote('Inter, sans-serif'), - font-family-secondary: unquote('Inter, sans-serif'), + font-family-primary: string.unquote('Inter, sans-serif'), + font-family-secondary: string.unquote('Inter, sans-serif'), button-outline-text-transform: none, button-filled-medium-padding: 0.4375rem 0.875rem, button-outline-medium-padding: 0.4375rem 0.875rem, diff --git a/apps/server-api/src/assets/styles/material/_material-dark.scss b/apps/server-api/src/assets/styles/material/_material-dark.scss index 5f10928010c..64fd08c0d5c 100644 --- a/apps/server-api/src/assets/styles/material/_material-dark.scss +++ b/apps/server-api/src/assets/styles/material/_material-dark.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #fff2f7, color-primary-200: #ffd4e3, color-primary-300: #fc9abc, @@ -358,13 +359,13 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote( + shadow: string.unquote( '0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12)' ), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12)' ), diff --git a/apps/server-api/src/assets/styles/material/_material-light.scss b/apps/server-api/src/assets/styles/material/_material-light.scss index 3058c9da301..81b23ab5ef8 100644 --- a/apps/server-api/src/assets/styles/material/_material-light.scss +++ b/apps/server-api/src/assets/styles/material/_material-light.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #e8cbfe, color-primary-200: #ce97fd, color-primary-300: #ae63f9, @@ -358,11 +359,11 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), + shadow: string.unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12)' ), diff --git a/apps/server-api/src/assets/styles/themes.scss b/apps/server-api/src/assets/styles/themes.scss index 88c7ec12f43..7488ae760f2 100644 --- a/apps/server-api/src/assets/styles/themes.scss +++ b/apps/server-api/src/assets/styles/themes.scss @@ -1,3 +1,4 @@ +@use "sass:string"; // @nebular theming framework @import '@nebular/theme/styles/theming'; // @nebular out of the box themes @@ -6,6 +7,7 @@ @import './material/material-dark'; @import './material/material-light'; + $nb-themes: nb-register-theme( ( font-family-secondary: font-family-primary, @@ -305,8 +307,8 @@ $nb-themes: nb-register-theme( tabset-tab-focus-underline-color: none, tabset-tab-text-transform: capitalize, button-filled-text-transform: none, - font-family-primary: unquote('Inter, sans-serif'), - font-family-secondary: unquote('Inter, sans-serif'), + font-family-primary: string.unquote('Inter, sans-serif'), + font-family-secondary: string.unquote('Inter, sans-serif'), button-outline-text-transform: none, gauzy-text-contact: #323232, button-filled-medium-padding: 0.4375rem 0.875rem, @@ -389,8 +391,8 @@ $nb-themes: nb-register-theme( tabset-tab-focus-underline-color: none, tabset-tab-text-transform: capitalize, button-filled-text-transform: none, - font-family-primary: unquote('Inter, sans-serif'), - font-family-secondary: unquote('Inter, sans-serif'), + font-family-primary: string.unquote('Inter, sans-serif'), + font-family-secondary: string.unquote('Inter, sans-serif'), button-outline-text-transform: none, button-filled-medium-padding: 0.4375rem 0.875rem, button-outline-medium-padding: 0.4375rem 0.875rem, diff --git a/apps/server/src/assets/styles/material/_material-dark.scss b/apps/server/src/assets/styles/material/_material-dark.scss index 5f10928010c..64fd08c0d5c 100644 --- a/apps/server/src/assets/styles/material/_material-dark.scss +++ b/apps/server/src/assets/styles/material/_material-dark.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #fff2f7, color-primary-200: #ffd4e3, color-primary-300: #fc9abc, @@ -358,13 +359,13 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote( + shadow: string.unquote( '0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12)' ), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12)' ), diff --git a/apps/server/src/assets/styles/material/_material-light.scss b/apps/server/src/assets/styles/material/_material-light.scss index 3058c9da301..81b23ab5ef8 100644 --- a/apps/server/src/assets/styles/material/_material-light.scss +++ b/apps/server/src/assets/styles/material/_material-light.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #e8cbfe, color-primary-200: #ce97fd, color-primary-300: #ae63f9, @@ -358,11 +359,11 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), + shadow: string.unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12)' ), diff --git a/apps/server/src/assets/styles/themes.scss b/apps/server/src/assets/styles/themes.scss index 88c7ec12f43..bda30d5654e 100644 --- a/apps/server/src/assets/styles/themes.scss +++ b/apps/server/src/assets/styles/themes.scss @@ -1,3 +1,4 @@ +@use "sass:string"; // @nebular theming framework @import '@nebular/theme/styles/theming'; // @nebular out of the box themes @@ -305,8 +306,8 @@ $nb-themes: nb-register-theme( tabset-tab-focus-underline-color: none, tabset-tab-text-transform: capitalize, button-filled-text-transform: none, - font-family-primary: unquote('Inter, sans-serif'), - font-family-secondary: unquote('Inter, sans-serif'), + font-family-primary: string.unquote('Inter, sans-serif'), + font-family-secondary: string.unquote('Inter, sans-serif'), button-outline-text-transform: none, gauzy-text-contact: #323232, button-filled-medium-padding: 0.4375rem 0.875rem, @@ -389,8 +390,8 @@ $nb-themes: nb-register-theme( tabset-tab-focus-underline-color: none, tabset-tab-text-transform: capitalize, button-filled-text-transform: none, - font-family-primary: unquote('Inter, sans-serif'), - font-family-secondary: unquote('Inter, sans-serif'), + font-family-primary: string.unquote('Inter, sans-serif'), + font-family-secondary: string.unquote('Inter, sans-serif'), button-outline-text-transform: none, button-filled-medium-padding: 0.4375rem 0.875rem, button-outline-medium-padding: 0.4375rem 0.875rem, diff --git a/apps/server/src/package.json b/apps/server/src/package.json index e3ea6fa7b8e..e70e9598255 100755 --- a/apps/server/src/package.json +++ b/apps/server/src/package.json @@ -22,8 +22,6 @@ "bin": "api/main.js", "workspaces": { "packages": [ - "../../../dist/packages/plugins/integration-ai", - "../../../dist/packages/plugins/job-proposal", "../../../dist/packages/config", "../../../dist/packages/contracts", "../../../dist/packages/desktop-lib", @@ -32,7 +30,9 @@ "../../../dist/packages/auth", "../../../dist/packages/plugin", "../../../dist/packages/core", - "../../../dist/packages/common" + "../../../dist/packages/common", + "../../../dist/packages/plugins/integration-ai", + "../../../dist/packages/plugins/job-proposal" ] }, "build": { @@ -131,10 +131,13 @@ "@datorama/akita-ngdevtools": "^7.0.0", "@datorama/akita": "^7.1.1", "@electron/remote": "^2.0.8", - "@gauzy/config": "file:../../../dist/packages/config", "@gauzy/auth": "file:../../../dist/packages/auth", - "@gauzy/plugin": "file:../../../dist/packages/plugin", + "@gauzy/contracts": "file:../../../dist/packages/contracts", + "@gauzy/config": "file:../../../dist/packages/config", "@gauzy/core": "file:../../../dist/packages/core", + "@gauzy/desktop-lib": "file:../../../dist/packages/desktop-lib", + "@gauzy/desktop-window": "file:../../../dist/packages/desktop-window", + "@gauzy/plugin": "file:../../../dist/packages/plugin", "@gauzy/plugin-changelog": "file:../../../dist/packages/plugins/changelog", "@gauzy/plugin-integration-ai": "file:../../../dist/packages/plugins/integration-ai", "@gauzy/plugin-integration-github": "file:../../../dist/packages/plugins/integration-github", @@ -148,9 +151,6 @@ "@gauzy/plugin-product-reviews": "file:../../../dist/packages/plugins/product-reviews", "@gauzy/plugin-sentry": "file:../../../dist/packages/plugins/sentry-tracing", "@gauzy/plugin-videos": "file:../../../dist/packages/plugins/videos", - "@gauzy/contracts": "^0.1.0", - "@gauzy/desktop-lib": "^0.1.0", - "@gauzy/desktop-window": "^0.1.0", "@gauzy/ui-config": "file:../../../dist/packages/ui-config", "@nestjs/platform-express": "^10.3.7", "@sentry/electron": "^4.18.0", diff --git a/package.json b/package.json index b01cb408929..a8d91e3af2f 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,11 @@ "config": "yarn ts-node ./.scripts/configure.ts", "config:dev": "yarn run config -- --environment=dev", "config:prod": "yarn run config -- --environment=prod", + "config:electron": "yarn ts-node ./.scripts/electron.env.ts", + "config:desktop:prod": "yarn run config:electron -- --environment=prod --desktop=desktop", + "config:desktop-timer:prod": "yarn run config:electron -- --environment=prod --desktop=desktop-timer", + "config:server:prod": "yarn run config:electron -- --environment=prod --desktop=server", + "config:server-api:prod": "yarn run config:electron -- --environment=prod --desktop=server-api", "start": "yarn build:package:all && yarn concurrently --raw --kill-others \"yarn start:api\" \"yarn start:gauzy\"", "start:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn build:package:all && yarn concurrently --raw --kill-others \"yarn start:api:prod\" \"yarn start:gauzy:prod\"", "start:gauzy": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn run postinstall.web && yarn build:package:ui-config && yarn ng serve gauzy --open", @@ -95,7 +100,7 @@ "postinstall.manual": "yarn ts-node ./.scripts/postinstall.ts", "postinstall.electron": "yarn electron-builder install-app-deps && yarn node tools/electron/postinstall", "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 run 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 run gauzy:desktop-ui --base-href ./ && yarn run prepare:desktop && yarn ng:prod run api:desktop-api && yarn ng:prod build desktop-api --output-path=dist/apps/desktop/desktop-api && yarn ng:prod build desktop --base-href ./ && yarn run copy-files-desktop && yarn run copy-assets-gauzy", + "build:desktop": "cross-env NODE_ENV=production yarn run copy-files-i18n-desktop && yarn run postinstall.electron && yarn run config:desktop:prod && yarn run build:package:all && yarn run pack:desktop && yarn run generate:icons:desktop --environment=prod && yarn ng:prod run gauzy:desktop-ui --base-href ./ && yarn run prepare:desktop && yarn ng:prod run api:desktop-api && yarn ng:prod build desktop-api --output-path=dist/apps/desktop/desktop-api && yarn ng:prod build desktop --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=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", @@ -243,14 +248,16 @@ "build:package:plugin:integration-wakatime:docker": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=60000 yarn nx build plugin-integration-wakatime", "build:package:all": "yarn run build:package:contracts && yarn run build:package:common && yarn run build:package:config && yarn run build:package:plugin && yarn run build:package:auth && yarn run build:package:plugins:pre && yarn run build:package:core && yarn run build:package:plugins:post && yarn run build:package:desktop-lib && yarn run build:package:plugin:integration-wakatime && yarn run build:package:desktop-ui-lib", "build:package:all:prod": "yarn run build:package:contracts:prod && yarn run build:package:common:prod && yarn run build:package:config:prod && yarn run build:package:plugin:prod && yarn run build:package:auth:prod && yarn run build:package:plugins:pre:prod && yarn run build:package:core:prod && yarn run build:package:plugins:post:prod && yarn run build:package:desktop-lib:prod && yarn run build:package:plugin:integration-wakatime:prod && yarn run build:package:desktop-ui-lib:prod", + "build:package:all:docker": "yarn run build:package:contracts:docker && yarn run build:package:common:docker && yarn run build:package:config:docker && yarn run build:package:plugin:docker && yarn run build:package:auth:docker && yarn run build:package:plugins:pre:docker && yarn run build:package:core:docker && yarn run build:package:plugins:post:docker && yarn run build:package:desktop-lib:docker && yarn run build:package:plugin:integration-wakatime:docker && yarn run build:package:desktop-ui-lib:docker", "build:package:api": "yarn run build:package:contracts && yarn run build:package:common && yarn run build:package:config && yarn run build:package:plugin && yarn run build:package:auth && yarn run build:package:core && yarn run build:package:plugins:post && yarn run build:package:plugin:integration-wakatime", "build:package:api:prod": "yarn run build:package:contracts:prod && yarn run build:package:common:prod && yarn run build:package:config:prod && yarn run build:package:plugin:prod && yarn run build:package:auth:prod && yarn run build:package:core:prod && yarn run build:package:plugins:post:prod", "build:package:api:docker": "yarn run build:package:contracts:docker && yarn run build:package:common:docker && yarn run build:package:config:docker && yarn run build:package:plugin:docker && yarn run build:package:auth:docker && yarn run build:package:core:docker && yarn run build:package:plugins:post:docker", "build:package:gauzy": "yarn run build:package:contracts && yarn run build:package:common && yarn run build:package:config && yarn run build:package:plugin && yarn run build:package:auth && yarn run build:package:plugins:pre && yarn run build:package:core && yarn run build:package:plugins:post", + "build:package:gauzy:prod": "yarn run build:package:contracts:prod && yarn run build:package:common:prod && yarn run build:package:config:prod && yarn run build:package:plugin:prod && yarn run build:package:auth:prod && yarn run build:package:plugins:pre:prod && yarn run build:package:core:prod && yarn run build:package:plugins:post:prod", "build:package:gauzy:docker": "yarn run build:package:contracts:docker && yarn run build:package:common:docker && yarn run build:package:config:docker && yarn run build:package:plugin:docker && yarn run build:package:auth:docker && yarn run build:package:plugins:pre:docker && yarn run build:package:core:docker && yarn run build:package:plugins:post:docker", "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 --base-href=./ && yarn run prepare:desktop-timer && yarn ng:prod build desktop-api --configuration=production --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.electron.json", + "build:desktop-timer": "cross-env NODE_ENV=production yarn copy-files-i18n-desktop-timer && yarn run postinstall.electron && yarn run config:prod && yarn run config:desktop-timer:prod && yarn build:package:all && yarn run pack:desktop-timer && yarn run generate:icons:desktop-timer --environment=prod && yarn ng:prod build desktop-timer --base-href=./ && yarn run prepare:desktop-timer && yarn ng:prod build desktop-api --configuration=production --output-path=dist/apps/desktop-timer/desktop-api && yarn run copy-assets-gauzy-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", @@ -262,14 +269,9 @@ "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", - "config:server:prod": "yarn run config:electron -- --environment=prod --desktop=server", - "config:desktop:prod": "yarn run config:electron -- --environment=prod --desktop=desktop", - "config:desktop-timer:prod": "yarn run config:electron -- --environment=prod --desktop=desktop-timer", "prepare:gauzy-server": "yarn run postinstall.electron && tsc -p apps/server/tsconfig.electron.json", "prepare:gauzy-server:dev": "yarn run postinstall.electron && tsc -p apps/server/tsconfig.dev.json", - "build:gauzy-server": "cross-env NODE_ENV=production yarn run copy-files-i18n-server && yarn run postinstall.electron && yarn run config:prod && yarn ng:prod run gauzy:server-ui && yarn ng:prod run api:gauzy-server-api && yarn run copy-files-gauzy-server", - "copy-files-gauzy-server": "copyfiles -f packages/core/src/**/*.gql dist/apps/gauzy-server/data/", + "build:gauzy-server": "cross-env NODE_ENV=production yarn run copy-files-i18n-server && yarn run postinstall.electron && yarn run config:server:prod && yarn run build:package:all:prod && yarn run pack:server && yarn run generate:icons:server --environment=prod && yarn ng:prod build gauzy-server --base-href ./ && yarn run prepare:gauzy-server && yarn ng run gauzy:server-ui && yarn ng run api:gauzy-server-api && yarn run copy-files-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", @@ -282,6 +284,7 @@ "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", + "copy-files-gauzy-server": "copyfiles -f packages/core/src/**/*.gql dist/apps/gauzy-server/data/", "generate:icons": "yarn ts-node .scripts/icon-utils/icon-factory.ts", "generate:icons:desktop-timer": "yarn run generate:icons --desktop=desktop-timer", "generate:icons:desktop": "yarn run generate:icons --desktop=desktop", @@ -291,10 +294,8 @@ "pack:desktop": "yarn run pack --desktop=desktop", "pack:server": "yarn run pack --desktop=server", "download:translations": "yarn ts-node .scripts/translation/translation-util.ts", - "config:api-server:prod": "yarn run config:electron -- --environment=prod --desktop=server-api", "prepare:gauzy-api-server": "yarn run postinstall.electron && tsc -p apps/server-api/tsconfig.electron.json", - "copy-files-gauzy-api-server": "copyfiles -f packages/core/src/**/*.gql dist/apps/gauzy-api-server/data/", - "build:gauzy-api-server": "cross-env NODE_ENV=production yarn run copy-files-i18n-api-server && yarn run postinstall.electron && yarn run config:prod && yarn build:package:all && 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 --base-href ./ && yarn run prepare:gauzy-api-server && yarn ng:prod run api:server-api && yarn run copy-files-gauzy-api-server", + "build:gauzy-api-server": "cross-env NODE_ENV=production yarn run copy-files-i18n-api-server && yarn run postinstall.electron && yarn run config:server-api:prod && yarn build:package:all && yarn run pack:api-server && yarn run generate:icons:server-api --environment=prod && yarn ng:prod build gauzy-api-server --base-href ./ && yarn run prepare:gauzy-api-server && yarn ng:prod run api:server-api && yarn run copy-files-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", @@ -304,6 +305,7 @@ "build:gauzy-api-server:linux:release:gh": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=60000 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", + "copy-files-gauzy-api-server": "copyfiles -f packages/core/src/**/*.gql dist/apps/gauzy-api-server/data/", "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" diff --git a/packages/contracts/src/lib/base-entity.model.ts b/packages/contracts/src/lib/base-entity.model.ts index 5915d1f3b8d..82a16651ba4 100644 --- a/packages/contracts/src/lib/base-entity.model.ts +++ b/packages/contracts/src/lib/base-entity.model.ts @@ -78,6 +78,7 @@ export enum BaseEntityEnum { Currency = 'Currency', DailyPlan = 'DailyPlan', Dashboard = 'Dashboard', + DashboardWidget = 'DashboardWidget', Employee = 'Employee', Expense = 'Expense', Invoice = 'Invoice', diff --git a/packages/contracts/src/lib/dashboard-widget.model.ts b/packages/contracts/src/lib/dashboard-widget.model.ts index e1060ddc5ac..d98dc76d8ef 100644 --- a/packages/contracts/src/lib/dashboard-widget.model.ts +++ b/packages/contracts/src/lib/dashboard-widget.model.ts @@ -21,4 +21,4 @@ export interface IDashboardWidget export interface IDashboardWidgetCreateInput extends IDashboardWidget {} -export interface IDashboardWidgetUpdateInput extends IDashboardWidgetCreateInput {} +export interface IDashboardWidgetUpdateInput extends Partial {} diff --git a/packages/core/src/lib/app/app.module.ts b/packages/core/src/lib/app/app.module.ts index c9f713c2259..334d41af227 100644 --- a/packages/core/src/lib/app/app.module.ts +++ b/packages/core/src/lib/app/app.module.ts @@ -156,7 +156,7 @@ import { ResourceLinkModule } from '../resource-link/resource-link.module'; import { MentionModule } from '../mention/mention.module'; import { SubscriptionModule } from '../subscription/subscription.module'; import { DashboardModule } from '../dashboard/dashboard.module'; - +import { DashboardWidgetModule } from '../dashboard/dashboard-widget/dashboard-widget.module'; const { unleashConfig } = environment; if (unleashConfig.url) { @@ -460,7 +460,8 @@ if (environment.THROTTLE_ENABLED) { ResourceLinkModule, MentionModule, SubscriptionModule, - DashboardModule + DashboardModule, + DashboardWidgetModule ], controllers: [AppController], providers: [ diff --git a/packages/core/src/lib/bootstrap/index.ts b/packages/core/src/lib/bootstrap/index.ts index 227ce3b2227..659132dae1b 100644 --- a/packages/core/src/lib/bootstrap/index.ts +++ b/packages/core/src/lib/bootstrap/index.ts @@ -105,10 +105,30 @@ export async function bootstrap(pluginConfig?: Partial) // Enable CORS with specific settings app.enableCors({ origin: '*', - methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', credentials: true, - allowedHeaders: - 'Authorization, Language, Tenant-Id, Organization-Id, X-Requested-With, X-Auth-Token, X-HTTP-Method-Override, Content-Type, Content-Language, Accept, Accept-Language, Observe' + methods: [ + 'GET', + 'HEAD', + 'PUT', + 'PATCH', + 'POST', + 'DELETE', + 'OPTIONS' + ].join(','), + allowedHeaders: [ + 'Authorization', + 'Language', + 'Tenant-Id', + 'Organization-Id', + 'X-Requested-With', + 'X-Auth-Token', + 'X-HTTP-Method-Override', + 'Content-Type', + 'Content-Language', + 'Accept', + 'Accept-Language', + 'Observe' + ].join(', ') }); // TODO: enable csurf is not good idea because it was deprecated. diff --git a/packages/core/src/lib/core/core.module.ts b/packages/core/src/lib/core/core.module.ts index 94213594b82..c2bc50420f8 100644 --- a/packages/core/src/lib/core/core.module.ts +++ b/packages/core/src/lib/core/core.module.ts @@ -13,6 +13,10 @@ import { GraphqlModule } from '../graphql/graphql.module'; import { GraphqlApiModule } from '../graphql/graphql-api.module'; import { DatabaseModule } from '../database/database.module'; +console.log(path.join(path.resolve(__dirname, '../**/', 'schema'), '*.gql')); +console.log(path.join(path.resolve(__dirname, '../../../../../../../data/'), '*.gql')); +console.log(environment.isElectron, 'Environment Is Electron'); + @Module({ imports: [ DatabaseModule, @@ -22,11 +26,31 @@ import { DatabaseModule } from '../database/database.module'; playground: configService.graphqlConfigOptions.playground, debug: configService.graphqlConfigOptions.debug, cors: { - methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', - credentials: true, origin: '*', - allowedHeaders: - 'Authorization, Language, Tenant-Id, Organization-Id, X-Requested-With, X-Auth-Token, X-HTTP-Method-Override, Content-Type, Content-Language, Accept, Accept-Language, Observe' + credentials: true, + methods: [ + 'GET', + 'HEAD', + 'PUT', + 'PATCH', + 'POST', + 'DELETE', + 'OPTIONS' + ].join(','), + allowedHeaders: [ + 'Authorization', + 'Language', + 'Tenant-Id', + 'Organization-Id', + 'X-Requested-With', + 'X-Auth-Token', + 'X-HTTP-Method-Override', + 'Content-Type', + 'Content-Language', + 'Accept', + 'Accept-Language', + 'Observe' + ].join(', ') }, typePaths: [ environment.isElectron @@ -41,7 +65,17 @@ import { DatabaseModule } from '../database/database.module'; providers: [] }) export class CoreModule implements NestModule { - configure(consumer: MiddlewareConsumer) { + /** + * Configures middleware for the application. + * + * This method applies the specified middleware to the application using the + * provided `MiddlewareConsumer`. In this case, the `RequestContextMiddleware` + * is applied to all routes in the application. + * + * @param consumer - The `MiddlewareConsumer` provided by NestJS, used to manage + * middleware configurations for the application. + */ + configure(consumer: MiddlewareConsumer): void { consumer.apply(RequestContextMiddleware).forRoutes('*'); } } diff --git a/packages/core/src/lib/dashboard/dashboard-widget/commands/dashboard-widget.create.command.ts b/packages/core/src/lib/dashboard/dashboard-widget/commands/dashboard-widget.create.command.ts new file mode 100644 index 00000000000..b912e1cdbbd --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/commands/dashboard-widget.create.command.ts @@ -0,0 +1,8 @@ +import { ICommand } from '@nestjs/cqrs'; +import { IDashboardWidgetCreateInput } from '@gauzy/contracts'; + +export class DashboardWidgetCreateCommand implements ICommand { + static readonly type = '[DashboardWidget] Create'; + + constructor(public readonly input: IDashboardWidgetCreateInput) {} +} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/commands/dashboard-widget.update.command.ts b/packages/core/src/lib/dashboard/dashboard-widget/commands/dashboard-widget.update.command.ts new file mode 100644 index 00000000000..91ee5c37677 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/commands/dashboard-widget.update.command.ts @@ -0,0 +1,8 @@ +import { ICommand } from '@nestjs/cqrs'; +import { ID, IDashboardWidgetUpdateInput } from '@gauzy/contracts'; + +export class DashboardWidgetUpdateCommand implements ICommand { + static readonly type = '[DashboardWidget] Update'; + + constructor(public readonly id: ID, public readonly input: IDashboardWidgetUpdateInput) {} +} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/dashboard-widget.create.handler.ts b/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/dashboard-widget.create.handler.ts new file mode 100644 index 00000000000..570978d09c6 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/dashboard-widget.create.handler.ts @@ -0,0 +1,20 @@ +import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; +import { IDashboardWidget } from '@gauzy/contracts'; +import { DashboardWidgetService } from '../../dashboard-widget.service'; +import { DashboardWidgetCreateCommand } from '../dashboard-widget.create.command'; + +@CommandHandler(DashboardWidgetCreateCommand) +export class DashboardWidgetCreateHandler implements ICommandHandler { + constructor(private readonly dashboardWidgetService: DashboardWidgetService) {} + + /** + * Handles the DashboardWidgetCreateCommand to create a new dashboard widget. + * + * @param command - The command containing the input data for dashboard widget creation. + * @returns A promise that resolves to the created dashboard widget. + */ + public async execute(command: DashboardWidgetCreateCommand): Promise { + const { input } = command; + return this.dashboardWidgetService.create(input); + } +} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/dashboard-widget.update.handler.ts b/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/dashboard-widget.update.handler.ts new file mode 100644 index 00000000000..5bee8d02582 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/dashboard-widget.update.handler.ts @@ -0,0 +1,20 @@ +import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; +import { IDashboardWidget } from '@gauzy/contracts'; +import { DashboardWidgetService } from '../../dashboard-widget.service'; +import { DashboardWidgetUpdateCommand } from '../dashboard-widget.update.command'; + +@CommandHandler(DashboardWidgetUpdateCommand) +export class DashboardWidgetUpdateHandler implements ICommandHandler { + constructor(private readonly dashboardWidgetService: DashboardWidgetService) {} + + /** + * Handles the DashboardWidgetUpdateCommand to update an existing dashboard widget. + * + * @param command - The command containing the id and input data for dashboard widget update. + * @returns A promise that resolves to the updated dashboard widget. + */ + public async execute(command: DashboardWidgetUpdateCommand): Promise { + const { id, input } = command; + return this.dashboardWidgetService.update(id, input); + } +} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/index.ts b/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/index.ts new file mode 100644 index 00000000000..3f264350798 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/commands/handlers/index.ts @@ -0,0 +1,4 @@ +import { DashboardWidgetCreateHandler } from './dashboard-widget.create.handler'; +import { DashboardWidgetUpdateHandler } from './dashboard-widget.update.handler'; + +export const CommandHandlers = [DashboardWidgetCreateHandler, DashboardWidgetUpdateHandler]; diff --git a/packages/core/src/lib/dashboard/dashboard-widget/commands/index.ts b/packages/core/src/lib/dashboard/dashboard-widget/commands/index.ts new file mode 100644 index 00000000000..8a5a1838669 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/commands/index.ts @@ -0,0 +1,2 @@ +export * from './dashboard-widget.create.command'; +export * from './dashboard-widget.update.command'; diff --git a/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.controller.ts b/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.controller.ts new file mode 100644 index 00000000000..6f4e3521f8f --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.controller.ts @@ -0,0 +1,114 @@ +import { CommandBus } from '@nestjs/cqrs'; +import { Controller, Query, Get, HttpStatus, Param, Post, Body, HttpCode, Put, Delete } from '@nestjs/common'; +import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; +import { UseGuards } from '@nestjs/common'; +import { DeleteResult } from 'typeorm'; +import { ID, IPagination, PermissionsEnum } from '@gauzy/contracts'; +import { PermissionGuard, TenantPermissionGuard } from '../../shared/guards'; +import { Permissions } from '../../shared/decorators'; +import { UseValidationPipe, UUIDValidationPipe } from '../../shared/pipes'; +import { CrudController, PaginationParams } from '../../core/crud'; +import { DashboardWidget } from './dashboard-widget.entity'; +import { DashboardWidgetCreateCommand, DashboardWidgetUpdateCommand } from './commands'; +import { DashboardWidgetService } from './dashboard-widget.service'; +import { CreateDashboardWidgetDTO, UpdateDashboardWidgetDTO } from './dto'; + +@ApiTags('Dashboard Widget') +@UseGuards(TenantPermissionGuard, PermissionGuard) +@Permissions(PermissionsEnum.DASHBOARD_READ) +@Controller('dashboard-widget') +export class DashboardWidgetController extends CrudController { + constructor( + private readonly dashboardWidgetService: DashboardWidgetService, + private readonly commandBus: CommandBus + ) { + super(dashboardWidgetService); + } + + @ApiOperation({ summary: 'Get dashboard widgets.' }) + @ApiResponse({ + status: HttpStatus.OK, + description: 'Found dashboard widgets', + type: DashboardWidget + }) + @ApiResponse({ + status: HttpStatus.NOT_FOUND, + description: 'Records not found' + }) + @Permissions(PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.DASHBOARD_READ) + @Get() + async findAll(@Query() params: PaginationParams): Promise> { + return this.dashboardWidgetService.findAll(params); + } + + @ApiOperation({ summary: 'Find by id.' }) + @ApiResponse({ + status: HttpStatus.OK, + description: 'Found dashboard widget', + type: DashboardWidget + }) + @ApiResponse({ + status: HttpStatus.NOT_FOUND, + description: 'Record not found' + }) + @Permissions(PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.DASHBOARD_READ) + @Get(':id') + @UseValidationPipe() + async findById( + @Param('id', UUIDValidationPipe) id: ID, + @Query() params: PaginationParams + ): Promise { + return this.dashboardWidgetService.findOneByIdString(id, params); + } + + @ApiOperation({ summary: 'Create dashboard widget.' }) + @ApiResponse({ + status: HttpStatus.CREATED, + description: 'The record has been successfully created.' + }) + @Permissions(PermissionsEnum.ALL_ORG_EDIT) + @Post() + @UseValidationPipe({ whitelist: true }) + async create(@Body() entity: CreateDashboardWidgetDTO): Promise { + return await this.commandBus.execute(new DashboardWidgetCreateCommand(entity)); + } + + @ApiOperation({ summary: 'Update dashboard widget.' }) + @ApiResponse({ + status: HttpStatus.CREATED, + description: 'The record has been successfully updated.' + }) + @ApiResponse({ + status: HttpStatus.NOT_FOUND, + description: 'Record not found' + }) + @ApiResponse({ + status: HttpStatus.BAD_REQUEST, + description: 'Invalid input, The response body may contain clues as to what went wrong' + }) + @HttpCode(HttpStatus.ACCEPTED) + @Permissions(PermissionsEnum.ALL_ORG_EDIT) + @Put(':id') + @UseValidationPipe({ whitelist: true }) + async update( + @Param('id', UUIDValidationPipe) id: ID, + @Body() entity: UpdateDashboardWidgetDTO + ): Promise { + return await this.commandBus.execute(new DashboardWidgetUpdateCommand(id, entity)); + } + + @ApiOperation({ summary: 'Delete dashboard widget.' }) + @ApiResponse({ + status: HttpStatus.OK, + description: 'The record has been successfully deleted.' + }) + @ApiResponse({ + status: HttpStatus.NOT_FOUND, + description: 'Record not found' + }) + @Permissions(PermissionsEnum.ALL_ORG_EDIT) + @Delete(':id') + async delete(@Param('id', UUIDValidationPipe) id: ID): Promise { + return await this.dashboardWidgetService.delete(id); + } +} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.module.ts b/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.module.ts index 9634fae415c..0daf0204256 100644 --- a/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.module.ts +++ b/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.module.ts @@ -1,4 +1,23 @@ +import { CqrsModule } from '@nestjs/cqrs'; +import { MikroOrmModule } from '@mikro-orm/nestjs'; import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { RolePermissionModule } from '../../role-permission/role-permission.module'; +import { CommandHandlers } from './commands/handlers'; +import { DashboardWidget } from './dashboard-widget.entity'; +import { DashboardWidgetService } from './dashboard-widget.service'; +import { DashboardWidgetController } from './dashboard-widget.controller'; +import { TypeOrmDashboardWidgetRepository } from './repository/type-orm-dashboard-widget.repository'; -@Module({}) +@Module({ + imports: [ + MikroOrmModule.forFeature([DashboardWidget]), + TypeOrmModule.forFeature([DashboardWidget]), + RolePermissionModule, + CqrsModule + ], + providers: [DashboardWidgetService, TypeOrmDashboardWidgetRepository, ...CommandHandlers], + controllers: [DashboardWidgetController], + exports: [TypeOrmModule, DashboardWidgetService, TypeOrmDashboardWidgetRepository] +}) export class DashboardWidgetModule {} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.service.ts b/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.service.ts new file mode 100644 index 00000000000..27469cf8561 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.service.ts @@ -0,0 +1,112 @@ +import { Injectable } from '@nestjs/common'; + +import { HttpException, HttpStatus, NotFoundException } from '@nestjs/common'; +import { + ActionTypeEnum, + BaseEntityEnum, + ActorTypeEnum, + IDashboardWidgetCreateInput, + IDashboardWidgetUpdateInput, + ID +} from '@gauzy/contracts'; +import { TenantAwareCrudService } from '../../core/crud'; +import { RequestContext } from '../../core/context'; +import { DashboardWidget } from './dashboard-widget.entity'; +import { TypeOrmDashboardWidgetRepository } from './repository/type-orm-dashboard-widget.repository'; +import { MikroOrmDashboardWidgetRepository } from './repository/mikro-orm-dashboard-widget.repository'; +import { ActivityLogService } from '../../activity-log/activity-log.service'; + +@Injectable() +export class DashboardWidgetService extends TenantAwareCrudService { + constructor( + readonly typeOrmDashboardWidgetRepository: TypeOrmDashboardWidgetRepository, + readonly mikroOrmDashboardWidgetRepository: MikroOrmDashboardWidgetRepository, + private readonly activityLogService: ActivityLogService + ) { + super(typeOrmDashboardWidgetRepository, mikroOrmDashboardWidgetRepository); + } + + /** + * Creates a new dashboard widget + * + * @param {IDashboardWidgetCreateInput} input - The input data for creating a dashboard widget + * @returns {Promise} The created dashboard widget + */ + async create(input: IDashboardWidgetCreateInput): Promise { + try { + const employeeId = input.employeeId || RequestContext.currentEmployeeId(); + const tenantId = RequestContext.currentTenantId(); + const { organizationId } = input; + + // create dashboard widget + const dashboardWidget = await super.create({ + ...input, + employeeId, + tenantId + }); + + // Generate the activity log + this.activityLogService.logActivity( + BaseEntityEnum.DashboardWidget, + ActionTypeEnum.Created, + ActorTypeEnum.User, + dashboardWidget.id, + dashboardWidget.name, + dashboardWidget, + organizationId, + tenantId + ); + + // Return the created widget + return dashboardWidget; + } catch (error) { + throw new HttpException(`Failed to create dashboard widget: ${error.message}`, HttpStatus.BAD_REQUEST); + } + } + + /** + * Updates an existing dashboard widget + * + * @param {ID} id - The ID of the dashboard widget to update + * @param {IDashboardWidgetUpdateInput} input - The input data for updating a dashboard widget + * @returns {Promise} The updated dashboard widget + */ + async update(id: ID, input: IDashboardWidgetUpdateInput): Promise { + const tenantId = RequestContext.currentTenantId() || input.tenantId; + + try { + const { organizationId } = input; + + // Retrieve existing dashboard widget + const existingDashboardWidget = await this.findOneByIdString(id); + + if (!existingDashboardWidget) { + throw new NotFoundException(`Dashboard widget with id ${id} not found`); + } + + // Update the widget + const updatedWidget = await super.create({ + ...input, + id + }); + + // Log the update activity + this.activityLogService.logActivity( + BaseEntityEnum.DashboardWidget, + ActionTypeEnum.Updated, + ActorTypeEnum.User, + updatedWidget.id, + updatedWidget.name, + updatedWidget, + organizationId, + tenantId, + existingDashboardWidget, + input + ); + + return updatedWidget; + } catch (error) { + throw new HttpException(`Failed to update dashboard widget: ${error.message}`, HttpStatus.BAD_REQUEST); + } + } +} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.subscriber.ts b/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.subscriber.ts new file mode 100644 index 00000000000..1601aa3b406 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/dashboard-widget.subscriber.ts @@ -0,0 +1,84 @@ +import { EventSubscriber } from 'typeorm'; +import { isSqlite, isBetterSqlite3 } from '@gauzy/config'; +import { BaseEntityEventSubscriber } from '../../core/entities/subscribers/base-entity-event.subscriber'; +import { DashboardWidget } from './dashboard-widget.entity'; + +@EventSubscriber() +export class DashboardWidgetSubscriber extends BaseEntityEventSubscriber { + /** + * Indicates that this subscriber only listens to DashboardWidget events. + */ + listenTo() { + return DashboardWidget; + } + + /** + * Called before a DashboardWidget entity is inserted or updated in the database. + * This method prepares the entity for insertion or update by serializing the options property to a JSON string + * for SQLite databases. + * + * @param entity The DashboardWidget entity that is about to be created or updated. + * @returns {Promise} A promise that resolves when the pre-creation or pre-update processing is complete. + */ + private async serializeOptionsForSQLite(entity: DashboardWidget): Promise { + try { + // Check if the database is SQLite + if (isSqlite() || isBetterSqlite3()) { + // serialize the `options` field if it's an object + if (typeof entity.options === 'object') { + entity.options = JSON.stringify(entity.options); + } + } + } catch (error) { + // Log the error and reset the data to an empty object if JSON parsing fails + console.error(error); + entity.options = '{}'; + } + } + + /** + * Called before a DashboardWidget entity is inserted or created in the database. + * This method prepares the entity for insertion by serializing the options property to a JSON string for SQLite DBs + * + * @param entity The DashboardWidget entity that is about to be created. + * @returns {Promise} A promise that resolves when the pre-insertion processing is complete. + */ + async beforeEntityCreate(entity: DashboardWidget): Promise { + await this.serializeOptionsForSQLite(entity); + } + + /** + * Called before a DashboardWidget entity is updated in the database. + * This method prepares the entity for update by serializing the options property to a JSON string + * + * @param entity The DashboardWidget entity that is about to be updated. + * @returns {Promise} A promise that resolves when the pre-update processing is complete. + */ + async beforeEntityUpdate(entity: DashboardWidget): Promise { + await this.serializeOptionsForSQLite(entity); + } + + /** + * Handles the parsing of JSON data after the DashboardWidget entity is loaded from the database. + * This function ensures that if the database is SQLite, the `options` field, stored as a JSON string, + * is parsed back into a JavaScript object. + * + * @param {DashboardWidget} entity - The DashboardWidget entity that has been loaded from the database. + * @returns {Promise} A promise that resolves once the after-load processing is complete. + */ + async afterEntityLoad(entity: DashboardWidget): Promise { + try { + // Check if the database is SQLite + if (isSqlite() || isBetterSqlite3()) { + // Parse the `options` field if it's a string + if (typeof entity.options === 'string') { + entity.options = JSON.parse(entity.options); + } + } + } catch (error) { + // Log the error and reset the options to an empty object if JSON parsing fails + console.error('Error parsing options JSON:', error); + entity.options = {}; + } + } +} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/dto/create-dashboard-widget.dto.ts b/packages/core/src/lib/dashboard/dashboard-widget/dto/create-dashboard-widget.dto.ts new file mode 100644 index 00000000000..b37efc5cca3 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/dto/create-dashboard-widget.dto.ts @@ -0,0 +1,11 @@ +import { IntersectionType } from '@nestjs/swagger'; +import { IDashboardWidgetCreateInput } from '@gauzy/contracts'; +import { TenantOrganizationBaseDTO } from '../../../core/dto'; +import { DashboardWidget } from '../dashboard-widget.entity'; + +/** + * Create Dashboard Widget validation request DTO + */ +export class CreateDashboardWidgetDTO + extends IntersectionType(TenantOrganizationBaseDTO, DashboardWidget) + implements IDashboardWidgetCreateInput {} diff --git a/packages/core/src/lib/dashboard/dashboard-widget/dto/index.ts b/packages/core/src/lib/dashboard/dashboard-widget/dto/index.ts new file mode 100644 index 00000000000..6275e9dab34 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/dto/index.ts @@ -0,0 +1,2 @@ +export * from './create-dashboard-widget.dto'; +export * from './update-dashboard-widget.dto'; diff --git a/packages/core/src/lib/dashboard/dashboard-widget/dto/update-dashboard-widget.dto.ts b/packages/core/src/lib/dashboard/dashboard-widget/dto/update-dashboard-widget.dto.ts new file mode 100644 index 00000000000..8e1fec952d9 --- /dev/null +++ b/packages/core/src/lib/dashboard/dashboard-widget/dto/update-dashboard-widget.dto.ts @@ -0,0 +1,7 @@ +import { PartialType } from '@nestjs/swagger'; +import { IDashboardWidgetUpdateInput } from '@gauzy/contracts'; +import { CreateDashboardWidgetDTO } from './create-dashboard-widget.dto'; + +export class UpdateDashboardWidgetDTO + extends PartialType(CreateDashboardWidgetDTO) + implements IDashboardWidgetUpdateInput {} diff --git a/packages/core/src/lib/dashboard/dashboard.controller.ts b/packages/core/src/lib/dashboard/dashboard.controller.ts index a777a89a856..8e06c9fa940 100644 --- a/packages/core/src/lib/dashboard/dashboard.controller.ts +++ b/packages/core/src/lib/dashboard/dashboard.controller.ts @@ -13,6 +13,7 @@ import { UseGuards } from '@nestjs/common'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; +import { DeleteResult } from 'typeorm'; import { ID, IPagination, PermissionsEnum } from '@gauzy/contracts'; import { PermissionGuard, TenantPermissionGuard } from '../shared/guards'; import { Permissions } from '../shared/decorators'; @@ -22,7 +23,6 @@ import { Dashboard } from './dashboard.entity'; import { DashboardService } from './dashboard.service'; import { DashboardCreateCommand, DashboardUpdateCommand } from './commands'; import { CreateDashboardDTO, UpdateDashboardDTO } from './dto'; -import { DeleteResult } from 'typeorm'; @ApiTags('Dashboard') @UseGuards(TenantPermissionGuard, PermissionGuard) diff --git a/packages/core/src/lib/dashboard/dashboard.service.ts b/packages/core/src/lib/dashboard/dashboard.service.ts index 82c69f5e939..608a0226222 100644 --- a/packages/core/src/lib/dashboard/dashboard.service.ts +++ b/packages/core/src/lib/dashboard/dashboard.service.ts @@ -64,6 +64,7 @@ export class DashboardService extends TenantAwareCrudService { /** * Updates an existing dashboard * + * @param {ID} id - The ID of the dashboard to update * @param {IDashboardUpdateInput} input - The input data for updating a dashboard * @returns {Promise} The updated dashboard */ diff --git a/packages/core/src/lib/graphql/graphql-helper.ts b/packages/core/src/lib/graphql/graphql-helper.ts index da19b688be0..831ff200290 100644 --- a/packages/core/src/lib/graphql/graphql-helper.ts +++ b/packages/core/src/lib/graphql/graphql-helper.ts @@ -25,10 +25,31 @@ export async function createGraphqlModuleOptions( playground: options.playground || false, debug: options.debug || false, cors: { - methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', - credentials: true, origin: '*', - allowedHeaders: 'Authorization, Language, Tenant-Id, Organization-Id, X-Requested-With, X-Auth-Token, X-HTTP-Method-Override, Content-Type, Content-Language, Accept, Accept-Language, Observe' + credentials: true, + methods: [ + 'GET', + 'HEAD', + 'PUT', + 'PATCH', + 'POST', + 'DELETE', + 'OPTIONS' + ].join(','), + allowedHeaders: [ + 'Authorization', + 'Language', + 'Tenant-Id', + 'Organization-Id', + 'X-Requested-With', + 'X-Auth-Token', + 'X-HTTP-Method-Override', + 'Content-Type', + 'Content-Language', + 'Accept', + 'Accept-Language', + 'Observe' + ].join(', ') }, include: [options.resolverModule] } as GqlModuleOptions; diff --git a/packages/ui-core/static/styles/material/_material-dark.scss b/packages/ui-core/static/styles/material/_material-dark.scss index 5f10928010c..64fd08c0d5c 100644 --- a/packages/ui-core/static/styles/material/_material-dark.scss +++ b/packages/ui-core/static/styles/material/_material-dark.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #fff2f7, color-primary-200: #ffd4e3, color-primary-300: #fc9abc, @@ -358,13 +359,13 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote( + shadow: string.unquote( '0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12)' ), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12)' ), diff --git a/packages/ui-core/static/styles/material/_material-light.scss b/packages/ui-core/static/styles/material/_material-light.scss index 3058c9da301..81b23ab5ef8 100644 --- a/packages/ui-core/static/styles/material/_material-light.scss +++ b/packages/ui-core/static/styles/material/_material-light.scss @@ -3,8 +3,9 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ +@use "sass:string"; - $theme: ( +$theme: ( color-primary-100: #e8cbfe, color-primary-200: #ce97fd, color-primary-300: #ae63f9, @@ -358,11 +359,11 @@ text-danger-active-color: color-danger-active, text-danger-disabled-color: color-danger-400, - font-family-primary: unquote('Roboto, sans-serif'), + font-family-primary: string.unquote('Roboto, sans-serif'), - shadow: unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), + shadow: string.unquote('0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12)'), card-shadow: shadow, - header-shadow: unquote( + header-shadow: string.unquote( '0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12)' ), diff --git a/packages/ui-core/static/styles/themes.scss b/packages/ui-core/static/styles/themes.scss index 2780cfc1922..6d164240e3c 100644 --- a/packages/ui-core/static/styles/themes.scss +++ b/packages/ui-core/static/styles/themes.scss @@ -1,3 +1,4 @@ +@use "sass:string"; // @nebular theming framework @import '@nebular/theme/styles/theming'; // @nebular out of the box themes @@ -305,8 +306,8 @@ $nb-themes: nb-register-theme( tabset-tab-focus-underline-color: none, tabset-tab-text-transform: capitalize, button-filled-text-transform: none, - font-family-primary: unquote('Inter, sans-serif'), - font-family-secondary: unquote('Inter, sans-serif'), + font-family-primary: string.unquote('Inter, sans-serif'), + font-family-secondary: string.unquote('Inter, sans-serif'), button-outline-text-transform: none, gauzy-text-contact: #323232, button-filled-medium-padding: 0.4375rem 0.875rem, @@ -389,8 +390,8 @@ $nb-themes: nb-register-theme( tabset-tab-focus-underline-color: none, tabset-tab-text-transform: capitalize, button-filled-text-transform: none, - font-family-primary: unquote('Inter, sans-serif'), - font-family-secondary: unquote('Inter, sans-serif'), + font-family-primary: string.unquote('Inter, sans-serif'), + font-family-secondary: string.unquote('Inter, sans-serif'), button-outline-text-transform: none, button-filled-medium-padding: 0.4375rem 0.875rem, button-outline-medium-padding: 0.4375rem 0.875rem,