From 7d8c8733899cd6d6d9c8ac4ed0f8e1f9ccc586a6 Mon Sep 17 00:00:00 2001 From: samuelmbabhazi Date: Fri, 18 Oct 2024 20:29:28 +0200 Subject: [PATCH 01/68] Fix employee fields edition --- .../job-employee/job-employee.component.ts | 22 ++++-- .../src/lib/table-components/editors/index.ts | 2 + ...ob-search-availability-editor.component.ts | 69 +++++++++++++++++++ .../non-editable-number-editor.component.ts | 19 +++++ .../shared/src/lib/table-components/index.ts | 2 + .../table-components.module.ts | 11 ++- 6 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts create mode 100644 packages/ui-core/shared/src/lib/table-components/editors/non-editable-number-editor.component.ts diff --git a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts index f18f17bc82f..efd48de2348 100644 --- a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts +++ b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts @@ -29,7 +29,9 @@ import { NumberEditorComponent, EmployeeLinkEditorComponent, PaginationFilterBaseComponent, - SmartTableToggleComponent + SmartTableToggleComponent, + NonEditableNumberEditorComponent, + JobSearchAvailabilityComponent } from '@gauzy/ui-core/shared'; /** @@ -238,7 +240,11 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen width: '10%', // The width of the column isSortable: false, // Indicates whether the column is sortable isEditable: false, // Indicates whether the column is editable - valuePrepareFunction: (rawValue: any) => rawValue || 0 + valuePrepareFunction: (rawValue: any) => rawValue || 0, + editor: { + type: 'custom', + component: NonEditableNumberEditorComponent + } }); // Register the data table column @@ -251,7 +257,11 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen width: '10%', // The width of the column isSortable: false, // Indicates whether the column is sortable isEditable: false, // Indicates whether the column is editable - valuePrepareFunction: (rawValue: any) => rawValue || 0 + valuePrepareFunction: (rawValue: any) => rawValue || 0, + editor: { + type: 'custom', + component: NonEditableNumberEditorComponent + } }); // Register the data table column @@ -305,7 +315,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen type: 'custom', // The type of the column width: '20%', // The width of the column isSortable: false, // Indicates whether the column is sortable - isEditable: false, // Indicates whether the column is editable + isEditable: true, // Indicates whether the column is editable renderComponent: SmartTableToggleComponent, componentInitFunction: (instance: SmartTableToggleComponent, cell: Cell) => { // Get the employee data from the cell @@ -318,6 +328,10 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen instance.toggleChange.pipe(untilDestroyed(this)).subscribe((toggle: boolean) => { this.updateJobSearchAvailability(employee, toggle); }); + }, + editor: { + type: 'custom', + component: JobSearchAvailabilityComponent } }); } diff --git a/packages/ui-core/shared/src/lib/table-components/editors/index.ts b/packages/ui-core/shared/src/lib/table-components/editors/index.ts index 790692b98b1..4579c69546c 100644 --- a/packages/ui-core/shared/src/lib/table-components/editors/index.ts +++ b/packages/ui-core/shared/src/lib/table-components/editors/index.ts @@ -1,2 +1,4 @@ export * from './number-editor.component'; export * from './employee-link-editor.component'; +export * from './job-search-availability-editor.component'; +export * from './non-editable-number-editor.component'; diff --git a/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts b/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts new file mode 100644 index 00000000000..a0b5ab35917 --- /dev/null +++ b/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts @@ -0,0 +1,69 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { IEmployee } from '@gauzy/contracts'; +import { JobService, ToastrService } from '@gauzy/ui-core/core'; +import { Cell, DefaultEditor } from 'angular2-smart-table'; +import { BehaviorSubject, Observable } from 'rxjs'; + +@Component({ + template: `
+ +
` +}) +export class JobSearchAvailabilityComponent extends DefaultEditor implements OnInit { + private _checked$: BehaviorSubject = new BehaviorSubject(false); + @Input() cell!: Cell; + @Output() toggleChange: EventEmitter = new EventEmitter(); + + constructor(private readonly _jobService: JobService, private readonly _toastrService: ToastrService) { + super(); + } + + public get checked$(): Observable { + return this._checked$.asObservable(); + } + + ngOnInit() { + if (this.cell) { + const employee: IEmployee = this.cell.getRow()?.getData(); + if (employee) { + this.value = employee.isJobSearchActive; // Initialize the toggle value + } + } + } + + @Input() public set value(checked: boolean) { + this._checked$.next(checked); + } + + onCheckedChange(isChecked: boolean) { + this.toggleChange.emit(isChecked); // Emit the toggle change event + this._checked$.next(isChecked); + this.updateJobSearchAvailability(isChecked); // Update job search availability + } + + async updateJobSearchAvailability(isJobSearchActive: boolean): Promise { + if (!this.cell) return; // Ensure 'cell' is available + const employee: IEmployee = this.cell.getRow()?.getData(); + if (!employee) return; // Ensure employee data is available + + try { + await this._jobService.updateJobSearchStatus(employee.id, { + isJobSearchActive, + organizationId: employee.organizationId, + tenantId: employee.tenantId + }); + + const toastrMessageKey = isJobSearchActive + ? 'TOASTR.MESSAGE.EMPLOYEE_JOB_STATUS_ACTIVE' + : 'TOASTR.MESSAGE.EMPLOYEE_JOB_STATUS_INACTIVE'; + + this._toastrService.success(toastrMessageKey, { name: employee.fullName }); + } catch (error) { + this._toastrService.danger(error); + } + } +} diff --git a/packages/ui-core/shared/src/lib/table-components/editors/non-editable-number-editor.component.ts b/packages/ui-core/shared/src/lib/table-components/editors/non-editable-number-editor.component.ts new file mode 100644 index 00000000000..c3dde52b6e2 --- /dev/null +++ b/packages/ui-core/shared/src/lib/table-components/editors/non-editable-number-editor.component.ts @@ -0,0 +1,19 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Cell, DefaultEditor } from 'angular2-smart-table'; + +@Component({ + template: ` +
+ {{ cellValue }} +
+ ` +}) +export class NonEditableNumberEditorComponent extends DefaultEditor implements OnInit { + cellValue!: string; + + @Input() cell!: Cell; + + ngOnInit() { + this.cellValue = this.cell.getValue(); + } +} diff --git a/packages/ui-core/shared/src/lib/table-components/index.ts b/packages/ui-core/shared/src/lib/table-components/index.ts index b79500375cd..5e99fb49c3e 100644 --- a/packages/ui-core/shared/src/lib/table-components/index.ts +++ b/packages/ui-core/shared/src/lib/table-components/index.ts @@ -11,6 +11,7 @@ export * from './document-date/document-date.component'; export * from './document-url/document-url.component'; export * from './editors/number-editor.component'; export * from './editors/employee-link-editor.component'; +export * from './editors/job-search-availability-editor.component'; export * from './email/email.component'; export * from './employee-links/employee-links.component'; export * from './employee-with-links/employee-with-links.component'; @@ -39,6 +40,7 @@ export * from './toggle-switch/toggle-switch.component'; export * from './trust-html/trust-html.component'; export * from './value-with-units/value-with-units.component'; export * from './visibility/visibility.component'; +export * from './editors/non-editable-number-editor.component'; // export * from './table-components.module'; diff --git a/packages/ui-core/shared/src/lib/table-components/table-components.module.ts b/packages/ui-core/shared/src/lib/table-components/table-components.module.ts index ccb528adb55..be2665fe4c8 100644 --- a/packages/ui-core/shared/src/lib/table-components/table-components.module.ts +++ b/packages/ui-core/shared/src/lib/table-components/table-components.module.ts @@ -5,7 +5,12 @@ import { NbIconModule, NbTooltipModule, NbBadgeModule, NbToggleModule, NbButtonM import { TranslateModule } from '@ngx-translate/core'; import { ComponentsModule } from '../components/components.module'; import { PipesModule } from '../pipes/pipes.module'; -import { EmployeeLinkEditorComponent, NumberEditorComponent } from './editors'; +import { + EmployeeLinkEditorComponent, + JobSearchAvailabilityComponent, + NonEditableNumberEditorComponent, + NumberEditorComponent +} from './editors'; import { AllowScreenshotCaptureComponent } from './allow-screenshot-capture/allow-screenshot-capture.component'; import { AssignedToComponent } from './assigned-to/assigned-to.component'; import { ClickableLinkComponent } from './clickable-link/clickable-link.component'; @@ -104,7 +109,9 @@ import { TaskBadgeViewComponentModule } from '../tasks/task-badge-view/task-badg ToggleSwitchComponent, TrustHtmlLinkComponent, ValueWithUnitComponent, - VisibilityComponent + VisibilityComponent, + NonEditableNumberEditorComponent, + JobSearchAvailabilityComponent ], exports: [ AllowScreenshotCaptureComponent, From ff381720a7fc37e363a231a77ced645a6d24eb99 Mon Sep 17 00:00:00 2001 From: samuelmbabhazi Date: Fri, 18 Oct 2024 20:47:18 +0200 Subject: [PATCH 02/68] Rename jobSearchAvailability component --- .../src/lib/components/job-employee/job-employee.component.ts | 4 ++-- .../editors/job-search-availability-editor.component.ts | 2 +- .../src/lib/table-components/table-components.module.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts index efd48de2348..7c05b33868c 100644 --- a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts +++ b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts @@ -31,7 +31,7 @@ import { PaginationFilterBaseComponent, SmartTableToggleComponent, NonEditableNumberEditorComponent, - JobSearchAvailabilityComponent + JobSearchAvailabilityEditorComponent } from '@gauzy/ui-core/shared'; /** @@ -331,7 +331,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen }, editor: { type: 'custom', - component: JobSearchAvailabilityComponent + component: JobSearchAvailabilityEditorComponent } }); } diff --git a/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts b/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts index a0b5ab35917..a30586a6290 100644 --- a/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts +++ b/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts @@ -13,7 +13,7 @@ import { BehaviorSubject, Observable } from 'rxjs'; > ` }) -export class JobSearchAvailabilityComponent extends DefaultEditor implements OnInit { +export class JobSearchAvailabilityEditorComponent extends DefaultEditor implements OnInit { private _checked$: BehaviorSubject = new BehaviorSubject(false); @Input() cell!: Cell; @Output() toggleChange: EventEmitter = new EventEmitter(); diff --git a/packages/ui-core/shared/src/lib/table-components/table-components.module.ts b/packages/ui-core/shared/src/lib/table-components/table-components.module.ts index be2665fe4c8..5a784137780 100644 --- a/packages/ui-core/shared/src/lib/table-components/table-components.module.ts +++ b/packages/ui-core/shared/src/lib/table-components/table-components.module.ts @@ -7,7 +7,7 @@ import { ComponentsModule } from '../components/components.module'; import { PipesModule } from '../pipes/pipes.module'; import { EmployeeLinkEditorComponent, - JobSearchAvailabilityComponent, + JobSearchAvailabilityEditorComponent, NonEditableNumberEditorComponent, NumberEditorComponent } from './editors'; @@ -111,7 +111,7 @@ import { TaskBadgeViewComponentModule } from '../tasks/task-badge-view/task-badg ValueWithUnitComponent, VisibilityComponent, NonEditableNumberEditorComponent, - JobSearchAvailabilityComponent + JobSearchAvailabilityEditorComponent ], exports: [ AllowScreenshotCaptureComponent, From 434c237c7efec50faf4b21268c0093497e8840eb Mon Sep 17 00:00:00 2001 From: samuelmbabhazi Date: Fri, 18 Oct 2024 22:13:19 +0200 Subject: [PATCH 03/68] coderabbitai suggestion integrations --- .../job-search-availability-editor.component.ts | 3 ++- .../non-editable-number-editor.component.ts | 15 ++++++++++++--- .../table-components/table-components.module.ts | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts b/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts index a30586a6290..7e6bb917498 100644 --- a/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts +++ b/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts @@ -63,7 +63,8 @@ export class JobSearchAvailabilityEditorComponent extends DefaultEditor implemen this._toastrService.success(toastrMessageKey, { name: employee.fullName }); } catch (error) { - this._toastrService.danger(error); + const errorMessage = error?.message || 'An error occurred while updating the job search availability.'; + this._toastrService.danger(errorMessage); } } } diff --git a/packages/ui-core/shared/src/lib/table-components/editors/non-editable-number-editor.component.ts b/packages/ui-core/shared/src/lib/table-components/editors/non-editable-number-editor.component.ts index c3dde52b6e2..c8b85b59518 100644 --- a/packages/ui-core/shared/src/lib/table-components/editors/non-editable-number-editor.component.ts +++ b/packages/ui-core/shared/src/lib/table-components/editors/non-editable-number-editor.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { Cell, DefaultEditor } from 'angular2-smart-table'; @Component({ @@ -9,11 +9,20 @@ import { Cell, DefaultEditor } from 'angular2-smart-table'; ` }) export class NonEditableNumberEditorComponent extends DefaultEditor implements OnInit { - cellValue!: string; + cellValue!: string | number; @Input() cell!: Cell; ngOnInit() { - this.cellValue = this.cell.getValue(); + const value = this.cell.getValue(); + if (value === null || value === undefined) { + console.warn('Cell value is null or undefined'); + this.cellValue = ''; + } else if (typeof value === 'number' || typeof value === 'string') { + this.cellValue = value; + } else { + console.error('Unexpected cell value type:', typeof value); + this.cellValue = ''; + } } } diff --git a/packages/ui-core/shared/src/lib/table-components/table-components.module.ts b/packages/ui-core/shared/src/lib/table-components/table-components.module.ts index 5a784137780..aaeee1761bb 100644 --- a/packages/ui-core/shared/src/lib/table-components/table-components.module.ts +++ b/packages/ui-core/shared/src/lib/table-components/table-components.module.ts @@ -136,6 +136,8 @@ import { TaskBadgeViewComponentModule } from '../tasks/task-badge-view/task-badg InvoiceTotalValueComponent, NotesWithTagsComponent, NumberEditorComponent, + JobSearchAvailabilityEditorComponent, + NonEditableNumberEditorComponent, OrganizationWithTagsComponent, PhoneUrlComponent, PictureNameTagsComponent, From af9e72fd4d769c433bfd1e3bbfba21c49eb0f737 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Sat, 19 Oct 2024 16:40:48 +0530 Subject: [PATCH 04/68] feat(header): update header-container styles based on position --- .../theme/src/lib/components/header/header.component.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/ui-core/theme/src/lib/components/header/header.component.html b/packages/ui-core/theme/src/lib/components/header/header.component.html index 55701b3c539..47eb963a0df 100644 --- a/packages/ui-core/theme/src/lib/components/header/header.component.html +++ b/packages/ui-core/theme/src/lib/components/header/header.component.html @@ -3,6 +3,11 @@ Click here to Sign Up and start using for free!
+
+
Date: Sun, 20 Oct 2024 12:41:06 +0200 Subject: [PATCH 05/68] [Fix] Employee Duplication in the Selection Input During Task Retrieval for a Single Employee --- .../lib/tasks/add-task-dialog/add-task-dialog.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui-core/shared/src/lib/tasks/add-task-dialog/add-task-dialog.component.ts b/packages/ui-core/shared/src/lib/tasks/add-task-dialog/add-task-dialog.component.ts index b72717dcfa8..a86e6cffe27 100644 --- a/packages/ui-core/shared/src/lib/tasks/add-task-dialog/add-task-dialog.component.ts +++ b/packages/ui-core/shared/src/lib/tasks/add-task-dialog/add-task-dialog.component.ts @@ -115,7 +115,7 @@ export class AddTaskDialogComponent extends TranslationBaseComponent implements distinctUntilChange(), filter((employee: ISelectedEmployee) => !!employee && !!employee.id), tap((employee: ISelectedEmployee) => { - if (!this.task) { + if (!this.selectedTask) { this.selectedMembers.push(employee.id); } }), @@ -127,7 +127,7 @@ export class AddTaskDialogComponent extends TranslationBaseComponent implements distinctUntilChange(), filter((project: IOrganizationProject) => !!project && !!project.id), tap((project: IOrganizationProject) => { - if (!this.task) { + if (!this.selectedTask) { this.form.get('project').setValue(project); this.form.get('projectId').setValue(project.id); this.form.updateValueAndValidity(); From 7d78377b8d693b01e017bb56218023aaf56c78f1 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Mon, 21 Oct 2024 11:40:47 +0530 Subject: [PATCH 06/68] fix: toggle switcher output events --- .../integration-list/list.component.html | 6 +-- .../src/lib/components/view/view.component.ts | 12 +++--- .../smart-table-toggle.component.html | 6 ++- .../shared/src/lib/table-components/index.ts | 4 +- .../table-components.module.ts | 6 +-- .../toggle-switch.component.html | 5 --- .../toggle-switcher.component.html | 7 ++++ .../toggle-switcher.component.ts} | 41 +++++++++---------- 8 files changed, 45 insertions(+), 42 deletions(-) delete mode 100644 packages/ui-core/shared/src/lib/table-components/toggle-switch/toggle-switch.component.html create mode 100644 packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.html rename packages/ui-core/shared/src/lib/table-components/{toggle-switch/toggle-switch.component.ts => toggle-switcher/toggle-switcher.component.ts} (70%) diff --git a/apps/gauzy/src/app/pages/integrations/components/integration-list/list.component.html b/apps/gauzy/src/app/pages/integrations/components/integration-list/list.component.html index 5ac9a3c99c1..e4c92f0528b 100644 --- a/apps/gauzy/src/app/pages/integrations/components/integration-list/list.component.html +++ b/apps/gauzy/src/app/pages/integrations/components/integration-list/list.component.html @@ -62,11 +62,11 @@

{{ integration?.lastSyncedAt || integration?.updatedAt | dateTimeFormat }}

- + (onSwitched)="updateIntegrationTenant(integration, $event)" + >
{ + renderComponent: ToggleSwitcherComponent, + componentInitFunction: (instance: ToggleSwitcherComponent, cell: Cell) => { // Get the data of the entire row const rowData = cell.getRow().getData(); - // Set properties on the ToggleSwitchComponent instance + // Set properties on the ToggleSwitcherComponent instance instance.rowData = rowData; instance.value = rowData?.customFields?.repository?.hasSyncEnabled || false; - // Subscribe to the 'switched' event of the ToggleSwitchComponent - instance.switched.subscribe({ + // Subscribe to the 'switched' event of the ToggleSwitcherComponent + instance.onSwitched.pipe(untilDestroyed(this)).subscribe({ // When the switch state changes, execute the following callback next: (hasSyncEnabled: boolean) => { // Call the 'updateGithubRepository' method with the row data and the new switch state diff --git a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.html b/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.html index 8b830e016d5..3f0e83d8aa5 100644 --- a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.html +++ b/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.html @@ -1,3 +1,7 @@
- +
diff --git a/packages/ui-core/shared/src/lib/table-components/index.ts b/packages/ui-core/shared/src/lib/table-components/index.ts index b79500375cd..fc742fb9f25 100644 --- a/packages/ui-core/shared/src/lib/table-components/index.ts +++ b/packages/ui-core/shared/src/lib/table-components/index.ts @@ -35,10 +35,10 @@ export * from './status-view/status-view.component'; export * from './tags-only/tags-only.component'; export * from './task-estimate/task-estimate.component'; export * from './task-teams/task-teams.component'; -export * from './toggle-switch/toggle-switch.component'; +export * from './toggle-switcher/toggle-switcher.component'; export * from './trust-html/trust-html.component'; export * from './value-with-units/value-with-units.component'; export * from './visibility/visibility.component'; -// +// Export the table components main module export * from './table-components.module'; diff --git a/packages/ui-core/shared/src/lib/table-components/table-components.module.ts b/packages/ui-core/shared/src/lib/table-components/table-components.module.ts index ccb528adb55..0f134d21589 100644 --- a/packages/ui-core/shared/src/lib/table-components/table-components.module.ts +++ b/packages/ui-core/shared/src/lib/table-components/table-components.module.ts @@ -41,7 +41,7 @@ import { StatusViewComponent } from './status-view/status-view.component'; import { TagsOnlyComponent } from './tags-only/tags-only.component'; import { TaskEstimateComponent } from './task-estimate/task-estimate.component'; import { TaskTeamsComponent } from './task-teams/task-teams.component'; -import { ToggleSwitchComponent } from './toggle-switch/toggle-switch.component'; +import { ToggleSwitcherComponent } from './toggle-switcher/toggle-switcher.component'; import { TrustHtmlLinkComponent } from './trust-html/trust-html.component'; import { ValueWithUnitComponent } from './value-with-units/value-with-units.component'; import { VisibilityComponent } from './visibility/visibility.component'; @@ -101,7 +101,7 @@ import { TaskBadgeViewComponentModule } from '../tasks/task-badge-view/task-badg TagsOnlyComponent, TaskEstimateComponent, TaskTeamsComponent, - ToggleSwitchComponent, + ToggleSwitcherComponent, TrustHtmlLinkComponent, ValueWithUnitComponent, VisibilityComponent @@ -143,7 +143,7 @@ import { TaskBadgeViewComponentModule } from '../tasks/task-badge-view/task-badg TagsOnlyComponent, TaskEstimateComponent, TaskTeamsComponent, - ToggleSwitchComponent, + ToggleSwitcherComponent, TrustHtmlLinkComponent, ValueWithUnitComponent, VisibilityComponent diff --git a/packages/ui-core/shared/src/lib/table-components/toggle-switch/toggle-switch.component.html b/packages/ui-core/shared/src/lib/table-components/toggle-switch/toggle-switch.component.html deleted file mode 100644 index 42fa0be455b..00000000000 --- a/packages/ui-core/shared/src/lib/table-components/toggle-switch/toggle-switch.component.html +++ /dev/null @@ -1,5 +0,0 @@ - - - {{ ((toggle_switch$ | async) ? 'BUTTONS.ENABLED' : 'BUTTONS.DISABLED') | translate }} - - diff --git a/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.html b/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.html new file mode 100644 index 00000000000..61e0c4a4fef --- /dev/null +++ b/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.html @@ -0,0 +1,7 @@ +
+ + + {{ ((switcher$ | async) ? 'BUTTONS.ENABLED' : 'BUTTONS.DISABLED') | translate }} + + +
diff --git a/packages/ui-core/shared/src/lib/table-components/toggle-switch/toggle-switch.component.ts b/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.ts similarity index 70% rename from packages/ui-core/shared/src/lib/table-components/toggle-switch/toggle-switch.component.ts rename to packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.ts index 90e17345c9c..0b9b61739a3 100644 --- a/packages/ui-core/shared/src/lib/table-components/toggle-switch/toggle-switch.component.ts +++ b/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.ts @@ -1,28 +1,25 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; -import { Observable } from 'rxjs/internal/Observable'; -import { tap } from 'rxjs/operators'; +import { BehaviorSubject, Observable, tap } from 'rxjs'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; @UntilDestroy({ checkProperties: true }) @Component({ - selector: 'ngx-toggle-switch', - templateUrl: './toggle-switch.component.html' + selector: 'ngx-toggle-switcher', + templateUrl: './toggle-switcher.component.html' }) -export class ToggleSwitchComponent implements OnInit { - +export class ToggleSwitcherComponent implements OnInit { /** * A class member that represents a boolean switch or toggle using a BehaviorSubject. */ - private _toggle_switch$: BehaviorSubject = new BehaviorSubject(false); + private _switcher$: BehaviorSubject = new BehaviorSubject(false); /** * Getter method for retrieving the toggle switch state as an Observable. * * @returns An Observable that emits the current state and subsequent changes of the toggle switch. */ - public get toggle_switch$(): Observable { - return this._toggle_switch$.asObservable(); + public get switcher$(): Observable { + return this._switcher$.asObservable(); } /** @@ -45,7 +42,7 @@ export class ToggleSwitchComponent implements OnInit { */ @Input() set value(value: any) { // Updates the dynamic element's value using a BehaviorSubject or similar mechanism. - this._toggle_switch$.next(value); + this._switcher$.next(value); // Stores the value in the local variable for future reference. this._value = value; @@ -86,22 +83,22 @@ export class ToggleSwitchComponent implements OnInit { * * This is used to create a custom event named 'switched' that can be listened to by external components. */ - @Output() switched: EventEmitter = new EventEmitter(); - + @Output() onSwitched: EventEmitter = new EventEmitter(); - constructor() { } + constructor() {} /** * The ngOnInit lifecycle hook is called when the component is initialized. - * This method subscribes to the 'switched' Observable, and upon changes, updates the '_toggle_switch$' BehaviorSubject. + * This method subscribes to the 'switched' Observable, and upon changes, updates the '_switcher$' BehaviorSubject. */ ngOnInit(): void { - this.switched.pipe( - // The 'tap' operator allows side-effects without changing the emitted values. - tap((enable: boolean) => this._toggle_switch$.next(enable)), - // The 'untilDestroyed' operator helps to automatically unsubscribe when the component is destroyed. - untilDestroyed(this) - ).subscribe(); // Subscribe to the Observable but perform actions in 'tap'. + this.onSwitched + .pipe( + tap((enable: boolean) => this._switcher$.next(enable)), + // The 'untilDestroyed' operator helps to automatically unsubscribe when the component is destroyed. + untilDestroyed(this) + ) + .subscribe(); // Subscribe to the Observable but perform actions in 'tap'. } /** @@ -111,6 +108,6 @@ export class ToggleSwitchComponent implements OnInit { */ onCheckedChange(event: boolean) { // Emits the provided boolean 'event' using the 'switched' EventEmitter. - this.switched.emit(event); + this.onSwitched.emit(event); } } From fc98cdfa36b82fb9951bd5ef8a71eb3b3368ff3a Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Mon, 21 Oct 2024 12:29:58 +0530 Subject: [PATCH 07/68] refactor: use common toggle switcher --- .../src/lib/components/view/view.component.ts | 2 +- .../job-employee/job-employee.component.ts | 65 +++++-------------- .../core/src/lib/services/job/index.ts | 3 +- .../lib/services/job/job-preset.service.ts | 3 +- .../services/job/job-search.store.service.ts | 56 ++++++++++++++++ .../shared/src/lib/smart-data-layout/index.ts | 1 - .../smart-data-view-layout.module.ts | 12 ++-- .../smart-table-toggle.component.html | 7 -- .../smart-table-toggle.component.scss | 0 .../smart-table-toggle.component.spec.ts | 25 ------- .../smart-table-toggle.component.ts | 36 ---------- .../toggle-switcher.component.html | 7 +- 12 files changed, 87 insertions(+), 130 deletions(-) create mode 100644 packages/ui-core/core/src/lib/services/job/job-search.store.service.ts delete mode 100644 packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.html delete mode 100644 packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.scss delete mode 100644 packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.spec.ts delete mode 100644 packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.ts diff --git a/packages/plugins/integration-github-ui/src/lib/components/view/view.component.ts b/packages/plugins/integration-github-ui/src/lib/components/view/view.component.ts index f436e75fedc..8c7856a5ff4 100644 --- a/packages/plugins/integration-github-ui/src/lib/components/view/view.component.ts +++ b/packages/plugins/integration-github-ui/src/lib/components/view/view.component.ts @@ -412,7 +412,7 @@ export class GithubViewComponent extends PaginationFilterBaseComponent implement instance.value = rowData?.customFields?.repository?.hasSyncEnabled || false; // Subscribe to the 'switched' event of the ToggleSwitcherComponent - instance.onSwitched.pipe(untilDestroyed(this)).subscribe({ + instance.onSwitched.subscribe({ // When the switch state changes, execute the following callback next: (hasSyncEnabled: boolean) => { // Call the 'updateGithubRepository' method with the row data and the new switch state diff --git a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts index f18f17bc82f..711d684ae7a 100644 --- a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts +++ b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts @@ -20,7 +20,8 @@ import { ToastrService, PageTabsetRegistryId, PageTabRegistryService, - PageDataTableRegistryId + PageDataTableRegistryId, + JobSearchStoreService } from '@gauzy/ui-core/core'; import { I18nService } from '@gauzy/ui-core/i18n'; import { @@ -29,7 +30,7 @@ import { NumberEditorComponent, EmployeeLinkEditorComponent, PaginationFilterBaseComponent, - SmartTableToggleComponent + ToggleSwitcherComponent } from '@gauzy/ui-core/shared'; /** @@ -75,6 +76,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen private readonly _store: Store, private readonly _employeesService: EmployeesService, private readonly _jobService: JobService, + private readonly _jobSearchStoreService: JobSearchStoreService, private readonly _toastrService: ToastrService, private readonly _currencyPipe: CurrencyPipe, private readonly _i18nService: I18nService, @@ -206,7 +208,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen registerDataTableColumns(_pageDataTableRegistryService: PageDataTableRegistryService): void { // Register the data table column _pageDataTableRegistryService.registerPageDataTableColumn({ - dataTableId: 'job-employee', // The identifier for the data table location + dataTableId: this.dataTableId, // The identifier for the data table location columnId: 'name', // The identifier for the column order: 0, // The order of the column in the table title: () => this.getTranslation('JOB_EMPLOYEE.EMPLOYEE'), // The title of the column @@ -230,7 +232,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen // Register the data table column _pageDataTableRegistryService.registerPageDataTableColumn({ - dataTableId: 'job-employee', // The identifier for the data table location + dataTableId: this.dataTableId, // The identifier for the data table location columnId: 'availableJobs', // The identifier for the column order: 1, // The order of the column in the table title: () => this.getTranslation('JOB_EMPLOYEE.AVAILABLE_JOBS'), // The title of the column @@ -243,7 +245,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen // Register the data table column _pageDataTableRegistryService.registerPageDataTableColumn({ - dataTableId: 'job-employee', // The identifier for the data table location + dataTableId: this.dataTableId, // The identifier for the data table location columnId: 'appliedJobs', // The identifier for the column order: 2, // The order of the column in the table title: () => this.getTranslation('JOB_EMPLOYEE.APPLIED_JOBS'), // The title of the column @@ -256,7 +258,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen // Register the data table column _pageDataTableRegistryService.registerPageDataTableColumn({ - dataTableId: 'job-employee', // The identifier for the data table location + dataTableId: this.dataTableId, // The identifier for the data table location columnId: 'billRateValue', // The identifier for the column order: 3, // The order of the column in the table title: () => this.getTranslation('JOB_EMPLOYEE.BILLING_RATE'), // The title of the column @@ -278,7 +280,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen // Register the data table column _pageDataTableRegistryService.registerPageDataTableColumn({ - dataTableId: 'job-employee', // The identifier for the data table location + dataTableId: this.dataTableId, // The identifier for the data table location columnId: 'minimumBillingRate', // The identifier for the column order: 4, // The order of the column in the table title: () => this.getTranslation('JOB_EMPLOYEE.MINIMUM_BILLING_RATE'), // The title of the column @@ -298,7 +300,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen // Register the data table column _pageDataTableRegistryService.registerPageDataTableColumn({ - dataTableId: 'job-employee', // The identifier for the data table location + dataTableId: this.dataTableId, // The identifier for the data table location columnId: 'isJobSearchActive', // The identifier for the column order: 5, // The order of the column in the table title: () => this.getTranslation('JOB_EMPLOYEE.JOB_SEARCH_STATUS'), // The title of the column @@ -306,17 +308,20 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen width: '20%', // The width of the column isSortable: false, // Indicates whether the column is sortable isEditable: false, // Indicates whether the column is editable - renderComponent: SmartTableToggleComponent, - componentInitFunction: (instance: SmartTableToggleComponent, cell: Cell) => { + renderComponent: ToggleSwitcherComponent, + componentInitFunction: (instance: ToggleSwitcherComponent, cell: Cell) => { // Get the employee data from the cell const employee: IEmployee = cell.getRow().getData(); + // Set the label property to false to hide the label + instance.label = false; // Set the initial value of the toggle instance.value = employee.isJobSearchActive; // Subscribe to the toggleChange event - instance.toggleChange.pipe(untilDestroyed(this)).subscribe((toggle: boolean) => { - this.updateJobSearchAvailability(employee, toggle); + instance.onSwitched.subscribe((toggle: boolean) => { + // Call the JobSearchStoreService to update the job search availability + this._jobSearchStoreService.updateJobSearchAvailability(this.organization, employee, toggle); }); } }); @@ -525,42 +530,6 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen } } - /** - * Updates the job search availability status of an employee within the organization. - * @param employee - The employee object to update. - * @param isJobSearchActive - A boolean flag indicating whether the job search is active. - * @returns {Promise} - A Promise resolving to void. - */ - async updateJobSearchAvailability(employee: IEmployee, isJobSearchActive: boolean): Promise { - try { - // Ensure the organization context is available before proceeding. - if (!this.organization) { - return; - } - - // Destructure organization properties for clarity. - const { id: organizationId, tenantId } = this.organization; - - // Update the job search status using the employeesService. - await this._jobService.updateJobSearchStatus(employee.id, { - isJobSearchActive, - organizationId, - tenantId - }); - - // Display a success toastr notification based on the job search status. - const toastrMessageKey = isJobSearchActive - ? 'TOASTR.MESSAGE.EMPLOYEE_JOB_STATUS_ACTIVE' - : 'TOASTR.MESSAGE.EMPLOYEE_JOB_STATUS_INACTIVE'; - - const fullName = employee.fullName.trim() || 'Unknown Employee'; - this._toastrService.success(toastrMessageKey, { name: fullName }); - } catch (error) { - // Display an error toastr notification in case of any exceptions. - this._toastrService.danger(error); - } - } - /** * Applies translations to the Smart Table settings when the language changes. * This method listens for the onLangChange event from the translateService. diff --git a/packages/ui-core/core/src/lib/services/job/index.ts b/packages/ui-core/core/src/lib/services/job/index.ts index d4f512d7ea0..a6379958983 100644 --- a/packages/ui-core/core/src/lib/services/job/index.ts +++ b/packages/ui-core/core/src/lib/services/job/index.ts @@ -1,4 +1,5 @@ export * from './job-preset.service'; export * from './job-search-category.service'; export * from './job-search-occupation.service'; -export * from './job.service'; \ No newline at end of file +export * from './job.service'; +export * from './job-search.store.service'; diff --git a/packages/ui-core/core/src/lib/services/job/job-preset.service.ts b/packages/ui-core/core/src/lib/services/job/job-preset.service.ts index 7e97f2372ed..3f9485a8e15 100644 --- a/packages/ui-core/core/src/lib/services/job/job-preset.service.ts +++ b/packages/ui-core/core/src/lib/services/job/job-preset.service.ts @@ -2,8 +2,7 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { firstValueFrom } from 'rxjs'; import { ID, IEmployeePresetInput, IGetJobPresetInput, IJobPreset, IMatchingCriterions } from '@gauzy/contracts'; -import { toParams } from '@gauzy/ui-core/common'; -import { API_PREFIX } from '@gauzy/ui-core/common'; +import { API_PREFIX, toParams } from '@gauzy/ui-core/common'; @Injectable({ providedIn: 'root' diff --git a/packages/ui-core/core/src/lib/services/job/job-search.store.service.ts b/packages/ui-core/core/src/lib/services/job/job-search.store.service.ts new file mode 100644 index 00000000000..e2381a07a65 --- /dev/null +++ b/packages/ui-core/core/src/lib/services/job/job-search.store.service.ts @@ -0,0 +1,56 @@ +import { Injectable } from '@angular/core'; +import { IEmployee, IOrganization } from '@gauzy/contracts'; +import { JobService } from './job.service'; +import { ToastrService } from '../notification/toastr.service'; + +@Injectable({ + providedIn: 'root' +}) +export class JobSearchStoreService { + constructor(private readonly _jobService: JobService, private readonly _toastrService: ToastrService) {} + + /** + * Updates the job search availability status of an employee within the organization. + * + * @param organization - The current organization context. + * @param employee - The employee object to update. + * @param isJobSearchActive - A boolean flag indicating whether the job search is active. + * @returns {Promise} - A Promise resolving to void. + */ + async updateJobSearchAvailability( + organization: IOrganization | undefined, + employee: IEmployee, + isJobSearchActive: boolean + ): Promise { + try { + // Ensure the organization context is available before proceeding. + if (!organization) { + console.warn('No organization provided to update job search availability.'); + return; + } + + // Destructure organization properties for clarity. + const { id: organizationId, tenantId } = organization; + + // Update the job search status using the employeesService. + await this._jobService.updateJobSearchStatus(employee.id, { + isJobSearchActive, + organizationId, + tenantId + }); + + // Display a success toastr notification based on the job search status. + const toastrMessageKey = isJobSearchActive + ? 'TOASTR.MESSAGE.EMPLOYEE_JOB_STATUS_ACTIVE' + : 'TOASTR.MESSAGE.EMPLOYEE_JOB_STATUS_INACTIVE'; + + const fullName = employee.fullName.trim() || 'Unknown Employee'; + this._toastrService.success(toastrMessageKey, { name: fullName }); + } catch (error) { + // Display an error toastr notification in case of any exceptions. + const errorMessage = error?.message || 'An error occurred while updating the job search availability.'; + console.error('Error while updating job search availability:', error?.message); + this._toastrService.danger(errorMessage); + } + } +} diff --git a/packages/ui-core/shared/src/lib/smart-data-layout/index.ts b/packages/ui-core/shared/src/lib/smart-data-layout/index.ts index 9b4429ecf12..4858e8493bd 100644 --- a/packages/ui-core/shared/src/lib/smart-data-layout/index.ts +++ b/packages/ui-core/shared/src/lib/smart-data-layout/index.ts @@ -4,7 +4,6 @@ export * from './no-data-message/no-data-message.module'; // Components export * from './no-data-message/no-data-message.component'; -export * from './smart-table-toggle/smart-table-toggle.component'; export * from './pagination/pagination.component'; export * from './pagination/pagination-filter-base.component'; export * from './pagination/pagination-v2/pagination-v2.component'; diff --git a/packages/ui-core/shared/src/lib/smart-data-layout/smart-data-view-layout.module.ts b/packages/ui-core/shared/src/lib/smart-data-layout/smart-data-view-layout.module.ts index 698d24bd796..a8269b53376 100644 --- a/packages/ui-core/shared/src/lib/smart-data-layout/smart-data-view-layout.module.ts +++ b/packages/ui-core/shared/src/lib/smart-data-layout/smart-data-view-layout.module.ts @@ -1,5 +1,4 @@ import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; import { NbIconModule, NbSelectModule, NbToggleModule } from '@nebular/theme'; import { TranslateModule } from '@ngx-translate/core'; import { Angular2SmartTableModule } from 'angular2-smart-table'; @@ -9,19 +8,16 @@ import { GauzyButtonActionModule } from '../gauzy-button-action/gauzy-button-act import { NoDataMessageModule } from './no-data-message/no-data-message.module'; import { PaginationComponent } from './pagination/pagination.component'; import { PaginationV2Component } from './pagination/pagination-v2/pagination-v2.component'; -import { SmartTableToggleComponent } from './smart-table-toggle/smart-table-toggle.component'; - -// Nebular Modules -const NB_MODULES = [NbToggleModule, NbIconModule, NbSelectModule]; // Components -const COMPONENTS = [PaginationComponent, PaginationV2Component, SmartTableToggleComponent]; +const COMPONENTS = [PaginationComponent, PaginationV2Component]; @NgModule({ declarations: [...COMPONENTS], imports: [ - CommonModule, - ...NB_MODULES, + NbToggleModule, + NbIconModule, + NbSelectModule, TranslateModule.forChild(), NgxPermissionsModule.forChild(), Angular2SmartTableModule, diff --git a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.html b/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.html deleted file mode 100644 index 3f0e83d8aa5..00000000000 --- a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.html +++ /dev/null @@ -1,7 +0,0 @@ -
- -
diff --git a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.scss b/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.scss deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.spec.ts b/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.spec.ts deleted file mode 100644 index 0f0476daeba..00000000000 --- a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SmartTableToggleComponent } from './smart-table-toggle.component'; - -describe('SmartTableToggleComponent', () => { - let component: SmartTableToggleComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [SmartTableToggleComponent], - teardown: { destroyAfterEach: false } - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(SmartTableToggleComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.ts b/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.ts deleted file mode 100644 index 6aeef4a914f..00000000000 --- a/packages/ui-core/shared/src/lib/smart-data-layout/smart-table-toggle/smart-table-toggle.component.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { BehaviorSubject, Observable } from 'rxjs'; - -@Component({ - selector: 'ngx-smart-table-toggle-switcher', - templateUrl: './smart-table-toggle.component.html', - styleUrls: ['./smart-table-toggle.component.scss'] -}) -export class SmartTableToggleComponent { - private _checked$: BehaviorSubject = new BehaviorSubject(false); - public get checked$(): Observable { - return this._checked$.asObservable(); - } - - /** - * Set the value of the toggle. - * @param checked The value to set the toggle to. - */ - @Input() public set value(checked: boolean) { - this._checked$.next(checked); - } - - /** - * Get the value of the toggle. - */ - @Output() toggleChange: EventEmitter = new EventEmitter(); - - /** - * Set the value of the toggle. - * @param isChecked - */ - onCheckedChange(isChecked: boolean) { - this.toggleChange.emit(isChecked); - this._checked$.next(isChecked); - } -} diff --git a/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.html b/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.html index 61e0c4a4fef..66e06c8acf3 100644 --- a/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.html +++ b/packages/ui-core/shared/src/lib/table-components/toggle-switcher/toggle-switcher.component.html @@ -1,5 +1,10 @@
- + {{ ((switcher$ | async) ? 'BUTTONS.ENABLED' : 'BUTTONS.DISABLED') | translate }} From 19d94da1969f471fff773ca79e8696da6a606383 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Mon, 21 Oct 2024 12:30:53 +0530 Subject: [PATCH 08/68] chore: add integration UI plugins build command to scripts --- package.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 523c69d0c94..c409bcc7817 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 && 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: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:integration-ui-plugins", + "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:prod && 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:integration-ui-plugins: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", @@ -160,13 +160,15 @@ "build:package:plugin:job-search": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/job-search build", "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:integration-github-ui": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-github-ui lib:build", - "build:package:plugin:integration-github-ui:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-github-ui lib:build:prod", "build:package:plugin:integration-upwork-ui": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-upwork-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: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:integration-github-ui:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-github-ui lib:build:prod", "build:package:plugin:integration-upwork-ui:prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn --cwd ./packages/plugins/integration-upwork-ui lib:build:prod", + "build:integration-ui-plugins": "yarn run build:package:plugin:integration-ai-ui && yarn run build:package:plugin:integration-hubstaff-ui && yarn run build:package:plugin:integration-upwork-ui && yarn run build:package:plugin:integration-github-ui", + "build:integration-ui-plugins:prod": "yarn run build:package:plugin:integration-ai-ui:prod && yarn run build:package:plugin:integration-hubstaff-ui:prod && yarn run build:package:plugin:integration-upwork-ui:prod && yarn run build:package:plugin:integration-github-ui: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", From 9b70600f632a8f98c5bdbe2ed870f973ded96ac9 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Mon, 21 Oct 2024 13:02:07 +0530 Subject: [PATCH 09/68] fix: use common toggle switcher for job search status --- .../job-employee/job-employee.component.ts | 3 +- ...ob-search-availability-editor.component.ts | 106 +++++++++--------- 2 files changed, 56 insertions(+), 53 deletions(-) diff --git a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts index b728ac9b77e..d4e7cc071ad 100644 --- a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts +++ b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts @@ -30,9 +30,8 @@ import { NumberEditorComponent, EmployeeLinkEditorComponent, PaginationFilterBaseComponent, - SmartTableToggleComponent, NonEditableNumberEditorComponent, - JobSearchAvailabilityEditorComponent + JobSearchAvailabilityEditorComponent, ToggleSwitcherComponent } from '@gauzy/ui-core/shared'; diff --git a/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts b/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts index 7e6bb917498..411ac536866 100644 --- a/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts +++ b/packages/ui-core/shared/src/lib/table-components/editors/job-search-availability-editor.component.ts @@ -1,70 +1,74 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { IEmployee } from '@gauzy/contracts'; -import { JobService, ToastrService } from '@gauzy/ui-core/core'; +import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core'; +import { filter, tap } from 'rxjs'; import { Cell, DefaultEditor } from 'angular2-smart-table'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { IEmployee, IOrganization } from '@gauzy/contracts'; +import { distinctUntilChange } from '@gauzy/ui-core/common'; +import { JobSearchStoreService, Store } from '@gauzy/ui-core/core'; +import { ToggleSwitcherComponent } from '../toggle-switcher/toggle-switcher.component'; +@UntilDestroy({ checkProperties: true }) @Component({ - template: `
- -
` + template: ` + + ` }) -export class JobSearchAvailabilityEditorComponent extends DefaultEditor implements OnInit { - private _checked$: BehaviorSubject = new BehaviorSubject(false); +export class JobSearchAvailabilityEditorComponent extends DefaultEditor implements AfterViewInit, OnInit { + public organization: IOrganization; + public employee: IEmployee; + + // Reference to the cell object @Input() cell!: Cell; - @Output() toggleChange: EventEmitter = new EventEmitter(); - constructor(private readonly _jobService: JobService, private readonly _toastrService: ToastrService) { - super(); - } + // Reference to the ToggleSwitcherComponent instance + @ViewChild(ToggleSwitcherComponent) switcher!: ToggleSwitcherComponent; - public get checked$(): Observable { - return this._checked$.asObservable(); + constructor( + private readonly _cdr: ChangeDetectorRef, + private readonly _store: Store, + private readonly _jobSearchStoreService: JobSearchStoreService + ) { + super(); } ngOnInit() { - if (this.cell) { - const employee: IEmployee = this.cell.getRow()?.getData(); - if (employee) { - this.value = employee.isJobSearchActive; // Initialize the toggle value - } - } + this._store.selectedOrganization$ + .pipe( + distinctUntilChange(), + filter((organization: IOrganization) => !!organization), + tap((organization: IOrganization) => { + this.organization = organization; + this.employee = this.cell.getRow()?.getData(); + }), + untilDestroyed(this) + ) + .subscribe(); } - @Input() public set value(checked: boolean) { - this._checked$.next(checked); - } - - onCheckedChange(isChecked: boolean) { - this.toggleChange.emit(isChecked); // Emit the toggle change event - this._checked$.next(isChecked); - this.updateJobSearchAvailability(isChecked); // Update job search availability + ngAfterViewInit(): void { + if (!this.switcher) { + return; + } + this.switcher.value = this.employee?.isJobSearchActive || false; + this._cdr.detectChanges(); // Force change detection to update the UI } - async updateJobSearchAvailability(isJobSearchActive: boolean): Promise { - if (!this.cell) return; // Ensure 'cell' is available - const employee: IEmployee = this.cell.getRow()?.getData(); - if (!employee) return; // Ensure employee data is available - + /** + * Updates the job search availability status of an employee within the organization. + * + * @param isJobSearchActive - A boolean flag indicating whether the job search is active. + */ + updateJobSearchAvailability(isJobSearchActive: boolean): void { try { - await this._jobService.updateJobSearchStatus(employee.id, { - isJobSearchActive, - organizationId: employee.organizationId, - tenantId: employee.tenantId - }); - - const toastrMessageKey = isJobSearchActive - ? 'TOASTR.MESSAGE.EMPLOYEE_JOB_STATUS_ACTIVE' - : 'TOASTR.MESSAGE.EMPLOYEE_JOB_STATUS_INACTIVE'; - - this._toastrService.success(toastrMessageKey, { name: employee.fullName }); + // Call the service to update the job search availability status + this._jobSearchStoreService.updateJobSearchAvailability( + this.organization, + this.employee, + isJobSearchActive + ); } catch (error) { - const errorMessage = error?.message || 'An error occurred while updating the job search availability.'; - this._toastrService.danger(errorMessage); + // Log the error for debugging purposes + console.log('Error while updating job search availability:', error); } } } From b5c93175aae786f29d69a7a6f739dcf162f746e0 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Mon, 21 Oct 2024 13:04:37 +0530 Subject: [PATCH 10/68] feat: apply code rabbit suggestions --- .../lib/components/job-employee/job-employee.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts index d4e7cc071ad..44521abaabe 100644 --- a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts +++ b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts @@ -10,7 +10,7 @@ import { TranslateService } from '@ngx-translate/core'; import { Cell } from 'angular2-smart-table'; import { NgxPermissionsService } from 'ngx-permissions'; import { ID, IEmployee, IOrganization, LanguagesEnum, PermissionsEnum } from '@gauzy/contracts'; -import { API_PREFIX, distinctUntilChange } from '@gauzy/ui-core/common'; +import { API_PREFIX, distinctUntilChange, isNotNullOrUndefined } from '@gauzy/ui-core/common'; import { PageDataTableRegistryService, EmployeesService, @@ -242,7 +242,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen width: '10%', // The width of the column isSortable: false, // Indicates whether the column is sortable isEditable: false, // Indicates whether the column is editable - valuePrepareFunction: (rawValue: any) => rawValue || 0, + valuePrepareFunction: (rawValue: any) => (isNotNullOrUndefined(rawValue) ? rawValue : 0), editor: { type: 'custom', component: NonEditableNumberEditorComponent @@ -259,7 +259,7 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen width: '10%', // The width of the column isSortable: false, // Indicates whether the column is sortable isEditable: false, // Indicates whether the column is editable - valuePrepareFunction: (rawValue: any) => rawValue || 0, + valuePrepareFunction: (rawValue: any) => (isNotNullOrUndefined(rawValue) ? rawValue : 0), editor: { type: 'custom', component: NonEditableNumberEditorComponent From 0eb8b3b03506c593bb9baa6a92dea92740990e7a Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Mon, 21 Oct 2024 13:25:09 +0530 Subject: [PATCH 11/68] fix: implement refresh the data table on edit cancellation --- .../job-employee/job-employee.component.html | 1 + .../job-employee/job-employee.component.ts | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.html b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.html index 5578d94fe8c..1a25595f902 100644 --- a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.html +++ b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.html @@ -32,6 +32,7 @@

[settings]="settingsSmartTable" [source]="smartTableSource" (editConfirm)="onEditConfirm($event)" + (editCancel)="onEditCancel($event)" (userRowSelect)="onSelectEmployee($event)" >

diff --git a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts index 44521abaabe..a538278d573 100644 --- a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts +++ b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts @@ -544,6 +544,21 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen } } + /** + * Handles the cancellation of an edit operation in the smart table. + * Refreshes the data table to reflect any changes made. + * + * @param event - The event object containing details about the canceled edit. + * + */ + onEditCancel(event: any): void { + // Optionally, you can log the event for debugging purposes + console.log('Edit canceled for row:', event); + + // Refresh the data table to revert any changes made during the edit + this.smartTableSource.refresh(); + } + /** * Applies translations to the Smart Table settings when the language changes. * This method listens for the onLangChange event from the translateService. From e6dca1059f9814e186dbf46eee49b96323bccd11 Mon Sep 17 00:00:00 2001 From: samuelmbabhazi Date: Mon, 21 Oct 2024 12:45:50 +0200 Subject: [PATCH 12/68] Dates should be translated when switching to other languages --- .../date-range-title/date-range-title.component.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts b/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts index cc73aba40f3..17aefc98ac1 100644 --- a/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts +++ b/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts @@ -1,7 +1,8 @@ -import { Component, Input } from '@angular/core'; +import { Component, Inject, Input, LOCALE_ID } from '@angular/core'; import { UntilDestroy } from '@ngneat/until-destroy'; import { DateRangePickerBuilderService } from '@gauzy/ui-core/core'; import { DateFormatPipe } from '../../pipes'; +import { ThemeLanguageSelectorService } from '@gauzy/ui-core/theme'; @UntilDestroy({ checkProperties: true }) @Component({ @@ -43,7 +44,8 @@ export class DateRangeTitleComponent { constructor( readonly _dateFormatPipe: DateFormatPipe, - readonly _dateRangePickerBuilderService: DateRangePickerBuilderService + readonly _dateRangePickerBuilderService: DateRangePickerBuilderService, + private readonly _themeLanguageService: ThemeLanguageSelectorService ) {} /** @@ -56,9 +58,11 @@ export class DateRangeTitleComponent { // Check if it’s a single date picker const isSingleDatePicker = this._dateRangePickerBuilderService.datePickerConfig.isSingleDatePicker; + const language = this._themeLanguageService.preferredLanguage; + // Use provided `start` and `end` or fallback to the default range values - const start = this._dateFormatPipe.transform(this.start || startDate, null, this.format); - const end = this._dateFormatPipe.transform(this.end || endDate, null, this.format); + const start = this._dateFormatPipe.transform(this.start || startDate, language, this.format); + const end = this._dateFormatPipe.transform(this.end || endDate, language, this.format); // If it's a single date picker, return only the start date, otherwise return the date range return isSingleDatePicker ? start : [start, end].filter(Boolean).join(' - '); From d9b6b5474b22569cee97ad7833acc8435fa8c56a Mon Sep 17 00:00:00 2001 From: samuelmbabhazi Date: Mon, 21 Oct 2024 12:51:37 +0200 Subject: [PATCH 13/68] Dates should be translated when switching to other languages --- .../components/date-range-title/date-range-title.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts b/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts index 17aefc98ac1..10aa435275b 100644 --- a/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts +++ b/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, Input, LOCALE_ID } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { UntilDestroy } from '@ngneat/until-destroy'; import { DateRangePickerBuilderService } from '@gauzy/ui-core/core'; import { DateFormatPipe } from '../../pipes'; From bb8f989d840ad76755678168fd51cdd3ba5d2420 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Mon, 21 Oct 2024 19:03:30 +0530 Subject: [PATCH 14/68] chore(deps): bump angular2-smart-table from 3.2.0 to 3.3.0 --- apps/gauzy/package.json | 2 +- package.json | 2 +- packages/desktop-ui-lib/package.json | 2 +- packages/plugins/integration-github-ui/package.json | 2 +- packages/plugins/integration-hubstaff-ui/package.json | 2 +- packages/plugins/integration-upwork-ui/package.json | 2 +- packages/plugins/job-employee-ui/package.json | 2 +- packages/plugins/job-proposal-ui/package.json | 2 +- packages/plugins/job-search-ui/package.json | 2 +- packages/ui-core/package.json | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/gauzy/package.json b/apps/gauzy/package.json index dea89eb5772..76b6c7f4275 100644 --- a/apps/gauzy/package.json +++ b/apps/gauzy/package.json @@ -88,7 +88,7 @@ "@sentry/types": "^7.101.1", "@sentry/utils": "^7.90.0", "@swimlane/ngx-charts": "^20.1.0", - "angular2-smart-table": "^3.2.0", + "angular2-smart-table": "^3.3.0", "angular2-toaster": "^11.0.1", "bootstrap": "^4.3.1", "brace": "^0.11.1", diff --git a/package.json b/package.json index c409bcc7817..7a708dcde77 100644 --- a/package.json +++ b/package.json @@ -339,7 +339,7 @@ "@nebular/security": "^12.0.0", "@nebular/theme": "^12.0.0", "@ng-select/ng-select": "^11.2.0", - "angular2-smart-table": "^3.2.0", + "angular2-smart-table": "^3.3.0", "autoprefixer": "10.4.14", "bcrypt": "^5.1.1", "camelcase": "^6.3.0", diff --git a/packages/desktop-ui-lib/package.json b/packages/desktop-ui-lib/package.json index 783121698e7..958f25e547d 100644 --- a/packages/desktop-ui-lib/package.json +++ b/packages/desktop-ui-lib/package.json @@ -53,7 +53,7 @@ "@ngx-translate/core": "^15.0.0", "@ngx-translate/http-loader": "^8.0.0", "@swimlane/ngx-charts": "20.5.0", - "angular2-smart-table": "^3.2.0", + "angular2-smart-table": "^3.3.0", "ckeditor4-angular": "4.0.1", "electron-log": "^4.4.8", "electron-store": "^8.1.0", diff --git a/packages/plugins/integration-github-ui/package.json b/packages/plugins/integration-github-ui/package.json index abd3c3c0ece..3b0ee5d10be 100644 --- a/packages/plugins/integration-github-ui/package.json +++ b/packages/plugins/integration-github-ui/package.json @@ -44,7 +44,7 @@ "@nebular/theme": "^12.0.0", "@ngneat/until-destroy": "^9.2.0", "@ngx-translate/core": "^15.0.0", - "angular2-smart-table": "^3.2.0", + "angular2-smart-table": "^3.3.0", "ngx-permissions": "^13.0.1", "rxjs": "^7.4.0", "tslib": "^2.6.2" diff --git a/packages/plugins/integration-hubstaff-ui/package.json b/packages/plugins/integration-hubstaff-ui/package.json index 867c79437d1..b1e41fbca29 100644 --- a/packages/plugins/integration-hubstaff-ui/package.json +++ b/packages/plugins/integration-hubstaff-ui/package.json @@ -47,7 +47,7 @@ "@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", + "angular2-smart-table": "^3.3.0", "ngx-permissions": "^13.0.1", "rxjs": "^7.4.0", "tslib": "^2.6.2" diff --git a/packages/plugins/integration-upwork-ui/package.json b/packages/plugins/integration-upwork-ui/package.json index f0e38980ce0..31404f2ceb7 100644 --- a/packages/plugins/integration-upwork-ui/package.json +++ b/packages/plugins/integration-upwork-ui/package.json @@ -44,7 +44,7 @@ "@nebular/theme": "^12.0.0", "@ngneat/until-destroy": "^9.2.0", "@ngx-translate/core": "^15.0.0", - "angular2-smart-table": "^3.2.0", + "angular2-smart-table": "^3.3.0", "ngx-permissions": "^13.0.1", "rxjs": "^7.4.0", "tslib": "^2.6.2" diff --git a/packages/plugins/job-employee-ui/package.json b/packages/plugins/job-employee-ui/package.json index 7a5cd6c74c2..b0a0ae8d4fd 100644 --- a/packages/plugins/job-employee-ui/package.json +++ b/packages/plugins/job-employee-ui/package.json @@ -44,7 +44,7 @@ "@ngneat/until-destroy": "^9.2.0", "@ngx-translate/core": "^15.0.0", "@ngx-translate/http-loader": "^8.0.0", - "angular2-smart-table": "^3.2.0", + "angular2-smart-table": "^3.3.0", "ngx-permissions": "^13.0.1", "rxjs": "^7.4.0", "tslib": "^2.6.2" diff --git a/packages/plugins/job-proposal-ui/package.json b/packages/plugins/job-proposal-ui/package.json index 4df54349620..c4b3a6973ae 100644 --- a/packages/plugins/job-proposal-ui/package.json +++ b/packages/plugins/job-proposal-ui/package.json @@ -45,7 +45,7 @@ "@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", + "angular2-smart-table": "^3.3.0", "ckeditor4-angular": "4.0.1", "moment": "^2.30.1", "ngx-infinite-scroll": "^16.0.0", diff --git a/packages/plugins/job-search-ui/package.json b/packages/plugins/job-search-ui/package.json index d69f015cf3f..147fe8dfda2 100644 --- a/packages/plugins/job-search-ui/package.json +++ b/packages/plugins/job-search-ui/package.json @@ -45,7 +45,7 @@ "@ngneat/until-destroy": "^9.2.0", "@ngx-translate/core": "^15.0.0", "@ngx-translate/http-loader": "^8.0.0", - "angular2-smart-table": "^3.2.0", + "angular2-smart-table": "^3.3.0", "ckeditor4-angular": "4.0.1", "ng2-file-upload": "^5.0.0", "ngx-moment": "^6.0.2", diff --git a/packages/ui-core/package.json b/packages/ui-core/package.json index 2db0a57d70c..dc22c9fbb5f 100644 --- a/packages/ui-core/package.json +++ b/packages/ui-core/package.json @@ -77,7 +77,7 @@ "@ngx-translate/core": "^15.0.0", "@ngx-translate/http-loader": "^8.0.0", "@sentry/angular-ivy": "^7.101.1", - "angular2-smart-table": "^3.2.0", + "angular2-smart-table": "^3.3.0", "bootstrap": "^4.3.1", "camelcase": "^6.3.0", "chart.js": "^4.4.1", From bf4efbe344173c4356fd0193452101cb182998a3 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Mon, 21 Oct 2024 19:12:59 +0530 Subject: [PATCH 15/68] chore(deps): bump angular2-smart-table from 3.2.0 to 3.3.0 --- yarn.lock | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3b27aa15432..59ca11f8101 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12964,12 +12964,12 @@ analytics@0.8.9: "@analytics/core" "^0.12.7" "@analytics/storage-utils" "^0.4.2" -angular2-smart-table@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/angular2-smart-table/-/angular2-smart-table-3.2.0.tgz#85f7e2d31c3e74c41a8d30ae5ad7a3aa87ada16b" - integrity sha512-4UPYY1kYpZbRMZFhCQaVRpTKhesbt42oX4APz09dbpusD3wlhOmPvSG4+U+Fxqy/7+SHtdzlVEf/L++NqCRWwQ== +angular2-smart-table@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/angular2-smart-table/-/angular2-smart-table-3.3.0.tgz#d5781ee3ec6e319d055d175dfb18aea123a8bd54" + integrity sha512-J2XiiiB7ugcn9jCuamA30UsphJ8dWtMA2gY2FX0NxGHFRzzKkP5KERIDEcMLDqMIY/QgqQJvn+XjWEETmMx76A== dependencies: - tslib "^2.6.0" + tslib "~2.7.0" angular2-toaster@^11.0.1: version "11.0.1" @@ -36087,7 +36087,7 @@ tslib@2.6.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== -tslib@2.6.2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.5.0, tslib@^2.6.0, tslib@^2.6.1, tslib@^2.6.2: +tslib@2.6.2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.5.0, tslib@^2.6.1, tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -36097,6 +36097,11 @@ tslib@^1.10.0, tslib@^1.11.1, tslib@^1.13.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@~2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + tslint-config-prettier@^1.18.0: version "1.18.0" resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37" From 443dd2e270309cf6d42958ec27c54d6193fc7fce Mon Sep 17 00:00:00 2001 From: samuelmbabhazi Date: Mon, 21 Oct 2024 15:46:35 +0200 Subject: [PATCH 16/68] add allow manual time filed --- packages/contracts/src/employee.model.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/contracts/src/employee.model.ts b/packages/contracts/src/employee.model.ts index bf4bab5e5fe..8192d8cf5e5 100644 --- a/packages/contracts/src/employee.model.ts +++ b/packages/contracts/src/employee.model.ts @@ -123,6 +123,9 @@ export interface IEmployee extends IBasePerTenantAndOrganizationEntityModel, ITa isTrackingTime?: boolean; // True mean active, false away isAway?: boolean; + allowManualTime?: boolean; + allowModifyTime?: boolean; + allowDeleteTime?: boolean; } export type IEmployeeJobsStatisticsResponse = IEmployee & IEmployeeJobsStatistics; From b4e63c5dbf888e836823117945a65f52c61dffd1 Mon Sep 17 00:00:00 2001 From: samuelmbabhazi Date: Mon, 21 Oct 2024 17:13:02 +0200 Subject: [PATCH 17/68] Dates should be translated when switching to other languages --- .../date-range-title/date-range-title.component.ts | 10 +++------- .../shared/src/lib/pipes/date-format.pipe.ts | 14 +++++++++++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts b/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts index 10aa435275b..cc73aba40f3 100644 --- a/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts +++ b/packages/ui-core/shared/src/lib/components/date-range-title/date-range-title.component.ts @@ -2,7 +2,6 @@ import { Component, Input } from '@angular/core'; import { UntilDestroy } from '@ngneat/until-destroy'; import { DateRangePickerBuilderService } from '@gauzy/ui-core/core'; import { DateFormatPipe } from '../../pipes'; -import { ThemeLanguageSelectorService } from '@gauzy/ui-core/theme'; @UntilDestroy({ checkProperties: true }) @Component({ @@ -44,8 +43,7 @@ export class DateRangeTitleComponent { constructor( readonly _dateFormatPipe: DateFormatPipe, - readonly _dateRangePickerBuilderService: DateRangePickerBuilderService, - private readonly _themeLanguageService: ThemeLanguageSelectorService + readonly _dateRangePickerBuilderService: DateRangePickerBuilderService ) {} /** @@ -58,11 +56,9 @@ export class DateRangeTitleComponent { // Check if it’s a single date picker const isSingleDatePicker = this._dateRangePickerBuilderService.datePickerConfig.isSingleDatePicker; - const language = this._themeLanguageService.preferredLanguage; - // Use provided `start` and `end` or fallback to the default range values - const start = this._dateFormatPipe.transform(this.start || startDate, language, this.format); - const end = this._dateFormatPipe.transform(this.end || endDate, language, this.format); + const start = this._dateFormatPipe.transform(this.start || startDate, null, this.format); + const end = this._dateFormatPipe.transform(this.end || endDate, null, this.format); // If it's a single date picker, return only the start date, otherwise return the date range return isSingleDatePicker ? start : [start, end].filter(Boolean).join(' - '); diff --git a/packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts b/packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts index 07aad42a282..0a28c394306 100644 --- a/packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts +++ b/packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts @@ -14,6 +14,7 @@ import { Store } from '@gauzy/ui-core/core'; export class DateFormatPipe implements PipeTransform { dateFormat: string = 'd MMMM, y'; regionCode: string = RegionsEnum.EN; + locale!: string; constructor(private readonly store: Store) { this.store.selectedOrganization$ @@ -27,6 +28,17 @@ export class DateFormatPipe implements PipeTransform { untilDestroyed(this) ) .subscribe(); + + this.store.preferredLanguage$ + .pipe( + distinctUntilChange(), + filter((preferredLanguage: string) => !!preferredLanguage), + tap((preferredLanguage: string) => { + this.locale = preferredLanguage; + }), + untilDestroyed(this) + ) + .subscribe(); } /** @@ -52,7 +64,7 @@ export class DateFormatPipe implements PipeTransform { } if (isEmpty(locale)) { - locale = this.regionCode; + locale = this.locale; } if (date && defaultFormat) { From 380335857c35417aecbb580a8dc651f234a3cd84 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Tue, 22 Oct 2024 07:07:10 +0200 Subject: [PATCH 18/68] fix: add type validation for sprint entity --- .../core/src/organization-sprint/organization-sprint.entity.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/core/src/organization-sprint/organization-sprint.entity.ts b/packages/core/src/organization-sprint/organization-sprint.entity.ts index 1637d1b668d..df195e7720e 100644 --- a/packages/core/src/organization-sprint/organization-sprint.entity.ts +++ b/packages/core/src/organization-sprint/organization-sprint.entity.ts @@ -1,6 +1,7 @@ import { JoinColumn } from 'typeorm'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsDate, IsEnum, IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator'; +import { Type } from 'class-transformer'; import { isMySQL, isPostgres } from '@gauzy/config'; import { ID, @@ -56,12 +57,14 @@ export class OrganizationSprint extends TenantOrganizationBaseEntity implements @ApiPropertyOptional({ type: () => Date }) @IsDate() @IsOptional() + @Type(() => Date) @MultiORMColumn({ nullable: true }) startDate?: Date; @ApiPropertyOptional({ type: () => Date }) @IsDate() @IsOptional() + @Type(() => Date) @MultiORMColumn({ nullable: true }) endDate?: Date; From fa8c2ce9d7e59747718fecd9736c6fc921230502 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Tue, 22 Oct 2024 13:18:36 +0530 Subject: [PATCH 19/68] fix: register dynamic data-table columns for employee management page --- .../employees/employees-routing.module.ts | 72 ++- .../pages/employees/employees.component.html | 125 +++-- .../pages/employees/employees.component.ts | 510 ++++++++++-------- .../job-employee/job-employee.component.ts | 2 - .../lib/common/component-registry.types.ts | 5 +- .../page/page-data-table-registry.service.ts | 90 ++-- .../utils/smart-table/server.data-source.ts | 30 +- 7 files changed, 495 insertions(+), 339 deletions(-) diff --git a/apps/gauzy/src/app/pages/employees/employees-routing.module.ts b/apps/gauzy/src/app/pages/employees/employees-routing.module.ts index 1814434c172..88158b3d48d 100644 --- a/apps/gauzy/src/app/pages/employees/employees-routing.module.ts +++ b/apps/gauzy/src/app/pages/employees/employees-routing.module.ts @@ -18,25 +18,25 @@ import { } from './edit-employee/edit-employee-profile'; import { EmployeeResolver } from './employee.resolver'; -export function redirectTo() { - return '/pages/dashboard'; -} - const routes: Routes = [ { path: '', component: EmployeesComponent, canActivate: [PermissionsGuard], data: { + // The data table identifier for the route + dataTableId: 'employee-manage', + // The permission required to access the route permissions: { only: [PermissionsEnum.ORG_EMPLOYEES_VIEW], - redirectTo + redirectTo: '/pages/dashboard' }, + // The selectors for the route selectors: { + team: false, project: false, employee: false, - date: false, - team: false + date: false } } }, @@ -47,7 +47,7 @@ const routes: Routes = [ data: { permissions: { only: [PermissionsEnum.ORG_EMPLOYEES_EDIT, PermissionsEnum.PROFILE_EDIT], - redirectTo + redirectTo: '/pages/dashboard' } }, resolve: { @@ -64,9 +64,11 @@ const routes: Routes = [ component: EditEmployeeMainComponent, data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false } } }, @@ -75,9 +77,11 @@ const routes: Routes = [ component: EditEmployeeNetworksComponent, data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false } } }, @@ -86,9 +90,11 @@ const routes: Routes = [ component: EditEmployeeRatesComponent, data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false } } }, @@ -98,13 +104,15 @@ const routes: Routes = [ canActivate: [PermissionsGuard], data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false }, permissions: { only: [PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_PROJECT_VIEW], - redirectTo + redirectTo: '/pages/dashboard' } } }, @@ -113,9 +121,11 @@ const routes: Routes = [ component: EditEmployeeContactComponent, data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false } } }, @@ -124,9 +134,11 @@ const routes: Routes = [ component: EditEmployeeLocationComponent, data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false } } }, @@ -135,9 +147,11 @@ const routes: Routes = [ component: EditEmployeeHiringComponent, data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false } } }, @@ -146,9 +160,11 @@ const routes: Routes = [ component: EditEmployeeEmploymentComponent, data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false } } }, @@ -157,9 +173,11 @@ const routes: Routes = [ component: EditEmployeeOtherSettingsComponent, data: { selectors: { + team: false, project: false, - organization: false, - date: false + employee: false, + date: false, + organization: false } } } diff --git a/apps/gauzy/src/app/pages/employees/employees.component.html b/apps/gauzy/src/app/pages/employees/employees.component.html index 6e2530a5098..20a1b8709f5 100644 --- a/apps/gauzy/src/app/pages/employees/employees.component.html +++ b/apps/gauzy/src/app/pages/employees/employees.component.html @@ -12,7 +12,7 @@

- + @@ -44,10 +44,44 @@

- - + + + + +
+ +
+
+ + + +
+
+ + + +
+ +
+
+ + + +

{{ 'SETTINGS_MENU.NO_LAYOUT' | translate }}

+
+
@@ -57,6 +91,33 @@

+ + + + + + + + + + + + + + + + + +
@@ -146,57 +207,3 @@

- - - - - - - - - - - - - - -
- -
-
- - - -
-
- - -
- -
-
- - - - - diff --git a/apps/gauzy/src/app/pages/employees/employees.component.ts b/apps/gauzy/src/app/pages/employees/employees.component.ts index 20dd4e757f4..e2e800d377a 100644 --- a/apps/gauzy/src/app/pages/employees/employees.component.ts +++ b/apps/gauzy/src/app/pages/employees/employees.component.ts @@ -3,14 +3,14 @@ import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { HttpClient } from '@angular/common/http'; import { NbDialogService } from '@nebular/theme'; import { TranslateService } from '@ngx-translate/core'; -import { Cell } from 'angular2-smart-table'; -import { debounceTime, filter, tap } from 'rxjs/operators'; -import { Subject, firstValueFrom } from 'rxjs'; +import { Cell, IColumns, Settings } from 'angular2-smart-table'; +import { Subject, debounceTime, filter, firstValueFrom, tap } from 'rxjs'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { EmployeeStore, EmployeesService, ErrorHandlingService, + PageDataTableRegistryService, ServerDataSource, Store, ToastrService @@ -36,12 +36,12 @@ import { EmployeeStartWorkComponent, InputFilterComponent, InviteMutationComponent, + PaginationFilterBaseComponent, PictureNameTagsComponent, TagsColorFilterComponent, TagsOnlyComponent, ToggleFilterComponent } from '@gauzy/ui-core/shared'; -import { PaginationFilterBaseComponent, IPaginationBase } from '@gauzy/ui-core/shared'; import { EmployeeAverageBonusComponent, EmployeeAverageExpensesComponent, @@ -52,11 +52,12 @@ import { @UntilDestroy({ checkProperties: true }) @Component({ + selector: 'ga-employees-list', templateUrl: './employees.component.html', styleUrls: ['./employees.component.scss'] }) export class EmployeesComponent extends PaginationFilterBaseComponent implements OnInit, OnDestroy { - public settingsSmartTable: object; + public settingsSmartTable: Settings; public smartTableSource: ServerDataSource; public selectedEmployee: EmployeeViewModel; public employees: EmployeeViewModel[] = []; @@ -68,7 +69,6 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements public disableButton: boolean = true; public includeDeleted: boolean = false; public loading: boolean = false; - public organizationInvitesAllowed: boolean = false; public organization: IOrganization; public refresh$: Subject = new Subject(); public employees$: Subject = this.subject$; @@ -96,16 +96,17 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements private readonly _errorHandlingService: ErrorHandlingService, private readonly _employeeStore: EmployeeStore, private readonly _httpClient: HttpClient, - private readonly _dateFormatPipe: DateFormatPipe + private readonly _dateFormatPipe: DateFormatPipe, + private readonly _pageDataTableRegistryService: PageDataTableRegistryService ) { super(translateService); this.setView(); } ngOnInit() { + this._registerDataTableColumns(); this._loadSmartTableSettings(); - this._applyTranslationOnSmartTable(); - + this._subscribeToQueryParams(); this.employees$ .pipe( debounceTime(300), @@ -128,22 +129,12 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements distinctUntilChange(), filter((organization: IOrganization) => !!organization), tap((organization: IOrganization) => (this.organization = organization)), - tap(({ invitesAllowed }) => (this.organizationInvitesAllowed = invitesAllowed)), tap(() => this._additionalColumns()), tap(() => this.refresh$.next(true)), tap(() => this.employees$.next(true)), untilDestroyed(this) ) .subscribe(); - this._route.queryParamMap - .pipe( - filter((params: ParamMap) => !!params), - filter((params: ParamMap) => params.get('openAddDialog') === 'true'), - debounceTime(1000), - tap(() => this.add()), - untilDestroyed(this) - ) - .subscribe(); this.refresh$ .pipe( filter(() => this.dataLayoutStyle === ComponentLayoutStyleEnum.CARDS_GRID), @@ -154,6 +145,26 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements .subscribe(); } + ngAfterViewInit(): void { + this._applyTranslationOnSmartTable(); + } + + /** + * Subscribes to the query parameters and performs actions based on the 'openAddDialog' parameter. + */ + private _subscribeToQueryParams(): void { + this._route.queryParamMap + .pipe( + // Check if 'openAddDialog' is set to 'true' and filter out falsy values + filter((params: ParamMap) => params?.get('openAddDialog') === 'true'), + // Trigger the add method + tap(() => this.add()), + // Automatically unsubscribe when component is destroyed + untilDestroyed(this) + ) + .subscribe(); + } + /** * Checks if the current user has the necessary permissions to perform button actions. * @returns A boolean indicating whether the user has the required permissions. @@ -163,7 +174,10 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements } /** - * + * @description + * This method sets the view layout for the component based on the current layout configuration. + * It listens for layout changes from the store and updates the `dataLayoutStyle`. + * Depending on the layout (e.g., if it's `CARDS_GRID`), it clears the employee list and triggers a refresh. */ setView() { this._store @@ -597,46 +611,46 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements } /** + * Maps an IEmployee object to a formatted employee object. * - * @param employee - * @returns + * @param employee The IEmployee object to map. + * @returns The formatted employee object. */ private employeeMapper(employee: IEmployee) { const { id, - user, + user: { name, email, imageUrl } = {}, isActive, endWork, tags, - averageIncome, - averageExpenses, - averageBonus, + averageIncome = 0, + averageExpenses = 0, + averageBonus = 0, startedWorkOn, isTrackingEnabled, isDeleted } = employee; - /** - * "Range" when was hired and when exit - */ + // Format start and end work dates, and create the work status range const start = this._dateFormatPipe.transform(startedWorkOn, null, 'LL'); const end = this._dateFormatPipe.transform(endWork, null, 'LL'); const workStatus = [start, end].filter(Boolean).join(' - '); + + // Return the mapped object return { - fullName: `${user.name}`, - email: user.email, + fullName: name || '', // Ensure default values for safety + email: email || '', id, isActive, endWork: endWork ? new Date(endWork) : '', workStatus: endWork ? workStatus : '', - imageUrl: user.imageUrl, - tags, - // TODO: load real bonus and bonusDate - bonus: this.bonusForSelectedMonth, + imageUrl: imageUrl || '', + tags: tags || [], + bonus: this.bonusForSelectedMonth, // TODO: load real bonus and bonusDate averageIncome: Math.floor(averageIncome), averageExpenses: Math.floor(averageExpenses), averageBonus: Math.floor(averageBonus), - bonusDate: Date.now(), + bonusDate: Date.now(), // Placeholder for actual bonus date employeeId: id, employee, startedWorkOn, @@ -645,144 +659,219 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements }; } + /** + * Registers custom columns for the 'employee-manage' data table. + * This method defines and registers the columns with various properties, + * including a custom filter function and a rendering component. + */ + private _registerDataTableColumns(): void { + // Register the data table column + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'fullName', // The identifier for the column + order: 0, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.FULL_NAME'), // The title of the column + type: 'custom', // The type of the column + class: 'align-row', + width: '20%', // The width of the column + isFilterable: true, + renderComponent: PictureNameTagsComponent, + componentInitFunction: (instance: PictureNameTagsComponent, cell: Cell) => { + instance.rowData = cell.getRow().getData(); + instance.value = cell.getRawValue(); + }, + filter: { + type: 'custom', + component: InputFilterComponent + }, + filterFunction: (value: string) => { + this.setFilter({ field: 'user.name', search: value }); + return value.length > 0; // Return `true` if the value is non-empty, `false` otherwise + } + }); + + // Register the data table column + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'email', // The identifier for the column + order: 1, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.EMAIL'), // The title of the column + type: 'text', // The type of the column + class: 'align-row', + width: '20%', // The width of the column + isFilterable: true, + filter: { + type: 'custom', + component: InputFilterComponent + }, + // Use the custom filter function, passing the instance context + filterFunction: (value: string) => { + this.setFilter({ field: 'user.email', search: value }); + return value.length > 0; // Return `true` if the value is non-empty, `false` otherwise + } + }); + + // Register the data table column + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'averageIncome', // The identifier for the column + order: 2, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.INCOME'), // The title of the column + type: 'custom', // The type of the column + isFilterable: false, // Indicates whether the column is filterable + isSortable: true, // Indicates whether the column is sortable + class: 'text-center', // The class of the column + width: '5%', // The width of the column + renderComponent: EmployeeAverageIncomeComponent, // The component to render the column + componentInitFunction: (instance: EmployeeAverageIncomeComponent, cell: Cell) => { + instance.rowData = cell.getRow().getData(); + } + }); + + // Register the data table column + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'averageExpenses', // The identifier for the column + order: 3, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.EXPENSES'), // The title of the column + type: 'custom', // The type of the column + isFilterable: false, // Indicates whether the column is filterable + isSortable: true, // Indicates whether the column is sortable + class: 'text-center', // The class of the column + width: '5%', // The width of the column + renderComponent: EmployeeAverageExpensesComponent, // The component to render the column + componentInitFunction: (instance: EmployeeAverageExpensesComponent, cell: Cell) => { + instance.rowData = cell.getRow().getData(); + } + }); + + // Register the data table column + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'averageBonus', // The identifier for the column + order: 4, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.BONUS_AVG'), // The title of the column + type: 'custom', // The type of the column + isFilterable: false, // Indicates whether the column is filterable + isSortable: true, // Indicates whether the column is sortable + class: 'text-center', // The class of the column + width: '5%', // The width of the column + renderComponent: EmployeeAverageBonusComponent, // The component to render the column + componentInitFunction: (instance: EmployeeAverageBonusComponent, cell: Cell) => { + instance.rowData = cell.getRow().getData(); + } + }); + + // Register the data table column + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'isTrackingEnabled', // The identifier for the column + order: 5, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.TIME_TRACKING'), // The title of the column + type: 'custom', // The type of the column + isFilterable: true, // Indicates whether the column is filterable + isSortable: true, // Indicates whether the column is sortable + class: 'text-center', // The class of the column + width: '5%', // The width of the column + filter: { + type: 'custom', + component: ToggleFilterComponent + }, + filterFunction: (isTrackingEnabled: boolean) => { + this.setFilter({ field: 'isTrackingEnabled', search: isTrackingEnabled }); + return isTrackingEnabled; + }, + renderComponent: EmployeeTimeTrackingStatusComponent, // The component to render the column + componentInitFunction: (instance: EmployeeTimeTrackingStatusComponent, cell: Cell) => { + instance.rowData = cell.getRow().getData(); + } + }); + + // Register the data table column + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'tags', // The identifier for the column + order: 6, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.TAGS'), // The title of the column + type: 'custom', // The type of the column + width: '20%', // The width of the column + isFilterable: true, // Indicates whether the column is filterable + isSortable: false, + filter: { + type: 'custom', + component: TagsColorFilterComponent + }, + filterFunction: (tags: ITag[]) => { + // Extract tag IDs from the tags array + const tagIds = tags.map((tag) => tag.id); + // Set the filter to the tag IDs + this.setFilter({ field: 'tags', search: tagIds }); + return tags.length > 0; + }, + renderComponent: TagsOnlyComponent, // The component to render the column + componentInitFunction: (instance: TagsOnlyComponent, cell: Cell) => { + instance.rowData = cell.getRow().getData(); + instance.value = cell.getValue(); + } + }); + + // Register the data table column + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'workStatus', // The identifier for the column + order: 7, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.STATUS'), // The title of the column + type: 'custom', // The type of the column + class: 'text-center', // The class of the column + width: '5%', // The width of the column + isFilterable: true, // Indicates whether the column is filterable + isSortable: false, + filter: { + type: 'custom', + component: ToggleFilterComponent + }, + filterFunction: (isActive: boolean) => { + this.setFilter({ field: 'isActive', search: isActive }); + return isActive; + }, + renderComponent: EmployeeWorkStatusComponent, // The component to render the column + componentInitFunction: (instance: EmployeeWorkStatusComponent, cell: Cell) => { + instance.rowData = cell.getRow().getData(); + } + }); + } + + /** + * Retrieves the registered columns for the 'employee-manage' data table. + * + * This method fetches all the column configurations registered under the + * 'employee-manage' data table from the PageDataTableRegistryService. + * It returns the columns in the format of `IColumns`, which can be used for rendering or + * further manipulation in the smart table. + * + * @returns {IColumns} The column configurations for the 'employee-manage' table. + */ + getColumns(): IColumns { + // Fetch and return the columns for 'employee-manage' data table + return this._pageDataTableRegistryService.getPageDataTableColumns('employee-manage'); + } + /** * Load Smart Table settings */ private _loadSmartTableSettings() { - const pagination: IPaginationBase = this.getPagination(); + // Get pagination settings + const { itemsPerPage } = this.getPagination() || { itemsPerPage: this.minItemPerPage }; + + // Configure Smart Table settings this.settingsSmartTable = { actions: false, - selectedRowIndex: -1, + noDataMessage: this.getTranslation('SM_TABLE.NO_DATA.EMPLOYEE'), pager: { display: false, - perPage: pagination ? pagination.itemsPerPage : this.minItemPerPage + perPage: itemsPerPage }, - noDataMessage: this.getTranslation('SM_TABLE.NO_DATA.EMPLOYEE'), - columns: { - fullName: { - title: this.getTranslation('SM_TABLE.FULL_NAME'), - type: 'custom', - class: 'align-row', - width: '20%', - renderComponent: PictureNameTagsComponent, - componentInitFunction: (instance: PictureNameTagsComponent, cell: Cell) => { - instance.rowData = cell.getRow().getData(); - instance.value = cell.getRawValue(); - }, - filter: { - type: 'custom', - component: InputFilterComponent - }, - filterFunction: (value: string) => { - this.setFilter({ field: 'user.name', search: value }); - } - }, - email: { - title: this.getTranslation('SM_TABLE.EMAIL'), - type: 'email', - class: 'email-column', - width: '20%', - filter: { - type: 'custom', - component: InputFilterComponent - }, - filterFunction: (value: string) => { - this.setFilter({ field: 'user.email', search: value }); - } - }, - averageIncome: { - title: this.getTranslation('SM_TABLE.INCOME'), - type: 'custom', - isFilterable: false, - class: 'text-center', - width: '5%', - renderComponent: EmployeeAverageIncomeComponent, - componentInitFunction: (instance: EmployeeAverageIncomeComponent, cell: Cell) => { - instance.rowData = cell.getRow().getData(); - } - }, - averageExpenses: { - title: this.getTranslation('SM_TABLE.EXPENSES'), - type: 'custom', - isFilterable: false, - class: 'text-center', - width: '5%', - renderComponent: EmployeeAverageExpensesComponent, - componentInitFunction: (instance: EmployeeAverageExpensesComponent, cell: Cell) => { - instance.rowData = cell.getRow().getData(); - } - }, - averageBonus: { - title: this.getTranslation('SM_TABLE.BONUS_AVG'), - type: 'custom', - isFilterable: false, - class: 'text-center', - width: '5%', - renderComponent: EmployeeAverageBonusComponent, - componentInitFunction: (instance: EmployeeAverageBonusComponent, cell: Cell) => { - instance.rowData = cell.getRow().getData(); - } - }, - isTrackingEnabled: { - title: this.getTranslation('SM_TABLE.TIME_TRACKING'), - type: 'custom', - class: 'text-center', - width: '5%', - renderComponent: EmployeeTimeTrackingStatusComponent, - componentInitFunction: (instance: EmployeeTimeTrackingStatusComponent, cell: Cell) => { - instance.rowData = cell.getRow().getData(); - }, - filter: { - type: 'custom', - component: ToggleFilterComponent - }, - filterFunction: (checked: boolean) => { - this.setFilter({ - field: 'isTrackingEnabled', - search: checked - }); - } - }, - tags: { - title: this.getTranslation('SM_TABLE.TAGS'), - type: 'custom', - width: '20%', - renderComponent: TagsOnlyComponent, - componentInitFunction: (instance: TagsOnlyComponent, cell: Cell) => { - instance.rowData = cell.getRow().getData(); - instance.value = cell.getValue(); - }, - filter: { - type: 'custom', - component: TagsColorFilterComponent - }, - filterFunction: (tags: ITag[]) => { - const tagIds = []; - for (const tag of tags) { - tagIds.push(tag.id); - } - this.setFilter({ field: 'tags', search: tagIds }); - }, - isSortable: false - }, - workStatus: { - title: this.getTranslation('SM_TABLE.STATUS'), - type: 'custom', - class: 'text-center', - width: '5%', - renderComponent: EmployeeWorkStatusComponent, - componentInitFunction: (instance: EmployeeWorkStatusComponent, cell: Cell) => { - instance.rowData = cell.getRow().getData(); - }, - filter: { - type: 'custom', - component: ToggleFilterComponent - }, - filterFunction: (isActive: boolean) => { - this.setFilter({ field: 'isActive', search: isActive }); - } - } - } + columns: { ...this.getColumns() } }; } @@ -799,52 +888,50 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements // Destructure properties for clarity const { allowScreenshotCapture } = this.organization; - // Check if screenshot capture is allowed - if (allowScreenshotCapture) { - // Configure the additional column for screenshot capture - this.settingsSmartTable['columns']['allowScreenshotCapture'] = { - title: this.getTranslation('SM_TABLE.SCREEN_CAPTURE'), + // Check if screenshot capture is allowed and hide the column if not + this._pageDataTableRegistryService.registerPageDataTableColumn({ + dataTableId: 'employee-manage', // The identifier for the data table location + columnId: 'allowScreenshotCapture', // The identifier for the column + order: 8, // The order of the column in the table + title: () => this.getTranslation('SM_TABLE.SCREEN_CAPTURE'), // The title of the column + type: 'custom', // The type of the column + class: 'text-center', // The class of the column + width: '5%', // The width of the column + isFilterable: true, // Indicates whether the column is filterable + isSortable: false, + hide: allowScreenshotCapture === false, + filter: { type: 'custom', - class: 'text-center', - editable: false, - addable: false, - notShownField: true, - // Configure custom filter for the column - filter: { - type: 'custom', - component: ToggleFilterComponent - }, - // Define filter function to update the filter settings - filterFunction: (isEnable: boolean) => { - this.setFilter({ - field: 'allowScreenshotCapture', - search: isEnable - }); - }, - // Configure custom component for rendering the column - renderComponent: AllowScreenshotCaptureComponent, - // Initialize component function to set initial values - componentInitFunction: (instance: AllowScreenshotCaptureComponent, cell: Cell) => { - instance.rowData = cell.getRow().getData(); - instance.value = cell.getValue(); - - // Subscribe to the allowScreenshotCaptureChange event - instance.allowScreenshotCaptureChange.subscribe({ - next: (isAllow: boolean) => { - // Clear selected items and update allowScreenshotCapture - this.clearItem(); - this._updateAllowScreenshotCapture(instance.rowData, isAllow); - }, - error: (err: any) => { - console.warn(err); - } - }); - } - }; - } + component: ToggleFilterComponent + }, + filterFunction: (isEnable: boolean) => { + this.setFilter({ field: 'allowScreenshotCapture', search: isEnable }); + return isEnable; + }, + renderComponent: AllowScreenshotCaptureComponent, // The component to render the column + componentInitFunction: (instance: AllowScreenshotCaptureComponent, cell: Cell) => { + instance.rowData = cell.getRow().getData(); + instance.value = cell.getValue(); + + // Subscribe to the allowScreenshotCaptureChange event + instance.allowScreenshotCaptureChange.subscribe({ + next: (isAllow: boolean) => { + // Clear selected items and update allowScreenshotCapture + this.clearItem(); + this._updateAllowScreenshotCapture(instance.rowData, isAllow); + }, + error: (err: any) => { + console.warn(err); + } + }); + } + }); - // Copy the settingsSmartTable to trigger change detection - this.settingsSmartTable = { ...this.settingsSmartTable }; + // Update the settingsSmartTable with the new columns + this.settingsSmartTable = { + ...this.settingsSmartTable, + columns: this.getColumns() + }; } /** @@ -901,10 +988,7 @@ export class EmployeesComponent extends PaginationFilterBaseComponent implements * Clear selected item */ clearItem() { - this.selectEmployee({ - isSelected: false, - data: null - }); + this.selectEmployee({ isSelected: false, data: null }); } /** diff --git a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts index a538278d573..2dba511bcb6 100644 --- a/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts +++ b/packages/plugins/job-employee-ui/src/lib/components/job-employee/job-employee.component.ts @@ -14,7 +14,6 @@ import { API_PREFIX, distinctUntilChange, isNotNullOrUndefined } from '@gauzy/ui import { PageDataTableRegistryService, EmployeesService, - JobService, ServerDataSource, Store, ToastrService, @@ -77,7 +76,6 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen private readonly _ngxPermissionsService: NgxPermissionsService, private readonly _store: Store, private readonly _employeesService: EmployeesService, - private readonly _jobService: JobService, private readonly _jobSearchStoreService: JobSearchStoreService, private readonly _toastrService: ToastrService, private readonly _currencyPipe: CurrencyPipe, diff --git a/packages/ui-core/core/src/lib/common/component-registry.types.ts b/packages/ui-core/core/src/lib/common/component-registry.types.ts index b68d6a2e4ab..98174b6146b 100644 --- a/packages/ui-core/core/src/lib/common/component-registry.types.ts +++ b/packages/ui-core/core/src/lib/common/component-registry.types.ts @@ -72,6 +72,7 @@ export type PageTabsetRegistryId = 'dashboard' | 'timesheet' | 'time-activity'; * on the context and requirements of the application. * * Possible values: - * - 'job-employee': A sub-page under the jobs section. + * - 'employee-manage': Employee management page + * - 'job-employee': Sub-page under the jobs section (Job employee management page) */ -export type PageDataTableRegistryId = 'job-employee'; +export type PageDataTableRegistryId = 'employee-manage' | 'job-employee'; diff --git a/packages/ui-core/core/src/lib/services/page/page-data-table-registry.service.ts b/packages/ui-core/core/src/lib/services/page/page-data-table-registry.service.ts index 3c9d3f50a80..f11b538a5cb 100644 --- a/packages/ui-core/core/src/lib/services/page/page-data-table-registry.service.ts +++ b/packages/ui-core/core/src/lib/services/page/page-data-table-registry.service.ts @@ -88,11 +88,46 @@ export class PageDataTableRegistryService implements IPageDataTableRegistry { * `PageDataTableRegistryId`. If any configurations are found, they are sorted based on their `order` property in * ascending order. If no configurations are found, an empty array is returned. * - * @param location - The identifier used to look up the data table column configurations. - * @returns An array of `PageDataTableRegistryConfig` objects sorted by the `order` property, or an empty array if none are found. + * @param dataTableId The identifier for the data table. + * @returns An array of `PageDataTableRegistryConfig` objects associated with the specified `dataTableId`, + * sorted by the `order` property in ascending order. */ - private getDataTableColumnsByOrder(location: PageDataTableRegistryId): PageDataTableRegistryConfig[] { - return this.registry.get(location)?.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)) || []; + public getColumnsByDataTableId(dataTableId: PageDataTableRegistryId): PageDataTableRegistryConfig[] { + const columns = this.registry.get(dataTableId) || []; + + // Sort the columns by the 'order' property in ascending order + return columns.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)); + } + + /** + * Maps a PageDataTableRegistryConfig object to an IColumn object. + * + * @param config The PageDataTableRegistryConfig object to map. + * @returns The corresponding IColumn object. + */ + private mapConfigToColumn(config: PageDataTableRegistryConfig): IColumn { + const column: IColumn = { + ...(config.title && { title: typeof config.title === 'function' ? config.title() : config.title }), + type: config.type, + width: config.width, + isSortable: config.isSortable ?? false, + isEditable: config.isEditable ?? false, + isFilterable: config.isFilterable ?? false, + hide: config.hide ?? false, + ...(config.editor && { editor: config.editor }), + ...(config.renderComponent && { renderComponent: config.renderComponent }), + ...(config.valuePrepareFunction && { valuePrepareFunction: config.valuePrepareFunction }), + ...(config.componentInitFunction && { componentInitFunction: config.componentInitFunction }), + ...(config.filter && { filter: config.filter }), + ...(config.filterFunction && { filterFunction: config.filterFunction }) + }; + + // Check if the column configuration has additional column options + if (config.column) { + Object.assign(column, config.column); + } + + return column; // Return the mapped IColumn object } /** @@ -111,7 +146,7 @@ export class PageDataTableRegistryService implements IPageDataTableRegistry { */ public getPageDataTableColumns(dataTableId: PageDataTableRegistryId): IColumns { // Get all registered columns for the specified location - let columns = this.getDataTableColumnsByOrder(dataTableId); + let columns = this.getColumnsByDataTableId(dataTableId); // Use a Set to track unique location-id combinations const dataTableIds = new Set(); @@ -122,7 +157,7 @@ export class PageDataTableRegistryService implements IPageDataTableRegistry { const identifier = `${config.dataTableId}-${config.columnId}`; // Check if the unique identifier is already in the Set - if (dataTableIds.has(identifier)) { + if (dataTableIds.has(identifier) || config.hide) { return false; // Duplicate found, filter it out } @@ -133,37 +168,26 @@ export class PageDataTableRegistryService implements IPageDataTableRegistry { // Map each unique configuration to an IColumn object return columns.reduce((acc: IColumns, config: PageDataTableRegistryConfig) => { - // Create and return a new IColumn object - const column: IColumn = { - ...(config.title && { - title: typeof config.title === 'function' ? config.title() : config.title - }), - type: config.type, - width: config.width, - isSortable: config.isSortable ?? false, - isEditable: config.isEditable ?? false, - ...(config.editor && { editor: config.editor }), - ...(config.renderComponent && { renderComponent: config.renderComponent }), - ...(config.valuePrepareFunction && { - valuePrepareFunction: (rawValue: any, cell: Cell) => config.valuePrepareFunction(rawValue, cell) - }), - ...(config.componentInitFunction && { - componentInitFunction: (component: any, cell: Cell) => config.componentInitFunction(component, cell) - }) - }; - - // Check if the column configuration has additional column options - if (config.column) { - Object.assign(column, config.column); - } - - // Add the column configuration to the accumulator object with the columnId as the key - acc[config.columnId] = column; - + const column = this.mapConfigToColumn(config); // Use the mapping function + acc[config.columnId] = column; // Add the column to the accumulator return acc; }, {}); } + /** + * Retrieves a specific column configuration by its dataTableId and columnId. + * + * @param dataTableId The identifier for the data table. + * @param columnId The identifier for the column. + * @returns The `IColumn` object for the specified column, or `null` if not found. + */ + public getColumnById(dataTableId: PageDataTableRegistryId, columnId: string): IColumns | null { + const columns = this.registry.get(dataTableId) || []; + const config = columns.find((column) => column.columnId === columnId); + + return config ? { [columnId]: this.mapConfigToColumn(config) } : null; + } + /** * Deletes a data table from the registry. * diff --git a/packages/ui-core/core/src/lib/utils/smart-table/server.data-source.ts b/packages/ui-core/core/src/lib/utils/smart-table/server.data-source.ts index 66bc462d75b..68fcb3a7622 100644 --- a/packages/ui-core/core/src/lib/utils/smart-table/server.data-source.ts +++ b/packages/ui-core/core/src/lib/utils/smart-table/server.data-source.ts @@ -104,16 +104,40 @@ export class ServerDataSource extends LocalDataSource { return toParams(requestParams); } - protected addSortRequestParams() { + /** + * Adds sorting parameters to the request based on the sorting configuration. + * + * This function processes the `sortConf` configuration and extracts the field + * and its direction (ascending or descending) to create a sorting object. + * If a field does not have a valid direction, it will be skipped, and a warning + * will be logged. The resulting sorting parameters are returned as part of an + * object that can be used in a request. + * + * @returns {Object} An object containing the sorting parameters. + */ + protected addSortRequestParams(): { [key: string]: any } { if (this.sortConf) { - const orders: any = {}; + // Initialize an object to hold sorting orders + const orders: { [key: string]: string } = {}; + + // Iterate through the sort configuration array this.sortConf.forEach((fieldConf) => { - orders[fieldConf.field] = fieldConf.direction.toUpperCase(); + // Ensure the field configuration has a valid direction + if (fieldConf.direction) { + // Convert direction to uppercase (e.g., ASC or DESC) and add it to orders + orders[fieldConf.field] = fieldConf.direction.toUpperCase(); + } else { + // Log a warning if the direction is not defined + console.warn(`Direction is not defined for field: ${fieldConf.field}`); + } }); + + // Return the sorting orders wrapped in the expected format return { [this.conf.sortDirKey]: orders }; } else { + // Return an empty object if there is no sorting configuration return {}; } } From ae68c885264b6c79d5814d61dd67b3852bbf8bbb Mon Sep 17 00:00:00 2001 From: samuelmbabhazi Date: Tue, 22 Oct 2024 09:58:46 +0200 Subject: [PATCH 20/68] avoid undefined locale --- packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts b/packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts index 0a28c394306..44bfa1be68b 100644 --- a/packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts +++ b/packages/ui-core/shared/src/lib/pipes/date-format.pipe.ts @@ -14,7 +14,7 @@ import { Store } from '@gauzy/ui-core/core'; export class DateFormatPipe implements PipeTransform { dateFormat: string = 'd MMMM, y'; regionCode: string = RegionsEnum.EN; - locale!: string; + locale: string; constructor(private readonly store: Store) { this.store.selectedOrganization$ @@ -64,7 +64,7 @@ export class DateFormatPipe implements PipeTransform { } if (isEmpty(locale)) { - locale = this.locale; + locale = this.locale || this.regionCode; } if (date && defaultFormat) { From a40fc0aff185d5d9a856d43692b658819292be48 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Tue, 22 Oct 2024 14:10:21 +0530 Subject: [PATCH 21/68] fix(deepscan): removed unused 'Cell' property --- .../src/lib/services/page/page-data-table-registry.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-core/core/src/lib/services/page/page-data-table-registry.service.ts b/packages/ui-core/core/src/lib/services/page/page-data-table-registry.service.ts index f11b538a5cb..360106da016 100644 --- a/packages/ui-core/core/src/lib/services/page/page-data-table-registry.service.ts +++ b/packages/ui-core/core/src/lib/services/page/page-data-table-registry.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { Cell, IColumn, IColumns } from 'angular2-smart-table'; +import { IColumn, IColumns } from 'angular2-smart-table'; import { PageDataTableRegistryId } from '../../common/component-registry.types'; import { IPageDataTableRegistry, PageDataTableRegistryConfig } from './page-data-table-registry.types'; From 9d16b4734b0a483577252f1aa5ee97892a4d810e Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Tue, 22 Oct 2024 14:34:49 +0530 Subject: [PATCH 22/68] fix: correct the property syntax --- apps/gauzy/src/app/pages/employees/employees.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gauzy/src/app/pages/employees/employees.component.html b/apps/gauzy/src/app/pages/employees/employees.component.html index 20a1b8709f5..5adff6fe806 100644 --- a/apps/gauzy/src/app/pages/employees/employees.component.html +++ b/apps/gauzy/src/app/pages/employees/employees.component.html @@ -95,7 +95,7 @@

- +

+ + + {{ 'ORGANIZATIONS_PAGE.EDIT.SETTINGS.TIMER_SETTINGS' | translate }} + + +
+
+
+
+ + {{ 'ORGANIZATIONS_PAGE.EDIT.SETTINGS.ALLOW_MANUAL_TIME' | translate }} + + +
+
+
+
+ + {{ 'ORGANIZATIONS_PAGE.EDIT.SETTINGS.ALLOW_MODIFY_TIME' | translate }} + + +
+
+
+
+ + {{ 'ORGANIZATIONS_PAGE.EDIT.SETTINGS.ALLOW_DELETE_TIME' | translate }} + + +
+
+ +
+ + {{ 'ORGANIZATIONS_PAGE.EDIT.SETTINGS.ALLOW_SCREEN_CAPTURE' | translate }} + + +
+
+
+
+
{{ 'EMPLOYEES_PAGE.EDIT_EMPLOYEE.INTEGRATIONS' | translate }} diff --git a/apps/gauzy/src/app/pages/employees/edit-employee/edit-employee-profile/edit-employee-settings/edit-employee-other-settings.component.scss b/apps/gauzy/src/app/pages/employees/edit-employee/edit-employee-profile/edit-employee-settings/edit-employee-other-settings.component.scss index f39bdbd2305..ce5a3031253 100644 --- a/apps/gauzy/src/app/pages/employees/edit-employee/edit-employee-profile/edit-employee-settings/edit-employee-other-settings.component.scss +++ b/apps/gauzy/src/app/pages/employees/edit-employee/edit-employee-profile/edit-employee-settings/edit-employee-other-settings.component.scss @@ -303,3 +303,22 @@ nb-accordion { width: 100%; } } +:host ::ng-deep nb-toggle { + padding: 10px; + border: 1px solid nb-theme(gauzy-border-default-color); + border-radius: nb-theme(border-radius); + & > label { + margin-bottom: 0; + } +} +:host ::ng-deep .toggle { + border: 1px solid #7e7e8f !important; + background-color: #7e7e8f !important; + &.checked { + background-color: nb-theme(text-primary-color) !important; + border: 1px solid nb-theme(text-primary-color) !important; + & + span { + color: nb-theme(text-primary-color); + } + } +} diff --git a/apps/gauzy/src/app/pages/employees/edit-employee/edit-employee-profile/edit-employee-settings/edit-employee-other-settings.component.ts b/apps/gauzy/src/app/pages/employees/edit-employee/edit-employee-profile/edit-employee-settings/edit-employee-other-settings.component.ts index ab62a34c899..2b41a8fa041 100644 --- a/apps/gauzy/src/app/pages/employees/edit-employee/edit-employee-profile/edit-employee-settings/edit-employee-other-settings.component.ts +++ b/apps/gauzy/src/app/pages/employees/edit-employee/edit-employee-profile/edit-employee-settings/edit-employee-other-settings.component.ts @@ -32,6 +32,7 @@ export class EditEmployeeOtherSettingsComponent implements OnInit, OnDestroy { */ @ViewChild('general') general: NbAccordionItemComponent; @ViewChild('integrations') integrations: NbAccordionItemComponent; + @ViewChild('timer') timer: NbAccordionItemComponent; /** * Employee other settings settings @@ -42,7 +43,11 @@ export class EditEmployeeOtherSettingsComponent implements OnInit, OnDestroy { timeZone: [], timeFormat: [], upworkId: [], - linkedInId: [] + linkedInId: [], + allowManualTime: [], + allowModifyTime: [], + allowDeleteTime: [], + allowScreenshotCapture: [] }); } @@ -82,7 +87,11 @@ export class EditEmployeeOtherSettingsComponent implements OnInit, OnDestroy { timeZone: user.timeZone || moment.tz.guess(), // set current timezone, if employee don't have any timezone timeFormat: user.timeFormat, upworkId: employee.upworkId, - linkedInId: employee.linkedInId + linkedInId: employee.linkedInId, + allowManualTime: employee.allowManualTime, + allowDeleteTime: employee.allowDeleteTime, + allowModifyTime: employee.allowModifyTime, + allowScreenshotCapture: employee.allowScreenshotCapture }); this.form.updateValueAndValidity(); } @@ -97,7 +106,16 @@ export class EditEmployeeOtherSettingsComponent implements OnInit, OnDestroy { return; } const { organizationId, tenantId } = this.selectedEmployee; - const { timeZone, timeFormat, upworkId, linkedInId } = this.form.value; + const { + timeZone, + timeFormat, + upworkId, + linkedInId, + allowScreenshotCapture, + allowManualTime, + allowModifyTime, + allowDeleteTime + } = this.form.value; /** Update user fields */ this.employeeStore.userForm = { @@ -110,7 +128,11 @@ export class EditEmployeeOtherSettingsComponent implements OnInit, OnDestroy { upworkId, linkedInId, organizationId, - tenantId + tenantId, + allowManualTime, + allowModifyTime, + allowDeleteTime, + allowScreenshotCapture }; } diff --git a/packages/contracts/src/employee.model.ts b/packages/contracts/src/employee.model.ts index 8192d8cf5e5..3bbd3957f24 100644 --- a/packages/contracts/src/employee.model.ts +++ b/packages/contracts/src/employee.model.ts @@ -113,6 +113,10 @@ export interface IEmployee extends IBasePerTenantAndOrganizationEntityModel, ITa isTrackingEnabled: boolean; isDeleted?: boolean; allowScreenshotCapture?: boolean; + allowManualTime?: boolean; + allowModifyTime?: boolean; + allowDeleteTime?: boolean; + /** Upwork ID For Gauzy AI*/ upworkId?: string; /** LinkedIn ID For Gauzy AI*/ @@ -123,9 +127,6 @@ export interface IEmployee extends IBasePerTenantAndOrganizationEntityModel, ITa isTrackingTime?: boolean; // True mean active, false away isAway?: boolean; - allowManualTime?: boolean; - allowModifyTime?: boolean; - allowDeleteTime?: boolean; } export type IEmployeeJobsStatisticsResponse = IEmployee & IEmployeeJobsStatistics; @@ -179,6 +180,9 @@ export interface IEmployeeUpdateInput extends IBasePerTenantAndOrganizationEntit upworkUrl?: string; profile_link?: string; allowScreenshotCapture?: boolean; + allowManualTime?: boolean; + allowModifyTime?: boolean; + allowDeleteTime?: boolean; /** Upwork ID For Gauzy AI*/ upworkId?: string; /** LinkedIn ID For Gauzy AI*/ From f51bd5644d1f064f355ad8d866cbc8d4808a4f82 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Wed, 23 Oct 2024 16:37:39 +0530 Subject: [PATCH 28/68] feat: add settings nav menu --- .../settings-nav-menu.component.html | 1 + .../settings-nav-menu.component.scss | 0 .../settings-nav-menu.component.ts | 24 +++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.html create mode 100644 packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.scss create mode 100644 packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.ts diff --git a/packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.html b/packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.html new file mode 100644 index 00000000000..f9bc7901699 --- /dev/null +++ b/packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.html @@ -0,0 +1 @@ + diff --git a/packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.scss b/packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.ts b/packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.ts new file mode 100644 index 00000000000..153361b7698 --- /dev/null +++ b/packages/ui-core/core/src/lib/components/settings-nav-menu/settings-nav-menu.component.ts @@ -0,0 +1,24 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable, map } from 'rxjs'; +import { NavMenuSectionItem } from '../../services/nav-builder/nav-builder-types'; +import { BaseNavMenuComponent } from '../base-nav-menu/base-nav-menu.component'; + +@Component({ + selector: 'ga-settings-nav-menu', + templateUrl: './settings-nav-menu.component.html', + styleUrls: ['./settings-nav-menu.component.scss'] +}) +export class SettingsNavMenuComponent extends BaseNavMenuComponent implements OnInit { + public settingsMenuConfig$: Observable; + + override ngOnInit(): void { + super.ngOnInit(); // Call the parent class's ngOnInit function + + // Subscribe to the menuConfig$ observable provided by _navMenuBuilderService + this.settingsMenuConfig$ = this._navMenuBuilderService.menuConfig$.pipe( + map((sections: NavMenuSectionItem[]) => + this.mapMenuSections(sections).filter((s) => s.menuCategory === 'settings') + ) + ); + } +} From 7076fcd0d5f24a3c6d53664269fa5e667157b1bf Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Wed, 23 Oct 2024 17:01:45 +0530 Subject: [PATCH 29/68] fix: prettier formatting --- .../server/src/assets/styles/gauzy/_gauzy-dialogs.scss | 2 +- apps/server/src/assets/styles/gauzy/_gauzy-table.scss | 2 +- apps/server/src/assets/styles/gauzy/index.ts | 2 +- .../server/src/assets/styles/gauzy/theme.gauzy-dark.ts | 10 ++-------- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/server/src/assets/styles/gauzy/_gauzy-dialogs.scss b/apps/server/src/assets/styles/gauzy/_gauzy-dialogs.scss index b5c00201c50..b3b2a2c797b 100644 --- a/apps/server/src/assets/styles/gauzy/_gauzy-dialogs.scss +++ b/apps/server/src/assets/styles/gauzy/_gauzy-dialogs.scss @@ -113,4 +113,4 @@ $shadow: 0 0 0 nb-theme(button-outline-width) rgba($color: $green, } @include dialog(var(--gauzy-card-1), var(--gauzy-sidebar-background-4)); -} \ No newline at end of file +} diff --git a/apps/server/src/assets/styles/gauzy/_gauzy-table.scss b/apps/server/src/assets/styles/gauzy/_gauzy-table.scss index ad4334cda60..a66381765ad 100644 --- a/apps/server/src/assets/styles/gauzy/_gauzy-table.scss +++ b/apps/server/src/assets/styles/gauzy/_gauzy-table.scss @@ -110,4 +110,4 @@ button { border-radius: nb-theme(border-radius); box-shadow: var(--gauzy-shadow) inset; } -} \ No newline at end of file +} diff --git a/apps/server/src/assets/styles/gauzy/index.ts b/apps/server/src/assets/styles/gauzy/index.ts index 178f1f36dbc..368e51a156c 100644 --- a/apps/server/src/assets/styles/gauzy/index.ts +++ b/apps/server/src/assets/styles/gauzy/index.ts @@ -1,2 +1,2 @@ export * from './theme.gauzy-dark'; -export * from './theme.gauzy-light'; \ No newline at end of file +export * from './theme.gauzy-light'; diff --git a/apps/server/src/assets/styles/gauzy/theme.gauzy-dark.ts b/apps/server/src/assets/styles/gauzy/theme.gauzy-dark.ts index 4ec88895401..698f56a65a1 100644 --- a/apps/server/src/assets/styles/gauzy/theme.gauzy-dark.ts +++ b/apps/server/src/assets/styles/gauzy/theme.gauzy-dark.ts @@ -45,18 +45,12 @@ const theme = { export const GAUZY_DARK = { name: 'gauzy-dark', - base: 'dark', + base: 'dark', variables: { ...theme, temperature: { - arcFill: [ - theme.primary, - theme.primary, - theme.primary, - theme.primary, - theme.primary - ], + arcFill: [theme.primary, theme.primary, theme.primary, theme.primary, theme.primary], arcEmpty: theme.bg2, thumbBg: theme.bg2, thumbBorder: theme.primary From 72b2cf8aace7a9aacf9adc34e63f119a3f66e6d1 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Wed, 23 Oct 2024 17:05:55 +0530 Subject: [PATCH 30/68] feat: registered settings menu into base nan menu component --- .../base-nav-menu/base-nav-menu.component.ts | 221 +++++++++++++++++- .../src/lib/components/common-nav.module.ts | 14 +- 2 files changed, 225 insertions(+), 10 deletions(-) diff --git a/packages/ui-core/core/src/lib/components/base-nav-menu/base-nav-menu.component.ts b/packages/ui-core/core/src/lib/components/base-nav-menu/base-nav-menu.component.ts index 2c34b3ad464..00ccaa192c4 100644 --- a/packages/ui-core/core/src/lib/components/base-nav-menu/base-nav-menu.component.ts +++ b/packages/ui-core/core/src/lib/components/base-nav-menu/base-nav-menu.component.ts @@ -46,6 +46,18 @@ export class BaseNavMenuComponent extends TranslationBaseComponent implements On */ private defineBaseNavMenus() { this._navMenuBuilderService.defineNavMenuSections([ + ...this._getMainMenu(), + ...this._getAccordionMenu(), + ...this._getSettingsMenu() + ]); + } + + /** + * Retrieves the main navigation menu configuration. + * @returns An array of NavMenuSectionItem objects representing the main menu. + */ + private _getMainMenu(): NavMenuSectionItem[] { + return [ { id: 'dashboards', title: 'Dashboards', @@ -877,7 +889,214 @@ export class BaseNavMenuComponent extends TranslationBaseComponent implements On } ] } - ]); + ]; + } + + /** + * Retrieves the accordion menu configuration based on user permissions. + * Each menu item includes an ID, title, icon, link, and additional data such as translation keys, + * permission keys, and feature keys. + * + * @returns An array of NavMenuSectionItem objects representing the accordion menu. + */ + private _getAccordionMenu(): NavMenuSectionItem[] { + return [ + { + id: 'invite-people', + title: 'Invite people', + icon: 'fas fa-user-plus', + link: '/pages/employees/invites', + menuCategory: 'accordion', + data: { + translationKey: 'MENU.INVITE_PEOPLE', + permissionKeys: [PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_INVITE_VIEW], + featureKey: FeatureEnum.FEATURE_MANAGE_INVITE + } + }, + { + id: 'users', + title: 'Users', + icon: 'fas fa-users', + link: '/pages/users', + menuCategory: 'accordion', + data: { + translationKey: 'MENU.USERS', + permissionKeys: [PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_USERS_VIEW], + featureKey: FeatureEnum.FEATURE_USER + } + }, + { + id: 'import-export', + title: 'Import/Export', + icon: 'fas fa-exchange-alt', + link: '/pages/settings/import-export', + menuCategory: 'accordion', + data: { + translationKey: 'MENU.IMPORT_EXPORT.IMPORT_EXPORT', + permissionKeys: [ + PermissionsEnum.ALL_ORG_VIEW, + PermissionsEnum.IMPORT_ADD, + PermissionsEnum.EXPORT_ADD + ], + featureKey: FeatureEnum.FEATURE_IMPORT_EXPORT + } + }, + { + id: 'organizations', + title: 'Organizations', + icon: 'fas fa-globe', + link: '/pages/organizations', + menuCategory: 'accordion', + data: { + translationKey: 'MENU.ORGANIZATIONS', + permissionKeys: [PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_EXPENSES_EDIT], + featureKey: FeatureEnum.FEATURE_ORGANIZATIONS + } + }, + { + id: 'integrations', + title: 'Integrations', + icon: 'fas fa-swatchbook', + link: '/pages/integrations', + menuCategory: 'accordion', + pathMatch: 'prefix', + data: { + translationKey: 'MENU.INTEGRATIONS', + permissionKeys: [PermissionsEnum.INTEGRATION_ADD, PermissionsEnum.INTEGRATION_EDIT], + featureKey: FeatureEnum.FEATURE_APP_INTEGRATION + } + } + ]; + } + + /** + * Retrieves the settings menu configuration. + * + * @returns An array containing a single NavMenuSectionItem for settings. + */ + private _getSettingsMenu(): NavMenuSectionItem[] { + return [ + { + id: 'settings', + title: 'Settings', + icon: 'fas fa-cog', + menuCategory: 'settings', + data: { + translationKey: 'MENU.SETTINGS' + }, + items: [ + { + id: 'settings-general', + title: 'General', + icon: 'fas fa-pen', + link: '/pages/settings/general', + data: { + translationKey: 'MENU.GENERAL', + featureKey: FeatureEnum.FEATURE_SETTING + } + }, + { + id: 'settings-features', + title: 'Features', + icon: 'fas fa-swatchbook', + link: '/pages/settings/features', + data: { + translationKey: 'MENU.FEATURES', + permissionKeys: [PermissionsEnum.ALL_ORG_EDIT, PermissionsEnum.ALL_ORG_VIEW] + } + }, + { + id: 'settings-email-history', + title: 'Email History', + icon: 'fas fa-envelope-open', + link: '/pages/settings/email-history', + data: { + translationKey: 'MENU.EMAIL_HISTORY', + permissionKeys: [PermissionsEnum.VIEW_ALL_EMAILS], + featureKey: FeatureEnum.FEATURE_EMAIL_HISTORY + } + }, + { + id: 'settings-email-templates', + title: 'Email Templates', + icon: 'fas fa-envelope', + link: '/pages/settings/email-templates', + data: { + translationKey: 'MENU.EMAIL_TEMPLATES', + permissionKeys: [PermissionsEnum.VIEW_ALL_EMAIL_TEMPLATES], + featureKey: FeatureEnum.FEATURE_EMAIL_TEMPLATE + } + }, + { + id: 'settings-accounting-templates', + title: 'Accounting Templates', + icon: 'fas fa-address-card', + link: '/pages/settings/accounting-templates', + data: { + translationKey: 'MENU.ACCOUNTING_TEMPLATES', + permissionKeys: [PermissionsEnum.VIEW_ALL_ACCOUNTING_TEMPLATES] + } + }, + { + id: 'settings-file-storage', + title: 'File storage', + icon: 'fas fa-database', + link: '/pages/settings/file-storage', + data: { + translationKey: 'MENU.FILE_STORAGE', + permissionKeys: [PermissionsEnum.FILE_STORAGE_VIEW], + featureKey: FeatureEnum.FEATURE_FILE_STORAGE + } + }, + { + id: 'settings-sms-gateways', + title: 'SMS Gateways', + icon: 'fas fa-at', + link: '/pages/settings/sms-gateway', + data: { + translationKey: 'MENU.SMS_GATEWAYS', + permissionKeys: [PermissionsEnum.SMS_GATEWAY_VIEW], + featureKey: FeatureEnum.FEATURE_SMS_GATEWAY + } + }, + { + id: 'settings-custom-smtp', + title: 'Custom SMTP', + icon: 'fas fa-at', + link: '/pages/settings/custom-smtp', + data: { + translationKey: 'MENU.CUSTOM_SMTP', + permissionKeys: [PermissionsEnum.CUSTOM_SMTP_VIEW], + featureKey: FeatureEnum.FEATURE_SMTP + } + }, + { + id: 'settings-roles-permissions', + title: 'Roles & Permissions', + link: '/pages/settings/roles-permissions', + icon: 'fas fa-award', + data: { + translationKey: 'MENU.ROLES', + permissionKeys: [PermissionsEnum.CHANGE_ROLES_PERMISSIONS], + featureKey: FeatureEnum.FEATURE_ROLES_PERMISSION + } + }, + { + id: 'settings-danger-zone', + title: 'Danger Zone', + link: '/pages/settings/danger-zone', + icon: 'fas fa-radiation-alt', + data: { + translationKey: 'MENU.DANGER_ZONE', + permissionKeys: [ + PermissionsEnum.ACCESS_DELETE_ACCOUNT, + PermissionsEnum.ACCESS_DELETE_ALL_DATA + ] + } + } + ] + } + ]; } /** diff --git a/packages/ui-core/core/src/lib/components/common-nav.module.ts b/packages/ui-core/core/src/lib/components/common-nav.module.ts index f4f7956118b..f49ff65e6c2 100644 --- a/packages/ui-core/core/src/lib/components/common-nav.module.ts +++ b/packages/ui-core/core/src/lib/components/common-nav.module.ts @@ -4,18 +4,14 @@ import { NgxPermissionsModule } from 'ngx-permissions'; import { NbAccordionModule, NbButtonModule, NbTooltipModule } from '@nebular/theme'; import { BaseNavMenuComponent } from './base-nav-menu/base-nav-menu.component'; import { MainNavMenuComponent } from './main-nav-menu/main-nav-menu.component'; +import { SettingsNavMenuComponent } from './settings-nav-menu/settings-nav-menu.component'; import { MenuItemComponent, SidebarMenuComponent, ChildrenMenuItemComponent, TooltipDirective } from './sidebar-menu'; +const COMPONENTS = [BaseNavMenuComponent, MainNavMenuComponent, SidebarMenuComponent, SettingsNavMenuComponent]; + @NgModule({ - declarations: [ - BaseNavMenuComponent, - MainNavMenuComponent, - SidebarMenuComponent, - MenuItemComponent, - ChildrenMenuItemComponent, - TooltipDirective - ], imports: [CommonModule, NbAccordionModule, NbTooltipModule, NbButtonModule, NgxPermissionsModule.forChild()], - exports: [BaseNavMenuComponent, MainNavMenuComponent, SidebarMenuComponent] + declarations: [...COMPONENTS, MenuItemComponent, ChildrenMenuItemComponent, TooltipDirective], + exports: [...COMPONENTS] }) export class CommonNavModule {} From bfb62a25df595a719b49443e6b351b0ee8910881 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Wed, 23 Oct 2024 17:11:45 +0530 Subject: [PATCH 31/68] fix: missing translation for bg.json --- packages/ui-core/i18n/assets/i18n/bg.json | 171 ++++++++++++---------- 1 file changed, 94 insertions(+), 77 deletions(-) diff --git a/packages/ui-core/i18n/assets/i18n/bg.json b/packages/ui-core/i18n/assets/i18n/bg.json index 65118a4ddf2..222b4e8d9c2 100644 --- a/packages/ui-core/i18n/assets/i18n/bg.json +++ b/packages/ui-core/i18n/assets/i18n/bg.json @@ -178,45 +178,45 @@ }, "SM_TABLE": { "NO_DATA": { - "LOADING": "Зареждане, моля, изчакайте...", + "LOADING": "Зареждане, моля изчакайте...", "RECEIVE_ESTIMATE": "Не сте получили никакви оценки.", - "INCOME": "Не сте създали никакви доходи.", + "INCOME": "Не сте създали никакви приходи.", "EXPENSE_CATEGORY": "Не сте създали никакви категории разходи.", "REPORT": "Не сте създали никакви отчети.", "CONTRACT": "Не сте създали никакви договори.", "TEAM": "Не сте създали никакви екипи.", "HISTORY_RECORD": "Не сте създали никакви записи.", - "PROFIT_HISTORY": "Не сте създали никаква история на печалбата.", + "PROFIT_HISTORY": "Не сте създали никаква история на печалбите.", "EMPLOYEE": "Не сте създали никакви служители.", "EXPENSE": "Не сте създали никакви разходи.", "PAYMENT": "Не сте получили никакви плащания.", "PROPOSAL_TEMPLATE": "Не сте създали никакви шаблони за предложения.", "PROPOSAL": "Не сте създали никакви предложения.", - "PIPELINE": "Не сте създали никакви тръбопроводи.", + "PIPELINE": "Не сте създали никакви канали.", "TASK": "Не сте създали никакви задачи.", "INVITE": "Не сте поканили никакви потребители.", "APPROVAL_REQUEST": "Не сте създали никакви заявки за одобрение.", "APPROVAL_POLICY": "Не сте създали никакви политики за одобрение.", - "TIME_OFF": "Не сте създали никакво време за отпуск.", - "TIME_OFF_POLICY": "Не сте създали политики за отпуск.", + "TIME_OFF": "Не сте създали никакви отпуски.", + "TIME_OFF_POLICY": "Не сте създали никакви политики за отпуск.", "CANDIDATE": "Не сте създали никакви кандидати.", "INTERVIEW": "Не сте създали никакви интервюта.", "EQUIPMENT": "Не сте създали никакво оборудване.", "EQUIPMENT_SHARING": "Не сте създали никакви записи за споделяне на оборудване.", "EQUIPMENT_SHARING_POLICY": "Не сте създали никакви политики за споделяне на оборудване.", - "INVENTORY": "Не сте създали никакви инвентари.", + "INVENTORY": "Не сте създали никакви инвентаризации.", "MERCHANT": "Не сте създали никакви търговци.", "WAREHOUSE": "Не сте създали никакви складове.", - "WAREHOUSE_PRODUCT": "Не сте създали никакви складови продукти.", - "PRODUCT_CATEGORY": "Не сте създали никакви категории продукти.", + "WAREHOUSE_PRODUCT": "Не сте създали никакви продукти за склад.", + "PRODUCT_CATEGORY": "Не сте създали никакви продуктови категории.", "TAGS": "Не сте създали никакви етикети.", "PROJECT": "Не сте създали никакви проекти.", "DEPARTMENT": "Не сте създали никакви отдели.", "CONTACT": "Не сте създали никакви контакти.", "CLIENT": "Не сте създали никакви клиенти.", "LEAD": "Не сте създали никакви потенциални клиенти.", - "TIME_FRAME": "Не сте създали никакви времеви периоди.", - "KPI": "Не сте създали никакви КПИ.", + "TIME_FRAME": "Не сте създали никакви времеви рамки.", + "KPI": "Не сте създали никакви KPI.", "INVOICE": "Не сте създали никакви фактури.", "ESTIMATE": "Не сте създали никакви оценки.", "EVENT_TYPE": "Не сте създали никакви типове събития.", @@ -229,10 +229,10 @@ "DATE": "Дата", "TITLE": "Заглавие", "STAGE": "Етап", - "START_DATE": "Начална дата", - "END_DATE": "Крайна дата", - "CLIENT_NAME": "Клиентско име", - "CONTACT_NAME": "Име на контакт", + "START_DATE": "Начална Дата", + "END_DATE": "Крайна Дата", + "CLIENT_NAME": "Име на Клиента", + "CONTACT_NAME": "Име на Контакта", "NAME": "Име", "VENDOR": "Доставчик", "CATEGORY": "Категория", @@ -241,26 +241,25 @@ "NOTES": "Бележки", "EMPLOYEE": "Служител", "EMPLOYEES": "Служители", - "FULL_NAME": "Пълно име", - "EMAIL": "Електронна поща", - "INCOME": "Доход (Средно)", + "FULL_NAME": "Пълно Име", + "EMAIL": "Имейл", + "INCOME": "Приходи (Средно)", "EXPENSES": "Разходи (Средно)", "BONUS": "Бонус", "BONUS_AVG": "Бонус (Средно)", - "PROFIT_BASED_BONUS": "Бонус въз основа на печалбата", - "REVENUE_BASED_BONUS": "Бонус въз основа на приходите", + "PROFIT_BASED_BONUS": "Бонус на база печалба", + "REVENUE_BASED_BONUS": "Бонус на база приходи", "STATUS": "Статус", "SOURCE": "Източник", - "WORK_STATUS": "Работен статус", "TODAY": "Днес", - "END_OF_MONTH": "Края на месеца", - "START_OF_MONTH": "Началото на месеца", - "RATE": "Почасова ставка", - "FLAT_FEE": "Фиксирана такса", - "MILESTONES": "Етапи", - "JOB_TITLE": "Заглавие на работа", - "JOB_POST_URL": "URL на работната обява", - "LINK_TO_JOBPOST": "Връзка към работната обява", + "END_OF_MONTH": "Край на Месеца", + "START_OF_MONTH": "Начало на Месеца", + "RATE": "Ставка", + "FLAT_FEE": "Фиксирана Такса", + "MILESTONES": "Милстоунове", + "JOB_TITLE": "Заглавие на Работата", + "JOB_POST_URL": "URL на Работното Обявление", + "LINK_TO_JOBPOST": "Връзка към Работното Обявление", "AUTHOR": "Автор", "MONDAY": "Понеделник", "TUESDAY": "Вторник", @@ -269,12 +268,12 @@ "FRIDAY": "Петък", "SATURDAY": "Събота", "SUNDAY": "Неделя", - "NONE": "Нито един", + "NONE": "Няма", "ROLE": "Роля", "PROJECTS": "Проекти", "PROJECT": "Проект", "INVITED_BY": "Поканен от", - "EXPIRE_DATE": "Дата на изтичане", + "EXPIRE_DATE": "Изтича на", "CLIENTS": "Клиенти", "CONTACTS": "Контакти", "CONTACT": "Контакт", @@ -284,12 +283,12 @@ "APPLIED": "Кандидатствал", "HIRED": "Нает", "REJECTED": "Отхвърлен", - "NO_RESULT": "Няма резултат", + "NO_RESULT": "Няма Резултат", "CLIENT": "Клиент", "INTERNAL": "Вътрешен", "START": "Начало", "END": "Край", - "REQUEST_DATE": "Дата на заявка", + "REQUEST_DATE": "Дата на Заявка", "REGION": { "BG": "Български (България)", "EN": "English (United States)", @@ -307,16 +306,28 @@ }, "CURRENT_VALUE": "Текуща стойност", "TARGET_VALUE": "Целева стойност", - "LAST_UPDATED": "Последна актуализация", + "LAST_UPDATED": "Последно обновено", + "LAST_SYNC_DATE": "Дата на последна синхронизация", "CREATED_BY": "Създадено от", "NO_DATA_MESSAGE": "Няма данни", "TAGS": "Тагове", + "LABELS": "Етикети", "CREATED": "Създадено", "APPLIED_DATE": "Дата на кандидатстване", "HIRED_DATE": "Дата на наемане", "REJECTED_DATE": "Дата на отхвърляне", "TIME_TRACKING": "Проследяване на време", - "CREATED_AT": "Създадено на" + "CREATED_AT": "Създадено на", + "SCREEN_CAPTURE": "Заснемане на екрана", + "NUMBER": "Номер", + "PROVIDER": "Доставчик", + "GITHUB_REPOSITORY": "GitHub Репозитори", + "ISSUES_SYNC": "Синхронизиране на проблеми", + "ISSUES_SYNC_COUNT": "{{ count }} Проблеми синхронизирани", + "RESYNC_ISSUES": "Повторна синхронизация на проблеми", + "ENABLED_DISABLED_SYNC": "Активирана / Деактивирана синхронизация", + "ENABLE_DISABLE_INTEGRATION": "Активиране / Деактивиране на интеграция", + "ACTIONS": "Действия" }, "FORM": { "USERNAME": "Потребителско име", @@ -1210,46 +1221,49 @@ "STANDARD_WORK_HOURS": "Стандартни работни часове ({{hours}})" }, "INTEGRATIONS": { + "TITLE": "Интеграции", "AVAILABLE_INTEGRATIONS": "Налични приложения и интеграции", - "ADDED_UPWORK_TRANSACTION": "Добавена транзакция от Upwork", - "TOTAL_UPWORK_TRANSACTIONS_SUCCEED": "Общо успешни транзакции за разходи: {{ totalExpenses }}. Общо успешни транзакции за приходи: {{ totalIncomes }}", + "ADDED_UPWORK_TRANSACTION": "Добавена Upwork транзакция", + "TOTAL_UPWORK_TRANSACTIONS_SUCCEED": "Общо успешни разходни транзакции: {{ totalExpenses }}. Общо успешни приходи транзакции: {{ totalIncomes }}", "HUBSTAFF_PAGE": { "TITLE": "Hubstaff", "SELECT_ORGANIZATION": "Изберете организация", "SYNCED_PROJECTS": "Синхронизирани проекти", - "SETTINGS_UPDATED": "Актуализирани настройки за интеграция", - "SYNCED_ENTITIES": "Автоматично синхронизирани единици", - "TOOLTIP_ACTIVITY_INFO": "Ограничение на периода: 7 дни Най-ранна дата: 6 пълни месеца", + "SETTINGS_UPDATED": "Настройките за интеграцията са актуализирани", + "SYNCED_ENTITIES": "Автоматично синхронизирани обекти", + "TOOLTIP_ACTIVITY_INFO": "Ограничение на обхвата на датите: 7 дни Най-ранна дата: 6 пълни месеца", "DATE_RANGE_PLACEHOLDER": "Изберете дата между", "CLIENT_ID": "Hubstaff клиентски идентификатор", - "CLIENT_SECRET": "Hubstaff клиентска тайна", - "GRANT_PERMISSION": "След това ще бъдете пренасочени към Hubstaff, за да предоставите разрешение на Gauzy.", - "ENTER_CLIENT_SECRET": "Въведете клиентския тайния ключ, за да получите достъп до токен." + "CLIENT_SECRET": "Hubstaff клиентски таен ключ", + "GRANT_PERMISSION": "Следващата стъпка е да бъдете прехвърлени в Hubstaff за предоставяне на разрешение на Gauzy.", + "ENTER_CLIENT_SECRET": "Въведете таен ключ, за да получите достъп до токен.", + "DESCRIPTION": "Активирайте Hubstaff интеграцията за подобрено управление на работната сила." }, "UPWORK_PAGE": { - "ACTIVITIES": "Активности", - "REPORTS": "Доклади", + "ACTIVITIES": "Дейности", + "REPORTS": "Отчети", "TRANSACTIONS": "Транзакции", - "SUCCESSFULLY_AUTHORIZED": "Успешно упълномощен", + "SUCCESSFULLY_AUTHORIZED": "Успешно оторизиран", "API_KEY": "Upwork API ключ", "SECRET": "Upwork таен ключ", - "NEXT_STEP_INFO": "След това ще бъдете пренасочени към Upwork, за да предоставите разрешение на Gauzy.", + "NEXT_STEP_INFO": "Следващата стъпка е да бъдете прехвърлени в Upwork за предоставяне на разрешение на Gauzy.", "CONTRACTS": "Договори", "SYNCED_CONTRACTS": "Синхронизирани договори", "SELECT_DATE": "Изберете дата", "ONLY_CONTRACTS": "Само договори", - "CONTRACTS_RELATED_DATA": "Синхронизирани данни, свързани с договори", + "CONTRACTS_RELATED_DATA": "Синхронизирани обекти, свързани с договори", "DATE_RANGE_PLACEHOLDER": "Изберете дата между", - "HOURLY": "Часов" + "HOURLY": "По час", + "DESCRIPTION": "Активирайте Upwork интеграцията за управление на фрийланс работна сила." }, "GAUZY_AI_PAGE": { - "TITLE": "Интеграция на Gauzy AI", + "TITLE": "Gauzy AI Интеграция", "API_KEY": "Gauzy AI ключ", "API_SECRET": "Gauzy AI таен ключ", - "OPEN_AI_API_SECRET_KEY": "Тайният ключ на OpenAI", - "OPEN_AI_ORGANIZATION_ID": "ID на OpenAI организация", - "DESCRIPTION": "Активирайте интеграцията с Gauzy AI за по-интелигентно търсене на работа.", - "CONSUMER_KEYS": "Потребителски ключове", + "OPEN_AI_API_SECRET_KEY": "Open AI таен ключ", + "OPEN_AI_ORGANIZATION_ID": "Open AI идентификатор на организация", + "DESCRIPTION": "Активирайте Gauzy AI интеграцията за по-умно търсене на работа.", + "CONSUMER_KEYS": "Ключове на потребители", "OPEN_AI_API_KEYS": "Open AI API ключове", "GENERATED": "Генерирани", "TAB": { @@ -1257,43 +1271,46 @@ "SETTINGS": "Настройки" }, "TOOLTIP": { - "API_KEY": "API ключът служи като идентификатор на вашето приложение за API заявки, оставайки постоянно скрит с някои видими символи.", - "API_SECRET": "API тайният ключ служи като идентификатор на вашето приложение за API заявки, оставайки постоянно скрит с някои видими символи.", - "OPEN_AI_API_SECRET_KEY": "Тайният API ключ на OpenAI служи като идентификатор на вашето приложение за API заявки, оставайки постоянно скрит с някои видими символи.", - "OPEN_AI_ORGANIZATION_ID": "Незадължителен идентификатор за организационни цели при взаимодействие с OpenAI API. Помага за организиране и разграничаване на различни обекти или проекти във вашата организация.", - "ENABLE_JOBS_SEARCH_MATCHING_ANALYSIS": "Активира разширен анализ на търсенето на работа и съвпадение за по-голяма точност. При изключване скрива пунктовете 'Преглед' и 'Съвпадение' за по-лесен интерфейс.", - "ENABLE_EMPLOYEE_PERFORMANCE_ANALYSIS": "Управлява предаването на метрики за работата на служителите, включително клавишни въвеждания, движения на мишката и снимки на екрана, за анализ от Gauzy AI. Включването позволява изчерпателен анализ на производителността. При изключване Gauzy AI няма да получава и анализира снимки или други подробни данни, за да гарантира строга конфиденциалност и контрол върху споделянето на данни." + "API_KEY": "API ключът служи като идентификатор на вашето приложение за API заявки и остава скрит, с видими само някои символи.", + "API_SECRET": "API тайният ключ служи като идентификатор на вашето приложение за API заявки и остава скрит, с видими само някои символи.", + "OPEN_AI_API_SECRET_KEY": "OpenAI API тайният ключ служи като идентификатор на вашето приложение за API заявки и остава скрит, с видими само някои символи.", + "OPEN_AI_ORGANIZATION_ID": "Незадължителен идентификатор за организационни цели при взаимодействие с OpenAI API. Той помага за организиране и разграничаване на различни обекти или проекти във вашата организация.", + "ENABLE_JOBS_SEARCH_MATCHING_ANALYSIS": "Активира анализ на търсенето и съвпадението на работни места за по-голяма точност. Деактивирането скрива елементите от менюто 'Browse' и 'Matching' за по-опростен интерфейс.", + "ENABLE_EMPLOYEE_PERFORMANCE_ANALYSIS": "Управлява предаването на работните метрики на служителите, включително клавиатурни въведения, движения на мишката и екранни снимки, за анализ от Gauzy AI. Активирайте за всеобхватен анализ на ефективността; деактивирайте за строга поверителност и контрол на данните." + }, + "MESSAGE": { + "JOBS_SEARCH_MATCHING_ENABLED": "Анализът на търсенето и съвпадението на работни места е активиран." } }, "GITHUB_PAGE": { - "TITLE": "GitHub Интеграция", - "AUTO_SYNC_TABLE_LABEL": "Синхронизиране на GitHub репозитории и проекти", - "SELECT_REPOSITORY": "Изберете репозитория", - "SEARCH_REPOSITORY": "Напишете, за да търсите репозитория", - "SYNCED_ISSUES": "'{{repository}}' проблеми и етикети успешно синхронизирани", - "HAS_SYNCED_ENABLED": "'{{repository}}' синхронизация успешно активирана", - "HAS_SYNCED_DISABLED": "'{{repository}}' синхронизация успешно деактивирана", - "DESCRIPTION": "Активирайте интеграцията с GitHub за синхронизиране на проекти и репозитории.", + "TITLE": "Интеграция с GitHub", + "AUTO_SYNC_TABLE_LABEL": "Синхронизиране на GitHub хранилища и проекти", + "SELECT_REPOSITORY": "Изберете хранилище", + "SEARCH_REPOSITORY": "Въведете за търсене на хранилище", + "SYNCED_ISSUES": "Задачи и етикети на '{{repository}}' синхронизирани успешно", + "HAS_SYNCED_ENABLED": "Синхронизацията на '{{repository}}' е успешно активирана", + "HAS_SYNCED_DISABLED": "Синхронизацията на '{{repository}}' е успешно деактивирана", + "DESCRIPTION": "Активирайте GitHub интеграцията за синхронизация на проекти и хранилища.", "TAB": { - "AUTO_SYNC": "Автоматична синхронизация", + "AUTO_SYNC": "Авто синхронизация", "MANUAL_SYNC": "Ръчна синхронизация" } }, - "COMING_SOON": "Скоро", - "RE_INTEGRATE": "Реинтеграция", + "COMING_SOON": "Очаквайте скоро", + "RE_INTEGRATE": "Повторно интегриране", "SETTINGS": "Настройки", "SELECT_GROUPS": "Изберете групи", - "FILTER_INTEGRATIONS": "Филтрирай интеграции", + "FILTER_INTEGRATIONS": "Филтриране на интеграции", "SEARCH_INTEGRATIONS": "Търсене на интеграции", "PAID": "Платено", "INTEGRATION": "Интеграция", "MESSAGE": { - "SETTINGS_UPDATED": "Актуализирани настройки за интеграция '{{provider}}'", - "INTEGRATION_DELETED": "Интеграция '{{provider}}' успешно изтрита", + "SETTINGS_UPDATED": "Настройките за интеграцията с '{{provider}}' бяха актуализирани", + "INTEGRATION_DELETED": "Интеграцията с '{{provider}}' беше успешно изтрита", "NO_INTEGRATIONS": "Не сте конфигурирали никакви интеграции", - "INTEGRATION_ENABLED": "Интеграция '{{provider}}' успешно активирана", - "INTEGRATION_DISABLED": "Интеграция '{{provider}}' успешно деактивирана", - "INTEGRATION_ADDED": "Интеграция '{{provider}}' е добавена към '{{organization}}'" + "INTEGRATION_ENABLED": "Интеграцията с '{{provider}}' беше успешно активирана", + "INTEGRATION_DISABLED": "Интеграцията с '{{provider}}' беше успешно деактивирана", + "INTEGRATION_ADDED": "Интеграцията с '{{provider}}' беше добавена към '{{organization}}'" }, "ENABLED": "Активирано", "DISABLED": "Деактивирано" From a222b27da56a440da26c35dc021fb090fe987cdf Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Wed, 23 Oct 2024 17:31:37 +0530 Subject: [PATCH 32/68] feat: add dynamic menus for settings/accordion --- .../main-nav-menu/main-nav-menu.component.ts | 14 +- .../menu-item/menu-item.component.html | 11 +- .../interface/menu-item.interface.ts | 1 + .../sidebar-menu/sidebar-menu.component.html | 1 + .../services/nav-builder/nav-builder-types.ts | 40 +-- .../nav-builder/nav-menu-builder.service.ts | 29 +-- .../gauzy-logo/gauzy-logo.component.html | 23 +- .../gauzy-logo/gauzy-logo.component.ts | 235 ++++-------------- 8 files changed, 123 insertions(+), 231 deletions(-) diff --git a/packages/ui-core/core/src/lib/components/main-nav-menu/main-nav-menu.component.ts b/packages/ui-core/core/src/lib/components/main-nav-menu/main-nav-menu.component.ts index b9f2641b18e..3e93f0c515a 100644 --- a/packages/ui-core/core/src/lib/components/main-nav-menu/main-nav-menu.component.ts +++ b/packages/ui-core/core/src/lib/components/main-nav-menu/main-nav-menu.component.ts @@ -1,7 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { NavMenuSectionItem } from '../../services/nav-builder/nav-builder-types'; +import { NavMenuCategory, NavMenuSectionItem } from '../../services/nav-builder/nav-builder-types'; import { BaseNavMenuComponent } from '../base-nav-menu/base-nav-menu.component'; @Component({ @@ -10,6 +10,10 @@ import { BaseNavMenuComponent } from '../base-nav-menu/base-nav-menu.component'; styleUrls: ['./main-nav-menu.component.scss'] }) export class MainNavMenuComponent extends BaseNavMenuComponent implements OnInit { + // Define the input property menuCategory of type NavMenuCategory | undefined + @Input() menuCategory: NavMenuCategory | undefined; + + // Define the observable property menuConfig$ of type Observable public mainMenuConfig$: Observable; override ngOnInit(): void { @@ -17,7 +21,11 @@ export class MainNavMenuComponent extends BaseNavMenuComponent implements OnInit // Subscribe to the menuConfig$ observable provided by _navMenuBuilderService this.mainMenuConfig$ = this._navMenuBuilderService.menuConfig$.pipe( - map((sections: NavMenuSectionItem[]) => this.mapMenuSections(sections)) + map((sections: NavMenuSectionItem[]) => + this.mapMenuSections(sections).filter((section) => + this.menuCategory ? section.menuCategory === this.menuCategory : !section.menuCategory + ) + ) ); } } diff --git a/packages/ui-core/core/src/lib/components/sidebar-menu/menu-items/concrete/menu-item/menu-item.component.html b/packages/ui-core/core/src/lib/components/sidebar-menu/menu-items/concrete/menu-item/menu-item.component.html index df94aca76cc..9674e3e1880 100644 --- a/packages/ui-core/core/src/lib/components/sidebar-menu/menu-items/concrete/menu-item/menu-item.component.html +++ b/packages/ui-core/core/src/lib/components/sidebar-menu/menu-items/concrete/menu-item/menu-item.component.html @@ -24,15 +24,18 @@ [ngClass]="onCollapse ? 'collapsed' : ''" (click)="redirectTo()" > - {{ item?.title }} + + + + {{ item?.title }} + +
void; // Function to be called when the menu item is clicked (optional) - data: NavMenuItemData; // Data associated with the section + id: string; // Unique identifier for the section + class?: string; // Additional class for styling (optional) + items?: NavMenuSectionItem[]; // Array of NavMenuItem objects representing the links within the section (optional) + onClick?: (event: MouseEvent) => void; // Function to be called when the menu item is clicked (optional) + data: NavMenuItemData; // Data associated with the section + menuCategory?: NavMenuCategory; // Category of the menu (optional) } /** * Data associated with a NavMenuItem or NavMenuSection. */ export interface NavMenuItemData { - translationKey: string; // Translation key for the title, mandatory for all items - permissionKeys?: PermissionsEnum[]; // Permissions required to display the item (optional) - featureKey?: FeatureEnum; // Feature key required to display the item (optional) - hide?: () => boolean | boolean; // Function to determine if the item should be hidden (optional) - add?: string; + translationKey: string; // Translation key for the title, mandatory for all items + permissionKeys?: PermissionsEnum[]; // Permissions required to display the item (optional) + featureKey?: FeatureEnum; // Feature key required to display the item (optional) + hide?: () => boolean | boolean; // Function to determine if the item should be hidden (optional) + add?: string; } /** * Represents the configuration for navigation menu sections. */ export interface NavMenuSectionConfig { - config: NavMenuSectionItem; // Configuration for the navigation menu section - before?: string; // (Optional) Identifier of the section before which this section should be inserted + config: NavMenuSectionItem; // Configuration for the navigation menu section + before?: string; // (Optional) Identifier of the section before which this section should be inserted } /** * Represents the configuration for navigation menu items. */ export interface NavMenuItemsConfig { - config: NavMenuSectionItem; // Configuration for the navigation menu item - sectionId: string; // Identifier of the section to which this item belongs - before?: string; // (Optional) Identifier of the item before which this item should be inserted + config: NavMenuSectionItem; // Configuration for the navigation menu item + sectionId: string; // Identifier of the section to which this item belongs + before?: string; // (Optional) Identifier of the item before which this item should be inserted } /** diff --git a/packages/ui-core/core/src/lib/services/nav-builder/nav-menu-builder.service.ts b/packages/ui-core/core/src/lib/services/nav-builder/nav-menu-builder.service.ts index fce44168ed4..fb97a0df9f9 100644 --- a/packages/ui-core/core/src/lib/services/nav-builder/nav-menu-builder.service.ts +++ b/packages/ui-core/core/src/lib/services/nav-builder/nav-menu-builder.service.ts @@ -1,16 +1,11 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, combineLatest, map, Observable, of, shareReplay } from 'rxjs'; -import { - NavMenuSectionItem, - NavMenuItemsConfig, - NavMenuSectionConfig, -} from './nav-builder-types'; +import { NavMenuSectionItem, NavMenuItemsConfig, NavMenuSectionConfig } from './nav-builder-types'; @Injectable({ providedIn: 'root' }) export class NavMenuBuilderService { - // Declare an observable property menuConfig$ of type Observable public menuConfig$: Observable; @@ -78,8 +73,8 @@ export class NavMenuBuilderService { */ addNavMenuItem(config: NavMenuSectionItem, sectionId: string, before?: string) { // Check if the item already exists - const existingIndex = this.addedNavMenuItems.findIndex(item => - item.config.id === config.id && item.sectionId === sectionId + const existingIndex = this.addedNavMenuItems.findIndex( + (item) => item.config.id === config.id && item.sectionId === sectionId ); if (existingIndex !== -1) { @@ -103,8 +98,8 @@ export class NavMenuBuilderService { addNavMenuItems(configs: NavMenuSectionItem[], sectionId: string, before?: string) { configs.forEach((config: NavMenuSectionItem) => { // Check if the item already exists - const existingIndex = this.addedNavMenuItems.findIndex((item) => - item.config.id === config.id && item.sectionId === sectionId + const existingIndex = this.addedNavMenuItems.findIndex( + (item) => item.config.id === config.id && item.sectionId === sectionId ); if (existingIndex !== -1) { @@ -127,10 +122,14 @@ export class NavMenuBuilderService { * @param sectionId The identifier of the section from which the item should be removed. */ removeNavMenuItem(itemId: string, sectionId: string): void { - const itemIndex = this.addedNavMenuItems.findIndex((item) => item.config.id === itemId && item.sectionId === sectionId); + const itemIndex = this.addedNavMenuItems.findIndex( + (item) => item.config.id === itemId && item.sectionId === sectionId + ); if (itemIndex !== -1) { // Check if the item is already present in the removedNavMenuItems array - const existingIndex = this.removedNavMenuItems.findIndex((item) => item.config.id === itemId && item.sectionId === sectionId); + const existingIndex = this.removedNavMenuItems.findIndex( + (item) => item.config.id === itemId && item.sectionId === sectionId + ); if (existingIndex === -1) { // Push the removed item into the removedNavMenuItems array this.removedNavMenuItems.push(this.addedNavMenuItems[itemIndex]); @@ -188,7 +187,7 @@ export class NavMenuBuilderService { return [...configMap.values()]; }), - shareReplay(1), + shareReplay(1) ); // Combine the combined configuration with item additions to produce the final menu configuration @@ -230,7 +229,9 @@ export class NavMenuBuilderService { } } } else { - console.error(`Could not add menu item "${item.config.id}", section "${item.sectionId}" does not exist`); + console.error( + `Could not add menu item "${item.config.id}", section "${item.sectionId}" does not exist` + ); } }); diff --git a/packages/ui-core/theme/src/lib/components/gauzy-logo/gauzy-logo.component.html b/packages/ui-core/theme/src/lib/components/gauzy-logo/gauzy-logo.component.html index 5c347691c48..aba74b3f00c 100644 --- a/packages/ui-core/theme/src/lib/components/gauzy-logo/gauzy-logo.component.html +++ b/packages/ui-core/theme/src/lib/components/gauzy-logo/gauzy-logo.component.html @@ -1,37 +1,38 @@ - +
-
{{ organization?.name }}
-
{{ organization?.website }}
+
+ {{ organization?.name }} +
+
+ {{ organization?.website }} +
- + - +
- +
- +
diff --git a/packages/desktop-ui-lib/src/lib/dialogs/about/about.component.scss b/packages/desktop-ui-lib/src/lib/dialogs/about/about.component.scss index 020389953df..cc210301002 100644 --- a/packages/desktop-ui-lib/src/lib/dialogs/about/about.component.scss +++ b/packages/desktop-ui-lib/src/lib/dialogs/about/about.component.scss @@ -46,4 +46,4 @@ div.logo { ::ng-deep nb-layout .layout .layout-container .content nb-layout-footer nav { padding: 0px; - } \ No newline at end of file +} diff --git a/packages/desktop-window/src/lib/desktop-window-about.ts b/packages/desktop-window/src/lib/desktop-window-about.ts index 65b61879bcb..6f4a61a9631 100644 --- a/packages/desktop-window/src/lib/desktop-window-about.ts +++ b/packages/desktop-window/src/lib/desktop-window-about.ts @@ -1,7 +1,6 @@ import * as remoteMain from '@electron/remote/main'; import { BrowserWindow, Menu } from 'electron'; import * as url from 'url'; -import { attachTitlebarToWindow } from 'custom-electron-titlebar/main'; import log from 'electron-log'; import { WindowManager } from './concretes/window.manager'; @@ -16,6 +15,13 @@ export async function createAboutWindow(filePath, preloadPath?) { const mainWindowSettings: Electron.BrowserWindowConstructorOptions = windowSetting(preloadPath); const manager = WindowManager.getInstance(); + const allwindows = BrowserWindow.getAllWindows(); + const aboutWindows = allwindows.find((win) => win.getTitle() === 'About'); + if (aboutWindows) { + aboutWindows.show(); + return aboutWindows; + } + const window = new BrowserWindow(mainWindowSettings); remoteMain.enable(window.webContents); const launchPath = url.format({ @@ -42,7 +48,7 @@ export async function createAboutWindow(filePath, preloadPath?) { manager.register(RegisteredWindow.ABOUT, window); if (preloadPath) { - attachTitlebarToWindow(window); + window.webContents.send('hide-menu'); } return window; } @@ -69,11 +75,6 @@ const windowSetting = (preloadPath) => { }; if (preloadPath) { mainWindowSettings.webPreferences.preload = preloadPath; - mainWindowSettings.titleBarOverlay = true; - mainWindowSettings.titleBarStyle = 'hidden'; - if (process.platform === 'linux') { - mainWindowSettings.frame = false; - } } return mainWindowSettings; }; diff --git a/packages/desktop-window/src/lib/desktop-window-timer.ts b/packages/desktop-window/src/lib/desktop-window-timer.ts index 35eb87ad7b7..53baaf5c2b5 100644 --- a/packages/desktop-window/src/lib/desktop-window-timer.ts +++ b/packages/desktop-window/src/lib/desktop-window-timer.ts @@ -12,6 +12,13 @@ Object.assign(console, log.functions); const Store = require('electron-store'); const store = new Store(); +function getScreenSize() { + const sizes = screen.getPrimaryDisplay().workAreaSize; + const width = sizes.height < 768 ? 310 : 360; + const height = sizes.height < 768 ? sizes.height - 20 : 768; + return { width, height } +} + export async function createTimeTrackerWindow(timeTrackerWindow, filePath, preloadPath?) { const mainWindowSettings: Electron.BrowserWindowConstructorOptions = windowSetting(preloadPath); const manager = WindowManager.getInstance(); @@ -29,6 +36,11 @@ export async function createTimeTrackerWindow(timeTrackerWindow, filePath, prelo timeTrackerWindow.hide(); await timeTrackerWindow.loadURL(launchPath); + if (preloadPath) { + attachTitlebarToWindow(timeTrackerWindow); + } + const { width, height } = getScreenSize(); + timeTrackerWindow.setMinimumSize(width, height); timeTrackerWindow.setMenu(null); timeTrackerWindow.on('close', (event) => { event.preventDefault(); @@ -36,17 +48,14 @@ export async function createTimeTrackerWindow(timeTrackerWindow, filePath, prelo }); manager.register(RegisteredWindow.TIMER, timeTrackerWindow); - if (preloadPath) { - attachTitlebarToWindow(timeTrackerWindow); - } + return timeTrackerWindow; } const windowSetting = (preloadPath?) => { const sizes = screen.getPrimaryDisplay().workAreaSize; - const height = sizes.height < 768 ? sizes.height - 20 : 768; + const { width, height } = getScreenSize(); const zoomF = sizes.height < 768 ? 0.8 : 1.0; - const width = sizes.height < 768 ? 310 : 360; const filesPath = store.get('filePath'); console.log('file path == ', filesPath); const mainWindowSettings: Electron.BrowserWindowConstructorOptions = {