diff --git a/angular.json b/angular.json index 16a2176a228..57a8fb71275 100644 --- a/angular.json +++ b/angular.json @@ -324,6 +324,41 @@ } } }, + "plugin-integration-hubstaff-ui": { + "projectType": "library", + "root": "packages/plugins/integration-hubstaff-ui", + "sourceRoot": "packages/plugins/integration-hubstaff-ui", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "packages/plugins/integration-hubstaff-ui/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "packages/plugins/integration-hubstaff-ui/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "packages/plugins/integration-hubstaff-ui/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "packages/plugins/integration-hubstaff-ui/tsconfig.spec.json", + "polyfills": ["zone.js", "zone.js/testing"] + } + } + }, + "schematics": { + "@nrwl/angular:component": { + "style": "scss" + } + } + }, "plugin-job-employee-ui": { "projectType": "library", "root": "packages/plugins/job-employee-ui", diff --git a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff-authorize/hubstaff-authorize.component.scss b/apps/gauzy/src/app/pages/hubstaff/components/hubstaff-authorize/hubstaff-authorize.component.scss deleted file mode 100644 index f6fb46b2ae3..00000000000 --- a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff-authorize/hubstaff-authorize.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../upwork/components/upwork-authorize/upwork-authorize.component.scss'; diff --git a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff-authorize/hubstaff-authorize.component.ts b/apps/gauzy/src/app/pages/hubstaff/components/hubstaff-authorize/hubstaff-authorize.component.ts deleted file mode 100644 index db6b32f956b..00000000000 --- a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff-authorize/hubstaff-authorize.component.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { Validators, UntypedFormGroup, UntypedFormBuilder } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { filter, tap } from 'rxjs/operators'; -import { IIntegration, IIntegrationTenant, IOrganization, IntegrationEnum } from '@gauzy/contracts'; -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; -import { HubstaffService, Store } from '@gauzy/ui-core/core'; -import { IntegrationsService } from '@gauzy/ui-core/core'; - -@UntilDestroy({ checkProperties: true }) -@Component({ - selector: 'ngx-hubstaff-authorize', - templateUrl: './hubstaff-authorize.component.html', - styleUrls: ['./hubstaff-authorize.component.scss'] -}) -export class HubstaffAuthorizeComponent implements OnInit, OnDestroy { - public hubStaffAuthorizeCode: string; - public organization: IOrganization; - - /** */ - public clientIdForm: UntypedFormGroup = HubstaffAuthorizeComponent.buildClientIdForm(this._fb); - static buildClientIdForm(fb: UntypedFormBuilder): UntypedFormGroup { - return fb.group({ - client_id: ['', Validators.required] - }); - } - - /** */ - public clientSecretForm: UntypedFormGroup = HubstaffAuthorizeComponent.buildClientSecretForm(this._fb); - static buildClientSecretForm(fb: UntypedFormBuilder): UntypedFormGroup { - return fb.group({ - client_secret: ['', Validators.required], - authorization_code: ['', Validators.required] - }); - } - - constructor( - private readonly _activatedRoute: ActivatedRoute, - private readonly _hubstaffService: HubstaffService, - private readonly _fb: UntypedFormBuilder, - private readonly _router: Router, - private readonly _store: Store, - private readonly _integrationsService: IntegrationsService - ) {} - - ngOnInit() { - this._store.selectedOrganization$ - .pipe( - filter((organization) => !!organization), - tap((organization: IOrganization) => (this.organization = organization)), - untilDestroyed(this) - ) - .subscribe(); - this._getHubstaffCode(); - } - - private _getHubstaffCode() { - this._activatedRoute.queryParams - .pipe( - filter(({ code }) => code), - tap(({ code }) => (this.hubStaffAuthorizeCode = code)), - tap(({ code, state }) => { - this.clientIdForm.patchValue({ client_id: state }); - this.clientSecretForm.patchValue({ - authorization_code: code - }); - }), - untilDestroyed(this) - ) - .subscribe(); - - if (!this.hubStaffAuthorizeCode) { - this.subscribeRouteData(); - } - } - - private subscribeRouteData() { - this._activatedRoute.data - .pipe( - // if remember state is true - filter(({ state }) => !!state && state === true), - tap(() => this._checkRememberState()), - untilDestroyed(this) - ) - .subscribe(); - } - - /** - * Hubstaff integration remember state API call - */ - private _checkRememberState() { - if (!this.organization) { - return; - } - const { id: organizationId, tenantId } = this.organization; - const state$ = this._integrationsService.getIntegrationByOptions({ - name: IntegrationEnum.HUBSTAFF, - organizationId, - tenantId - }); - state$ - .pipe( - filter((integration: IIntegrationTenant) => !!integration.id), - tap((integration: IIntegrationTenant) => { - this._redirectToHubstaffIntegration(integration.id); - }), - untilDestroyed(this) - ) - .subscribe(); - } - - /** - * Hubstaff integration remember state API call - */ - private _redirectToHubstaffIntegration(integrationId: IIntegration['id']) { - this._router.navigate(['pages/integrations/hubstaff', integrationId]); - } - - authorizeHubstaff() { - const { client_id } = this.clientIdForm.value; - this._hubstaffService.authorizeClient(client_id); - } - - addIntegration() { - if (!this.organization) { - return; - } - - const { client_secret } = this.clientSecretForm.value; - const { client_id } = this.clientIdForm.value; - const { id: organizationId } = this.organization; - - this._hubstaffService - .addIntegration({ - code: this.hubStaffAuthorizeCode, - client_secret, - client_id, - organizationId - }) - .pipe( - tap(({ id }) => { - this._redirectToHubstaffIntegration(id); - }), - untilDestroyed(this) - ) - .subscribe(); - } - - ngOnDestroy() {} -} diff --git a/apps/gauzy/src/app/pages/hubstaff/hubstaff-routing.module.ts b/apps/gauzy/src/app/pages/hubstaff/hubstaff-routing.module.ts deleted file mode 100644 index 03c36b55723..00000000000 --- a/apps/gauzy/src/app/pages/hubstaff/hubstaff-routing.module.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { HubstaffAuthorizeComponent } from './components/hubstaff-authorize/hubstaff-authorize.component'; -import { HubstaffComponent } from './components/hubstaff/hubstaff.component'; - -const routes: Routes = [ - { - path: '', - component: HubstaffAuthorizeComponent, - data: { state: true } - }, - { - path: 'regenerate', - component: HubstaffAuthorizeComponent, - data: { state: false } - }, - { - path: ':id', - component: HubstaffComponent - } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class HubstaffRoutingModule {} diff --git a/apps/gauzy/src/app/pages/hubstaff/hubstaff.module.ts b/apps/gauzy/src/app/pages/hubstaff/hubstaff.module.ts deleted file mode 100644 index b91181431bf..00000000000 --- a/apps/gauzy/src/app/pages/hubstaff/hubstaff.module.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { NgModule } from '@angular/core'; -import { - NbCardModule, - NbButtonModule, - NbInputModule, - NbIconModule, - NbSpinnerModule, - NbSelectModule, - NbCheckboxModule, - NbToggleModule, - NbDialogModule, - NbDatepickerModule, - NbTooltipModule, - NbActionsModule, - NbContextMenuModule -} from '@nebular/theme'; -import { NgxPermissionsModule } from 'ngx-permissions'; -import { NgSelectModule } from '@ng-select/ng-select'; -import { TranslateModule } from '@ngx-translate/core'; -import { SmartDataViewLayoutModule, SharedModule } from '@gauzy/ui-core/shared'; -import { HubstaffRoutingModule } from './hubstaff-routing.module'; -import { HubstaffComponent } from './components/hubstaff/hubstaff.component'; -import { HubstaffAuthorizeComponent } from './components/hubstaff-authorize/hubstaff-authorize.component'; -import { SettingsDialogComponent } from './components/settings-dialog/settings-dialog.component'; - -@NgModule({ - declarations: [HubstaffAuthorizeComponent, HubstaffComponent, SettingsDialogComponent], - imports: [ - NbCardModule, - HubstaffRoutingModule, - NbButtonModule, - NbTooltipModule, - NbInputModule, - NbIconModule, - NbSpinnerModule, - NgSelectModule, - NbSelectModule, - NbCheckboxModule, - NbToggleModule, - NbActionsModule, - NbContextMenuModule, - NgxPermissionsModule.forChild(), - SharedModule, - NbDatepickerModule, - NbDialogModule.forChild(), - TranslateModule.forChild(), - SmartDataViewLayoutModule - ] -}) -export class HubstaffModule {} diff --git a/apps/gauzy/src/app/pages/integrations/integrations.module.ts b/apps/gauzy/src/app/pages/integrations/integrations.module.ts index 968455b74c5..6341b127331 100644 --- a/apps/gauzy/src/app/pages/integrations/integrations.module.ts +++ b/apps/gauzy/src/app/pages/integrations/integrations.module.ts @@ -81,34 +81,38 @@ export class IntegrationsModule { // Register the routes for hubstaff integration this._pageRouteRegistryService.registerPageRoute({ + // Data to be passed to the component + data: { selectors: false }, // Register the location 'integrations' location: 'integrations', // Register the path 'hubstaff' path: 'hubstaff', // Register the loadChildren function to load the HubstaffModule lazy module - loadChildren: () => import('../hubstaff/hubstaff.module').then((m) => m.HubstaffModule) + loadChildren: () => import('@gauzy/plugin-integration-hubstaff-ui').then((m) => m.IntegrationHubstaffModule) }); // Register the routes for gauzy-ai integration this._pageRouteRegistryService.registerPageRoute({ + // Data to be passed to the component + data: { selectors: false }, // Register the location 'integrations' location: 'integrations', // Register the path 'gauzy-ai' path: 'gauzy-ai', // Register the loadChildren function to load the GauzyAIModule lazy module - loadChildren: () => import('./gauzy-ai/gauzy-ai.module').then((m) => m.GauzyAIModule), - data: { selectors: false } + loadChildren: () => import('./gauzy-ai/gauzy-ai.module').then((m) => m.GauzyAIModule) }); // Register the routes for github integration this._pageRouteRegistryService.registerPageRoute({ + // Data to be passed to the component + data: { selectors: false }, // Register the location 'integrations' location: 'integrations', // Register the path 'github' path: 'github', // Register the loadChildren function to load the GithubModule lazy module - loadChildren: () => import('./github/github.module').then((m) => m.GithubModule), - data: { selectors: false } + loadChildren: () => import('./github/github.module').then((m) => m.GithubModule) }); // Set hasRegisteredRoutes to true diff --git a/package.json b/package.json index 5e042a7464f..af6b1d050ab 100644 --- a/package.json +++ b/package.json @@ -137,8 +137,8 @@ "build:package:config:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/config build:prod", "build:package:plugin": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugin build", "build:package:plugin:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugin build", - "build:package:plugins:pre": "yarn run build:package:ui-config && yarn run build:package:ui-core && yarn run build:package:ui-auth && yarn run build:package:plugin:onboarding-ui && yarn run build:package:plugin:legal-ui && yarn run build:package:plugin:job-search-ui && yarn run build:package:plugin:job-matching-ui && yarn run build:package:plugin:job-employee-ui && yarn run build:package:plugin:job-proposal-ui && yarn run build:package:plugin:public-layout-ui && yarn run build:package:plugin:maintenance-ui && yarn run build:package:plugin:integration-ai-ui", - "build:package:plugins:pre:prod": "yarn run build:package:ui-config:prod && yarn run build:package:ui-core:prod && yarn run build:package:ui-auth && yarn run build:package:plugin:onboarding-ui:prod && yarn run build:package:plugin:legal-ui:prod && yarn run build:package:plugin:job-search-ui:prod && yarn run build:package:plugin:job-matching-ui:prod && yarn run build:package:plugin:job-employee-ui:prod && yarn run build:package:plugin:job-proposal-ui:prod && yarn run build:package:plugin:public-layout-ui:prod && yarn run build:package:plugin:maintenance-ui:prod && yarn run build:package:plugin:integration-ai-ui:prod", + "build:package:plugins:pre": "yarn run build:package:ui-config && yarn run build:package:ui-core && yarn run build:package:ui-auth && yarn run build:package:plugin:onboarding-ui && yarn run build:package:plugin:legal-ui && yarn run build:package:plugin:job-search-ui && yarn run build:package:plugin:job-matching-ui && yarn run build:package:plugin:job-employee-ui && yarn run build:package:plugin:job-proposal-ui && yarn run build:package:plugin:public-layout-ui && yarn run build:package:plugin:maintenance-ui && yarn run build:package:plugin:integration-ai-ui && yarn run build:package:plugin:integration-hubstaff-ui", + "build:package:plugins:pre:prod": "yarn run build:package:ui-config:prod && yarn run build:package:ui-core:prod && yarn run build:package:ui-auth && yarn run build:package:plugin:onboarding-ui:prod && yarn run build:package:plugin:legal-ui:prod && yarn run build:package:plugin:job-search-ui:prod && yarn run build:package:plugin:job-matching-ui:prod && yarn run build:package:plugin:job-employee-ui:prod && yarn run build:package:plugin:job-proposal-ui:prod && yarn run build:package:plugin:public-layout-ui:prod && yarn run build:package:plugin:maintenance-ui:prod && yarn run build:package:plugin:integration-ai-ui:prod && yarn run build:package:plugin:integration-hubstaff-ui:prod", "build:package:plugins:post": "yarn run build:package:plugin:integration-jira && yarn run build:package:plugin:integration-ai && yarn run build:package:plugin:sentry && yarn run build:package:plugin:jitsu-analytic && yarn run build:package:plugin:product-reviews && yarn run build:package:plugin:job-search && yarn run build:package:plugin:job-proposal && yarn run build:package:plugin:integration-github && yarn run build:package:plugin:knowledge-base && yarn run build:package:plugin:changelog && yarn run build:package:plugin:integration-hubstaff && yarn run build:package:plugin:integration-upwork", "build:package:plugins:post:prod": "yarn run build:package:plugin:integration-jira:prod && yarn run build:package:plugin:integration-ai:prod && yarn run build:package:plugin:sentry:prod && yarn run build:package:plugin:jitsu-analytic:prod && yarn run build:package:plugin:product-reviews:prod && yarn run build:package:plugin:job-search:prod && yarn run build:package:plugin:job-proposal:prod && yarn run build:package:plugin:integration-github:prod && yarn run build:package:plugin:knowledge-base:prod && yarn run build:package:plugin:changelog:prod && yarn run build:package:plugin:integration-hubstaff:prod && yarn run build:package:plugin:integration-upwork:prod", "build:package:plugin:integration-ai": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-ai build", @@ -161,6 +161,8 @@ "build:package:plugin:job-search:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/job-search build:prod", "build:package:plugin:integration-ai-ui": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-ai-ui lib:build", "build:package:plugin:integration-ai-ui:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-ai-ui lib:build:prod", + "build:package:plugin:integration-hubstaff-ui": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-hubstaff-ui lib:build", + "build:package:plugin:integration-hubstaff-ui:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-hubstaff-ui lib:build:prod", "build:package:plugin:job-employee-ui": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/job-employee-ui lib:build", "build:package:plugin:job-employee-ui:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/job-employee-ui lib:build:prod", "build:package:plugin:job-matching-ui": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/job-matching-ui lib:build", diff --git a/packages/plugins/integration-hubstaff-ui/.dockerignore b/packages/plugins/integration-hubstaff-ui/.dockerignore new file mode 100644 index 00000000000..6edd0523636 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/.dockerignore @@ -0,0 +1,20 @@ +docker +tmp +README.md +.env + +# git + +.git +.gitignore +.gitmodules + +# dependencies + +node_modules + +# misc + +npm-debug.log +dist +build diff --git a/packages/plugins/integration-hubstaff-ui/.eslintrc.json b/packages/plugins/integration-hubstaff-ui/.eslintrc.json new file mode 100644 index 00000000000..32896661eef --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "gauzy", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "gauzy", + "style": "kebab-case" + } + ] + }, + "extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"] + }, + { + "files": ["*.html"], + "extends": ["plugin:@nrwl/nx/angular-template"], + "rules": {} + } + ] +} diff --git a/packages/plugins/integration-hubstaff-ui/.gitignore b/packages/plugins/integration-hubstaff-ui/.gitignore new file mode 100644 index 00000000000..a34877c2c0e --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/.gitignore @@ -0,0 +1,6 @@ +# dependencies +node_modules/ + +# misc +npm-debug.log +dist \ No newline at end of file diff --git a/packages/plugins/integration-hubstaff-ui/.npmignore b/packages/plugins/integration-hubstaff-ui/.npmignore new file mode 100644 index 00000000000..1eb4beb9572 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/.npmignore @@ -0,0 +1,4 @@ +# .npmignore + +src/ +node_modules/ diff --git a/packages/plugins/integration-hubstaff-ui/README.md b/packages/plugins/integration-hubstaff-ui/README.md new file mode 100644 index 00000000000..4072b8b9556 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/README.md @@ -0,0 +1,7 @@ +# @gauzy/integration-hubstaff-ui + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test integration-hubstaff-ui` to execute the unit tests. diff --git a/packages/plugins/integration-hubstaff-ui/jest.config.ts b/packages/plugins/integration-hubstaff-ui/jest.config.ts new file mode 100644 index 00000000000..0894faa0d89 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'plugin-integration-hubstaff-ui', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/packages/plugins/integration-hubstaff-ui', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$' + } + ] + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment' + ] +}; diff --git a/packages/plugins/integration-hubstaff-ui/ng-package.json b/packages/plugins/integration-hubstaff-ui/ng-package.json new file mode 100644 index 00000000000..e47c9676c7f --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/ng-package.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../../dist/packages/plugins/integration-hubstaff-ui", + "lib": { + "entryFile": "src/index.ts", + "styleIncludePaths": ["../../../dist/packages/ui-core/static/styles"] + }, + "allowedNonPeerDependencies": ["."], + "assets": [] +} diff --git a/packages/plugins/integration-hubstaff-ui/package.json b/packages/plugins/integration-hubstaff-ui/package.json new file mode 100644 index 00000000000..867c79437d1 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/package.json @@ -0,0 +1,65 @@ +{ + "name": "@gauzy/plugin-integration-hubstaff-ui", + "version": "0.1.0", + "type": "commonjs", + "description": "UI components and integrations for Hubstaff within the Gauzy platform, enabling seamless time tracking and project management.", + "author": { + "name": "Ever Co. LTD", + "email": "ever@ever.co", + "url": "https://ever.co" + }, + "license": "AGPL-3.0", + "repository": { + "type": "git", + "url": "https://github.com/ever-co/ever-gauzy" + }, + "bugs": { + "url": "https://github.com/ever-co/ever-gauzy/issues" + }, + "homepage": "https://ever.co", + "keywords": [ + "hubstaff", + "gauzy", + "plugin", + "integration", + "time-tracking", + "project-management", + "angular", + "UI", + "ever-co", + "nestjs" + ], + "private": true, + "scripts": { + "lib:build": "ng build plugin-integration-hubstaff-ui --configuration=development", + "lib:build:prod": "ng build plugin-integration-hubstaff-ui --configuration=production", + "lib:watch": "ng build plugin-integration-hubstaff-ui --watch --configuration=development" + }, + "peerDependencies": { + "@angular/common": "^16.2.12", + "@angular/core": "^16.2.12" + }, + "dependencies": { + "@angular/forms": "^16.2.12", + "@angular/router": "^16.2.12", + "@gauzy/contracts": "^0.1.0", + "@nebular/theme": "^12.0.0", + "@ng-select/ng-select": "^11.2.0", + "@ngneat/until-destroy": "^9.2.0", + "@ngx-translate/core": "^15.0.0", + "angular2-smart-table": "^3.2.0", + "ngx-permissions": "^13.0.1", + "rxjs": "^7.4.0", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@types/jest": "^29.4.4", + "@types/node": "^20.14.9", + "jest-preset-angular": "^13.1.4" + }, + "engines": { + "node": ">=20.11.1", + "yarn": ">=1.22.19" + }, + "sideEffects": false +} diff --git a/packages/plugins/integration-hubstaff-ui/project.json b/packages/plugins/integration-hubstaff-ui/project.json new file mode 100644 index 00000000000..78243f168a9 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/project.json @@ -0,0 +1,50 @@ +{ + "name": "plugin-integration-hubstaff-ui", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/plugins/integration-hubstaff-ui/src", + "prefix": "gauzy", + "tags": [], + "projectType": "library", + "targets": { + "build": { + "executor": "@nrwl/angular:package", + "outputs": ["{workspaceRoot}/dist/{projectRoot}"], + "options": { + "project": "packages/plugins/integration-hubstaff-ui/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "packages/plugins/integration-hubstaff-ui/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "packages/plugins/integration-hubstaff-ui/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "packages/plugins/integration-hubstaff-ui/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": [ + "packages/plugins/integration-hubstaff-ui/**/*.ts", + "packages/plugins/integration-hubstaff-ui/**/*.html" + ] + } + } + } +} diff --git a/packages/plugins/integration-hubstaff-ui/src/index.ts b/packages/plugins/integration-hubstaff-ui/src/index.ts new file mode 100644 index 00000000000..5fa20cd0bf9 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/src/index.ts @@ -0,0 +1 @@ +export * from './lib/integration-hubstaff-ui.module'; diff --git a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff-authorize/hubstaff-authorize.component.html b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff-authorize/hubstaff-authorize.component.html similarity index 100% rename from apps/gauzy/src/app/pages/hubstaff/components/hubstaff-authorize/hubstaff-authorize.component.html rename to packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff-authorize/hubstaff-authorize.component.html diff --git a/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff-authorize/hubstaff-authorize.component.scss b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff-authorize/hubstaff-authorize.component.scss new file mode 100644 index 00000000000..49b0afb1ac7 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff-authorize/hubstaff-authorize.component.scss @@ -0,0 +1,16 @@ +.hint { + margin-bottom: 20px; + } + + button { + box-shadow: var(--gauzy-shadow)(0, 0, 0, 0.15); + border: none !important; + } + + :host { + + nb-card, + nb-card-body { + background-color: var(--gauzy-card-2); + } + } diff --git a/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff-authorize/hubstaff-authorize.component.ts b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff-authorize/hubstaff-authorize.component.ts new file mode 100644 index 00000000000..1c028c92f93 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff-authorize/hubstaff-authorize.component.ts @@ -0,0 +1,167 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Validators, UntypedFormGroup, UntypedFormBuilder } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { catchError, filter, of, tap } from 'rxjs'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { ID, IIntegrationTenant, IOrganization, IntegrationEnum } from '@gauzy/contracts'; +import { ErrorHandlingService, HubstaffService, IntegrationsService, Store } from '@gauzy/ui-core/core'; + +@UntilDestroy({ checkProperties: true }) +@Component({ + selector: 'ngx-hubstaff-authorize', + templateUrl: './hubstaff-authorize.component.html', + styleUrls: ['./hubstaff-authorize.component.scss'] +}) +export class HubstaffAuthorizeComponent implements OnInit, OnDestroy { + public hubStaffAuthorizeCode: string; + public organization: IOrganization; + public clientIdForm: UntypedFormGroup = this._fb.group({ + client_id: ['', Validators.required] + }); + public clientSecretForm: UntypedFormGroup = this._fb.group({ + client_secret: ['', Validators.required], + authorization_code: ['', Validators.required] + }); + + constructor( + private readonly _activatedRoute: ActivatedRoute, + private readonly _hubstaffService: HubstaffService, + private readonly _fb: UntypedFormBuilder, + private readonly _router: Router, + private readonly _store: Store, + private readonly _integrationsService: IntegrationsService, + private readonly _errorHandlingService: ErrorHandlingService + ) {} + + ngOnInit() { + this._store.selectedOrganization$ + .pipe( + filter((organization) => !!organization), + tap((organization: IOrganization) => { + this.organization = organization; + }), + untilDestroyed(this) + ) + .subscribe(); + this._getHubstaffCode(); + } + + /** + * Retrieves the Hubstaff authorization code from the query parameters. + * If the code is present, it updates the client ID and authorization + * code in the respective forms. If the code is not available, it subscribes + * to route data to handle any remembered state. + */ + private _getHubstaffCode() { + this._activatedRoute.queryParams + .pipe( + filter(({ code }) => !!code), // Ensure that a code is present + tap(({ code, state }) => { + this.hubStaffAuthorizeCode = code; // Set the authorization code + this.clientIdForm.patchValue({ client_id: state }); // Patch the client ID + this.clientSecretForm.patchValue({ authorization_code: code }); // Patch the authorization code + }), + untilDestroyed(this) // Automatically unsubscribes when the component is destroyed + ) + .subscribe(); + + // Subscribe to route data only if the authorize code is not set + if (!this.hubStaffAuthorizeCode) { + this.subscribeRouteData(); // Handle remembered state if no code + } + } + + /** + * Subscribes to the route data to check for a remembered state. + * If the state exists and is true, it checks the remembered state + * for the Hubstaff integration. + */ + private subscribeRouteData() { + this._activatedRoute.data + .pipe( + filter(({ state }) => !!state && state === true), // Check if the state is true + tap(() => this._checkRememberState()), // Call method to check remembered state + untilDestroyed(this) // Automatically unsubscribes when the component is destroyed + ) + .subscribe(); + } + + /** + * Checks the remembered state of the Hubstaff integration for the current organization. + * If an integration exists, it redirects to the Hubstaff integration page. + */ + private _checkRememberState() { + // Early return if organization is not defined + if (!this.organization) return; + + const { id: organizationId, tenantId } = this.organization; + + this._integrationsService + .getIntegrationByOptions({ + name: IntegrationEnum.HUBSTAFF, + organizationId, + tenantId + }) + .pipe( + filter((integration: IIntegrationTenant) => !!integration.id), // Filter out integrations without an ID + tap((integration: IIntegrationTenant) => this._redirectToHubstaffIntegration(integration.id)), // Redirect if a valid integration is found + untilDestroyed(this) + ) + .subscribe(); + } + + /** + * Hubstaff integration remember state API call + */ + private _redirectToHubstaffIntegration(integrationId: ID) { + this._router.navigate(['pages/integrations/hubstaff', integrationId]); + } + + /** + * Authorizes the Hubstaff client using the client ID provided in the form. + */ + authorizeHubstaff() { + const client_id = this.clientIdForm.get('client_id')?.value; + if (client_id) { + this._hubstaffService.authorizeClient(client_id); + } + } + + /** + * Adds Hubstaff integration for the selected organization using client credentials and authorization code. + * Validates the necessary inputs before proceeding. + */ + addIntegration() { + if (!this.organization) { + return; + } + + // Extract organizationId from the organization + const { id: organizationId } = this.organization; + + // Extract client_secret and client_id from the form + const client_secret = this.clientSecretForm.get('client_secret')?.value; + const client_id = this.clientIdForm.get('client_id')?.value; + + if (client_secret && client_id && organizationId) { + this._hubstaffService + .addIntegration({ + code: this.hubStaffAuthorizeCode, + client_secret, + client_id, + organizationId + }) + .pipe( + tap(({ id }) => this._redirectToHubstaffIntegration(id)), + catchError((error) => { + this._errorHandlingService.handleError(error); + return of(null); + }), + untilDestroyed(this) + ) + .subscribe(); + } + } + + ngOnDestroy() {} +} diff --git a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.html b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.html similarity index 100% rename from apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.html rename to packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.html diff --git a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.scss b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.scss similarity index 100% rename from apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.scss rename to packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.scss diff --git a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.spec.ts b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.spec.ts similarity index 100% rename from apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.spec.ts rename to packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.spec.ts diff --git a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.ts b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.ts similarity index 97% rename from apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.ts rename to packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.ts index 3629e2c9f1c..9796268f555 100644 --- a/apps/gauzy/src/app/pages/hubstaff/components/hubstaff/hubstaff.component.ts +++ b/packages/plugins/integration-hubstaff-ui/src/lib/components/hubstaff/hubstaff.component.ts @@ -1,15 +1,13 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { TitleCasePipe } from '@angular/common'; import { ActivatedRoute, Router } from '@angular/router'; -import { switchMap, tap, catchError, finalize } from 'rxjs/operators'; -import { Observable, of, firstValueFrom } from 'rxjs'; -import { filter } from 'rxjs/operators'; +import { Observable, of, firstValueFrom, filter, catchError, finalize, switchMap, tap } from 'rxjs'; import { NbDialogService } from '@nebular/theme'; import { TranslateService } from '@ngx-translate/core'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { ID, IHubstaffOrganization, IHubstaffProject, IOrganization } from '@gauzy/contracts'; -import { TranslationBaseComponent } from '@gauzy/ui-core/i18n'; import { ErrorHandlingService, HubstaffService, Store, ToastrService } from '@gauzy/ui-core/core'; +import { TranslationBaseComponent } from '@gauzy/ui-core/i18n'; import { SettingsDialogComponent } from '../settings-dialog/settings-dialog.component'; @UntilDestroy({ checkProperties: true }) @@ -20,7 +18,7 @@ import { SettingsDialogComponent } from '../settings-dialog/settings-dialog.comp providers: [TitleCasePipe] }) export class HubstaffComponent extends TranslationBaseComponent implements OnInit, OnDestroy { - public settingsSmartTable: object; + public settingsSmartTable: any; public organizations$: Observable; public organizations: IHubstaffOrganization[] = []; public projects$: Observable; diff --git a/apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.html b/packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.html similarity index 83% rename from apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.html rename to packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.html index a935df6235c..b6ba5ddfbcf 100644 --- a/apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.html +++ b/packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.html @@ -8,7 +8,6 @@ {{ entity.entity }} -
@@ -20,16 +19,13 @@ [icon]="expandOptions ? 'chevron-down-outline' : 'chevron-right-outline'" (click)="expandOptions = !expandOptions" > - - + >
- -
+
- + >
- diff --git a/apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.scss b/packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.scss similarity index 100% rename from apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.scss rename to packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.scss diff --git a/apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.spec.ts b/packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.spec.ts similarity index 100% rename from apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.spec.ts rename to packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.spec.ts diff --git a/apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.ts b/packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.ts similarity index 52% rename from apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.ts rename to packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.ts index b1a89b6c95c..b6bdbff96e5 100644 --- a/apps/gauzy/src/app/pages/hubstaff/components/settings-dialog/settings-dialog.component.ts +++ b/packages/plugins/integration-hubstaff-ui/src/lib/components/settings-dialog/settings-dialog.component.ts @@ -1,8 +1,8 @@ import { AfterViewInit, ChangeDetectorRef, Component, OnInit } from '@angular/core'; -import { NbDialogRef } from '@nebular/theme'; +import { NbCalendarRange, NbDialogRef } from '@nebular/theme'; import { Observable } from 'rxjs'; -import * as moment from 'moment'; import { tap } from 'rxjs/operators'; +import * as moment from 'moment'; import { IDateRangeActivityFilter, IntegrationEntity } from '@gauzy/contracts'; import { HubstaffService } from '@gauzy/ui-core/core'; @@ -14,26 +14,22 @@ import { HubstaffService } from '@gauzy/ui-core/core'; export class SettingsDialogComponent implements OnInit, AfterViewInit { entitiesToSync$: Observable = this._hubstaffService.entitiesToSync$; expandOptions: boolean; - + displayDate: string; maxDate: Date = new Date(); minDate: Date = new Date(moment().subtract(6, 'months').format('YYYY-MM-DD')); - defaultRange$: Observable; - displayDate: string; IntegrationEntity = IntegrationEntity; constructor( - public readonly dialogRef: NbDialogRef, - private readonly cdRef: ChangeDetectorRef, + private readonly _dialogRef: NbDialogRef, + private readonly _cdRef: ChangeDetectorRef, private readonly _hubstaffService: HubstaffService ) {} ngOnInit() { this.defaultRange$ = this._hubstaffService.dateRangeActivity$.pipe( - tap(() => { - this.expandOptions = false; - }), tap((displayDate: IDateRangeActivityFilter) => { + this.expandOptions = false; const { start, end } = displayDate; this.displayDate = `${moment(start).format('MMM D, YYYY')} - ${moment(end).format('MMM D, YYYY')}`; }) @@ -41,14 +37,36 @@ export class SettingsDialogComponent implements OnInit, AfterViewInit { } ngAfterViewInit(): void { - this.cdRef.detectChanges(); + this._cdRef.detectChanges(); + } + + /** + * Closes the dialog and returns a result. + * + * @param result The data to return when closing the dialog. + */ + closeDialog(result?: any) { + // Closes the dialog and passes the result back to the calling component + this._dialogRef.close(result); } /** - * Set activity date range - * @param dateRange + * Handles the date range change event from the date picker. + * Converts the NbCalendarRange into IDateRangeActivityFilter if both start and end dates are present. + * + * @param dateRange The date range object emitted by NbCalendarRange, containing start and end dates. */ - onDateChange(dateRange: IDateRangeActivityFilter) { - this._hubstaffService.setActivityDateRange(dateRange); + onDateChange(dateRange: NbCalendarRange) { + // Ensure both start and end dates are defined + if (dateRange.start && dateRange.end) { + // Construct the IDateRangeActivityFilter object + const dateRangeActivityFilter: IDateRangeActivityFilter = { + start: dateRange.start, + end: dateRange.end + }; + + // Call the service to set the activity date range + this._hubstaffService.setActivityDateRange(dateRangeActivityFilter); + } } } diff --git a/packages/plugins/integration-hubstaff-ui/src/lib/integration-hubstaff-routing.module.ts b/packages/plugins/integration-hubstaff-ui/src/lib/integration-hubstaff-routing.module.ts new file mode 100644 index 00000000000..099fc80c882 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/src/lib/integration-hubstaff-routing.module.ts @@ -0,0 +1,31 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { HubstaffAuthorizeComponent } from './components/hubstaff-authorize/hubstaff-authorize.component'; +import { HubstaffComponent } from './components/hubstaff/hubstaff.component'; + +@NgModule({ + imports: [ + RouterModule.forChild([ + { + path: '', + component: HubstaffAuthorizeComponent, + data: { + state: true + } + }, + { + path: 'regenerate', + component: HubstaffAuthorizeComponent, + data: { + state: false + } + }, + { + path: ':id', + component: HubstaffComponent + } + ]) + ], + exports: [RouterModule] +}) +export class IntegrationHubstaffRoutingModule {} diff --git a/packages/plugins/integration-hubstaff-ui/src/lib/integration-hubstaff-ui.module.ts b/packages/plugins/integration-hubstaff-ui/src/lib/integration-hubstaff-ui.module.ts new file mode 100644 index 00000000000..cdc3770553b --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/src/lib/integration-hubstaff-ui.module.ts @@ -0,0 +1,112 @@ +import { NgModule } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { filter, merge } from 'rxjs'; +import { + NbActionsModule, + NbButtonModule, + NbCardModule, + NbCheckboxModule, + NbContextMenuModule, + NbDatepickerModule, + NbDialogModule, + NbIconModule, + NbInputModule, + NbSelectModule, + NbSpinnerModule, + NbToggleModule, + NbTooltipModule +} from '@nebular/theme'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; +import { NgxPermissionsModule, NgxPermissionsService } from 'ngx-permissions'; +import { LanguagesEnum } from '@gauzy/contracts'; +import { distinctUntilChange } from '@gauzy/ui-core/common'; +import { Store } from '@gauzy/ui-core/core'; +import { HttpLoaderFactory, I18nService } from '@gauzy/ui-core/i18n'; +import { getBrowserLanguage, SmartDataViewLayoutModule, SharedModule } from '@gauzy/ui-core/shared'; +import { IntegrationHubstaffRoutingModule } from './integration-hubstaff-routing.module'; +import { HubstaffComponent } from './components/hubstaff/hubstaff.component'; +import { HubstaffAuthorizeComponent } from './components/hubstaff-authorize/hubstaff-authorize.component'; +import { SettingsDialogComponent } from './components/settings-dialog/settings-dialog.component'; + +// Nebular Modules +const NB_MODULES = [ + NbActionsModule, + NbButtonModule, + NbCardModule, + NbCheckboxModule, + NbContextMenuModule, + NbDatepickerModule, + NbDialogModule.forChild(), + NbIconModule, + NbInputModule, + NbSelectModule, + NbSpinnerModule, + NbToggleModule, + NbTooltipModule +]; + +// Third Party Modules +const THIRD_PARTY_MODULES = [ + NgSelectModule, + NgxPermissionsModule.forRoot(), + TranslateModule.forRoot({ + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient] + } + }) +]; + +@NgModule({ + declarations: [HubstaffAuthorizeComponent, HubstaffComponent, SettingsDialogComponent], + imports: [ + ...NB_MODULES, + ...THIRD_PARTY_MODULES, + IntegrationHubstaffRoutingModule, + SharedModule, + SmartDataViewLayoutModule + ] +}) +@UntilDestroy() +export class IntegrationHubstaffModule { + constructor( + readonly _translateService: TranslateService, + readonly _ngxPermissionsService: NgxPermissionsService, + readonly _store: Store, + readonly _i18nService: I18nService + ) { + this.initializeUiPermissions(); // Initialize UI permissions + this.initializeUiLanguagesAndLocale(); // Initialize UI languages and Update Locale + } + + /** + * Initialize UI permissions + */ + private initializeUiPermissions() { + // Load permissions + const permissions = this._store.userRolePermissions.map(({ permission }) => permission); + this._ngxPermissionsService.flushPermissions(); // Flush permissions + this._ngxPermissionsService.loadPermissions(permissions); // Load permissions + } + + /** + * Initialize UI languages and Update Locale + */ + private initializeUiLanguagesAndLocale() { + // Observable that emits when preferred language changes. + const preferredLanguage$ = merge(this._store.preferredLanguage$, this._i18nService.preferredLanguage$).pipe( + distinctUntilChange(), + filter((lang: LanguagesEnum) => !!lang), + untilDestroyed(this) + ); + + // Subscribe to preferred language changes + preferredLanguage$.subscribe((lang: string | LanguagesEnum) => { + this._translateService.use(lang); + }); + } +} diff --git a/packages/plugins/integration-hubstaff-ui/src/test-setup.ts b/packages/plugins/integration-hubstaff-ui/src/test-setup.ts new file mode 100644 index 00000000000..1100b3e8a6e --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/src/test-setup.ts @@ -0,0 +1 @@ +import 'jest-preset-angular/setup-jest'; diff --git a/packages/plugins/integration-hubstaff-ui/tsconfig.json b/packages/plugins/integration-hubstaff-ui/tsconfig.json new file mode 100644 index 00000000000..8a309f45a75 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": false, + "noImplicitOverride": false, + "noPropertyAccessFromIndexSignature": false, + "noImplicitReturns": false, + "noFallthroughCasesInSwitch": false, + "baseUrl": ".", + "paths": { + "@gauzy/ui-core/*": ["./../../../dist/packages/ui-core/*/index.d.ts"], + "@ngx-translate/*": ["./node_modules/@ngx-translate/*"], + "ngx-permissions": ["./node_modules/ngx-permissions"] + } + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/packages/plugins/integration-hubstaff-ui/tsconfig.lib.json b/packages/plugins/integration-hubstaff-ui/tsconfig.lib.json new file mode 100644 index 00000000000..5d1d67c0227 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/packages/plugins/integration-hubstaff-ui/tsconfig.lib.prod.json b/packages/plugins/integration-hubstaff-ui/tsconfig.lib.prod.json new file mode 100644 index 00000000000..7b29b93f6f3 --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/tsconfig.lib.prod.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/packages/plugins/integration-hubstaff-ui/tsconfig.spec.json b/packages/plugins/integration-hubstaff-ui/tsconfig.spec.json new file mode 100644 index 00000000000..0b8b86994ff --- /dev/null +++ b/packages/plugins/integration-hubstaff-ui/tsconfig.spec.json @@ -0,0 +1,11 @@ +{ + "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"] +} diff --git a/packages/plugins/job-employee-ui/src/lib/job-employee.module.ts b/packages/plugins/job-employee-ui/src/lib/job-employee.module.ts index 12a9888d57c..a6e1948d3d8 100644 --- a/packages/plugins/job-employee-ui/src/lib/job-employee.module.ts +++ b/packages/plugins/job-employee-ui/src/lib/job-employee.module.ts @@ -11,10 +11,9 @@ import { } from '@nebular/theme'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { NgxPermissionsModule } from 'ngx-permissions'; -import { LanguagesEnum } from '@gauzy/contracts'; import { PageRouteRegistryService } from '@gauzy/ui-core/core'; import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; -import { DynamicTabsModule, SharedModule, SmartDataViewLayoutModule } from '@gauzy/ui-core/shared'; +import { DynamicTabsModule, SharedModule, SmartDataViewLayoutModule, getBrowserLanguage } from '@gauzy/ui-core/shared'; import { createJobEmployeeRoutes } from './job-employee.routes'; import { JobEmployeeComponent } from './components/job-employee/job-employee.component'; @@ -29,7 +28,7 @@ const NB_MODULES = [NbButtonModule, NbCardModule, NbIconModule, NbSpinnerModule, const THIRD_PARTY_MODULES = [ NgxPermissionsModule.forRoot(), TranslateModule.forRoot({ - defaultLanguage: LanguagesEnum.ENGLISH, + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/plugins/job-matching-ui/src/lib/job-matching.module.ts b/packages/plugins/job-matching-ui/src/lib/job-matching.module.ts index ff3b3a6cff7..57ace6964e0 100644 --- a/packages/plugins/job-matching-ui/src/lib/job-matching.module.ts +++ b/packages/plugins/job-matching-ui/src/lib/job-matching.module.ts @@ -16,10 +16,9 @@ import { import { NgSelectModule } from '@ng-select/ng-select'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { NgxPermissionsModule } from 'ngx-permissions'; -import { LanguagesEnum } from '@gauzy/contracts'; import { PageRouteRegistryService } from '@gauzy/ui-core/core'; import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; -import { DialogsModule, SharedModule } from '@gauzy/ui-core/shared'; +import { DialogsModule, SharedModule, getBrowserLanguage } from '@gauzy/ui-core/shared'; import { createJobMatchingRoutes } from './job-matching.routes'; import { JobMatchingComponent } from './components/job-matching/job-matching.component'; import { COMPONENTS } from './components'; @@ -47,7 +46,7 @@ const THIRD_PARTY_MODULES = [ NgxPermissionsModule.forRoot(), NgSelectModule, TranslateModule.forRoot({ - defaultLanguage: LanguagesEnum.ENGLISH, + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/plugins/job-proposal-ui/src/lib/proposal-template/job-proposal-template.module.ts b/packages/plugins/job-proposal-ui/src/lib/proposal-template/job-proposal-template.module.ts index a3b28f7671a..69635c91fa7 100644 --- a/packages/plugins/job-proposal-ui/src/lib/proposal-template/job-proposal-template.module.ts +++ b/packages/plugins/job-proposal-ui/src/lib/proposal-template/job-proposal-template.module.ts @@ -16,7 +16,6 @@ import { import { CKEditorModule } from 'ckeditor4-angular'; import { NgxPermissionsModule } from 'ngx-permissions'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; -import { LanguagesEnum } from '@gauzy/contracts'; import { PageRouteRegistryService } from '@gauzy/ui-core/core'; import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; import { @@ -24,7 +23,8 @@ import { DialogsModule, EmployeeMultiSelectModule, SharedModule, - StatusBadgeModule + StatusBadgeModule, + getBrowserLanguage } from '@gauzy/ui-core/shared'; import { createJobProposalTemplateRoutes } from './job-proposal-template.routes'; import { ProposalTemplateComponent } from './components/proposal-template/proposal-template.component'; @@ -49,7 +49,7 @@ const THIRD_PARTY_MODULES = [ CKEditorModule, NgxPermissionsModule.forRoot(), TranslateModule.forRoot({ - defaultLanguage: LanguagesEnum.ENGLISH, + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/plugins/job-proposal-ui/src/lib/proposal/job-proposal.module.ts b/packages/plugins/job-proposal-ui/src/lib/proposal/job-proposal.module.ts index dcc52b0b8c7..6fc22b9c107 100644 --- a/packages/plugins/job-proposal-ui/src/lib/proposal/job-proposal.module.ts +++ b/packages/plugins/job-proposal-ui/src/lib/proposal/job-proposal.module.ts @@ -31,7 +31,8 @@ import { UserFormsModule, TableComponentsModule, TagsColorInputModule, - DateRangePickerResolver + DateRangePickerResolver, + getBrowserLanguage } from '@gauzy/ui-core/shared'; import { createProposalsRoutes } from './job-proposal.routes'; import { COMPONENTS, ProposalDetailsComponent, ProposalEditComponent, ProposalRegisterComponent } from './components'; @@ -71,6 +72,7 @@ const THIRD_PARTY_MODULES = [ NgSelectModule, NgxPermissionsModule.forRoot(), TranslateModule.forRoot({ + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/plugins/job-search-ui/src/lib/job-search.module.ts b/packages/plugins/job-search-ui/src/lib/job-search.module.ts index 9f7af3a17f0..0177c2bd523 100644 --- a/packages/plugins/job-search-ui/src/lib/job-search.module.ts +++ b/packages/plugins/job-search-ui/src/lib/job-search.module.ts @@ -20,7 +20,6 @@ import { CKEditorModule } from 'ckeditor4-angular'; import { MomentModule } from 'ngx-moment'; import { NgxPermissionsModule } from 'ngx-permissions'; import { FileUploadModule } from 'ng2-file-upload'; -import { LanguagesEnum } from '@gauzy/contracts'; import { PageRouteRegistryService } from '@gauzy/ui-core/core'; import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; import { @@ -29,14 +28,15 @@ import { ProposalTemplateSelectModule, SelectorsModule, SharedModule, - StatusBadgeModule + StatusBadgeModule, + getBrowserLanguage } from '@gauzy/ui-core/shared'; import { createJobSearchRoutes } from './job-search.routes'; import { JobSearchComponent } from './components/job-search/job-search.component'; import { COMPONENTS } from './components'; /** - * Nebular modules + * Nebular Modules */ const NB_MODULES = [ NbButtonModule, @@ -54,7 +54,7 @@ const NB_MODULES = [ ]; /* - * Third party modules + * Third Party Modules */ const THIRD_PARTY_MODULES = [ CKEditorModule, @@ -62,7 +62,7 @@ const THIRD_PARTY_MODULES = [ MomentModule, NgxPermissionsModule.forRoot(), TranslateModule.forRoot({ - defaultLanguage: LanguagesEnum.ENGLISH, + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/plugins/maintenance-ui/src/lib/maintenance-mode.module.ts b/packages/plugins/maintenance-ui/src/lib/maintenance-mode.module.ts index 73d8218367b..ddc86882a92 100644 --- a/packages/plugins/maintenance-ui/src/lib/maintenance-mode.module.ts +++ b/packages/plugins/maintenance-ui/src/lib/maintenance-mode.module.ts @@ -4,9 +4,9 @@ import { HttpClient } from '@angular/common/http'; import { RouterModule, ROUTES } from '@angular/router'; import { NbLayoutModule } from '@nebular/theme'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; -import { LanguagesEnum } from '@gauzy/contracts'; import { PageRouteRegistryService } from '@gauzy/ui-core/core'; import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; +import { getBrowserLanguage } from '@gauzy/ui-core/shared'; import { createMaintenanceRoutes } from './maintenance-mode.routes'; import { MaintenanceModeComponent } from './maintenance-mode.component'; @@ -14,7 +14,7 @@ import { MaintenanceModeComponent } from './maintenance-mode.component'; imports: [ CommonModule, TranslateModule.forRoot({ - defaultLanguage: LanguagesEnum.ENGLISH, + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/plugins/onboarding-ui/src/lib/onboarding.module.ts b/packages/plugins/onboarding-ui/src/lib/onboarding.module.ts index 533db8dfbcd..2569a14aa34 100644 --- a/packages/plugins/onboarding-ui/src/lib/onboarding.module.ts +++ b/packages/plugins/onboarding-ui/src/lib/onboarding.module.ts @@ -1,8 +1,10 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; import { ROUTES, RouterModule } from '@angular/router'; import { NbButtonModule, NbCardModule, NbIconModule, NbLayoutModule, NbSpinnerModule } from '@nebular/theme'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { NgxPermissionsModule } from 'ngx-permissions'; import { AuthService, FeatureStoreService, @@ -10,16 +12,13 @@ import { RoleGuard, TenantService } from '@gauzy/ui-core/core'; -import { OrganizationsStepFormModule } from '@gauzy/ui-core/shared'; +import { OrganizationsStepFormModule, getBrowserLanguage } from '@gauzy/ui-core/shared'; +import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; import { ThemeModule, ThemeSelectorModule, ThemeSettingsModule } from '@gauzy/ui-core/theme'; import { createOnboardingRoutes } from './onboarding.routes'; import { OnboardingComponent } from './components/onboarding.component'; import { TenantOnboardingComponent } from './components/tenant-onboarding/tenant-onboarding.component'; import { OnboardingCompleteComponent } from './components/onboarding-complete/onboarding-complete.component'; -import { LanguagesEnum } from '@gauzy/contracts'; -import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; -import { HttpClient } from '@angular/common/http'; -import { NgxPermissionsModule } from 'ngx-permissions'; // Nebular Modules const NB_MODULES = [NbButtonModule, NbCardModule, NbIconModule, NbLayoutModule, NbSpinnerModule]; @@ -28,7 +27,7 @@ const NB_MODULES = [NbButtonModule, NbCardModule, NbIconModule, NbLayoutModule, const THIRD_PARTY_MODULES = [ NgxPermissionsModule.forRoot(), TranslateModule.forRoot({ - defaultLanguage: LanguagesEnum.ENGLISH, + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/plugins/public-layout-ui/src/lib/public-layout.module.ts b/packages/plugins/public-layout-ui/src/lib/public-layout.module.ts index 1fbbeefe7dd..8bf063ebad3 100644 --- a/packages/plugins/public-layout-ui/src/lib/public-layout.module.ts +++ b/packages/plugins/public-layout-ui/src/lib/public-layout.module.ts @@ -26,7 +26,6 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { NgSelectModule } from '@ng-select/ng-select'; import { CKEditorModule } from 'ckeditor4-angular'; import { NgxPermissionsModule } from 'ngx-permissions'; -import { LanguagesEnum } from '@gauzy/contracts'; import { LanguagesService, PageRouteRegistryService, SkillsService } from '@gauzy/ui-core/core'; import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; import { @@ -42,7 +41,8 @@ import { SkillsInputModule, TableComponentsModule, TagsColorInputModule, - WorkInProgressModule + WorkInProgressModule, + getBrowserLanguage } from '@gauzy/ui-core/shared'; import { ThemeModule } from '@gauzy/ui-core/theme'; import { COMPONENTS } from './components'; @@ -79,7 +79,7 @@ const THIRD_PARTY_MODULES = [ NgSelectModule, NgxPermissionsModule.forRoot(), TranslateModule.forRoot({ - defaultLanguage: LanguagesEnum.ENGLISH, + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/ui-auth/src/lib/auth.module.ts b/packages/ui-auth/src/lib/auth.module.ts index b547a7f8ae8..30ba0099f78 100644 --- a/packages/ui-auth/src/lib/auth.module.ts +++ b/packages/ui-auth/src/lib/auth.module.ts @@ -19,7 +19,6 @@ import { NbTooltipModule } from '@nebular/theme'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; -import { LanguagesEnum } from '@gauzy/contracts'; import { ElectronService, InviteService, @@ -28,7 +27,7 @@ import { RoleService } from '@gauzy/ui-core/core'; import { ThemeModule, ThemeSelectorModule } from '@gauzy/ui-core/theme'; -import { NgxFaqModule, PasswordFormFieldModule, SharedModule } from '@gauzy/ui-core/shared'; +import { NgxFaqModule, PasswordFormFieldModule, SharedModule, getBrowserLanguage } from '@gauzy/ui-core/shared'; import { HttpLoaderFactory } from '@gauzy/ui-core/i18n'; import { createAuthRoutes } from './auth.routes'; import { WorkspaceSelectionComponent } from './components/workspace-selection/workspace-selection.component'; @@ -95,7 +94,7 @@ const COMPONENTS = [ const THIRD_PARTY_MODULES = [ TranslateModule.forRoot({ - defaultLanguage: LanguagesEnum.ENGLISH, + defaultLanguage: getBrowserLanguage(), // Get the browser language and fall back to a default if needed loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, diff --git a/packages/ui-core/i18n/assets/i18n/bg.json b/packages/ui-core/i18n/assets/i18n/bg.json index 0d7afc5b823..19481639b61 100644 --- a/packages/ui-core/i18n/assets/i18n/bg.json +++ b/packages/ui-core/i18n/assets/i18n/bg.json @@ -1,168 +1,178 @@ { "BUTTONS": { - "PAY": "Плати", - "ADD_EXISTING_USER": "Добавяне на съществуващ потребител", - "ADD_NEW": "Добавяне на нов", - "ADD": "Добавяне", - "CREATE": "Създаване", - "REGISTER": "Регистриране", - "CHANGE_PASSWORD": "Промяна на паролата", + "PAY": "Плащане", + "ADD_EXISTING_USER": "Добавете съществуващ потребител", + "ADD_NEW": "Добавете нов", + "ADD": "Добавете", + "ADD_INTEGRATION": "Добавете интеграция", + "RESET_INTEGRATION": "Нулиране на интеграцията", + "CREATE": "Създайте", + "REGISTER": "Регистрирайте се", + "CHANGE_PASSWORD": "Смяна на парола", "LOGIN": "Вход", "SIGNIN": "Вход", - "SEND_CODE": "Вход с имейл", - "ADD_NOTE": "Добави бележка", + "SEND_CODE": "Изпратете кода", + "SENDING_CODE": "Изпращане на кода...", + "ADD_NOTE": "Добавете бележка", "EDIT": "Редактиране", "MANAGE": "Управление", "DETAILS": "Детайли", "DUPLICATE": "Дублиране", "DELETE": "Изтриване", "REMOVE": "Премахване", - "ADD_EXISTING": "Добавяне на съществуващ", - "CONVERT_TO_EMPLOYEE": "Преобразуване в служител", - "OK": "Да", + "ADD_EXISTING": "Добавете съществуващ", + "CONVERT_TO_EMPLOYEE": "Конвертиране в служител", + "OK": "Ок", "YES": "Да", "NO": "Не", - "SAVE": "Запази", + "SAVE": "Запазване", "CLEAR_ALL": "Изчисти всичко", - "BACK": "Обратно", + "BACK": "Назад", "SENT": "Изпратено", "ACCEPTED": "Прието", - "MARK_AS_SENT": "Отбележи като изпратено", - "MARK_AS_ACCEPTED": "Отбележи като прието", + "MARK_AS_SENT": "Маркирай като изпратено", + "MARK_AS_ACCEPTED": "Маркирай като прието", "CANCEL": "Отказ", - "CLOSE": "Затваряне", + "CLOSE": "Затвори", "INVITE": "Покана", - "SELECT_ALL": "Селектиране на всички", - "COPY_LINK": "Копирай линка", - "COPIED": "Copied!", + "SELECT_ALL": "Изберете всички", + "COPY_LINK": "Копирайте линка", + "COPIED": "Копирано!", "MANAGE_INTERVIEWS": "Управление на интервюта", "MANAGE_INVITES": "Управление на покани", "MANAGE_SPRINTS": "Управление на спринтове", - "RESEND": "Преизпрати", + "RESEND": "Изпратете отново", "NEXT": "Следващ", "PREVIOUS": "Предишен", - "INVITE_AGAIN": "Покани отново", + "INVITE_AGAIN": "Поканете отново", "REQUEST": "Заявка", "HISTORY": "История", - "SYNC": "Синхронизация", - "UPDATE": "Актуализация", - "AUTO_SYNC": "Автоматична синхронизация", + "SYNC": "Синхронизиране", + "SYNCING": "Синхронизиране...", + "SELECTED_TASKS": "Избрани задачи", + "UPDATE": "Актуализиране", + "AUTO_SYNC": "Автоматично синхронизиране", + "AUTO_SYNCING": "Автоматично синхронизиране...", "VIEW": "Преглед", - "SEND": "Изпрати", + "SEND": "Изпратете", "ARCHIVE": "Архив", - "HIRE": "Наемане", + "HIRE": "Наемете", "MANAGE_CATEGORIES": "Управление на категории", "REJECT": "Отхвърли", - "FIND_TIME": "Намери време", - "DOWNLOAD": "Изтегли", - "ADD_KNOWLEDGE_BASE": "Добави база знания", - "CHOOSE_ICON": "Избери икона", + "FIND_TIME": "Намерете време", + "DOWNLOAD": "Изтеглете", + "ADD_KNOWLEDGE_BASE": "Добавете база знания", + "CHOOSE_ICON": "Изберете икона", "MAKE_PRIVATE": "Направи частно", "MAKE_PUBLIC": "Направи публично", "KNOWLEDGE_BASES": "Бази знания", - "SELECT": "Избери", + "SELECT": "Изберете", "EMAIL": "Имейл", "CONVERT_TO_INVOICE": "Конвертиране в фактура", "TO_INVOICE": "Към фактура", - "PUBLIC_APPOINTMENT_BOOK": "Резервирай публична среща", - "SAVE_AS_DRAFT": "Запази като чернова", - "SAVE_AND_SEND_CONTACT": "Запази и изпрати на контакт в gauzy", - "SAVE_AND_SEND_EMAIL": "Запази и изпрати по имейл", + "PUBLIC_APPOINTMENT_BOOK": "Резервирайте публична среща", + "SAVE_AS_DRAFT": "Запазване като чернова", + "SAVE_AND_SEND_CONTACT": "Запазване и изпращане на контакт в Gauzy", + "SAVE_AND_SEND_EMAIL": "Запазване и изпращане по имейл", "EVENT_TYPES": "Типове събития", "SEARCH": "Търсене", "RESET": "Нулиране", - "LEAVE_FEEDBACK": "Остави отзив", + "LEAVE_FEEDBACK": "Оставете отзив", "SPRINT": { - "CREATE": "Създай спринт", + "CREATE": "Създайте спринт", "EDIT": "Редактиране", - "DELETE": "Изтрий" + "DELETE": "Изтриване" }, "CANDIDATE_STATISTIC": "Статистика", "FILTER": "Филтър", - "REFRESH": "Опресняване", - "AUTO_REFRESH": "Автоматично опресняване", + "REFRESH": "Обновяване", + "AUTO_REFRESH": "Автоматично обновяване", "PROPOSAL_DELETE_MESSAGE": "Шаблонът на предложението е успешно изтрит", - "PROPOSAL_MAKE_DEFAULT_MESSAGE": "Шаблонът на предложението е успешно направен по подразбиране", + "PROPOSAL_MAKE_DEFAULT_MESSAGE": "Шаблонът за предложение успешно направен по подразбиране", "MANAGE_TEMPLATES": "Управление на шаблони", "MAKE_DEFAULT": "Направи по подразбиране", - "HIDE_ALL": "Скрий всичко", + "REMOVE_DEFAULT": "Премахни по подразбиране", + "HIDE_ALL": "Скрий всички", "SCHEDULES": "Графици", - "YES_HIDE_ALL_JOBS": "Да, скрий всички работи", - "VALIDATE": "Потвърди", - "VALIDATED": "Потвърдено", - "APPROVE": "Одобри", - "DENY": "Откажи", + "YES_HIDE_ALL_JOBS": "Да, скрий всички работни места", + "VALIDATE": "Валидирайте", + "VALIDATED": "Валидирано", + "APPROVE": "Одобрете", + "DENY": "Отхвърлете", "PAYMENTS": "Плащания", "NOTE": "Бележка", - "SKIP_CONTINUE": "Пропусни {{ label }} и продължи", + "SKIP_CONTINUE": "Пропуснете {{ label }} и продължете", "BUY": "Купи", - "DELETE_ACCOUNT": "Изтрий акаунта си", - "DELETE_ALL_DATA": "Изтрий всички данни", - "SELECT_AND_CONTINUE": "Избери и продължи", - "ADD_KPI": "Добави КПИ", - "PAID_DAYS_OFF": "Платени почивни дни", - "UNPAID_DAYS_OFF": "Неплатени почивни дни", + "DELETE_ACCOUNT": "Изтрийте акаунта си", + "DELETE_ALL_DATA": "Изтрийте всички данни", + "SELECT_AND_CONTINUE": "Изберете и продължете", + "ADD_KPI": "Добавете KPI", + "PAID_DAYS_OFF": "Платени дни отпуск", + "UNPAID_DAYS_OFF": "Неплатени дни отпуск", "CLEAR": "Изчисти", - "SET": "Задай", - "RECORD_FULL_PAYMENT": "Запиши пълното плащане", - "EXPORT_TO_CSV": "Експортиране в CSV", - "INVOICE_REMAINING_AMOUNT": "Фактурирай останалата сума", + "SET": "Задайте", + "RECORD_FULL_PAYMENT": "Запишете пълно плащане", + "EXPORT_TO_CSV": "Експортирайте в CSV", + "INVOICE_REMAINING_AMOUNT": "Оставаща сума по фактура", "PUBLIC_LINK": "Публичен линк", - "GENERATE": "Генериране", - "SEND_RECEIPT": "Изпрати разписка", - "ADD_COMMENT": "Добави коментар", + "GENERATE": "Генерирайте", + "SEND_RECEIPT": "Изпратете разписка", + "ADD_COMMENT": "Добавете коментар", "CONTINUE": "Продължи", - "SUPER_ADMIN_DEMO": "Демо на Супер администратор", - "ADMIN_DEMO": "Демо на Администратор", - "EMPLOYEE_DEMO": "Демо на Служител", + "SUPER_ADMIN_DEMO": "Демо на супер администратор", + "ADMIN_DEMO": "Демо на администратор", + "EMPLOYEE_DEMO": "Демо на служител", "DEMO_CREDENTIALS": "Демо идентификационни данни", - "CREATE_NEW_ROLE": "Създай роля за {{ name }}", - "DELETE_EXISTING_ROLE": "Изтрий роля за {{ name }}", - "RESTORE": "Възстанови", - "VIEW_ALL": "Прегледай всички", - "VIEW_REPORT": "Прегледай доклада", - "TIME_TRACKING_ENABLE": "Активирай проследяването на времето", - "TIME_TRACKING_DISABLE": "Деактивирай проследяването на времето", - "PRINT": "Печат", + "CREATE_NEW_ROLE": "Създайте роля {{ name }}", + "DELETE_EXISTING_ROLE": "Изтрийте роля {{ name }}", + "RESTORE": "Възстановете", + "VIEW_ALL": "Преглед на всички", + "VIEW_REPORT": "Преглед на доклад", + "TIME_TRACKING_ENABLE": "Активирайте проследяване на времето", + "TIME_TRACKING_DISABLE": "Деактивирайте проследяване на времето", + "PRINT": "Разпечатай", "FEEDBACK": "Обратна връзка", "EQUIPMENT_SHARING": "Споделяне на оборудване", "PRIVATE": "Частно", "PUBLIC": "Публично", "MANAGE_WIDGET": "Управление на джаджи", - "MOVE": "Преместване", - "COLLAPSE": "Сгъване", - "EXPAND": "Разгъване", - "SHOW_MORE": "Покажи повече", - "START_WORK": "Започни работа", - "APPLY": "Приложи", - "GENERATE_PROPOSAL": "Генериране на предложение", - "LET_S_GO": "Нека отидем", + "MOVE": "Премести", + "COLLAPSE": "Свий", + "EXPAND": "Разшири", + "SHOW_MORE": "Покажи още", + "START_WORK": "Започнете работа", + "APPLY": "Приложете", + "GENERATE_PROPOSAL": "Генерирайте предложение", + "LET_S_GO": "Да вървим", "CHECK": "Провери", - "CHECK_UPDATE": "Провери актуализацията", - "DOWNLOAD_NOW": "Изтегли сега", - "UPDATE_NOW": "Актуализирай сега", - "SAVE_RESTART": "Запази и рестартирай", + "CHECK_UPDATE": "Проверете актуализация", + "DOWNLOAD_NOW": "Изтеглете сега", + "UPDATE_NOW": "Актуализирайте сега", + "SAVE_RESTART": "Запазете и рестартирайте", "FILES": "Файлове", "START": "Старт", - "STOP": "Стоп", - "ACKNOWLEDGE": "Признай", - "RESTART": "Рестартирай", + "STOP": "Спри", + "ACKNOWLEDGE": "Признайте", + "RESTART": "Рестартиране", "LATER": "По-късно", - "UPGRADE": "Обнови", - "SKIP_NOW": "Пропусни сега", + "UPGRADE": "Актуализиране", + "SKIP_NOW": "Пропуснете сега", "EXIT": "Изход", - "LOGOUT": "Изход", - "COPY": "Копиране", - "CUT": "Изрязване", - "PASTE": "Поставяне", - "FORWARD_PORTS": "Препращане на портове", + "LOGOUT": "Излезте", + "COPY": "Копирай", + "CUT": "Изрежи", + "PASTE": "Постави", + "FORWARD_PORTS": "Пренасочете портовете", "REPORT": "Доклад", - "IGNORE": "Игнориране", - "INSTALL": "Инсталирай", - "UNINSTALL": "Деинсталирай", - "DEACTIVATE": "Деактивирай", - "ACTIVATE": "Активирай", - "ADD_PLUGIN": "Добави плъгин", + "IGNORE": "Игнорирайте", + "ENABLED": "Активирано", + "DISABLED": "Деактивирано", + "RESYNC": "Пресинхронизиране", + "INSTALL": "Инсталирайте", + "UNINSTALL": "Деинсталирайте", + "DEACTIVATE": "Деактивирайте", + "ACTIVATE": "Активирайте", + "ADD_PLUGIN": "Добавете плъгин", "LOAD_PLUGIN": "Зареди плъгин", "FROM_CDN": "От CDN" }, @@ -1211,8 +1221,8 @@ "SYNCED_ENTITIES": "Автоматично синхронизирани единици", "TOOLTIP_ACTIVITY_INFO": "Ограничение на периода: 7 дни Най-ранна дата: 6 пълни месеца", "DATE_RANGE_PLACEHOLDER": "Изберете дата между", - "CLIENT_ID": "Hubstaff Client ID", - "CLIENT_SECRET": "Hubstaff Client Secret", + "CLIENT_ID": "Hubstaff клиентски идентификатор", + "CLIENT_SECRET": "Hubstaff клиентска тайна", "GRANT_PERMISSION": "След това ще бъдете пренасочени към Hubstaff, за да предоставите разрешение на Gauzy.", "ENTER_CLIENT_SECRET": "Въведете клиентския тайния ключ, за да получите достъп до токен." }, @@ -1222,7 +1232,7 @@ "TRANSACTIONS": "Транзакции", "SUCCESSFULLY_AUTHORIZED": "Успешно упълномощен", "API_KEY": "Upwork API ключ", - "SECRET": "Upwork Secret", + "SECRET": "Upwork таен ключ", "NEXT_STEP_INFO": "След това ще бъдете пренасочени към Upwork, за да предоставите разрешение на Gauzy.", "CONTRACTS": "Договори", "SYNCED_CONTRACTS": "Синхронизирани договори", @@ -1235,7 +1245,7 @@ "GAUZY_AI_PAGE": { "TITLE": "Интеграция на Gauzy AI", "API_KEY": "Gauzy AI ключ", - "API_SECRET": "Gauzy AI Secret", + "API_SECRET": "Gauzy AI таен ключ", "OPEN_AI_API_SECRET_KEY": "Тайният ключ на OpenAI", "OPEN_AI_ORGANIZATION_ID": "ID на OpenAI организация", "DESCRIPTION": "Активирайте интеграцията с Gauzy AI за по-интелигентно търсене на работа.", @@ -1297,51 +1307,51 @@ "SELECT_A_MONTH_AND_EMPLOYEE": "Моля, изберете един месец и служител от менюто по-горе", "INSERT_TEXT_FOR_NOT_AUTHENTICATED_USERS": "Добави текст за неаутентикирани потребители", "CHARTS": { - "BAR": "Bar", - "DOUGHNUT": "Doughnut", - "STACKED_BAR": "Stacked Bar", - "CHART_TYPE": "Chart Type", - "REVENUE": "Revenue", + "BAR": "Бар", + "DOUGHNUT": "Поничка", + "STACKED_BAR": "Натрупана лента", + "CHART_TYPE": "Тип диаграма", + "REVENUE": "Приходи", "EXPENSES": "Разходи", "PROFIT": "Печалба", "BONUS": "Бонус", - "NO_MONTH_DATA": "No Data for this month", - "CASH_FLOW": "Cash Flow", - "WORKING": "Working", - "WORKING_NOW": "Working now", - "NOT_WORKING": "Not working", - "WORKING_TODAY": "Working today" + "NO_MONTH_DATA": "Няма данни за този месец", + "CASH_FLOW": "Паричен поток", + "WORKING": "Работи", + "WORKING_NOW": "Работи в момента", + "NOT_WORKING": "Не работи", + "WORKING_TODAY": "Работи днес" }, "PROFIT_HISTORY": { - "PROFIT_REPORT": "Репорт на печалбата", + "PROFIT_REPORT": "Доклад за печалбата", "TOTAL_EXPENSES": "Общи разходи", "TOTAL_INCOME": "Общ доход", - "TOTAL_PROFIT": "Печалба Общо", + "TOTAL_PROFIT": "Обща печалба", "DATE": "Дата", "EXPENSES": "Разходи", "INCOME": "Доход", - "DESCRIPTION": "Description" + "DESCRIPTION": "Описание" }, "TITLE": { - "PROFIT_REPORT": "Репорт на Печалбата", + "PROFIT_REPORT": "Доклад за Печалбата", "TOTAL_EXPENSES": "Общи разходи", "TOTAL_INCOME": "Общ доход", "PROFIT": "Печалба", - "TOTAL_BONUS": "Бонус Общо", - "TOTAL_DIRECT_INCOME": "Изтриване на доход", + "TOTAL_BONUS": "Общо бонуси", + "TOTAL_DIRECT_INCOME": "Директен доход", "SALARY": "Заплата", - "TOTAL_DIRECT_INCOME_INFO": "Income from direct bonus", - "TOTAL_INCOME_CALC": "Total Income = Income {{ totalNonBonusIncome }} + Direct Income {{ totalBonusIncome }}", - "TOTAL_PROFIT_BONUS": "Total Profit Bonus", - "TOTAL_DIRECT_BONUS": "Direct Income Bonus", - "TOTAL_DIRECT_BONUS_INFO": "This is equal to the direct income", - "TOTAL_PROFIT_BONUS_INFO": "{{ bonusPercentage }}% of the profit {{ difference }}", - "TOTAL_INCOME_BONUS": "Total Income Bonus", + "TOTAL_DIRECT_INCOME_INFO": "Доход от директен бонус", + "TOTAL_INCOME_CALC": "Общ доход = Доход {{ totalNonBonusIncome }} + Директен доход {{ totalBonusIncome }}", + "TOTAL_PROFIT_BONUS": "Общ бонус от печалба", + "TOTAL_DIRECT_BONUS": "Директен бонус от доход", + "TOTAL_DIRECT_BONUS_INFO": "Това е равно на директния доход", + "TOTAL_PROFIT_BONUS_INFO": "{{ bonusPercentage }}% от печалбата {{ difference }}", + "TOTAL_INCOME_BONUS": "Общ бонус от доходи", "TOTAL_INCOME_BONUS_INFO": "{{ bonusPercentage }}% от доходи {{ totalIncome }}", - "TOTAL_EXPENSE_CALC": "Total = Employee Expenses + Split Expenses + Recurring + Salary", - "TOTAL_EXPENSES_WITHOUT_SALARY": "Total Expense without salary", - "TOTAL_EXPENSES_WITHOUT_SALARY_CALC": "Expense = Employee Expenses + Split Expenses + Recurring", - "TOTAL_BONUS_CALC": "Total Bonus = Direct Income Bonus {{ totalBonusIncome }} + Bonus {{ calculatedBonus }}" + "TOTAL_EXPENSE_CALC": "Общо = Разходи за служители + Разделени разходи + Повтарящи се разходи + Заплата", + "TOTAL_EXPENSES_WITHOUT_SALARY": "Общи разходи без заплата", + "TOTAL_EXPENSES_WITHOUT_SALARY_CALC": "Разходи = Разходи за служители + Разделени разходи + Повтарящи се разходи", + "TOTAL_BONUS_CALC": "Общо бонус = Директен бонус от доход {{ totalBonusIncome }} + Бонус {{ calculatedBonus }}" }, "DEVELOPER": { "DEVELOPER": "Разработчик", @@ -1356,15 +1366,15 @@ }, "ADD_INCOME": "Добавете ново въвеждане на доходи", "ADD_EXPENSE": "Добавете ново въвеждане на разходи", - "RECURRING_EXPENSES": "Recurring Expenses", - "ADD_ORGANIZATION_RECURRING_EXPENSE": "Add New Recurring Expense Entry for Organization", - "ADD_EMPLOYEE_RECURRING_EXPENSE": "Add New Recurring Expense Entry for Employee", - "PLAN_MY_DAY": "Plan My Day", - "ADD_TODO": "Add Todo", - "MOST_VIEW_PROJECTS": "Most Viewed Projects", - "INBOX": "Inbox", - "RECENTLY_ASSIGNED": "Recently Assigned", - "NO_TODO_ASSIGNED": "No Todo Assigned" + "RECURRING_EXPENSES": "Повтарящи се разходи", + "ADD_ORGANIZATION_RECURRING_EXPENSE": "Добавете ново повтарящо се въвеждане на разходи за организация", + "ADD_EMPLOYEE_RECURRING_EXPENSE": "Добавете ново повтарящо се въвеждане на разходи за служител", + "PLAN_MY_DAY": "Планирайте деня ми", + "ADD_TODO": "Добавете задача", + "MOST_VIEW_PROJECTS": "Най-гледани проекти", + "INBOX": "Входящи", + "RECENTLY_ASSIGNED": "Наскоро възложени", + "NO_TODO_ASSIGNED": "Няма възложени задачи" }, "INCOME_PAGE": { "INCOME": "Доход", diff --git a/packages/ui-core/shared/src/lib/public-api.ts b/packages/ui-core/shared/src/lib/public-api.ts index 42473478233..cb6b3414205 100644 --- a/packages/ui-core/shared/src/lib/public-api.ts +++ b/packages/ui-core/shared/src/lib/public-api.ts @@ -72,3 +72,4 @@ export * from './workspaces'; export * from './work-in-progress'; export * from './goal'; export * from './miscellaneous'; +export * from './utils'; diff --git a/packages/ui-core/shared/src/lib/utils/index.ts b/packages/ui-core/shared/src/lib/utils/index.ts new file mode 100644 index 00000000000..928d76823dd --- /dev/null +++ b/packages/ui-core/shared/src/lib/utils/index.ts @@ -0,0 +1 @@ +export * from './language-utils'; diff --git a/packages/ui-core/shared/src/lib/utils/language-utils.ts b/packages/ui-core/shared/src/lib/utils/language-utils.ts new file mode 100644 index 00000000000..ec25b6ffd48 --- /dev/null +++ b/packages/ui-core/shared/src/lib/utils/language-utils.ts @@ -0,0 +1,13 @@ +import { LanguagesEnum } from '@gauzy/contracts'; + +/** + * Utility function to get the browser language and fall back to a default if needed. + * @returns {string} The browser language or the default language. + */ +export function getBrowserLanguage(): string { + const browserLang = window.navigator.language.split('-')[0]; // Get base language code + const supportedLanguages = Object.values(LanguagesEnum); // List of supported languages + + // Check if the browser language is supported; otherwise, return default + return supportedLanguages.includes(browserLang as LanguagesEnum) ? browserLang : LanguagesEnum.ENGLISH; +} diff --git a/tsconfig.json b/tsconfig.json index 8256b1e2bbc..94897f9d664 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,7 @@ "@gauzy/desktop-ui-lib": ["./packages/desktop-ui-lib/src/index.ts"], "@gauzy/desktop-window": ["./packages/desktop-window/src/index.ts"], "@gauzy/plugin-integration-ai-ui": ["./packages/plugins/integration-ai-ui/src/index.ts"], + "@gauzy/plugin-integration-hubstaff-ui": ["./packages/plugins/integration-hubstaff-ui/src/index.ts"], "@gauzy/plugin-job-employee-ui": ["./packages/plugins/job-employee-ui/src/index.ts"], "@gauzy/plugin-job-matching-ui": ["./packages/plugins/job-matching-ui/src/index.ts"], "@gauzy/plugin-job-proposal-ui": ["./packages/plugins/job-proposal-ui/src/index.ts"],