chore: update Angular to v21 (#9390)

* @rahul-rocket chore(deps): chore(deps): bump @angular/core from ^20.2.4 to 21.1.2

* fix(ui): update missing jest.preset.js

* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4

* chore(deps): bump jest-preset-angular to 16.0.0

* chore(deps): bump @nebular/* packages to 17.0.0 for Angular 21 compatibility

* chore(deps): upgrade all packages to Angular 21 and compatible dependencies

* chore(deps): upgrade all packages to Angular 21 and compatible dependencies

* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4

* Update yarn.lock

* Update yarn.lock

* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4

* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4

Replace 'jest-preset-angular/setup-jest' imports with the new 'setupZoneTestEnv' function.

* @nx/jest: replace-removed-matcher-aliases-v22-3

Replace removed matcher aliases in Jest v30 with their corresponding matcher

* chore(deps): @angular/common and @angular/core peerDependencies to ^21.1.0

* Update package.json

* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4

* chore(deps): bump @nebular/theme from ^16.0.0 to ^17.0.0

* chore(deps): upgrade all packages to Angular 21

* chore(deps): upgrade all packages to Angular 21

* fix(build): update helmet import to support 8.x default export

* fix(build): resolve TypeScript errors and improve code quality

- Fix TemplateRef type conflicts caused by duplicate @angular/core packages (ngx-permissions)
- Change moment imports from namespace to default imports for ESM compatibility
- Convert constructor injection to inject() function in multiple components
- Add OnPush change detection strategy to WindowLayoutComponent
- Make CountdownConfirmationComponent standalone
- Update LayoutWithDraggableObject to use any[] for draggableObject type

* fix(build): fix moment & timezone namespace packages

* fix(build): add jest config for missing packages

* chore(deps): bump swiper from 8.3.1 to 12.1.0

* fix(build): update swiper module and syntax

* Update time-tracking.component.ts

* chore(deps): downgrade `node-polyfill-webpack-plugin` from 4.1.0 to 1.1.4

* fix(deps): resolve browserslist "Unknown version 143 of and_chr" error

Add caniuse-lite and browserslist to yarn resolutions to force all

* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4

* fix(deps): standardize Angular 21.0.0 versions across all packages and fix compatibility issues

- Fix @angular/* packages to use exact version 21.0.0 (remove caret ^) across all apps, packages, and plugins
- Add @angular/cdk resolution to 21.0.0 to force consistent version

* fix(build): `ui-config` replace env files module issue

* fix(build): `ui-config` replace env files module issue

* fix(build): replace all TemplateRef<HTMLElement> with TemplateRef<any>

* Update package.json

* Update apps\agent\tsconfig.json

* chore(deps): upgrade packages to latest version

* Update yarn.lock

* Update yarn.lock

* fix(build): apply AI suggestion by bot agent reviewers

* fix(build): apply AI suggestion by bot agent reviewers

* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4

* chore(deps): bump @nestjs/common and @nestjs/core to 11.1.14

* fix(build): replace all TemplateRef<HTMLElement> with TemplateRef<any>

* fix(plugins): apply AI suggestion by bot agent reviewers

* Update yarn.lock

* chore(deps): bump packages

* Update yarn.lock

* chore(deps): bump packages

* chore(deps): bump packages

* fix(plugins): replace 'jest-preset-angular/setup-jest' imports with the new 'setupZoneTestEnv'

* fix(plugins): apply AI suggestion by bot agent reviewers

* fix(cspell): typo spelling :-)

* fix(plugins): apply AI suggestion by bot agent reviewers

* fix: fontawesome icon change version to FA 7

* refactor(ui-core): migrate dashboard directives to standalone

* refactor(ui-core): migrate pipes/directives to standalone

* fix(plugins): apply AI suggestion by bot agent reviewers

* fix(plugins): apply AI suggestion by bot agent reviewers

* chore(deps): bump packages

* refactor(ui-core): migrate directives to standalone

* fix(plugins): apply AI suggestion by bot agent reviewers

---------

Co-authored-by: Ruslan Konviser <evereq@gmail.com>
Co-authored-by: syns2191 <sutralian@gmail.com>
This commit is contained in:
Rahul R.
2026-02-20 09:52:34 +01:00
committed by GitHub
co-authored by Ruslan Konviser syns2191
parent ca6250692d
commit b161467904
594 changed files with 12147 additions and 10996 deletions
+5
View File
@@ -81,6 +81,7 @@
"Bykey",
"cacheable",
"camelcase",
"caniuse",
"camshot",
"camshot",
"camshots",
@@ -149,6 +150,7 @@
"dbname",
"DDTHH",
"dearmor",
"deepmerge",
"Dejavu",
"democivo",
"democw",
@@ -334,6 +336,7 @@
"iubgreen",
"IURL",
"iwindow",
"jalaali",
"jasminewd",
"javascripts",
"Jaye",
@@ -709,7 +712,9 @@
"theora",
"Theora",
"thmb",
"Tmpl",
"timeframe",
"timeformat",
"timegrid",
"TIMELOG",
"timelogs",
+15 -14
View File
@@ -37,22 +37,22 @@
"electronmon": "^2.0.2"
},
"dependencies": {
"@angular/animations": "^20.2.4",
"@angular/cdk": "^20.2.14",
"@angular/common": "^20.2.4",
"@angular/core": "^20.2.4",
"@angular/forms": "^20.2.4",
"@angular/material": "^20.2.14",
"@angular/router": "^20.2.4",
"@angular/animations": "21.0.0",
"@angular/cdk": "21.0.0",
"@angular/common": "21.0.0",
"@angular/core": "21.0.0",
"@angular/forms": "21.0.0",
"@angular/material": "21.0.0",
"@angular/router": "21.0.0",
"@datorama/akita": "^8.0.1",
"@datorama/akita-ngdevtools": "^7.0.0",
"@electron/remote": "^2.0.8",
"@grpc/grpc-js": "^1.6.7",
"@nebular/auth": "^16.0.0",
"@grpc/grpc-js": "^1.7.3",
"@nebular/auth": "^17.0.0",
"@nebular/bootstrap": "^9.1.0-rc.6",
"@nebular/security": "^16.0.0",
"@nebular/theme": "^16.0.0",
"@ng-select/ng-select": "^20.7.0",
"@nebular/security": "^17.0.0",
"@nebular/theme": "^17.0.0",
"@ng-select/ng-select": "^21.0.0",
"@ngx-translate/core": "^17.0.0",
"@ngx-translate/http-loader": "^17.0.0",
"@ngneat/until-destroy": "^10.0.0",
@@ -75,7 +75,7 @@
"moment-duration-format": "^2.3.2",
"moment-range": "^4.0.2",
"moment-timezone": "^0.6.0",
"mysql2": "^3.12.0",
"mysql2": "^3.16.3",
"node-fetch": "^2.6.7",
"node-notifier": "^8.0.0",
"pg": "^8.17.2",
@@ -85,7 +85,7 @@
"sound-play": "1.1.0",
"squirrelly": "^8.0.8",
"twing": "^5.0.2",
"underscore": "^1.13.3",
"underscore": "^1.13.8",
"form-data": "^4.0.1",
"is-online": "^9.0.1"
},
@@ -108,3 +108,4 @@
"logLevel": "quiet"
}
}
+3 -3
View File
@@ -638,7 +638,7 @@ angular2-smart-table {
}
.ng-arrow {
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
border-color: inherit !important;
border-width: 0 !important;
font-size: 10px;
@@ -692,7 +692,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 5 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
transform: rotate(180deg) !important;
@@ -709,7 +709,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
top: 55% !important;
@@ -444,7 +444,7 @@ $default-box-shadow: var(--gauzy-shadow);
border-width: 2px !important;
border-color: nb-theme(background-primary-color-1) !important;
font-family: 'Font Awesome 5 Pro' !important;
font-family: 'Font Awesome 7 free' !important;
font-style: normal !important;
font-weight: 400 !important;
font-size: 7px !important;
+3 -1
View File
@@ -5,7 +5,8 @@ import {
enableProdMode,
importProvidersFrom,
inject,
provideAppInitializer
provideAppInitializer,
provideZoneChangeDetection
} from '@angular/core';
import { BrowserModule, bootstrapApplication } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
@@ -83,6 +84,7 @@ if (environment.SENTRY_DSN) {
bootstrapApplication(AppComponent, {
providers: [
provideZoneChangeDetection(),
importProvidersFrom(
NbLayoutModule,
AuthModule,
+3 -1
View File
@@ -5,4 +5,6 @@ globalThis.ngJest = {
errorOnUnknownProperties: true
}
};
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv();
+3 -1
View File
@@ -8,7 +8,9 @@
"noPropertyAccessFromIndexSignature": false,
"noImplicitReturns": false,
"noFallthroughCasesInSwitch": false,
"types": ["node", "google.maps"]
"types": ["node", "google.maps"],
"module": "preserve",
"moduleResolution": "bundler"
},
"files": [],
"include": [],
+4 -2
View File
@@ -2,9 +2,11 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"module": "preserve",
"target": "es2016",
"types": ["jest", "node"]
"types": ["jest", "node"],
"moduleResolution": "bundler",
"isolatedModules": true
},
"files": ["src/test-setup.ts"],
"include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
+1 -1
View File
@@ -1,4 +1,4 @@
import * as path from 'path';
import * as path from 'node:path';
import * as chalk from 'chalk';
import { ApplicationPluginConfig } from '@gauzy/common';
import { DEFAULT_API_PORT, DEFAULT_GRAPHQL_API_PATH, DEFAULT_API_HOST, DEFAULT_API_BASE_URL } from '@gauzy/constants';
+1 -1
View File
@@ -38,7 +38,7 @@
],
"dependencies": {
"@grpc/grpc-js": "^1.6.7",
"@mikro-orm/core": "^6.6.5",
"@mikro-orm/core": "^6.6.7",
"@mikro-orm/nestjs": "^6.1.1",
"@nestjs/common": "^11.1.14",
"@nestjs/core": "^11.1.14",
@@ -1,17 +1,14 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
describe('AppController', () => {
let app: TestingModule;
beforeAll(async () => {
app = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService]
}).compile();
});
describe('getData', () => {
it('should return "Welcome to desktop-api!"', () => {
const appController = app.get<AppController>(AppController);
@@ -1,17 +1,13 @@
import { Test } from '@nestjs/testing';
import { AppService } from './app.service';
describe('AppService', () => {
let service: AppService;
beforeAll(async () => {
const app = await Test.createTestingModule({
providers: [AppService]
}).compile();
service = app.get<AppService>(AppService);
});
describe('getData', () => {
it('should return "Welcome to desktop-api!"', () => {
expect(service.getData()).toEqual({
+14 -13
View File
@@ -34,22 +34,22 @@
"terser-webpack-plugin": "^5.3.16"
},
"dependencies": {
"@angular/animations": "^20.2.4",
"@angular/cdk": "^20.2.14",
"@angular/common": "^20.2.4",
"@angular/core": "^20.2.4",
"@angular/forms": "^20.2.4",
"@angular/material": "^20.2.14",
"@angular/router": "^20.2.4",
"@angular/animations": "21.0.0",
"@angular/cdk": "21.0.0",
"@angular/common": "21.0.0",
"@angular/core": "21.0.0",
"@angular/forms": "21.0.0",
"@angular/material": "21.0.0",
"@angular/router": "21.0.0",
"@datorama/akita": "^8.0.1",
"@datorama/akita-ngdevtools": "^7.0.0",
"@electron/remote": "^2.0.8",
"@grpc/grpc-js": "^1.6.7",
"@nebular/auth": "^16.0.0",
"@nebular/auth": "^17.0.0",
"@nebular/bootstrap": "^9.1.0-rc.6",
"@nebular/security": "^16.0.0",
"@nebular/theme": "^16.0.0",
"@ng-select/ng-select": "^20.7.0",
"@nebular/security": "^17.0.0",
"@nebular/theme": "^17.0.0",
"@ng-select/ng-select": "^21.0.0",
"@ngneat/until-destroy": "^10.0.0",
"@ngx-translate/core": "^17.0.0",
"@ngx-translate/http-loader": "^17.0.0",
@@ -72,7 +72,7 @@
"moment-duration-format": "^2.3.2",
"moment-range": "^4.0.2",
"moment-timezone": "^0.6.0",
"mysql2": "^3.12.0",
"mysql2": "^3.16.3",
"node-fetch": "^2.6.7",
"node-notifier": "^8.0.0",
"pg": "^8.17.2",
@@ -82,7 +82,7 @@
"sound-play": "1.1.0",
"squirrelly": "^8.0.8",
"twing": "^5.0.2",
"underscore": "^1.13.3",
"underscore": "^1.13.8",
"undici": "^6.10.2"
},
"optionalDependencies": {
@@ -96,3 +96,4 @@
},
"sideEffects": false
}
@@ -638,7 +638,7 @@ angular2-smart-table {
}
.ng-arrow {
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
border-color: inherit !important;
border-width: 0 !important;
font-size: 10px;
@@ -692,7 +692,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 5 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
transform: rotate(180deg) !important;
@@ -709,7 +709,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
top: 55% !important;
@@ -444,7 +444,7 @@ $default-box-shadow: var(--gauzy-shadow);
border-width: 2px !important;
border-color: nb-theme(background-primary-color-1) !important;
font-family: 'Font Awesome 5 Pro' !important;
font-family: 'Font Awesome 7 Free' !important;
font-style: normal !important;
font-weight: 400 !important;
font-size: 7px !important;
+2 -2
View File
@@ -8,8 +8,8 @@ import { logger as log, store } from '@gauzy/desktop-core';
import * as Sentry from '@sentry/electron/main';
import { setupTitlebar } from 'custom-electron-titlebar/main';
import { app, BrowserWindow, ipcMain, Menu, MenuItemConstructorOptions, nativeTheme, shell } from 'electron';
import * as path from 'path';
import * as Url from 'url';
import * as path from 'node:path';
import * as Url from 'node:url';
import { initSentry } from './sentry';
require('module').globalPaths.push(path.join(__dirname, 'node_modules'));
+20 -12
View File
@@ -1,9 +1,27 @@
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { enableProdMode, ErrorHandler, importProvidersFrom, inject, provideAppInitializer } from '@angular/core';
import {
enableProdMode,
ErrorHandler,
importProvidersFrom,
inject,
provideAppInitializer,
provideZoneChangeDetection
} from '@angular/core';
import { bootstrapApplication, BrowserModule } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
import { Router } from '@angular/router';
import { akitaConfig, enableAkitaProdMode, persistState } from '@datorama/akita';
import {
NbDatepickerModule,
NbDialogModule,
NbDialogService,
NbIconLibraries,
NbMenuModule,
NbSidebarModule,
NbThemeModule,
NbToastrModule
} from '@nebular/theme';
import * as Sentry from '@sentry/angular';
import {
ActivityWatchInterceptor,
APIInterceptor,
@@ -30,17 +48,6 @@ import {
import { environment as gauzyEnvironment } from '@gauzy/ui-config';
import { provideI18n } from '@gauzy/ui-core/i18n';
import { TablerIconsModule } from '@gauzy/ui-core/icons';
import {
NbDatepickerModule,
NbDialogModule,
NbDialogService,
NbIconLibraries,
NbMenuModule,
NbSidebarModule,
NbThemeModule,
NbToastrModule
} from '@nebular/theme';
import * as Sentry from '@sentry/angular';
import { AppRoutingModule } from './app/app-routing.module';
import { AppComponent } from './app/app.component';
import { AppService } from './app/app.service';
@@ -63,6 +70,7 @@ if (environment.SENTRY_DSN) {
bootstrapApplication(AppComponent, {
providers: [
provideZoneChangeDetection(),
importProvidersFrom(
BrowserModule,
AppRoutingModule,
+179 -178
View File
@@ -1,185 +1,186 @@
{
"name": "gauzy-desktop-timer",
"name": "gauzy-desktop-timer",
"productName": "Gauzy Desktop Timer",
"version": "0.1.0",
"description": "Gauzy Desktop Timer",
"license": "AGPL-3.0",
"homepage": "https://gauzy.co",
"repository": {
"type": "git",
"url": "https://github.com/ever-co/ever-gauzy.git"
},
"bugs": {
"url": "https://github.com/ever-co/ever-gauzy/issues"
},
"private": true,
"author": {
"name": "Ever Co. LTD",
"email": "ever@ever.co",
"url": "https://ever.co"
},
"main": "index.js",
"build": {
"appId": "com.ever.gauzydesktoptimer",
"artifactName": "${name}-${arch}-${version}.${ext}",
"productName": "Gauzy Desktop Timer",
"version": "0.1.0",
"description": "Gauzy Desktop Timer",
"license": "AGPL-3.0",
"homepage": "https://gauzy.co",
"repository": {
"type": "git",
"url": "https://github.com/ever-co/ever-gauzy.git"
"copyright": "Copyright © 2019-Present. Ever Co. LTD",
"afterSign": "tools/notarize.js",
"dmg": {
"sign": false,
"artifactName": "${name}-${arch}-${version}.${ext}"
},
"bugs": {
"url": "https://github.com/ever-co/ever-gauzy/issues"
"asar": true,
"npmRebuild": true,
"asarUnpack": [
"node_modules/screenshot-desktop/lib/win32",
"node_modules/@sentry/electron",
"node_modules/better-sqlite3",
"node_modules/@sentry/profiling-node/lib"
],
"directories": {
"buildResources": "icons",
"output": "../desktop-timer-packages"
},
"private": true,
"author": {
"name": "Ever Co. LTD",
"email": "ever@ever.co",
"url": "https://ever.co"
},
"main": "index.js",
"build": {
"appId": "com.ever.gauzydesktoptimer",
"artifactName": "${name}-${arch}-${version}.${ext}",
"productName": "Gauzy Desktop Timer",
"copyright": "Copyright © 2019-Present. Ever Co. LTD",
"afterSign": "tools/notarize.js",
"dmg": {
"sign": false,
"artifactName": "${name}-${arch}-${version}.${ext}"
},
"asar": true,
"npmRebuild": true,
"asarUnpack": [
"node_modules/screenshot-desktop/lib/win32",
"node_modules/@sentry/electron",
"node_modules/better-sqlite3",
"node_modules/@sentry/profiling-node/lib"
],
"directories": {
"buildResources": "icons",
"output": "../desktop-timer-packages"
},
"publish": [
{
"provider": "github",
"repo": "ever-gauzy-desktop-timer",
"releaseType": "release"
},
{
"provider": "spaces",
"name": "ever",
"region": "sfo3",
"path": "/ever-gauzy-desktop-timer",
"acl": "public-read"
}
],
"mac": {
"category": "public.app-category.developer-tools",
"icon": "icon.icns",
"target": {
"target": "default",
"arch": [
"x64",
"arm64"
]
},
"asarUnpack": "**/*.node",
"artifactName": "${name}-${arch}-${version}.${ext}",
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "tools/build/entitlements.mas.plist",
"entitlementsInherit": "tools/build/entitlements.mas.plist",
"extendInfo": {
"NSAppleEventsUsageDescription": "This app requires access to script browser applications to detect the current URL when triggering instant lookup.",
"NSCameraUsageDescription": "Please allow access to the device camera to capture images and videos.",
"NSMicrophoneUsageDescription": "Please allow access to the device's microphone to capture audio and voice recordings.",
"NSScreenCaptureUsageDescription": "Please allow access to the device's screen to capture screenshots and videos."
}
},
"win": {
"target": "nsis",
"icon": "icon.ico",
"verifyUpdateCodeSignature": false
},
"linux": {
"icon": "linux",
"target": [
"deb",
"snap",
"tar.gz",
"rpm",
"AppImage"
],
"executableName": "gauzy-desktop-timer",
"artifactName": "${name}-${arch}-${version}.${ext}",
"synopsis": "Desktop",
"category": "Development"
},
"rpm": {
"fpm": [
"--rpm-rpmbuild-define",
"_build_id_links none"
]
},
"nsis": {
"oneClick": false,
"perMachine": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"allowToChangeInstallationDirectory": true,
"allowElevation": true,
"installerIcon": "icon.ico",
"artifactName": "${name}-${arch}-${version}.${ext}",
"deleteAppDataOnUninstall": true,
"menuCategory": true
},
"extraResources": [
"./data/**/*",
"databaseDir",
{
"from": "assets",
"to": "assets"
}
],
"extraFiles": [
"./**/desktop-lib/**/migrations/*"
"publish": [
{
"provider": "github",
"repo": "ever-gauzy-desktop-timer",
"releaseType": "release"
},
{
"provider": "spaces",
"name": "ever",
"region": "sfo3",
"path": "/ever-gauzy-desktop-timer",
"acl": "public-read"
}
],
"mac": {
"category": "public.app-category.developer-tools",
"icon": "icon.icns",
"target": {
"target": "default",
"arch": [
"x64",
"arm64"
]
},
"asarUnpack": "**/*.node",
"artifactName": "${name}-${arch}-${version}.${ext}",
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "tools/build/entitlements.mas.plist",
"entitlementsInherit": "tools/build/entitlements.mas.plist",
"extendInfo": {
"NSAppleEventsUsageDescription": "This app requires access to script browser applications to detect the current URL when triggering instant lookup.",
"NSCameraUsageDescription": "Please allow access to the device camera to capture images and videos.",
"NSMicrophoneUsageDescription": "Please allow access to the device's microphone to capture audio and voice recordings.",
"NSScreenCaptureUsageDescription": "Please allow access to the device's screen to capture screenshots and videos."
}
},
"dependencies": {
"@datorama/akita": "^8.0.1",
"@datorama/akita-ngdevtools": "^7.0.0",
"@electron/remote": "^2.0.8",
"@gauzy/contracts": "file:../../../dist/packages/contracts",
"@gauzy/constants": "file:../../../dist/packages/constants",
"@gauzy/common": "file:../../../dist/packages/common",
"@gauzy/desktop-core": "file:../../../dist/packages/desktop-core",
"@gauzy/desktop-activity": "file:../../../dist/packages/desktop-activity",
"@gauzy/desktop-lib": "file:../../../dist/packages/desktop-lib",
"@gauzy/desktop-window": "file:../../../dist/packages/desktop-window",
"@gauzy/ui-config": "file:../../../dist/packages/ui-config",
"@sentry/electron": "7.7.1",
"@sentry/node": "10.36.0",
"@sentry/profiling-node": "10.36.0",
"@sentry/core": "10.36.0",
"auto-launch": "5.0.5",
"consolidate": "^0.16.0",
"electron-log": "^4.4.8",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.7",
"electron-util": "^0.18.1",
"embedded-queue": "^0.0.11",
"form-data": "^4.0.1",
"htmlparser2": "^8.0.2",
"knex": "^3.1.0",
"libsql": "^0.3.16",
"moment": "^2.30.1",
"node-fetch": "^2.6.7",
"node-notifier": "^8.0.0",
"mysql2": "^3.12.0",
"pg": "^8.17.2",
"pg-query-stream": "^4.11.2",
"screenshot-desktop": "^1.15.0",
"sound-play": "1.1.0",
"squirrelly": "^8.0.8",
"tslib": "^2.6.2",
"twing": "^5.0.2",
"locutus": "^2.0.30",
"underscore": "^1.13.3",
"undici": "^6.10.2",
"custom-electron-titlebar": "^4.2.8",
"call-bind-apply-helpers": "^1.0.2",
"cheerio-select": "^2.1.0"
"win": {
"target": "nsis",
"icon": "icon.ico",
"verifyUpdateCodeSignature": false
},
"resolutions": {
"@gauzy/contracts": "file:../../../dist/packages/contracts",
"@gauzy/constants": "file:../../../dist/packages/constants",
"@gauzy/common": "file:../../../dist/packages/common",
"@gauzy/desktop-core": "file:../../../dist/packages/desktop-core",
"@gauzy/desktop-activity": "file:../../../dist/packages/desktop-activity",
"@gauzy/desktop-lib": "file:../../../dist/packages/desktop-lib",
"@gauzy/desktop-window": "file:../../../dist/packages/desktop-window",
"@gauzy/ui-config": "file:../../../dist/packages/ui-config"
}
}
"linux": {
"icon": "linux",
"target": [
"deb",
"snap",
"tar.gz",
"rpm",
"AppImage"
],
"executableName": "gauzy-desktop-timer",
"artifactName": "${name}-${arch}-${version}.${ext}",
"synopsis": "Desktop",
"category": "Development"
},
"rpm": {
"fpm": [
"--rpm-rpmbuild-define",
"_build_id_links none"
]
},
"nsis": {
"oneClick": false,
"perMachine": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"allowToChangeInstallationDirectory": true,
"allowElevation": true,
"installerIcon": "icon.ico",
"artifactName": "${name}-${arch}-${version}.${ext}",
"deleteAppDataOnUninstall": true,
"menuCategory": true
},
"extraResources": [
"./data/**/*",
"databaseDir",
{
"from": "assets",
"to": "assets"
}
],
"extraFiles": [
"./**/desktop-lib/**/migrations/*"
]
},
"dependencies": {
"@datorama/akita": "^8.0.1",
"@datorama/akita-ngdevtools": "^7.0.0",
"@electron/remote": "^2.0.8",
"@gauzy/contracts": "file:../../../dist/packages/contracts",
"@gauzy/constants": "file:../../../dist/packages/constants",
"@gauzy/common": "file:../../../dist/packages/common",
"@gauzy/desktop-core": "file:../../../dist/packages/desktop-core",
"@gauzy/desktop-activity": "file:../../../dist/packages/desktop-activity",
"@gauzy/desktop-lib": "file:../../../dist/packages/desktop-lib",
"@gauzy/desktop-window": "file:../../../dist/packages/desktop-window",
"@gauzy/ui-config": "file:../../../dist/packages/ui-config",
"@sentry/electron": "7.7.1",
"@sentry/node": "10.36.0",
"@sentry/profiling-node": "10.36.0",
"@sentry/core": "10.36.0",
"auto-launch": "5.0.5",
"consolidate": "^0.16.0",
"electron-log": "^4.4.8",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.7",
"electron-util": "^0.18.1",
"embedded-queue": "^0.0.11",
"form-data": "^4.0.1",
"htmlparser2": "^8.0.2",
"knex": "^3.1.0",
"libsql": "^0.3.16",
"moment": "^2.30.1",
"node-fetch": "^2.6.7",
"node-notifier": "^8.0.0",
"mysql2": "^3.16.3",
"pg": "^8.17.2",
"pg-query-stream": "^4.11.2",
"screenshot-desktop": "^1.15.0",
"sound-play": "1.1.0",
"squirrelly": "^8.0.8",
"tslib": "^2.6.2",
"twing": "^5.0.2",
"locutus": "^2.0.30",
"underscore": "^1.13.8",
"undici": "^6.10.2",
"custom-electron-titlebar": "^4.2.8",
"call-bind-apply-helpers": "^1.0.2",
"cheerio-select": "^2.1.0"
},
"resolutions": {
"@gauzy/contracts": "file:../../../dist/packages/contracts",
"@gauzy/constants": "file:../../../dist/packages/constants",
"@gauzy/common": "file:../../../dist/packages/common",
"@gauzy/desktop-core": "file:../../../dist/packages/desktop-core",
"@gauzy/desktop-activity": "file:../../../dist/packages/desktop-activity",
"@gauzy/desktop-lib": "file:../../../dist/packages/desktop-lib",
"@gauzy/desktop-window": "file:../../../dist/packages/desktop-window",
"@gauzy/ui-config": "file:../../../dist/packages/ui-config"
}
}
+3 -1
View File
@@ -5,4 +5,6 @@ globalThis.ngJest = {
errorOnUnknownProperties: true
}
};
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv();
+3 -1
View File
@@ -9,7 +9,9 @@
"noImplicitReturns": false,
"noFallthroughCasesInSwitch": false,
"skipLibCheck": true,
"types": ["node", "google.maps"]
"types": ["node", "google.maps"],
"module": "preserve",
"moduleResolution": "bundler"
},
"files": [],
"include": [],
+11 -19
View File
@@ -1,21 +1,13 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"target": "es2016",
"types": [
"jest",
"node"
]
},
"files": [
"src/test-setup.ts"
],
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "preserve",
"target": "es2016",
"types": ["jest", "node"],
"moduleResolution": "bundler",
"isolatedModules": true
},
"files": ["src/test-setup.ts"],
"include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
}
+11 -11
View File
@@ -35,23 +35,23 @@
"terser-webpack-plugin": "^5.3.16"
},
"dependencies": {
"@angular/animations": "^20.2.4",
"@angular/cdk": "^20.2.14",
"@angular/common": "^20.2.4",
"@angular/core": "^20.2.4",
"@angular/forms": "^20.2.4",
"@angular/material": "^20.2.14",
"@angular/router": "^20.2.4",
"@angular/animations": "21.0.0",
"@angular/cdk": "21.0.0",
"@angular/common": "21.0.0",
"@angular/core": "21.0.0",
"@angular/forms": "21.0.0",
"@angular/material": "21.0.0",
"@angular/router": "21.0.0",
"@datorama/akita": "^8.0.1",
"@datorama/akita-ngdevtools": "^7.0.0",
"@electron/remote": "^2.0.8",
"@grpc/grpc-js": "^1.6.7",
"@nebular/auth": "^16.0.0",
"@nebular/auth": "^17.0.0",
"@nebular/bootstrap": "^9.1.0-rc.6",
"@nebular/security": "^16.0.0",
"@nebular/theme": "^16.0.0",
"@nebular/security": "^17.0.0",
"@nebular/theme": "^17.0.0",
"@nestjs/typeorm": "^11.0.0",
"@ng-select/ng-select": "^20.7.0",
"@ng-select/ng-select": "^21.0.0",
"@ngneat/until-destroy": "^10.0.0",
"@ngx-translate/core": "^17.0.0",
"@ngx-translate/http-loader": "^17.0.0",
+9 -14
View File
@@ -5,7 +5,8 @@ import { authConnectionGuard } from '@gauzy/desktop-ui-lib';
const routes: Routes = [
{
path: '',
loadComponent: () => import('@gauzy/desktop-ui-lib').then((m) => m.TimeTrackerComponent)
redirectTo: 'time-tracker',
pathMatch: 'full'
},
{
path: 'setup',
@@ -15,12 +16,7 @@ const routes: Routes = [
path: 'time-tracker',
canActivate: [authConnectionGuard],
loadComponent: () => import('@gauzy/desktop-ui-lib').then((m) => m.TimeTrackerComponent),
children: [
{
path: '',
loadChildren: () => import('@gauzy/desktop-ui-lib').then((m) => m.RecapModule)
}
]
loadChildren: () => import('@gauzy/desktop-ui-lib').then((m) => m.RecapModule)
},
{
path: 'screen-capture',
@@ -29,12 +25,7 @@ const routes: Routes = [
{
path: 'plugins',
canActivate: [authConnectionGuard],
children: [
{
path: '',
loadChildren: () => import('@gauzy/desktop-ui-lib').then((m) => m.PluginRoutingModule)
}
]
loadChildren: () => import('@gauzy/desktop-ui-lib').then((m) => m.PluginRoutingModule)
},
{
path: 'settings',
@@ -59,6 +50,10 @@ const routes: Routes = [
{
path: 'always-on',
loadComponent: () => import('@gauzy/desktop-ui-lib').then((m) => m.AlwaysOnComponent)
},
{
path: '**',
redirectTo: ''
}
];
@@ -73,4 +68,4 @@ const config: ExtraOptions = {
imports: [RouterModule.forRoot(routes, config)],
exports: [RouterModule]
})
export class AppRoutingModule {}
export class AppRoutingModule { }
-4
View File
@@ -1,15 +1,11 @@
import { TestBed } from '@angular/core/testing';
import { AppService } from './app.service';
describe('AppService', () => {
let service: AppService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AppService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
@@ -660,7 +660,7 @@ angular2-smart-table {
}
.ng-arrow {
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
border-color: inherit !important;
border-width: 0 !important;
font-size: 10px;
@@ -714,7 +714,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 5 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
transform: rotate(180deg) !important;
@@ -731,7 +731,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
top: 55% !important;
@@ -444,7 +444,7 @@ $default-box-shadow: var(--gauzy-shadow);
border-width: 2px !important;
border-color: nb-theme(background-primary-color-1) !important;
font-family: 'Font Awesome 5 Pro' !important;
font-family: 'Font Awesome 7 Free' !important;
font-style: normal !important;
font-weight: 400 !important;
font-size: 7px !important;
+1 -1
View File
@@ -9,7 +9,7 @@ import * as remoteMain from '@electron/remote/main';
import { setupTitlebar } from 'custom-electron-titlebar/main';
import { BrowserWindow, Menu, MenuItemConstructorOptions, app, dialog, ipcMain, nativeTheme, shell } from 'electron';
import * as Store from 'electron-store';
import * as path from 'path';
import * as path from 'node:path';
import { environment } from './environments/environment';
+20 -13
View File
@@ -1,10 +1,27 @@
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { enableProdMode, ErrorHandler, importProvidersFrom, inject, provideAppInitializer } from '@angular/core';
import {
enableProdMode,
ErrorHandler,
importProvidersFrom,
inject,
provideAppInitializer,
provideZoneChangeDetection
} from '@angular/core';
import { bootstrapApplication, BrowserModule } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
import { Router } from '@angular/router';
import * as Sentry from '@sentry/angular';
import { akitaConfig, enableAkitaProdMode, persistState } from '@datorama/akita';
import {
NbDatepickerModule,
NbDialogModule,
NbDialogService,
NbIconLibraries,
NbMenuModule,
NbSidebarModule,
NbThemeModule,
NbToastrModule
} from '@nebular/theme';
import {
ActivityWatchInterceptor,
APIInterceptor,
@@ -30,17 +47,6 @@ import {
import { environment as gauzyEnvironment } from '@gauzy/ui-config';
import { provideI18n } from '@gauzy/ui-core/i18n';
import { TablerIconsModule } from '@gauzy/ui-core/icons';
import {
NbDatepickerModule,
NbDialogModule,
NbDialogService,
NbIconLibraries,
NbMenuModule,
NbSidebarModule,
NbThemeModule,
NbToastrModule
} from '@nebular/theme';
import * as Sentry from '@sentry/angular';
import { AppRoutingModule } from './app/app-routing.module';
import { AppComponent } from './app/app.component';
import { AppService } from './app/app.service';
@@ -69,6 +75,7 @@ if (environment.SENTRY_DSN) {
bootstrapApplication(AppComponent, {
providers: [
provideZoneChangeDetection(),
importProvidersFrom(
BrowserModule,
AppRoutingModule,
+233 -232
View File
@@ -1,240 +1,241 @@
{
"name": "gauzy-desktop",
"name": "gauzy-desktop",
"productName": "Gauzy Desktop",
"version": "0.1.0",
"description": "Gauzy Desktop",
"license": "AGPL-3.0",
"homepage": "https://gauzy.co",
"repository": {
"type": "git",
"url": "https://github.com/ever-co/ever-gauzy.git"
},
"bugs": {
"url": "https://github.com/ever-co/ever-gauzy/issues"
},
"private": true,
"author": {
"name": "Ever Co. LTD",
"email": "ever@ever.co",
"url": "https://ever.co"
},
"main": "index.js",
"build": {
"appId": "com.ever.gauzydesktop",
"artifactName": "${name}-${arch}-${version}.${ext}",
"productName": "Gauzy Desktop",
"version": "0.1.0",
"description": "Gauzy Desktop",
"license": "AGPL-3.0",
"homepage": "https://gauzy.co",
"repository": {
"type": "git",
"url": "https://github.com/ever-co/ever-gauzy.git"
"copyright": "Copyright © 2019-Present. Ever Co. LTD",
"afterSign": "tools/notarize.js",
"dmg": {
"sign": false,
"artifactName": "${name}-${arch}-${version}.${ext}"
},
"bugs": {
"url": "https://github.com/ever-co/ever-gauzy/issues"
"asar": true,
"npmRebuild": true,
"asarUnpack": [
"node_modules/screenshot-desktop/lib/win32",
"node_modules/@sentry/electron",
"node_modules/better-sqlite3",
"node_modules/@sentry/profiling-node/lib",
"node_modules/@gauzy/core/src/lib/i18n"
],
"directories": {
"buildResources": "icons",
"output": "../desktop-packages"
},
"private": true,
"author": {
"name": "Ever Co. LTD",
"email": "ever@ever.co",
"url": "https://ever.co"
},
"main": "index.js",
"build": {
"appId": "com.ever.gauzydesktop",
"artifactName": "${name}-${arch}-${version}.${ext}",
"productName": "Gauzy Desktop",
"copyright": "Copyright © 2019-Present. Ever Co. LTD",
"afterSign": "tools/notarize.js",
"dmg": {
"sign": false,
"artifactName": "${name}-${arch}-${version}.${ext}"
},
"asar": true,
"npmRebuild": true,
"asarUnpack": [
"node_modules/screenshot-desktop/lib/win32",
"node_modules/@sentry/electron",
"node_modules/better-sqlite3",
"node_modules/@sentry/profiling-node/lib",
"node_modules/@gauzy/core/src/lib/i18n"
],
"directories": {
"buildResources": "icons",
"output": "../desktop-packages"
},
"publish": [
{
"provider": "github",
"repo": "ever-gauzy-desktop",
"releaseType": "release",
"channel": "latest-x64"
},
{
"provider": "spaces",
"name": "ever",
"region": "sfo3",
"path": "/ever-gauzy-desktop",
"acl": "public-read",
"channel": "latest-x64"
}
],
"mac": {
"category": "public.app-category.developer-tools",
"icon": "icon.icns",
"target": {
"target": "default",
"arch": [
"x64",
"arm64"
]
},
"asarUnpack": "**/*.node",
"artifactName": "${name}-${arch}-${version}.${ext}",
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "tools/build/entitlements.mas.plist",
"entitlementsInherit": "tools/build/entitlements.mas.plist",
"extendInfo": {
"NSAppleEventsUsageDescription": "This app requires access to script browser applications to detect the current URL when triggering instant lookup.",
"NSCameraUsageDescription": "Please allow access to the device camera to capture images and videos.",
"NSMicrophoneUsageDescription": "Please allow access to the device's microphone to capture audio and voice recordings.",
"NSScreenCaptureUsageDescription": "Please allow access to the device's screen to capture screenshots and videos."
}
},
"win": {
"target": "nsis",
"icon": "icon.ico",
"verifyUpdateCodeSignature": false
},
"linux": {
"icon": "linux",
"target": [
"deb",
"snap",
"tar.gz",
"rpm",
"AppImage"
],
"executableName": "gauzy-desktop",
"artifactName": "${name}-${arch}-${version}.${ext}",
"synopsis": "Desktop",
"category": "Development"
},
"rpm": {
"fpm": [
"--rpm-rpmbuild-define",
"_build_id_links none"
]
},
"nsis": {
"oneClick": false,
"perMachine": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"allowToChangeInstallationDirectory": true,
"allowElevation": true,
"installerIcon": "icon.ico",
"artifactName": "${name}-${arch}-${version}.${ext}",
"deleteAppDataOnUninstall": true,
"menuCategory": true
},
"extraResources": [
"./data/**/*"
"publish": [
{
"provider": "github",
"repo": "ever-gauzy-desktop",
"releaseType": "release",
"channel": "latest-x64"
},
{
"provider": "spaces",
"name": "ever",
"region": "sfo3",
"path": "/ever-gauzy-desktop",
"acl": "public-read",
"channel": "latest-x64"
}
],
"mac": {
"category": "public.app-category.developer-tools",
"icon": "icon.icns",
"target": {
"target": "default",
"arch": [
"x64",
"arm64"
]
},
"asarUnpack": "**/*.node",
"artifactName": "${name}-${arch}-${version}.${ext}",
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "tools/build/entitlements.mas.plist",
"entitlementsInherit": "tools/build/entitlements.mas.plist",
"extendInfo": {
"NSAppleEventsUsageDescription": "This app requires access to script browser applications to detect the current URL when triggering instant lookup.",
"NSCameraUsageDescription": "Please allow access to the device camera to capture images and videos.",
"NSMicrophoneUsageDescription": "Please allow access to the device's microphone to capture audio and voice recordings.",
"NSScreenCaptureUsageDescription": "Please allow access to the device's screen to capture screenshots and videos."
}
},
"dependencies": {
"@datorama/akita-ngdevtools": "^7.0.0",
"@datorama/akita": "^8.0.1",
"@electron/remote": "^2.0.8",
"@gauzy/auth": "file:../../../dist/packages/auth",
"@gauzy/config": "file:../../../dist/packages/config",
"@gauzy/constants": "file:../../../dist/packages/constants",
"@gauzy/contracts": "file:../../../dist/packages/contracts",
"@gauzy/common": "file:../../../dist/packages/common",
"@gauzy/core": "file:../../../dist/packages/core",
"@gauzy/desktop-core": "file:../../../dist/packages/desktop-core",
"@gauzy/desktop-activity": "file:../../../dist/packages/desktop-activity",
"@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",
"@gauzy/plugin-integration-hubstaff": "file:../../../dist/packages/plugins/integration-hubstaff",
"@gauzy/plugin-integration-jira": "file:../../../dist/packages/plugins/integration-jira",
"@gauzy/plugin-integration-make-com": "file:../../../dist/packages/plugins/integration-make-com",
"@gauzy/plugin-integration-upwork": "file:../../../dist/packages/plugins/integration-upwork",
"@gauzy/plugin-integration-wakatime": "file:../../../dist/packages/plugins/integration-wakatime",
"@gauzy/plugin-integration-zapier": "file:../../../dist/packages/plugins/integration-zapier",
"@gauzy/plugin-jitsu-analytics": "file:../../../dist/packages/plugins/jitsu-analytics",
"@gauzy/plugin-job-proposal": "file:../../../dist/packages/plugins/job-proposal",
"@gauzy/plugin-job-search": "file:../../../dist/packages/plugins/job-search",
"@gauzy/plugin-knowledge-base": "file:../../../dist/packages/plugins/knowledge-base",
"@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/plugin-registry": "file:../../../dist/packages/plugins/registry",
"@gauzy/plugin-posthog": "file:../../../dist/packages/plugins/posthog",
"@gauzy/plugin-camshot": "file:../../../dist/packages/plugins/camshot",
"@gauzy/plugin-soundshot": "file:../../../dist/packages/plugins/soundshot",
"@gauzy/plugin-integration-activepieces": "file:../../../dist/packages/plugins/integration-activepieces",
"@gauzy/ui-config": "file:../../../dist/packages/ui-config",
"@gauzy/utils": "file:../../../dist/packages/utils",
"@nestjs/platform-express": "^11.1.14",
"@sentry/electron": "7.7.1",
"@sentry/node": "10.36.0",
"@sentry/profiling-node": "10.36.0",
"@sentry/core": "10.36.0",
"auto-launch": "5.0.5",
"consolidate": "^0.16.0",
"electron-log": "^4.4.8",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.7",
"electron-util": "^0.18.1",
"embedded-queue": "^0.0.11",
"form-data": "^4.0.1",
"htmlparser2": "^8.0.2",
"knex": "^3.1.0",
"libsql": "^0.3.16",
"locutus": "^2.0.30",
"moment": "^2.30.1",
"node-fetch": "^2.6.7",
"node-notifier": "^8.0.0",
"node-static": "^0.7.11",
"pdfmake": "^0.2.0",
"pg-query-stream": "^4.11.2",
"pg": "^8.17.2",
"screenshot-desktop": "^1.15.0",
"sound-play": "1.1.0",
"squirrelly": "^8.0.8",
"tslib": "^2.6.2",
"twing": "^5.0.2",
"underscore": "^1.13.3",
"undici": "^6.10.2",
"custom-electron-titlebar": "^4.2.8",
"call-bind-apply-helpers": "^1.0.2",
"cheerio-select": "^2.1.0",
"@as-integrations/express5": "^1.1.2"
"win": {
"target": "nsis",
"icon": "icon.ico",
"verifyUpdateCodeSignature": false
},
"resolutions": {
"@gauzy/auth": "file:../../../dist/packages/auth",
"@gauzy/config": "file:../../../dist/packages/config",
"@gauzy/constants": "file:../../../dist/packages/constants",
"@gauzy/contracts": "file:../../../dist/packages/contracts",
"@gauzy/common": "file:../../../dist/packages/common",
"@gauzy/core": "file:../../../dist/packages/core",
"@gauzy/desktop-core": "file:../../../dist/packages/desktop-core",
"@gauzy/desktop-activity": "file:../../../dist/packages/desktop-activity",
"@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",
"@gauzy/plugin-integration-hubstaff": "file:../../../dist/packages/plugins/integration-hubstaff",
"@gauzy/plugin-integration-jira": "file:../../../dist/packages/plugins/integration-jira",
"@gauzy/plugin-integration-make-com": "file:../../../dist/packages/plugins/integration-make-com",
"@gauzy/plugin-integration-upwork": "file:../../../dist/packages/plugins/integration-upwork",
"@gauzy/plugin-integration-wakatime": "file:../../../dist/packages/plugins/integration-wakatime",
"@gauzy/plugin-integration-zapier": "file:../../../dist/packages/plugins/integration-zapier",
"@gauzy/plugin-jitsu-analytics": "file:../../../dist/packages/plugins/jitsu-analytics",
"@gauzy/plugin-job-proposal": "file:../../../dist/packages/plugins/job-proposal",
"@gauzy/plugin-job-search": "file:../../../dist/packages/plugins/job-search",
"@gauzy/plugin-knowledge-base": "file:../../../dist/packages/plugins/knowledge-base",
"@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/plugin-registry": "file:../../../dist/packages/plugins/registry",
"@gauzy/plugin-posthog": "file:../../../dist/packages/plugins/posthog",
"@gauzy/plugin-camshot": "file:../../../dist/packages/plugins/camshot",
"@gauzy/plugin-soundshot": "file:../../../dist/packages/plugins/soundshot",
"@gauzy/plugin-integration-activepieces": "file:../../../dist/packages/plugins/integration-activepieces",
"@gauzy/ui-config": "file:../../../dist/packages/ui-config",
"@gauzy/utils": "file:../../../dist/packages/utils"
"linux": {
"icon": "linux",
"target": [
"deb",
"snap",
"tar.gz",
"rpm",
"AppImage"
],
"executableName": "gauzy-desktop",
"artifactName": "${name}-${arch}-${version}.${ext}",
"synopsis": "Desktop",
"category": "Development"
},
"optionalDependencies": {
"node-linux": "^0.1.12",
"node-mac": "^1.0.1",
"node-windows": "^1.0.0-beta.8"
}
}
"rpm": {
"fpm": [
"--rpm-rpmbuild-define",
"_build_id_links none"
]
},
"nsis": {
"oneClick": false,
"perMachine": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"allowToChangeInstallationDirectory": true,
"allowElevation": true,
"installerIcon": "icon.ico",
"artifactName": "${name}-${arch}-${version}.${ext}",
"deleteAppDataOnUninstall": true,
"menuCategory": true
},
"extraResources": [
"./data/**/*"
]
},
"dependencies": {
"@datorama/akita-ngdevtools": "^7.0.0",
"@datorama/akita": "^8.0.1",
"@electron/remote": "^2.0.8",
"@gauzy/auth": "file:../../../dist/packages/auth",
"@gauzy/config": "file:../../../dist/packages/config",
"@gauzy/constants": "file:../../../dist/packages/constants",
"@gauzy/contracts": "file:../../../dist/packages/contracts",
"@gauzy/common": "file:../../../dist/packages/common",
"@gauzy/core": "file:../../../dist/packages/core",
"@gauzy/desktop-core": "file:../../../dist/packages/desktop-core",
"@gauzy/desktop-activity": "file:../../../dist/packages/desktop-activity",
"@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",
"@gauzy/plugin-integration-hubstaff": "file:../../../dist/packages/plugins/integration-hubstaff",
"@gauzy/plugin-integration-jira": "file:../../../dist/packages/plugins/integration-jira",
"@gauzy/plugin-integration-make-com": "file:../../../dist/packages/plugins/integration-make-com",
"@gauzy/plugin-integration-upwork": "file:../../../dist/packages/plugins/integration-upwork",
"@gauzy/plugin-integration-wakatime": "file:../../../dist/packages/plugins/integration-wakatime",
"@gauzy/plugin-integration-zapier": "file:../../../dist/packages/plugins/integration-zapier",
"@gauzy/plugin-jitsu-analytics": "file:../../../dist/packages/plugins/jitsu-analytics",
"@gauzy/plugin-job-proposal": "file:../../../dist/packages/plugins/job-proposal",
"@gauzy/plugin-job-search": "file:../../../dist/packages/plugins/job-search",
"@gauzy/plugin-knowledge-base": "file:../../../dist/packages/plugins/knowledge-base",
"@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/plugin-registry": "file:../../../dist/packages/plugins/registry",
"@gauzy/plugin-posthog": "file:../../../dist/packages/plugins/posthog",
"@gauzy/plugin-camshot": "file:../../../dist/packages/plugins/camshot",
"@gauzy/plugin-soundshot": "file:../../../dist/packages/plugins/soundshot",
"@gauzy/plugin-integration-activepieces": "file:../../../dist/packages/plugins/integration-activepieces",
"@gauzy/ui-config": "file:../../../dist/packages/ui-config",
"@gauzy/utils": "file:../../../dist/packages/utils",
"@nestjs/platform-express": "^11.1.14",
"@sentry/electron": "7.7.1",
"@sentry/node": "10.36.0",
"@sentry/profiling-node": "10.36.0",
"@sentry/core": "10.36.0",
"auto-launch": "5.0.5",
"consolidate": "^0.16.0",
"electron-log": "^4.4.8",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.7",
"electron-util": "^0.18.1",
"embedded-queue": "^0.0.11",
"form-data": "^4.0.1",
"htmlparser2": "^8.0.2",
"knex": "^3.1.0",
"libsql": "^0.3.16",
"locutus": "^2.0.30",
"moment": "^2.30.1",
"node-fetch": "^2.6.7",
"node-notifier": "^8.0.0",
"node-static": "^0.7.11",
"pdfmake": "^0.2.0",
"pg-query-stream": "^4.11.2",
"pg": "^8.17.2",
"screenshot-desktop": "^1.15.0",
"sound-play": "1.1.0",
"squirrelly": "^8.0.8",
"tslib": "^2.6.2",
"twing": "^5.0.2",
"underscore": "^1.13.8",
"undici": "^6.10.2",
"custom-electron-titlebar": "^4.2.8",
"call-bind-apply-helpers": "^1.0.2",
"cheerio-select": "^2.1.0",
"@as-integrations/express5": "^1.1.2"
},
"resolutions": {
"@gauzy/auth": "file:../../../dist/packages/auth",
"@gauzy/config": "file:../../../dist/packages/config",
"@gauzy/constants": "file:../../../dist/packages/constants",
"@gauzy/contracts": "file:../../../dist/packages/contracts",
"@gauzy/common": "file:../../../dist/packages/common",
"@gauzy/core": "file:../../../dist/packages/core",
"@gauzy/desktop-core": "file:../../../dist/packages/desktop-core",
"@gauzy/desktop-activity": "file:../../../dist/packages/desktop-activity",
"@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",
"@gauzy/plugin-integration-hubstaff": "file:../../../dist/packages/plugins/integration-hubstaff",
"@gauzy/plugin-integration-jira": "file:../../../dist/packages/plugins/integration-jira",
"@gauzy/plugin-integration-make-com": "file:../../../dist/packages/plugins/integration-make-com",
"@gauzy/plugin-integration-upwork": "file:../../../dist/packages/plugins/integration-upwork",
"@gauzy/plugin-integration-wakatime": "file:../../../dist/packages/plugins/integration-wakatime",
"@gauzy/plugin-integration-zapier": "file:../../../dist/packages/plugins/integration-zapier",
"@gauzy/plugin-jitsu-analytics": "file:../../../dist/packages/plugins/jitsu-analytics",
"@gauzy/plugin-job-proposal": "file:../../../dist/packages/plugins/job-proposal",
"@gauzy/plugin-job-search": "file:../../../dist/packages/plugins/job-search",
"@gauzy/plugin-knowledge-base": "file:../../../dist/packages/plugins/knowledge-base",
"@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/plugin-registry": "file:../../../dist/packages/plugins/registry",
"@gauzy/plugin-posthog": "file:../../../dist/packages/plugins/posthog",
"@gauzy/plugin-camshot": "file:../../../dist/packages/plugins/camshot",
"@gauzy/plugin-soundshot": "file:../../../dist/packages/plugins/soundshot",
"@gauzy/plugin-integration-activepieces": "file:../../../dist/packages/plugins/integration-activepieces",
"@gauzy/ui-config": "file:../../../dist/packages/ui-config",
"@gauzy/utils": "file:../../../dist/packages/utils"
},
"optionalDependencies": {
"node-linux": "^0.1.12",
"node-mac": "^1.0.1",
"node-windows": "^1.0.0-beta.8"
}
}
+3 -1
View File
@@ -5,4 +5,6 @@ globalThis.ngJest = {
errorOnUnknownProperties: true
}
};
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv();
+3 -1
View File
@@ -8,7 +8,9 @@
"noPropertyAccessFromIndexSignature": false,
"noImplicitReturns": false,
"noFallthroughCasesInSwitch": false,
"types": ["node", "google.maps"]
"types": ["node", "google.maps"],
"module": "preserve",
"moduleResolution": "bundler"
},
"files": [],
"include": [],
+4 -2
View File
@@ -2,9 +2,11 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"module": "preserve",
"target": "es2016",
"types": ["jest", "node"]
"types": ["jest", "node"],
"moduleResolution": "bundler",
"isolatedModules": true
},
"files": ["src/test-setup.ts"],
"include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
+5 -5
View File
@@ -49,23 +49,23 @@
"postinstall.web": "yarn node ./decorate-angular-cli.js && yarn node tools/web/postinstall"
},
"dependencies": {
"@faker-js/faker": "^10.2.0",
"@faker-js/faker": "^10.3.0",
"dayjs": "^1.11.4",
"resolve": "^1.20.0"
},
"devDependencies": {
"@4tw/cypress-drag-drop": "^2.1.0",
"@cypress/browserify-preprocessor": "^3.0.2",
"@types/jest": "29.5.14",
"@types/jest": "30.0.0",
"concurrently": "^9.2.1",
"cross-env": "^10.1.0",
"cypress": "^9.4.1",
"cypress": "^15.9.0",
"cypress-cucumber-preprocessor": "^4.3.1",
"cypress-file-upload": "^5.0.8",
"jasmine-core": "^3.6.0",
"jasmine-spec-reporter": "^6.0.0",
"jest": "^29.7.0",
"jest-preset-angular": "14.6.2",
"jest": "30.0.0",
"jest-preset-angular": "16.0.0",
"karma": "^6.4.4",
"karma-chrome-launcher": "^3.2.0",
"karma-cli": "^2.0.0",
+2 -6
View File
@@ -1,10 +1,6 @@
/* eslint-disable */
export default {
name: 'gauzy',
displayName: 'gauzy',
preset: '../../jest.preset.js',
coverageDirectory: '../../coverage/apps/gauzy',
snapshotSerializers: [
'jest-preset-angular/AngularSnapshotSerializer.js',
'jest-preset-angular/HTMLCommentSerializer.js'
]
coverageDirectory: '../../coverage/apps/gauzy'
};
+39 -40
View File
@@ -24,29 +24,29 @@
},
"dependencies": {
"@akveo/ng2-completer": "^9.0.1",
"@ali-hm/angular-tree-component": "^20.1.6",
"@angular-slider/ngx-slider": "^20.0.0",
"@angular/animations": "^20.2.4",
"@angular/cdk": "^20.2.14",
"@angular/common": "^20.2.4",
"@angular/core": "^20.2.4",
"@angular/forms": "^20.2.4",
"@angular/language-service": "^20.2.4",
"@angular/material": "^20.2.14",
"@angular/platform-browser": "^20.2.4",
"@angular/platform-browser-dynamic": "^20.2.4",
"@angular/router": "^20.2.4",
"@angular/service-worker": "^20.2.4",
"@bluehalo/ngx-leaflet": "^20.0.0",
"@ali-hm/angular-tree-component": "^21.0.3",
"@angular-slider/ngx-slider": "^21.0.0",
"@angular/animations": "21.0.0",
"@angular/cdk": "21.0.0",
"@angular/common": "21.0.0",
"@angular/core": "21.0.0",
"@angular/forms": "21.0.0",
"@angular/language-service": "21.0.0",
"@angular/material": "21.0.0",
"@angular/platform-browser": "21.0.0",
"@angular/platform-browser-dynamic": "21.0.0",
"@angular/router": "21.0.0",
"@angular/service-worker": "21.0.0",
"@bluehalo/ngx-leaflet": "^21.0.0",
"@datorama/akita": "^8.0.1",
"@datorama/akita-ngdevtools": "^7.0.0",
"@electron/remote": "^2.0.8",
"@fortawesome/angular-fontawesome": "^3.0.0",
"@fortawesome/fontawesome-free": "^6.7.2",
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-brands-svg-icons": "^6.7.2",
"@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/angular-fontawesome": "^4.0.0",
"@fortawesome/fontawesome-free": "^7.1.0",
"@fortawesome/fontawesome-svg-core": "^7.1.0",
"@fortawesome/free-brands-svg-icons": "^7.1.0",
"@fortawesome/free-regular-svg-icons": "^7.1.0",
"@fortawesome/free-solid-svg-icons": "^7.1.0",
"@fullcalendar/angular": "^6.1.20",
"@fullcalendar/core": "^6.1.20",
"@fullcalendar/daygrid": "^6.1.20",
@@ -65,13 +65,13 @@
"@gauzy/plugin-public-layout-ui": "^0.1.0",
"@jitsu/js": "^1.10.4",
"@kurkle/color": "^0.4.0",
"@nebular/auth": "^16.0.0",
"@nebular/auth": "^17.0.0",
"@nebular/bootstrap": "^9.1.0-rc.6",
"@nebular/security": "^16.0.0",
"@nebular/theme": "^16.0.0",
"@nebular/security": "^17.0.0",
"@nebular/theme": "^17.0.0",
"@ng-maps/core": "^8.0.0",
"@ng-maps/google": "^8.0.0",
"@ng-select/ng-select": "^20.7.0",
"@ng-select/ng-select": "^21.0.0",
"@ngneat/until-destroy": "^10.0.0",
"@ngx-translate/core": "^17.0.0",
"@ngx-translate/http-loader": "^17.0.0",
@@ -79,7 +79,7 @@
"@sentry/browser": "10.36.0",
"@sentry/core": "10.36.0",
"@sentry/node": "10.36.0",
"@swimlane/ngx-charts": "^23.0.0",
"@swimlane/ngx-charts": "^23.1.0",
"angular2-smart-table": "^4.1.1",
"bootstrap": "^4.3.1",
"brace": "^0.11.1",
@@ -91,11 +91,9 @@
"core-js": "^3.8.3",
"d3": "^7.4.4",
"d3-selection-multi": "^1.0.1",
"date-fns": "^2.28.0",
"date-holidays": "^1.6.1",
"date-fns": "^4.1.0",
"date-holidays": "^3.26.8",
"dayjs": "^1.11.4",
"detect-passive-events": "^1.0.4",
"fast-json-stringify": "^2.7.12",
"file-saver": "^2.0.5",
"filepond": "^4.25.1",
"filepond-plugin-file-encode": "^2.1.9",
@@ -110,7 +108,7 @@
"fullcalendar": "^6.1.17",
"hammerjs": "^2.0.8",
"handlebars": "^4.7.6",
"hotkeys-js": "^3.12.0",
"hotkeys-js": "^4.0.0",
"html-to-text": "^9.0.5",
"html2canvas": "^1.0.0-rc.7",
"immer": "^9.0.6",
@@ -128,13 +126,13 @@
"ngx-ace-editor-wrapper": "^9.1.12",
"ngx-clipboard": "^16.0.0",
"ngx-color-picker": "^20.1.1",
"ngx-cookie-service": "^20.1.1",
"ngx-countdown": "^20.0.0",
"ngx-cookie-service": "^21.1.0",
"ngx-countdown": "^21.0.0",
"ngx-daterangepicker-material": "^6.0.4",
"ngx-draggable-dom": "^20.0.0",
"ngx-draggable-dom": "^21.0.7",
"ngx-feature-toggle": "^12.0.0",
"ngx-filepond": "^7.0.3",
"ngx-infinite-scroll": "^20.0.0",
"ngx-infinite-scroll": "^21.0.0",
"ngx-moment": "^6.0.2",
"ngx-page-scroll": "^15.0.1",
"ngx-page-scroll-core": "^15.0.1",
@@ -149,16 +147,16 @@
"smooth-scrollbar": "^8.7.4",
"socicon": "^3.0.5",
"squirrelly": "^8.0.8",
"swiper": "^12.1.0",
"swiper": "^12.1.2",
"tslib": "^2.6.2",
"twing": "^5.0.2",
"typeface-exo": "^0.0.61",
"underscore": "^1.13.3",
"underscore": "^1.13.8",
"underscore.string": "^3.3.6",
"uuid": "^13.0.0",
"web-animations-js": "^2.3.2",
"yargs": "^17.5.0",
"zone.js": "0.15.0"
"zone.js": "0.16.0"
},
"devDependencies": {
"@types/async": "^3.2.5",
@@ -169,7 +167,7 @@
"@types/hammerjs": "^2.0.36",
"@types/html-to-text": "^9.0.1",
"@types/i18n": "^0.12.0",
"@types/jest": "29.5.14",
"@types/jest": "30.0.0",
"@types/leaflet": "^1.8.0",
"@types/moment-duration-format": "^2.2.7",
"@types/node": "^24.10.0",
@@ -178,8 +176,8 @@
"@types/yargs": "^15.0.9",
"jasmine-core": "^3.6.0",
"jasmine-spec-reporter": "^6.0.0",
"jest": "^29.7.0",
"jest-preset-angular": "14.6.2",
"jest": "30.0.0",
"jest-preset-angular": "16.0.0",
"karma": "^6.4.4",
"karma-chrome-launcher": "^3.2.0",
"karma-cli": "^2.0.0",
@@ -194,3 +192,4 @@
"webpack-node-externals": "^3.0.0"
}
}
+6
View File
@@ -58,7 +58,9 @@
"brace/mode/handlebars",
"camelcase",
"dayjs",
"deepmerge",
"file-saver",
"jalaali-js",
"leaflet",
"localforage",
"mobx",
@@ -216,7 +218,9 @@
"brace/mode/handlebars",
"camelcase",
"dayjs",
"deepmerge",
"file-saver",
"jalaali-js",
"leaflet",
"localforage",
"mobx",
@@ -324,7 +328,9 @@
"brace/mode/handlebars",
"camelcase",
"dayjs",
"deepmerge",
"file-saver",
"jalaali-js",
"leaflet",
"localforage",
"mobx",
-2
View File
@@ -1,7 +1,6 @@
import { TestBed, async } from '@angular/core/testing';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
@@ -11,7 +10,6 @@ describe('AppComponent', () => {
providers: [provideHttpClient(withInterceptorsFromDi())]
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
+3 -2
View File
@@ -1,4 +1,4 @@
import { inject, NgModule, OnDestroy } from '@angular/core';
import { inject, NgModule, OnDestroy, provideZoneChangeDetection } from '@angular/core';
import { PLUGIN_UI_CONFIG, getPluginUiConfig, PluginUiModule, PluginUiRegistryService } from '@gauzy/plugin-ui';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@@ -27,7 +27,8 @@ import { AppComponent } from './app.component';
{
provide: PLUGIN_UI_CONFIG,
useFactory: getPluginUiConfig
}
},
provideZoneChangeDetection({ eventCoalescing: true })
],
bootstrap: [AppComponent]
})
@@ -150,35 +150,35 @@
}}
</div>
<div class="form-block-criterion">
<div
class="form-block-criterion-item"
*ngFor="
let technologyRating of form.get(
[
'feedbacks',
0,
'technologies'
]
).controls;
index as i
"
>
@if (technologiesList) {
<span
class="form-block-criterion-title"
>
{{
technologiesList[i]
?.name
}}
</span>
}
<ga-star-rating-input
@for (
technologyRating of form.get(
[
'feedbacks',
0,
'technologies'
]
).controls; track
technologyRating; let i = $index) {
<div
class="form-block-criterion-item"
>
@if (technologiesList) {
<span
class="form-block-criterion-title"
>
{{
technologiesList[i]
?.name
}}
</span>
}
<ga-star-rating-input
[formControl]="
technologyRating
"
></ga-star-rating-input>
</div>
></ga-star-rating-input>
</div>
}
</div>
</div>
}
@@ -203,38 +203,38 @@
}}
</div>
<div class="form-block-criterion">
<div
class="form-block-criterion-item"
*ngFor="
let personalQualityRating of form.get(
[
'feedbacks',
0,
'personalQualities'
]
).controls;
index as i
"
>
@if (
personalQualitiesList
) {
<span
class="form-block-criterion-title"
>
{{
personalQualitiesList[
i
]?.name
}}
</span>
}
<ga-star-rating-input
@for (
personalQualityRating of form.get(
[
'feedbacks',
0,
'personalQualities'
]
).controls; track
personalQualityRating; let i = $index) {
<div
class="form-block-criterion-item"
>
@if (
personalQualitiesList
) {
<span
class="form-block-criterion-title"
>
{{
personalQualitiesList[
i
]?.name
}}
</span>
}
<ga-star-rating-input
[formControl]="
personalQualityRating
"
></ga-star-rating-input>
</div>
></ga-star-rating-input>
</div>
}
</div>
</div>
}
@@ -7,17 +7,19 @@
</ngx-header-title>
</h4>
</div>
<div *ngIf="!showAddCard" class="align-self-end">
<ngx-gauzy-button-action
[componentName]="viewComponentName"
[isDisable]="disableButton"
[buttonTemplate]="actionButtons"
[buttonTemplateVisible]="visible"
></ngx-gauzy-button-action>
</div>
@if (!showAddCard) {
<div class="align-self-end">
<ngx-gauzy-button-action
[componentName]="viewComponentName"
[isDisable]="disableButton"
[buttonTemplate]="actionButtons"
[buttonTemplateVisible]="visible"
></ngx-gauzy-button-action>
</div>
}
</nb-card-header>
<nb-card-body [ngClass]="{ mutation: showAddCard }" class="custom-card">
<ng-container *ngIf="showAddCard; else layout">
@if (showAddCard) {
<ga-contact-mutation
class="w-100"
[contactType]="contactType"
@@ -26,9 +28,8 @@
(canceled)="cancel()"
(addOrEditOrganizationContact)="addOrEditOrganizationContact($event)"
></ga-contact-mutation>
</ng-container>
<ng-template #layout>
<ng-template [ngIf]="dataLayoutStyle === componentLayoutStyleEnum.TABLE" [ngIfElse]="contactsGridLayout">
} @else {
@if (dataLayoutStyle === componentLayoutStyleEnum.TABLE) {
<div class="table-scroll-container">
<angular2-smart-table
style="cursor: pointer"
@@ -38,12 +39,11 @@
></angular2-smart-table>
</div>
<div class="pagination-container align-self-end">
<ng-container *ngIf="smartTableSource">
@if (smartTableSource) {
<ngx-pagination [source]="smartTableSource"></ngx-pagination>
</ng-container>
}
</div>
</ng-template>
<ng-template #contactsGridLayout>
} @else {
<ga-card-grid
[totalItems]="pagination?.totalItems"
(onSelectedItem)="selectContact($event)"
@@ -51,24 +51,25 @@
[source]="organizationContacts"
(scroll)="onScroll()"
></ga-card-grid>
</ng-template>
</ng-template>
}
}
</nb-card-body>
</nb-card>
<ng-template #actionButtons>
<ngx-favorite-toggle
*ngIf="selectedOrganizationContact"
[entityType]="'OrganizationContact'"
[entityId]="selectedOrganizationContact.id"
[entityName]="selectedOrganizationContact.name"
size="small"
status="basic"
spacing="list"
[disabled]="disableButton"
[showLabel]="false"
(favoriteToggled)="onContactFavoriteToggled($event)"
></ngx-favorite-toggle>
@if (selectedOrganizationContact) {
<ngx-favorite-toggle
[entityType]="'OrganizationContact'"
[entityId]="selectedOrganizationContact.id"
[entityName]="selectedOrganizationContact.name"
size="small"
status="basic"
spacing="list"
[disabled]="disableButton"
[showLabel]="false"
(favoriteToggled)="onContactFavoriteToggled($event)"
></ngx-favorite-toggle>
}
<ng-template ngxPermissionsOnly="ORG_CONTACT_EDIT">
<div class="btn-group actions">
<ngx-contact-action
@@ -1,42 +1,42 @@
<div class="charts">
<label class="chart-select-label">
{{ 'DASHBOARD_PAGE.CHARTS.CHART_TYPE' | translate }}
</label>
<nb-select
placeholder="Select chart"
class="select-charts"
filled
status="success"
[(selected)]="selectedChart"
size="tiny"
>
<nb-option [value]="EmployeeChartEnum.BAR">
<img width="auto" height="24" style="margin-right: 10px" src="assets/images/others/bar-chart.svg" />
{{ 'DASHBOARD_PAGE.CHARTS.BAR' | translate }}
</nb-option>
<nb-option [value]="EmployeeChartEnum.DOUGHNUT">
<img width="auto" height="24" style="margin-right: 10px" src="assets/images/others/doughnut.svg" />
{{ 'DASHBOARD_PAGE.CHARTS.DOUGHNUT' | translate }}
</nb-option>
<nb-option [value]="EmployeeChartEnum.STACKED_BAR">
<img width="auto" height="24" style="margin-right: 10px" src="assets/images/others/stacked-bar-chart.svg" />
{{ 'DASHBOARD_PAGE.CHARTS.STACKED_BAR' | translate }}
</nb-option>
</nb-select>
<label class="chart-select-label">
{{ 'DASHBOARD_PAGE.CHARTS.CHART_TYPE' | translate }}
</label>
<nb-select
placeholder="Select chart"
class="select-charts"
filled
status="success"
[(selected)]="selectedChart"
size="tiny"
>
<nb-option [value]="EmployeeChartEnum.BAR">
<img width="auto" height="24" style="margin-right: 10px" src="assets/images/others/bar-chart.svg" />
{{ 'DASHBOARD_PAGE.CHARTS.BAR' | translate }}
</nb-option>
<nb-option [value]="EmployeeChartEnum.DOUGHNUT">
<img width="auto" height="24" style="margin-right: 10px" src="assets/images/others/doughnut.svg" />
{{ 'DASHBOARD_PAGE.CHARTS.DOUGHNUT' | translate }}
</nb-option>
<nb-option [value]="EmployeeChartEnum.STACKED_BAR">
<img width="auto" height="24" style="margin-right: 10px" src="assets/images/others/stacked-bar-chart.svg" />
{{ 'DASHBOARD_PAGE.CHARTS.STACKED_BAR' | translate }}
</nb-option>
</nb-select>
</div>
<div class="chart-wrap">
<ng-container [ngSwitch]="selectedChart">
<ng-container *ngSwitchCase="EmployeeChartEnum.DOUGHNUT">
<ga-employee-doughnut-chart [employeeStatistics]="employeeStatistics"></ga-employee-doughnut-chart>
</ng-container>
<ng-container *ngSwitchCase="EmployeeChartEnum.STACKED_BAR">
<ga-employee-stacked-bar-chart [employeeStatistics]="employeeStatistics"></ga-employee-stacked-bar-chart>
</ng-container>
<ng-container *ngSwitchDefault>
<ga-employee-horizontal-bar-chart
[employeeStatistics]="employeeStatistics"
></ga-employee-horizontal-bar-chart>
</ng-container>
</ng-container>
@switch (selectedChart) {
@case (EmployeeChartEnum.DOUGHNUT) {
<ga-employee-doughnut-chart [employeeStatistics]="employeeStatistics"></ga-employee-doughnut-chart>
}
@case (EmployeeChartEnum.STACKED_BAR) {
<ga-employee-stacked-bar-chart [employeeStatistics]="employeeStatistics"></ga-employee-stacked-bar-chart>
}
@default {
<ga-employee-horizontal-bar-chart
[employeeStatistics]="employeeStatistics"
></ga-employee-horizontal-bar-chart>
}
}
</div>
@@ -2,7 +2,7 @@
<nb-card-header class="card-header">
<div class="row">
<div class="col-auto">
<ng-container *ngIf="selectedDateRange?.startDate && selectedDateRange?.endDate">
@if (selectedDateRange?.startDate && selectedDateRange?.endDate) {
<h4>
<ngx-header-title>
{{ headerTitle }}
@@ -14,7 +14,7 @@
[end]="selectedDateRange?.endDate"
[format]="'dddd, LL'"
></ngx-date-range-title>
</ng-container>
}
</div>
<div class="mb-4 ml-auto col-auto d-flex align-items-center">
<ga-timezone-filter
@@ -69,8 +69,8 @@
</nb-card-body>
</nb-card>
<!-- widgets -->
<ng-template #widget>
<ng-container *ngIf="!hideEmployeeBlock">
<ng-template gaWidgetTemplate>
@if (!hideEmployeeBlock) {
<ng-container *ngxPermissionsOnly="PermissionsEnum.CHANGE_SELECTED_EMPLOYEE">
<nb-card [nbSpinner]="countsLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-body>
@@ -92,10 +92,10 @@
</nb-card-body>
</nb-card>
</ng-container>
</ng-container>
}
</ng-template>
<ng-template #widget>
<ng-container *ngIf="!hideProjectBlock">
<ng-template gaWidgetTemplate>
@if (!hideProjectBlock) {
<nb-card [nbSpinner]="countsLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-body>
<div class="header-widget">
@@ -115,9 +115,9 @@
</div>
</nb-card-body>
</nb-card>
</ng-container>
}
</ng-template>
<ng-template #widget>
<ng-template gaWidgetTemplate>
<nb-card [nbSpinner]="countsLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-body>
<div class="header-widget">
@@ -132,7 +132,7 @@
</nb-card-body>
</nb-card>
</ng-template>
<ng-template #widget>
<ng-template gaWidgetTemplate>
<nb-card [nbSpinner]="countsLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-body>
<div class="header-widget">
@@ -153,25 +153,25 @@
</nb-card-body>
</nb-card>
</ng-template>
<ng-template #widget>
<ng-template gaWidgetTemplate>
<nb-card [nbSpinner]="countsLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-body>
<div class="header-widget">
<div class="title">
<ng-container [ngSwitch]="selectedPeriod">
<ng-container *ngSwitchCase="RangePeriod.PERIOD">
@switch (selectedPeriod) {
@case (RangePeriod.PERIOD) {
{{ 'TIMESHEET.WORKED_OVER_PERIOD' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.DAY">
}
@case (RangePeriod.DAY) {
{{ 'TIMESHEET.WORKED_FOR_DAY' | translate }}
</ng-container>
<ng-container *ngSwitchDefault>
}
@default {
{{
(isCurrentWeek() ? 'TIMESHEET.WORKED_THIS_WEEK' : 'TIMESHEET.WORKED_FOR_WEEK')
| translate
}}
</ng-container>
</ng-container>
}
}
</div>
</div>
<div class="h1">
@@ -187,22 +187,22 @@
</nb-card-body>
</nb-card>
</ng-template>
<ng-template #widget>
<ng-template gaWidgetTemplate>
<nb-card [nbSpinner]="countsLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-body>
<div class="header-widget">
<div class="title">
<ng-container [ngSwitch]="selectedPeriod">
<ng-container *ngSwitchCase="RangePeriod.PERIOD">
@switch (selectedPeriod) {
@case (RangePeriod.PERIOD) {
{{ 'TIMESHEET.ACTIVITY_OVER_PERIOD' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.DAY">
}
@case (RangePeriod.DAY) {
{{ 'TIMESHEET.ACTIVITY_FOR_DAY' | translate }}
</ng-container>
<ng-container *ngSwitchDefault>
}
@default {
{{ 'TIMESHEET.ACTIVITY_FOR_WEEK' | translate }}
</ng-container>
</ng-container>
}
}
</div>
</div>
<div class="h1">{{ counts?.weekActivities || 0 }}%</div>
@@ -213,110 +213,111 @@
</nb-card>
</ng-template>
<!-- Windows -->
<ng-template #window>
<ng-template gaWindowTemplate>
<nb-card [nbSpinner]="timeSlotLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-header>{{ 'TIMESHEET.RECENT_ACTIVITIES' | translate }}</nb-card-header>
<nb-card-body class="custom-card-body-inner">
<ng-template [ngIf]="timeSlotEmployees?.length > 0" [ngIfElse]="noScreenshot">
<div class="row" *ngFor="let employee of timeSlotEmployees">
<ng-container *ngIf="employee?.timeSlots?.length > 0">
<div class="col">
<div class="hour-label mb-3">
<ng-template [ngxPermissionsOnly]="PermissionsEnum.CHANGE_SELECTED_EMPLOYEE">
<ngx-avatar
class="avatar-dashboard activity"
[size]="'sm'"
[name]="employee?.user?.name"
[src]="employee?.user?.imageUrl"
[appendCaption]="'TIMESHEET.LAST_WORKED' | translate"
[caption]="(employee?.timeSlots)[0]?.startedAt | utcToLocal | dateFormat"
[id]="employee?.id"
[employee]="employee"
></ngx-avatar>
</ng-template>
<div></div>
<div class="button-container">
<div class="swiper-button-container">
<div class="swiper-button" (click)="slidePrev(swiperRef)">
<i class="fas fa-angle-left"></i>
@if (timeSlotEmployees?.length > 0) {
@for (employee of timeSlotEmployees; track employee) {
<div class="row">
@if (employee?.timeSlots?.length > 0) {
<div class="col">
<div class="hour-label mb-3">
<ng-template [ngxPermissionsOnly]="PermissionsEnum.CHANGE_SELECTED_EMPLOYEE">
<ngx-avatar
class="avatar-dashboard activity"
[size]="'sm'"
[name]="employee?.user?.name"
[src]="employee?.user?.imageUrl"
[appendCaption]="'TIMESHEET.LAST_WORKED' | translate"
[caption]="(employee?.timeSlots)[0]?.startedAt | utcToLocal | dateFormat"
[id]="employee?.id"
[employee]="employee"
></ngx-avatar>
</ng-template>
<div></div>
<div class="button-container">
<div class="swiper-button-container">
<div class="swiper-button" (click)="slidePrev(swiperRef)">
<i class="fas fa-angle-left"></i>
</div>
<div class="swiper-button" (click)="slideNext(swiperRef)">
<i class="fas fa-angle-right"></i>
</div>
</div>
<div class="swiper-button" (click)="slideNext(swiperRef)">
<i class="fas fa-angle-right"></i>
<div
*ngxPermissionsOnly="PermissionsEnum.CHANGE_SELECTED_EMPLOYEE"
class="view-all"
>
<ng-container>
<button
nbButton
status="primary"
size="small"
outline
(click)="redirectToScreenshots(employee)"
>
{{ 'BUTTONS.VIEW_ALL' | translate }}
</button>
</ng-container>
</div>
</div>
<div
*ngxPermissionsOnly="PermissionsEnum.CHANGE_SELECTED_EMPLOYEE"
class="view-all"
</div>
<div>
<swiper-container
#swiperRef
slides-per-view="3"
space-between="16"
slides-per-group="3"
loop="false"
navigation="true"
[pagination]="{ clickable: true }"
class="m-swiper"
>
<ng-container>
<button
nbButton
status="primary"
size="small"
outline
(click)="redirectToScreenshots(employee)"
>
{{ 'BUTTONS.VIEW_ALL' | translate }}
</button>
</ng-container>
</div>
@for (timeSlot of employee.timeSlots; track timeSlot) {
<swiper-slide>
<ngx-screenshots-item
[timeFormat]="filters?.timeFormat"
[timezone]="filters?.timeZone"
[timeSlot]="timeSlot"
(delete)="onDelete()"
[multiple]="false"
[employeeId]="timeSlot?.employee?.id"
></ngx-screenshots-item>
</swiper-slide>
}
</swiper-container>
</div>
</div>
<div>
<swiper-container
#swiperRef
slides-per-view="3"
space-between="16"
slides-per-group="3"
loop="false"
navigation="true"
[pagination]="{ clickable: true }"
class="m-swiper"
>
<ng-container *ngFor="let timeSlot of employee.timeSlots">
<swiper-slide>
<ngx-screenshots-item
[timeFormat]="filters?.timeFormat"
[timezone]="filters?.timeZone"
[timeSlot]="timeSlot"
(delete)="onDelete()"
[multiple]="false"
[employeeId]="timeSlot?.employee?.id"
></ngx-screenshots-item>
</swiper-slide>
</ng-container>
</swiper-container>
</div>
</div>
</ng-container>
</div>
</ng-template>
<ng-template #noScreenshot>
<ng-container *ngIf="!timeSlotLoading">
<div class="text-center">
<ng-container [ngSwitch]="selectedPeriod">
<ng-container *ngSwitchCase="RangePeriod.DAY">
{{ 'TIMESHEET.NO_SCREENSHOT_DAY' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.WEEK">
{{ 'TIMESHEET.NO_SCREENSHOT_WEEK' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.PERIOD">
{{ 'TIMESHEET.NO_SCREENSHOT_PERIOD' | translate }}
</ng-container>
</ng-container>
}
</div>
</ng-container>
</ng-template>
}
} @else {
@if (!timeSlotLoading) {
<div class="text-center">
@switch (selectedPeriod) {
@case (RangePeriod.DAY) {
{{ 'TIMESHEET.NO_SCREENSHOT_DAY' | translate }}
}
@case (RangePeriod.WEEK) {
{{ 'TIMESHEET.NO_SCREENSHOT_WEEK' | translate }}
}
@case (RangePeriod.PERIOD) {
{{ 'TIMESHEET.NO_SCREENSHOT_PERIOD' | translate }}
}
}
</div>
}
}
</nb-card-body>
</nb-card>
</ng-template>
<ng-template #window>
<ng-template gaWindowTemplate>
<nb-card [nbSpinner]="manualTimeLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-header class="nb-card-header">
{{ 'TIMESHEET.MANUAL_TIME' | translate }}
</nb-card-header>
<ng-template [ngIf]="manualTimes?.length > 0" [ngIfElse]="noManualTimes">
@if (manualTimes?.length > 0) {
<nb-card-body class="custom-card-body-inner-list">
<div class="custom-card-button">
<button nbButton status="primary" outline size="small" (click)="redirectToManualTimeReport()">
@@ -342,59 +343,60 @@
</div>
</div>
</nb-list-item>
<nb-list-item *ngFor="let manualTime of manualTimes">
<div class="w-100">
<div class="row">
<div class="col-sm-3">
<ngx-avatar
[name]="manualTime?.user?.name"
[src]="manualTime?.user?.imageUrl"
[id]="manualTime?.employeeId"
[employee]="manualTime?.employee"
size="sm"
class="avatar-dashboard"
></ngx-avatar>
</div>
<div class="col project-name">
{{ manualTime.project.name }}
</div>
<div class="col">
{{ manualTime.duration | durationFormat }}
</div>
<div class="col">
{{ manualTime.startedAt | dateFormat }}
@for (manualTime of manualTimes; track manualTime) {
<nb-list-item>
<div class="w-100">
<div class="row">
<div class="col-sm-3">
<ngx-avatar
[name]="manualTime?.user?.name"
[src]="manualTime?.user?.imageUrl"
[id]="manualTime?.employeeId"
[employee]="manualTime?.employee"
size="sm"
class="avatar-dashboard"
></ngx-avatar>
</div>
<div class="col project-name">
{{ manualTime.project.name }}
</div>
<div class="col">
{{ manualTime.duration | durationFormat }}
</div>
<div class="col">
{{ manualTime.startedAt | dateFormat }}
</div>
</div>
</div>
</div>
</nb-list-item>
</nb-list-item>
}
</nb-list>
</nb-card-body>
</ng-template>
<ng-template #noManualTimes>
<ng-container *ngIf="!manualTimeLoading">
} @else {
@if (!manualTimeLoading) {
<div class="text-center p-3">
<ng-container [ngSwitch]="selectedPeriod">
<ng-container *ngSwitchCase="RangePeriod.DAY">
@switch (selectedPeriod) {
@case (RangePeriod.DAY) {
{{ 'TIMESHEET.NO_MANUAL_TIME_DAY' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.WEEK">
}
@case (RangePeriod.WEEK) {
{{ 'TIMESHEET.NO_MANUAL_TIME_WEEK' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.PERIOD">
}
@case (RangePeriod.PERIOD) {
{{ 'TIMESHEET.NO_MANUAL_TIME_PERIOD' | translate }}
</ng-container>
</ng-container>
}
}
</div>
</ng-container>
</ng-template>
}
}
</nb-card>
</ng-template>
<ng-template #window>
<ng-template gaWindowTemplate>
<nb-card [nbSpinner]="tasksLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-header class="nb-card-header">
{{ 'TIMESHEET.TASKS' | translate }}
</nb-card-header>
<ng-template [ngIf]="tasks?.length > 0" [ngIfElse]="noTasks">
@if (tasks?.length > 0) {
<nb-card-body class="custom-card-body-inner-list">
<div class="custom-card-button">
<button size="small" nbButton status="primary" outline (click)="redirectToTask()">
@@ -402,110 +404,112 @@
</button>
</div>
<nb-list>
<nb-list-item *ngFor="let task of tasks">
<div class="w-100">
<div class="row align-items-center">
<div class="col-5 project-name text-left">
{{ task.title }}
</div>
<div class="col-4 text-center">
<div class="d-flex align-items-center">
{{ task.durationPercentage }}%
<nb-progress-bar
class="mb-1 ml-3 mr-3 w-100 custom-progress"
[value]="task.durationPercentage"
[status]="progressStatus(task.durationPercentage)"
[displayValue]="true"
size="tiny"
>
</nb-progress-bar>
@for (task of tasks; track task) {
<nb-list-item>
<div class="w-100">
<div class="row align-items-center">
<div class="col-5 project-name text-left">
{{ task.title }}
</div>
<div class="col-4 text-center">
<div class="d-flex align-items-center">
{{ task.durationPercentage }}%
<nb-progress-bar
class="mb-1 ml-3 mr-3 w-100 custom-progress"
[value]="task.durationPercentage"
[status]="progressStatus(task.durationPercentage)"
[displayValue]="true"
size="tiny"
>
</nb-progress-bar>
</div>
</div>
<div class="col text-right">
{{ task.duration | durationFormat }}
</div>
</div>
<div class="col text-right">
{{ task.duration | durationFormat }}
</div>
</div>
</div>
</nb-list-item>
</nb-list-item>
}
</nb-list>
</nb-card-body>
</ng-template>
<ng-template #noTasks>
<ng-container *ngIf="!tasksLoading">
} @else {
@if (!tasksLoading) {
<div class="text-center p-3">
<ng-container [ngSwitch]="selectedPeriod">
<ng-container *ngSwitchCase="RangePeriod.DAY">
@switch (selectedPeriod) {
@case (RangePeriod.DAY) {
{{ 'TIMESHEET.NO_TASK_ACTIVITY_DAY' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.WEEK">
}
@case (RangePeriod.WEEK) {
{{ 'TIMESHEET.NO_TASK_ACTIVITY_WEEK' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.PERIOD">
}
@case (RangePeriod.PERIOD) {
{{ 'TIMESHEET.NO_TASK_ACTIVITY_PERIOD' | translate }}
</ng-container>
</ng-container>
}
}
</div>
</ng-container>
</ng-template>
}
}
</nb-card>
</ng-template>
<ng-template #window>
<ng-template gaWindowTemplate>
<nb-card [nbSpinner]="projectsLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-header>{{ 'TIMESHEET.PROJECTS' | translate }}</nb-card-header>
<ng-template [ngIf]="projects?.length > 0" [ngIfElse]="noProjects">
@if (projects?.length > 0) {
<nb-card-body class="custom-card-body-inner-list">
<nb-list>
<nb-list-item *ngFor="let project of projects">
<div class="w-100">
<div class="row align-items-center">
<div class="col-5 project-name text-left">
{{ project.name }}
</div>
<div class="col-4 text-center">
<div class="d-flex align-items-center">
{{ project.durationPercentage }}%
<nb-progress-bar
class="mb-1 ml-3 mr-3 w-100 custom-progress"
[value]="project.durationPercentage"
[status]="progressStatus(project.durationPercentage)"
[displayValue]="true"
size="tiny"
>
</nb-progress-bar>
@for (project of projects; track project) {
<nb-list-item>
<div class="w-100">
<div class="row align-items-center">
<div class="col-5 project-name text-left">
{{ project.name }}
</div>
<div class="col-4 text-center">
<div class="d-flex align-items-center">
{{ project.durationPercentage }}%
<nb-progress-bar
class="mb-1 ml-3 mr-3 w-100 custom-progress"
[value]="project.durationPercentage"
[status]="progressStatus(project.durationPercentage)"
[displayValue]="true"
size="tiny"
>
</nb-progress-bar>
</div>
</div>
<div class="col text-right">
{{ project.duration | durationFormat }}
</div>
</div>
<div class="col text-right">
{{ project.duration | durationFormat }}
</div>
</div>
</div>
</nb-list-item>
</nb-list-item>
}
</nb-list>
</nb-card-body>
</ng-template>
<ng-template #noProjects>
<ng-container *ngIf="!projectsLoading">
} @else {
@if (!projectsLoading) {
<div class="text-center p-3">
<ng-container [ngSwitch]="selectedPeriod">
<ng-container *ngSwitchCase="RangePeriod.DAY">
@switch (selectedPeriod) {
@case (RangePeriod.DAY) {
{{ 'TIMESHEET.NO_PROJECT_ACTIVITY_DAY' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.WEEK">
}
@case (RangePeriod.WEEK) {
{{ 'TIMESHEET.NO_PROJECT_ACTIVITY_WEEK' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.PERIOD">
}
@case (RangePeriod.PERIOD) {
{{ 'TIMESHEET.NO_PROJECT_ACTIVITY_PERIOD' | translate }}
</ng-container>
</ng-container>
}
}
</div>
</ng-container>
</ng-template>
}
}
</nb-card>
</ng-template>
<ng-template #window>
<ng-template gaWindowTemplate>
<nb-card [nbSpinner]="activitiesLoading" nbSpinnerSize="giant" nbSpinnerStatus="primary">
<nb-card-header class="nb-card-header">{{ 'TIMESHEET.APPS_URLS' | translate }} </nb-card-header>
<ng-template [ngIf]="activities?.length > 0" [ngIfElse]="noActivities">
@if (activities?.length > 0) {
<nb-card-body class="custom-card-body-inner-list">
<div class="custom-card-button">
<button nbButton status="primary" size="small" outline (click)="redirectToAppUrlReport()">
@@ -513,38 +517,39 @@
</button>
</div>
<nb-list>
<nb-list-item *ngFor="let activity of activities">
<div class="w-100">
<ngx-activity-item
class="tracking-progress"
[item]="activity"
[isDashboard]="true"
></ngx-activity-item>
</div>
</nb-list-item>
@for (activity of activities; track activity) {
<nb-list-item>
<div class="w-100">
<ngx-activity-item
class="tracking-progress"
[item]="activity"
[isDashboard]="true"
></ngx-activity-item>
</div>
</nb-list-item>
}
</nb-list>
</nb-card-body>
</ng-template>
<ng-template #noActivities>
<ng-container *ngIf="!activitiesLoading">
} @else {
@if (!activitiesLoading) {
<div class="text-center p-3">
<ng-container [ngSwitch]="selectedPeriod">
<ng-container *ngSwitchCase="RangePeriod.DAY">
@switch (selectedPeriod) {
@case (RangePeriod.DAY) {
{{ 'TIMESHEET.NO_APP_URL_ACTIVITY_DAY' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.WEEK">
}
@case (RangePeriod.WEEK) {
{{ 'TIMESHEET.NO_APP_URL_ACTIVITY_WEEK' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.PERIOD">
}
@case (RangePeriod.PERIOD) {
{{ 'TIMESHEET.NO_APP_URL_ACTIVITY_PERIOD' | translate }}
</ng-container>
</ng-container>
}
}
</div>
</ng-container>
</ng-template>
}
}
</nb-card>
</ng-template>
<ng-template #window>
<ng-template gaWindowTemplate>
<nb-card
class="member-list"
[nbSpinner]="memberLoading"
@@ -554,7 +559,7 @@
>
<nb-card-header>{{ 'TIMESHEET.MEMBERS' | translate }}</nb-card-header>
<nb-card-body class="custom-card-body-inner-list">
<ng-template [ngIf]="members?.length > 0" [ngIfElse]="noMember">
@if (members?.length > 0) {
<div class="list">
<nb-list>
<nb-list-item>
@@ -577,80 +582,82 @@
</div>
</div>
</nb-list-item>
<nb-list-item *ngFor="let member of members">
<div class="w-100">
<div class="row">
<div class="col-3">
<ngx-avatar
[name]="member?.user?.name"
[src]="member?.user?.imageUrl"
[id]="member?.id"
[employee]="member"
size="sm"
class="avatar-dashboard"
>
</ngx-avatar>
</div>
<div class="col-3 text-center">
<div class="activity">
<div class="duration">
{{ member?.todayTime?.duration || 0 | durationFormat }}
</div>
<div class="activity-percentage">
<nb-badge
[status]="progressStatus(member?.todayTime?.overall)"
[text]="(member?.todayTime?.overall || 0) + '%'"
></nb-badge>
</div>
@for (member of members; track member) {
<nb-list-item>
<div class="w-100">
<div class="row">
<div class="col-3">
<ngx-avatar
[name]="member?.user?.name"
[src]="member?.user?.imageUrl"
[id]="member?.id"
[employee]="member"
size="sm"
class="avatar-dashboard"
>
</ngx-avatar>
</div>
</div>
<div class="col text-center">
<div [ngClass]="!isMoreThanWeek() ? 'd-flex' : ''">
<div class="activity text-center">
<div class="col-3 text-center">
<div class="activity">
<div class="duration">
{{ member?.weekTime?.duration || 0 | durationFormat }}
{{ member?.todayTime?.duration || 0 | durationFormat }}
</div>
<div class="activity-percentage">
<nb-badge
[status]="progressStatus(member?.weekTime?.overall)"
[text]="(member?.weekTime?.overall || 0) + '%'"
[status]="progressStatus(member?.todayTime?.overall)"
[text]="(member?.todayTime?.overall || 0) + '%'"
></nb-badge>
</div>
</div>
<ng-container *ngIf="!isMoreThanWeek()">
<div class="member-weekly-activity-graph">
<div
*ngFor="let weekHour of member.weekHours"
class="bar-graph-entry"
[style.height]="weekHour.duration + '%'"
></div>
</div>
<div class="col text-center">
<div [ngClass]="!isMoreThanWeek() ? 'd-flex' : ''">
<div class="activity text-center">
<div class="duration">
{{ member?.weekTime?.duration || 0 | durationFormat }}
</div>
<div class="activity-percentage">
<nb-badge
[status]="progressStatus(member?.weekTime?.overall)"
[text]="(member?.weekTime?.overall || 0) + '%'"
></nb-badge>
</div>
</div>
</ng-container>
@if (!isMoreThanWeek()) {
<div class="member-weekly-activity-graph">
@for (weekHour of member.weekHours; track weekHour) {
<div
class="bar-graph-entry"
[style.height]="weekHour.duration + '%'"
></div>
}
</div>
}
</div>
</div>
</div>
</div>
</div>
</nb-list-item>
</nb-list-item>
}
</nb-list>
</div>
</ng-template>
<ng-template #noMember>
<ng-container *ngIf="!memberLoading">
} @else {
@if (!memberLoading) {
<div class="text-center">
<ng-container [ngSwitch]="selectedPeriod">
<ng-container *ngSwitchCase="RangePeriod.DAY">
@switch (selectedPeriod) {
@case (RangePeriod.DAY) {
{{ 'TIMESHEET.NO_MEMBER_ACTIVITY_DAY' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.WEEK">
}
@case (RangePeriod.WEEK) {
{{ 'TIMESHEET.NO_MEMBER_ACTIVITY_WEEK' | translate }}
</ng-container>
<ng-container *ngSwitchCase="RangePeriod.PERIOD">
}
@case (RangePeriod.PERIOD) {
{{ 'TIMESHEET.NO_MEMBER_ACTIVITY_PERIOD' | translate }}
</ng-container>
</ng-container>
}
}
</div>
</ng-container>
</ng-template>
}
}
</nb-card-body>
</nb-card>
</ng-template>
@@ -662,8 +669,8 @@
{{ 'TIMESHEET.VIEW_WIDGETS' | translate }}
<button class="manage-widget undo" (click)="undo()" nbButton><i class="fas fa-undo"></i>Undo</button>
</div>
<ng-container *ngIf="widgets.length > 0">
<ng-container *ngFor="let widget of widgets">
@if (widgets.length > 0) {
@for (widget of widgets; track widget) {
<div (click)="updateWidgetVisibility(widget)" class="title">
<i
[ngStyle]="{
@@ -675,8 +682,8 @@
{{ titleMapper(widget.position) | translate }}
</div>
</div>
</ng-container>
</ng-container>
}
}
</div>
<div class="line"></div>
<div class="category">
@@ -686,8 +693,8 @@
<i class="fas fa-undo"></i>Undo
</button>
</div>
<ng-container *ngIf="windows.length > 0">
<ng-container *ngFor="let window of windows">
@if (windows.length > 0) {
@for (window of windows; track window) {
<div (click)="updateWindowVisibility(window)" class="title">
<i
[ngStyle]="{
@@ -699,8 +706,8 @@
{{ titleMapper(window.position, false) | translate }}
</div>
</div>
</ng-container>
</ng-container>
}
}
</div>
</div>
</ng-template>
@@ -60,7 +60,9 @@ import {
GalleryService,
TimeZoneService,
WidgetService,
WidgetTemplateDirective,
WindowService,
WindowTemplateDirective,
getAdjustDateRangeFutureAllowed
} from '@gauzy/ui-core/shared';
@@ -140,10 +142,11 @@ export class TimeTrackingComponent
public filters: ITimeLogFilters = { timeFormat: TimeFormatEnum.FORMAT_12_HOURS };
public payloads$: BehaviorSubject<ITimeLogFilters> = new BehaviorSubject(null);
@ViewChildren('widget') listOfWidgets: QueryList<TemplateRef<HTMLElement>>;
@ViewChildren('window') listOfWindows: QueryList<TemplateRef<HTMLElement>>;
public widgetsRef: TemplateRef<HTMLElement>[] = [];
public windowsRef: TemplateRef<HTMLElement>[] = [];
@ViewChildren(WidgetTemplateDirective, { read: TemplateRef }) listOfWidgets: QueryList<TemplateRef<any>>;
@ViewChildren(WindowTemplateDirective, { read: TemplateRef }) listOfWindows: QueryList<TemplateRef<any>>;
public widgetsRef: TemplateRef<any>[] = [];
public windowsRef: TemplateRef<any>[] = [];
public widgets: GuiDrag[];
public windows: GuiDrag[];
@@ -632,7 +635,7 @@ export class TimeTrackingComponent
employeeLevel: people.employeeLevel,
fullName: people.user.name,
shortDescription: people.short_description
} as ISelectedEmployee)
} as ISelectedEmployee)
: ALL_EMPLOYEES_SELECTED;
if (this._store.selectedEmployee) {
this._router.navigate([`/pages/employees/activity/screenshots`]);
@@ -1,23 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AppUrlActivityComponent } from './app-url-activity.component';
describe('AppUrlActivityComponent', () => {
let component: AppUrlActivityComponent;
let fixture: ComponentFixture<AppUrlActivityComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AppUrlActivityComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppUrlActivityComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivityLayoutComponent } from './layout.component';
describe('ActivityLayoutComponent', () => {
let component: ActivityLayoutComponent;
let fixture: ComponentFixture<ActivityLayoutComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ActivityLayoutComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ActivityLayoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ScreenshotComponent } from './screenshot.component';
describe('ScreenshotComponent', () => {
let component: ScreenshotComponent;
let fixture: ComponentFixture<ScreenshotComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ScreenshotComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ScreenshotComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TimeActivitiesComponent } from './time-activities.component';
describe('TimeActivitiesComponent', () => {
let component: TimeActivitiesComponent;
let fixture: ComponentFixture<TimeActivitiesComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [TimeActivitiesComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TimeActivitiesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -14,7 +14,7 @@ import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { distinctUntilChange } from '@gauzy/ui-core/common';
import { combineLatest } from 'rxjs';
import { debounceTime, filter, tap } from 'rxjs/operators';
import { CKEditor4 } from 'ckeditor4-angular/ckeditor';
import { CKEditor4 } from 'ckeditor4-angular';
import { ckEditorConfig } from '@gauzy/ui-core/shared';
import {
EmployeeLevelService,
@@ -28,10 +28,10 @@ import { ToastrService } from '@gauzy/ui-core/core';
@UntilDestroy({ checkProperties: true })
@Component({
selector: 'ga-edit-employee-employment',
templateUrl: './edit-employee-employment.component.html',
styleUrls: ['./edit-employee-employment.component.scss'],
standalone: false
selector: 'ga-edit-employee-employment',
templateUrl: './edit-employee-employment.component.html',
styleUrls: ['./edit-employee-employment.component.scss'],
standalone: false
})
export class EditEmployeeEmploymentComponent implements OnInit, OnDestroy {
selectedEmployee: IEmployee;
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ApprovalsComponent } from './approvals.component';
describe('ApprovalsComponent', () => {
let component: ApprovalsComponent;
let fixture: ComponentFixture<ApprovalsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ApprovalsComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ApprovalsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CalendarComponent } from './calendar.component';
describe('CalendarComponent', () => {
let component: CalendarComponent;
let fixture: ComponentFixture<CalendarComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [CalendarComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CalendarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DailyComponent } from './daily.component';
describe('DailyComponent', () => {
let component: DailyComponent;
let fixture: ComponentFixture<DailyComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DailyComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DailyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TimesheetLayoutComponent } from './layout.component';
describe('TimesheetLayoutComponent', () => {
let component: TimesheetLayoutComponent;
let fixture: ComponentFixture<TimesheetLayoutComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TimesheetLayoutComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TimesheetLayoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ViewComponent } from './view.component';
describe('ViewComponent', () => {
let component: ViewComponent;
let fixture: ComponentFixture<ViewComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ViewComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ViewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { WeeklyComponent } from './weekly.component';
describe('WeeklyComponent', () => {
let component: WeeklyComponent;
let fixture: ComponentFixture<WeeklyComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [WeeklyComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(WeeklyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { GoalsComponent } from './goals.component';
describe('GoalsComponent', () => {
let component: GoalsComponent;
let fixture: ComponentFixture<GoalsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [GoalsComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GoalsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit, Input } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { NbDialogRef } from '@nebular/theme';
import { TranslateService } from '@ngx-translate/core';
import { CKEditor4 } from 'ckeditor4-angular/ckeditor';
import { CKEditor4 } from 'ckeditor4-angular';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { IHelpCenterArticle, IEmployee, IHelpCenterAuthor, IOrganization } from '@gauzy/contracts';
import { ckEditorConfig } from '@gauzy/ui-core/shared';
@@ -17,10 +17,10 @@ import {
@UntilDestroy()
@Component({
selector: 'ga-add-article',
templateUrl: 'add-article.component.html',
styleUrls: ['add-article.component.scss'],
standalone: false
selector: 'ga-add-article',
templateUrl: 'add-article.component.html',
styleUrls: ['add-article.component.scss'],
standalone: false
})
export class AddArticleComponent extends TranslationBaseComponent implements OnInit, OnDestroy {
@Input() article?: IHelpCenterArticle;
@@ -1,117 +1,125 @@
<nb-card [nbSpinner]="isLoading$ | async" class="card-scroll">
<nb-card-header>
<h4>{{ 'INTEGRATIONS.AVAILABLE_INTEGRATIONS' | translate }}</h4>
<button
nbButton
status="basic"
size="medium"
class="plugins-navigation-button"
[routerLink]="['..', 'plugins']"
>
<nb-icon icon="cube-outline" pack="eva"></nb-icon>
<span>{{ 'INTEGRATIONS.PLUGINS' | translate }}</span>
</button>
</nb-card-header>
<nb-card-body>
<ng-template [ngxPermissionsOnly]="['INTEGRATION_ADD', 'INTEGRATION_EDIT']">
<ng-template [ngxPermissionsOnly]="['INTEGRATION_VIEW']">
<div class="integration-filters">
<div class="container">
<div class="row">
<div class="col-xl-7 col-12">
<input
#searchElement
fullWidth
id="integrationSearch"
type="text"
nbInput
[placeholder]="'INTEGRATIONS.SEARCH_INTEGRATIONS' | translate"
(input)="doSearch($event)"
/>
</div>
</div>
<div class="row mt-4">
<div class="col-xl-4 col-6">
<div class="selectors">
<div *ngIf="integrationGroups$ | async as integrationGroups">
<label>{{ 'INTEGRATIONS.INTEGRATION' | translate }}</label>
<nb-select
fullWidth
class="integration-selector"
[placeholder]="'INTEGRATIONS.SELECT_GROUPS' | translate"
[selected]="selectedIntegrationTypeId$ | async"
(selectedChange)="setSelectedIntegrationType($event)"
>
<nb-option-group
*ngFor="let integrationGroup of integrationGroups"
[title]="integrationGroup.groupName"
>
<nb-option
*ngFor="let integrationType of integrationGroup.integrationTypes"
[value]="integrationType.id"
>
{{ integrationType.name }}
</nb-option>
</nb-option-group>
</nb-select>
</div>
<div>
<label>{{ 'INTEGRATIONS.PAID' | translate }}</label>
<nb-select
[placeholder]="'INTEGRATIONS.FILTER_INTEGRATIONS' | translate"
fullWidth
[selected]="selectedIntegrationFilter$ | async"
(selectedChange)="setSelectedIntegrationFilter($event)"
>
<nb-option *ngFor="let filter of filters" [value]="filter.value">
{{ filter.label }}
</nb-option>
</nb-select>
</div>
</div>
</div>
<div class="col-xl-3 col-6 d-flex align-items-end justify-content-end">
<div class="clear-filter">
<button (click)="clearFilter()" status="danger" size="small" nbButton>
{{ 'BUTTONS.CLEAR_ALL' | translate }}
</button>
</div>
</div>
</div>
</div>
</div>
<div class="grid-container">
<div class="integrations-list" *ngIf="integrations$ | async as integrations">
<ng-container *ngFor="let integration of integrations">
<a
class="list-item"
[ngClass]="integration.isComingSoon ? 'disabled' : ''"
[routerLink]="['../', integration.redirectUrl]"
>
<img
[src]="integration.fullImgUrl"
width="100%"
height="100%"
alt="image not found"
[title]="integration.name | replace : '_' : ' '"
/>
<ng-container *ngIf="integration.isComingSoon">
<div class="coming-soon-wrapper">
<span class="coming-soon">
{{ 'INTEGRATIONS.COMING_SOON' | translate }}
</span>
</div>
</ng-container>
</a>
</ng-container>
</div>
</div>
</ng-template>
</ng-template>
<ng-template [ngxPermissionsExcept]="['INTEGRATION_ADD', 'INTEGRATION_EDIT']">
<div>
<!-- Content to display if the user does not have 'canEditComponent' permission -->
</div>
</ng-template>
</nb-card-body>
</nb-card>
<nb-card-header>
<h4>{{ 'INTEGRATIONS.AVAILABLE_INTEGRATIONS' | translate }}</h4>
<button
nbButton
status="basic"
size="medium"
class="plugins-navigation-button"
[routerLink]="['..', 'plugins']"
>
<nb-icon icon="cube-outline" pack="eva"></nb-icon>
<span>{{ 'INTEGRATIONS.PLUGINS' | translate }}</span>
</button>
</nb-card-header>
<nb-card-body>
<ng-template [ngxPermissionsOnly]="['INTEGRATION_ADD', 'INTEGRATION_EDIT']">
<ng-template [ngxPermissionsOnly]="['INTEGRATION_VIEW']">
<div class="integration-filters">
<div class="container">
<div class="row">
<div class="col-xl-7 col-12">
<input
#searchElement
fullWidth
id="integrationSearch"
type="text"
nbInput
[placeholder]="'INTEGRATIONS.SEARCH_INTEGRATIONS' | translate"
(input)="doSearch($event)"
/>
</div>
</div>
<div class="row mt-4">
<div class="col-xl-4 col-6">
<div class="selectors">
@if (integrationGroups$ | async; as integrationGroups) {
<div>
<label>{{ 'INTEGRATIONS.INTEGRATION' | translate }}</label>
<nb-select
fullWidth
class="integration-selector"
[placeholder]="'INTEGRATIONS.SELECT_GROUPS' | translate"
[selected]="selectedIntegrationTypeId$ | async"
(selectedChange)="setSelectedIntegrationType($event)"
>
@for (integrationGroup of integrationGroups; track integrationGroup) {
<nb-option-group
[title]="integrationGroup.groupName"
>
@for (integrationType of integrationGroup.integrationTypes; track integrationType) {
<nb-option
[value]="integrationType.id"
>
{{ integrationType.name }}
</nb-option>
}
</nb-option-group>
}
</nb-select>
</div>
}
<div>
<label>{{ 'INTEGRATIONS.PAID' | translate }}</label>
<nb-select
[placeholder]="'INTEGRATIONS.FILTER_INTEGRATIONS' | translate"
fullWidth
[selected]="selectedIntegrationFilter$ | async"
(selectedChange)="setSelectedIntegrationFilter($event)"
>
@for (filter of filters; track filter) {
<nb-option [value]="filter.value">
{{ filter.label }}
</nb-option>
}
</nb-select>
</div>
</div>
</div>
<div class="col-xl-3 col-6 d-flex align-items-end justify-content-end">
<div class="clear-filter">
<button (click)="clearFilter()" status="danger" size="small" nbButton>
{{ 'BUTTONS.CLEAR_ALL' | translate }}
</button>
</div>
</div>
</div>
</div>
</div>
<div class="grid-container">
@if (integrations$ | async; as integrations) {
<div class="integrations-list">
@for (integration of integrations; track integration) {
<a
class="list-item"
[ngClass]="integration.isComingSoon ? 'disabled' : ''"
[routerLink]="['../', integration.redirectUrl]"
>
<img
[src]="integration.fullImgUrl"
width="100%"
height="100%"
alt="image not found"
[title]="integration.name | replace : '_' : ' '"
/>
@if (integration.isComingSoon) {
<div class="coming-soon-wrapper">
<span class="coming-soon">
{{ 'INTEGRATIONS.COMING_SOON' | translate }}
</span>
</div>
}
</a>
}
</div>
}
</div>
</ng-template>
</ng-template>
<ng-template [ngxPermissionsExcept]="['INTEGRATION_ADD', 'INTEGRATION_EDIT']">
<div>
<!-- Content to display if the user does not have 'canEditComponent' permission -->
</div>
</ng-template>
</nb-card-body>
</nb-card>
@@ -1,23 +1,19 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { IntegrationsComponent } from './integrations.component';
describe('IntegrationsComponent', () => {
let component: IntegrationsComponent;
let fixture: ComponentFixture<IntegrationsComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [IntegrationsComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(IntegrationsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { IntegrationLayoutComponent } from './layout.component';
describe('IntegrationLayoutComponent', () => {
let component: IntegrationLayoutComponent;
let fixture: ComponentFixture<IntegrationLayoutComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [IntegrationLayoutComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(IntegrationLayoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,23 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProductTypesComponent } from './product-types.component';
describe('ProductTypeComponent', () => {
let component: ProductTypesComponent;
let fixture: ComponentFixture<ProductTypesComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProductTypesComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProductTypesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProjectLayoutComponent } from './layout.component';
describe('ProjectLayoutComponent', () => {
let component: ProjectLayoutComponent;
let fixture: ComponentFixture<ProjectLayoutComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ProjectLayoutComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProjectLayoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AllReportComponent } from './all-report.component';
describe('AllReportComponent', () => {
let component: AllReportComponent;
let fixture: ComponentFixture<AllReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AllReportComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AllReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AmountsOwedReportComponent } from './amounts-owed-report.component';
describe('AmountsOwedReportComponent', () => {
let component: AmountsOwedReportComponent;
let fixture: ComponentFixture<AmountsOwedReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AmountsOwedReportComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AmountsOwedReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppsUrlsReportComponent } from './apps-urls-report.component';
describe('AppsUrlsReportComponent', () => {
let component: AppsUrlsReportComponent;
let fixture: ComponentFixture<AppsUrlsReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AppsUrlsReportComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AppsUrlsReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ClientBudgetsReportComponent } from './client-budgets-report.component';
describe('ClientBudgetsReportComponent', () => {
let component: ClientBudgetsReportComponent;
let fixture: ComponentFixture<ClientBudgetsReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ClientBudgetsReportComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ClientBudgetsReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ExpensesReportComponent } from './expenses-report.component';
describe('ExpensesReportComponent', () => {
let component: ExpensesReportComponent;
let fixture: ComponentFixture<ExpensesReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ExpensesReportComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ExpensesReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ManualTimeComponent } from './manual-time.component';
describe('ManualTimeComponent', () => {
let component: ManualTimeComponent;
let fixture: ComponentFixture<ManualTimeComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ManualTimeComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ManualTimeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PaymentReportComponent } from './payment-report.component';
describe('PaymentReportComponent', () => {
let component: PaymentReportComponent;
let fixture: ComponentFixture<PaymentReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PaymentReportComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PaymentReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ProjectBudgetsReportComponent } from './project-budgets-report.component';
describe('ProjectBudgetsReportComponent', () => {
let component: ProjectBudgetsReportComponent;
let fixture: ComponentFixture<ProjectBudgetsReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ProjectBudgetsReportComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ProjectBudgetsReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TimeLimitReportComponent } from './time-limit-report.component';
describe('TimeLimitReportComponent', () => {
let component: TimeLimitReportComponent;
let fixture: ComponentFixture<TimeLimitReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [TimeLimitReportComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TimeLimitReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TimeReportsComponent } from './time-reports.component';
describe('TimeReportsComponent', () => {
let component: TimeReportsComponent;
let fixture: ComponentFixture<TimeReportsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [TimeReportsComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TimeReportsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { WeeklyTimeReportsComponent } from './weekly-time-reports.component';
describe('WeeklyTimeReportsComponent', () => {
let component: WeeklyTimeReportsComponent;
let fixture: ComponentFixture<WeeklyTimeReportsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [WeeklyTimeReportsComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(WeeklyTimeReportsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,24 +1,19 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MyTaskDialogComponent } from './my-task-dialog.component';
describe('MyTaskDialogComponent', () => {
let component: MyTaskDialogComponent;
let fixture: ComponentFixture<MyTaskDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyTaskDialogComponent],
teardown: { destroyAfterEach: false }
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyTaskDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
@@ -1,7 +1,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { IEmployee, IOrganizationProject, ITag, ITask, TaskStatusEnum } from '@gauzy/contracts';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { CKEditor4 } from 'ckeditor4-angular/ckeditor';
import { CKEditor4 } from 'ckeditor4-angular';
import { NbDialogRef } from '@nebular/theme';
import { TranslateService } from '@ngx-translate/core';
import * as moment from 'moment';
@@ -29,10 +29,10 @@ const initialTaskValue = {
};
@Component({
selector: 'ngx-my-task-dialog',
templateUrl: './my-task-dialog.component.html',
styleUrls: ['./my-task-dialog.component.scss'],
standalone: false
selector: 'ngx-my-task-dialog',
templateUrl: './my-task-dialog.component.html',
styleUrls: ['./my-task-dialog.component.scss'],
standalone: false
})
export class MyTaskDialogComponent extends TranslationBaseComponent implements OnInit {
selectedTaskId: string;
@@ -1,179 +1,179 @@
<nb-card [nbSpinner]="loading" nbSpinnerStatus="primary" nbSpinnerSize="large">
<nb-card-header class="card-customer-header pb-0">
<div class="card-header-title">
<h4>
<ngx-header-title [allowEmployee]="false">
<ng-container *ngIf="isTasksPage()">
{{ 'TASKS_PAGE.HEADER' | translate }}
</ng-container>
<ng-container *ngIf="isMyTasksPage()">
{{ 'TASKS_PAGE.MY_TASK_HEADER' | translate }}
</ng-container>
<ng-container *ngIf="isTeamTaskPage()">
{{ 'TASKS_PAGE.TEAM_TASKS_HEADER' | translate }}
</ng-container>
</ngx-header-title>
</h4>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_PROJECT_EDIT']">
<ng-template [ngIf]="!isDefaultProject">
<button size="small" nbButton (click)="openTasksSettings(selectedProject)">
<nb-icon icon="settings-2-outline"></nb-icon>
</button>
</ng-template>
</ng-template>
</div>
<div class="tasks-component__settings">
<div class="gauzy-button-container">
<ngx-gauzy-button-action
[buttonTemplateVisible]="visibleButton"
[isDisable]="disableButton"
[buttonTemplate]="actionButtons"
[componentName]="viewComponentName"
></ngx-gauzy-button-action>
</div>
</div>
</nb-card-header>
<nb-card-body [ngClass]="{ project: selectedProject }">
<ng-template [ngxPermissionsOnly]="['ALL_ORG_VIEW', 'ORG_TASK_VIEW']">
<ng-container [ngSwitch]="viewMode">
<ng-container *ngSwitchCase="taskListTypeEnum.GRID">
<ng-template [ngIf]="dataLayoutStyle === componentLayoutStyleEnum.TABLE" [ngIfElse]="gridLayout">
<div class="table-scroll-container">
<angular2-smart-table
style="cursor: pointer"
[settings]="settingsSmartTable"
[source]="smartTableSource"
(userRowSelect)="selectTask($event)"
></angular2-smart-table>
</div>
<ng-container
<nb-card-header class="card-customer-header pb-0">
<div class="card-header-title">
<h4>
<ngx-header-title [allowEmployee]="false">
@if (isTasksPage()) {
{{ 'TASKS_PAGE.HEADER' | translate }}
}
@if (isMyTasksPage()) {
{{ 'TASKS_PAGE.MY_TASK_HEADER' | translate }}
}
@if (isTeamTaskPage()) {
{{ 'TASKS_PAGE.TEAM_TASKS_HEADER' | translate }}
}
</ngx-header-title>
</h4>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_PROJECT_EDIT']">
@if (!isDefaultProject) {
<button size="small" nbButton (click)="openTasksSettings(selectedProject)">
<nb-icon icon="settings-2-outline"></nb-icon>
</button>
}
</ng-template>
</div>
<div class="tasks-component__settings">
<div class="gauzy-button-container">
<ngx-gauzy-button-action
[buttonTemplateVisible]="visibleButton"
[isDisable]="disableButton"
[buttonTemplate]="actionButtons"
[componentName]="viewComponentName"
></ngx-gauzy-button-action>
</div>
</div>
</nb-card-header>
<nb-card-body [ngClass]="{ project: selectedProject }">
<ng-template [ngxPermissionsOnly]="['ALL_ORG_VIEW', 'ORG_TASK_VIEW']">
@switch (viewMode) {
@case (taskListTypeEnum.GRID) {
@if (dataLayoutStyle === componentLayoutStyleEnum.TABLE) {
<div class="table-scroll-container">
<angular2-smart-table
style="cursor: pointer"
[settings]="settingsSmartTable"
[source]="smartTableSource"
(userRowSelect)="selectTask($event)"
></angular2-smart-table>
</div>
<ng-container
*ngTemplateOutlet="
paginationTemplate;
context: {
pagination: pagination
}
"
></ng-container>
</ng-template>
<ng-template #gridLayout>
<ga-card-grid
[totalItems]="pagination?.totalItems"
[settings]="settingsSmartTable"
[source]="availableTasks$ | async"
(onSelectedItem)="selectTask($event)"
(scroll)="onScroll()"
></ga-card-grid>
</ng-template>
</ng-container>
<ng-container *ngSwitchCase="taskListTypeEnum.SPRINT">
<div class="sprint-view">
<ga-tasks-sprint-view
(createTaskEvent)="createTaskDialog()"
(editTaskEvent)="editTaskDialog($event)"
(deleteTaskEvent)="deleteTask($event)"
(selectedTaskEvent)="selectTask($event)"
[sync]="!disableButton"
[project]="selectedProject"
[tasks]="availableTasks$ | async"
></ga-tasks-sprint-view>
</div>
<ng-container
></ng-container>
} @else {
<ga-card-grid
[totalItems]="pagination?.totalItems"
[settings]="settingsSmartTable"
[source]="availableTasks$ | async"
(onSelectedItem)="selectTask($event)"
(scroll)="onScroll()"
></ga-card-grid>
}
}
@case (taskListTypeEnum.SPRINT) {
<div class="sprint-view">
<ga-tasks-sprint-view
(createTaskEvent)="createTaskDialog()"
(editTaskEvent)="editTaskDialog($event)"
(deleteTaskEvent)="deleteTask($event)"
(selectedTaskEvent)="selectTask($event)"
[sync]="!disableButton"
[project]="selectedProject"
[tasks]="availableTasks$ | async"
></ga-tasks-sprint-view>
</div>
<ng-container
*ngTemplateOutlet="
paginationTemplate;
context: {
pagination: pagination
}
"
></ng-container>
</ng-container>
</ng-container>
</ng-template>
</nb-card-body>
></ng-container>
}
}
</ng-template>
</nb-card-body>
</nb-card>
<ng-template #paginationTemplate let-pagination="pagination">
<div class="pagination-container">
<ng-container *ngIf="smartTableSource">
<ngx-pagination [source]="smartTableSource"></ngx-pagination>
</ng-container>
</div>
<div class="pagination-container">
@if (smartTableSource) {
<ngx-pagination [source]="smartTableSource"></ngx-pagination>
}
</div>
</ng-template>
<ng-template #actionButtons>
<ng-template
[ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ALL_ORG_VIEW', 'ORG_TASK_VIEW', 'ORG_TASK_EDIT', 'ORG_TASK_DELETE']"
>
<div class="btn-group actions">
<ngx-favorite-toggle
*ngIf="selectedTask"
[entityType]="'Task'"
[entityId]="selectedTask.id"
[entityName]="selectedTask.title"
size="small"
status="basic"
spacing="list"
[disabled]="disableButton"
[showLabel]="false"
(favoriteToggled)="onTaskFavoriteToggled($event)"
></ngx-favorite-toggle>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_VIEW', 'ORG_TASK_VIEW']">
<button
nbButton
status="basic"
class="action secondary"
[disabled]="disableButton"
size="small"
underConstruction
>
<nb-icon icon="eye-outline" pack="eva"></nb-icon>
{{ 'BUTTONS.VIEW' | translate }}
</button>
</ng-template>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_TASK_EDIT']">
<button
nbButton
status="basic"
(click)="editTaskDialog(selectedItem)"
[disabled]="disableButton"
class="action primary"
size="small"
>
<nb-icon icon="edit-outline"></nb-icon>
{{ 'BUTTONS.EDIT' | translate }}
</button>
</ng-template>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_TASK_EDIT']">
<button
nbButton
status="basic"
(click)="duplicateTaskDialog(selectedItem)"
[disabled]="disableButton"
class="action primary"
size="small"
>
<nb-icon icon="copy-outline"></nb-icon>
{{ 'BUTTONS.DUPLICATE' | translate }}
</button>
</ng-template>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_TASK_DELETE']">
<button
nbButton
status="basic"
(click)="deleteTask(selectedItem)"
[disabled]="disableButton"
class="action"
size="small"
[nbTooltip]="'BUTTONS.DELETE' | translate"
>
<nb-icon status="danger" icon="trash-2-outline"> </nb-icon>
</button>
</ng-template>
</div>
</ng-template>
<ng-template
[ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ALL_ORG_VIEW', 'ORG_TASK_VIEW', 'ORG_TASK_EDIT', 'ORG_TASK_DELETE']"
>
<div class="btn-group actions">
@if (selectedTask) {
<ngx-favorite-toggle
[entityType]="'Task'"
[entityId]="selectedTask.id"
[entityName]="selectedTask.title"
size="small"
status="basic"
spacing="list"
[disabled]="disableButton"
[showLabel]="false"
(favoriteToggled)="onTaskFavoriteToggled($event)"
></ngx-favorite-toggle>
}
<ng-template [ngxPermissionsOnly]="['ALL_ORG_VIEW', 'ORG_TASK_VIEW']">
<button
nbButton
status="basic"
class="action secondary"
[disabled]="disableButton"
size="small"
underConstruction
>
<nb-icon icon="eye-outline" pack="eva"></nb-icon>
{{ 'BUTTONS.VIEW' | translate }}
</button>
</ng-template>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_TASK_EDIT']">
<button
nbButton
status="basic"
(click)="editTaskDialog(selectedItem)"
[disabled]="disableButton"
class="action primary"
size="small"
>
<nb-icon icon="edit-outline"></nb-icon>
{{ 'BUTTONS.EDIT' | translate }}
</button>
</ng-template>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_TASK_EDIT']">
<button
nbButton
status="basic"
(click)="duplicateTaskDialog(selectedItem)"
[disabled]="disableButton"
class="action primary"
size="small"
>
<nb-icon icon="copy-outline"></nb-icon>
{{ 'BUTTONS.DUPLICATE' | translate }}
</button>
</ng-template>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_TASK_DELETE']">
<button
nbButton
status="basic"
(click)="deleteTask(selectedItem)"
[disabled]="disableButton"
class="action"
size="small"
[nbTooltip]="'BUTTONS.DELETE' | translate"
>
<nb-icon status="danger" icon="trash-2-outline"> </nb-icon>
</button>
</ng-template>
</div>
</ng-template>
</ng-template>
<ng-template #visibleButton>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_TASK_ADD']">
<button nbButton status="success" (click)="createTaskDialog()" size="small">
<nb-icon icon="plus-outline"></nb-icon>
{{ 'BUTTONS.ADD' | translate }}
</button>
</ng-template>
<ng-template [ngxPermissionsOnly]="['ALL_ORG_EDIT', 'ORG_TASK_ADD']">
<button nbButton status="success" (click)="createTaskDialog()" size="small">
<nb-icon icon="plus-outline"></nb-icon>
{{ 'BUTTONS.ADD' | translate }}
</button>
</ng-template>
</ng-template>
@@ -11,10 +11,10 @@ import { GauzyEditableGridComponent } from '@gauzy/ui-core/shared';
@UntilDestroy({ checkProperties: true })
@Component({
selector: 'ga-tasks-sprint-view',
templateUrl: './tasks-sprint-view.component.html',
styleUrls: ['./tasks-sprint-view.component.scss'],
standalone: false
selector: 'ga-tasks-sprint-view',
templateUrl: './tasks-sprint-view.component.html',
styleUrls: ['./tasks-sprint-view.component.scss'],
standalone: false
})
export class TasksSprintViewComponent extends GauzyEditableGridComponent<ITask> implements OnInit, OnChanges {
sprints: IOrganizationSprint[] = [];
@@ -45,9 +45,9 @@ export class TasksSprintViewComponent extends GauzyEditableGridComponent<ITask>
@Input() sync: boolean = false;
constructor(
private readonly store$: SprintStoreService,
translateService: TranslateService,
dialogService: NbDialogService,
private readonly store$: SprintStoreService,
private readonly taskStore: TasksStoreService,
private readonly storeService: Store
) {
@@ -13,7 +13,7 @@ import { NbDialogRef } from '@nebular/theme';
import { firstValueFrom } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import * as moment from 'moment';
import { CKEditor4 } from 'ckeditor4-angular/ckeditor';
import { CKEditor4 } from 'ckeditor4-angular';
import { TranslationBaseComponent } from '@gauzy/ui-core/i18n';
import { richTextCKEditorConfig } from '@gauzy/ui-core/shared';
import {
+3 -2
View File
@@ -2,9 +2,10 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "ES2022",
"module": "es2020",
"module": "preserve",
"downlevelIteration": true,
"useDefineForClassFields": false
"useDefineForClassFields": false,
"moduleResolution": "bundler"
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": false,
+4 -2
View File
@@ -2,8 +2,10 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node", "google.maps"]
"module": "preserve",
"types": ["jest", "node", "google.maps"],
"moduleResolution": "bundler",
"isolatedModules": true
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.test.ts", "**/*.d.ts"]
+1 -1
View File
@@ -1,4 +1,4 @@
export default {
module.exports = {
displayName: 'mcp-auth',
preset: '../../jest.preset.js',
testEnvironment: 'node',
+1 -1
View File
@@ -27,7 +27,7 @@
},
"dependencies": {
"@gauzy/mcp-server": "^0.1.0",
"@modelcontextprotocol/sdk": "^1.13.1",
"@modelcontextprotocol/sdk": "^1.25.3",
"electron-log": "^4.4.8"
},
"devDependencies": {
+11 -11
View File
@@ -35,23 +35,23 @@
"terser-webpack-plugin": "^5.3.16"
},
"dependencies": {
"@angular/animations": "^20.2.4",
"@angular/cdk": "^20.2.14",
"@angular/common": "^20.2.4",
"@angular/core": "^20.2.4",
"@angular/forms": "^20.2.4",
"@angular/material": "^20.2.14",
"@angular/router": "^20.2.4",
"@angular/animations": "21.0.0",
"@angular/cdk": "21.0.0",
"@angular/common": "21.0.0",
"@angular/core": "21.0.0",
"@angular/forms": "21.0.0",
"@angular/material": "21.0.0",
"@angular/router": "21.0.0",
"@datorama/akita": "^8.0.1",
"@datorama/akita-ngdevtools": "^7.0.0",
"@electron/remote": "^2.0.8",
"@grpc/grpc-js": "^1.6.7",
"@nebular/auth": "^16.0.0",
"@nebular/auth": "^17.0.0",
"@nebular/bootstrap": "^9.1.0-rc.6",
"@nebular/security": "^16.0.0",
"@nebular/theme": "^16.0.0",
"@nebular/security": "^17.0.0",
"@nebular/theme": "^17.0.0",
"@nestjs/typeorm": "^11.0.0",
"@ng-select/ng-select": "^20.7.0",
"@ng-select/ng-select": "^21.0.0",
"@ngneat/until-destroy": "^10.0.0",
"@ngx-translate/core": "^17.0.0",
"@ngx-translate/http-loader": "^17.0.0",
@@ -1,15 +1,11 @@
import { TestBed } from '@angular/core/testing';
import { AppService } from './app.service';
describe('AppService', () => {
let service: AppService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AppService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
@@ -633,7 +633,7 @@ angular2-smart-table {
}
.ng-arrow {
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
border-color: inherit !important;
border-width: 0 !important;
font-size: 10px;
@@ -687,7 +687,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 5 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
transform: rotate(180deg) !important;
@@ -704,7 +704,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
top: 55% !important;
@@ -444,7 +444,7 @@ $default-box-shadow: var(--gauzy-shadow);
border-width: 2px !important;
border-color: nb-theme(background-primary-color-1) !important;
font-family: 'Font Awesome 5 Pro' !important;
font-family: 'Font Awesome 7 Free' !important;
font-style: normal !important;
font-weight: 400 !important;
font-size: 7px !important;
+1 -1
View File
@@ -17,7 +17,7 @@ import {
shell,
Tray
} from 'electron';
import * as path from 'path';
import * as path from 'node:path';
import { environment } from './environments/environment';
+18 -10
View File
@@ -1,8 +1,24 @@
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { enableProdMode, ErrorHandler, importProvidersFrom, inject, provideAppInitializer } from '@angular/core';
import {
enableProdMode,
ErrorHandler,
importProvidersFrom,
inject,
provideAppInitializer,
provideZoneChangeDetection
} from '@angular/core';
import { bootstrapApplication, BrowserModule } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
import { Router, RouterModule } from '@angular/router';
import {
NbDialogModule,
NbDialogService,
NbMenuModule,
NbSidebarModule,
NbToastrModule,
NbIconLibraries
} from '@nebular/theme';
import * as Sentry from '@sentry/angular';
import { akitaConfig, persistState } from '@datorama/akita';
import {
ElectronService,
@@ -16,15 +32,6 @@ import {
import { environment as gauzyEnvironment } from '@gauzy/ui-config';
import { provideI18n } from '@gauzy/ui-core/i18n';
import { TablerIconsModule } from '@gauzy/ui-core/icons';
import {
NbDialogModule,
NbDialogService,
NbIconLibraries,
NbMenuModule,
NbSidebarModule,
NbToastrModule
} from '@nebular/theme';
import * as Sentry from '@sentry/angular';
import { AppRoutingModule } from './app/app-routing.module';
import { AppComponent } from './app/app.component';
import { AppService } from './app/app.service';
@@ -46,6 +53,7 @@ if (environment.SENTRY_DSN) {
bootstrapApplication(AppComponent, {
providers: [
provideZoneChangeDetection(),
importProvidersFrom(
NbDialogModule.forRoot(),
NbToastrModule.forRoot(),
+2 -2
View File
@@ -183,7 +183,7 @@
"squirrelly": "^8.0.8",
"tslib": "^2.6.2",
"twing": "^5.0.2",
"underscore": "^1.13.3",
"underscore": "^1.13.8",
"undici": "^6.10.2",
"custom-electron-titlebar": "^4.2.8",
"@as-integrations/express5": "^1.1.2",
@@ -243,4 +243,4 @@
"node20-win-x64"
]
}
}
}
+3 -1
View File
@@ -5,4 +5,6 @@ globalThis.ngJest = {
errorOnUnknownProperties: true
}
};
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv();
Executable → Regular
+3 -1
View File
@@ -8,7 +8,9 @@
"noPropertyAccessFromIndexSignature": false,
"noImplicitReturns": false,
"noFallthroughCasesInSwitch": false,
"types": ["node", "google.maps"]
"types": ["node", "google.maps"],
"module": "preserve",
"moduleResolution": "bundler"
},
"files": [],
"include": [],
+11 -19
View File
@@ -1,21 +1,13 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"target": "es2016",
"types": [
"jest",
"node"
]
},
"files": [
"src/test-setup.ts"
],
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "preserve",
"target": "es2016",
"types": ["jest", "node"],
"moduleResolution": "bundler",
"isolatedModules": true
},
"files": ["src/test-setup.ts"],
"include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
}
+1 -1
View File
@@ -6,5 +6,5 @@ export default {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }]
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../coverage/apps/server-mcp'
coverageDirectory: '../../coverage/apps/server-mcp'
};
+3 -3
View File
@@ -40,14 +40,14 @@
},
"dependencies": {
"@gauzy/mcp-server": "^0.1.0",
"@modelcontextprotocol/sdk": "^1.13.1",
"axios": "^1.9.0",
"@modelcontextprotocol/sdk": "^1.25.3",
"axios": "^1.13.5",
"dotenv": "^17.2.4",
"electron-log": "^4.4.8",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.7",
"electron-util": "^0.18.1",
"zod": "^4.3.5",
"zod": "^4.3.6",
"custom-electron-titlebar": "^4.2.8"
}
}
+11 -11
View File
@@ -30,23 +30,23 @@
"terser-webpack-plugin": "^5.3.16"
},
"dependencies": {
"@angular/animations": "^20.2.4",
"@angular/cdk": "^20.2.14",
"@angular/common": "^20.2.4",
"@angular/core": "^20.2.4",
"@angular/forms": "^20.2.4",
"@angular/material": "^20.2.14",
"@angular/router": "^20.2.4",
"@angular/animations": "21.0.0",
"@angular/cdk": "21.0.0",
"@angular/common": "21.0.0",
"@angular/core": "21.0.0",
"@angular/forms": "21.0.0",
"@angular/material": "21.0.0",
"@angular/router": "21.0.0",
"@datorama/akita": "^8.0.1",
"@datorama/akita-ngdevtools": "^7.0.0",
"@electron/remote": "^2.0.8",
"@grpc/grpc-js": "^1.6.7",
"@nebular/auth": "^16.0.0",
"@nebular/auth": "^17.0.0",
"@nebular/bootstrap": "^9.1.0-rc.6",
"@nebular/security": "^16.0.0",
"@nebular/theme": "^16.0.0",
"@nebular/security": "^17.0.0",
"@nebular/theme": "^17.0.0",
"@nestjs/typeorm": "^11.0.0",
"@ng-select/ng-select": "^20.7.0",
"@ng-select/ng-select": "^21.0.0",
"@ngneat/until-destroy": "^10.0.0",
"@ngx-translate/core": "^17.0.0",
"@ngx-translate/http-loader": "^17.0.0",
+1 -7
View File
@@ -1,7 +1,6 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { RouterTestingModule } from '@angular/router/testing';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
@@ -9,25 +8,20 @@ describe('AppComponent', () => {
declarations: [AppComponent]
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'desktop-web-ui'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('desktop-web-ui');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain(
'Welcome to desktop-web-ui!'
);
expect(compiled.querySelector('h1').textContent).toContain('Welcome to desktop-web-ui!');
});
});
-4
View File
@@ -1,15 +1,11 @@
import { TestBed } from '@angular/core/testing';
import { AppService } from './app.service';
describe('AppService', () => {
let service: AppService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AppService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
@@ -633,7 +633,7 @@ angular2-smart-table {
}
.ng-arrow {
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
border-color: inherit !important;
border-width: 0 !important;
font-size: 10px;
@@ -687,7 +687,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 5 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
transform: rotate(180deg) !important;
@@ -704,7 +704,7 @@ angular2-smart-table table tr.angular2-smart-titles th a.sort {
&:before {
color: rgba(126, 126, 143, 0.25);
font-size: 10px;
font-family: 'Font Awesome\ 6 Free' !important;
font-family: 'Font Awesome 7 Free' !important;
content: '\f063' !important;
font-weight: 900;
top: 55% !important;
@@ -444,7 +444,7 @@ $default-box-shadow: var(--gauzy-shadow);
border-width: 2px !important;
border-color: nb-theme(background-primary-color-1) !important;
font-family: 'Font Awesome 5 Pro' !important;
font-family: 'Font Awesome 7 Free' !important;
font-style: normal !important;
font-weight: 400 !important;
font-size: 7px !important;
+1 -1
View File
@@ -17,7 +17,7 @@ import {
shell,
Tray
} from 'electron';
import * as path from 'path';
import * as path from 'node:path';
import { environment } from './environments/environment';
+18 -10
View File
@@ -1,8 +1,24 @@
import {
enableProdMode,
ErrorHandler,
importProvidersFrom,
inject,
provideAppInitializer,
provideZoneChangeDetection
} from '@angular/core';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { enableProdMode, ErrorHandler, importProvidersFrom, inject, provideAppInitializer } from '@angular/core';
import { bootstrapApplication, BrowserModule } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
import { Router, RouterModule } from '@angular/router';
import {
NbDialogModule,
NbDialogService,
NbMenuModule,
NbSidebarModule,
NbToastrModule,
NbIconLibraries
} from '@nebular/theme';
import * as Sentry from '@sentry/angular';
import { akitaConfig, persistState } from '@datorama/akita';
import {
ElectronService,
@@ -16,15 +32,6 @@ import {
import { environment as gauzyEnvironment } from '@gauzy/ui-config';
import { provideI18n } from '@gauzy/ui-core/i18n';
import { TablerIconsModule } from '@gauzy/ui-core/icons';
import {
NbDialogModule,
NbDialogService,
NbIconLibraries,
NbMenuModule,
NbSidebarModule,
NbToastrModule
} from '@nebular/theme';
import * as Sentry from '@sentry/angular';
import { AppRoutingModule } from './app/app-routing.module';
import { AppComponent } from './app/app.component';
import { AppService } from './app/app.service';
@@ -46,6 +53,7 @@ if (environment.SENTRY_DSN) {
bootstrapApplication(AppComponent, {
providers: [
provideZoneChangeDetection(),
importProvidersFrom(
NbDialogModule.forRoot(),
NbSidebarModule.forRoot(),

Some files were not shown because too many files have changed in this diff Show More