Skip to content

Commit

Permalink
feat: static tabs load template or component dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
rahul-rocket committed Aug 30, 2024
1 parent 85b2ad2 commit e3ecc47
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 100 deletions.
20 changes: 10 additions & 10 deletions apps/gauzy/src/app/pages/dashboard/dashboard.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ export class DashboardComponent extends TranslationBaseComponent implements Afte
if (this._store.hasAnyPermission(PermissionsEnum.ADMIN_DASHBOARD_VIEW, PermissionsEnum.TEAM_DASHBOARD)) {
// Register the teams tab
this._pageTabRegistryService.registerPageTab({
tabsetId: 'dashboard', // The identifier for the tabset
tabsetId: this.tabsetId, // The identifier for the tabset
tabId: 'teams', // The identifier for the tab
tabsetType: 'route', // The type of tabset to use
route: this.getRoute('teams'), // The route for the tab
tabTitle: () => this.getTranslation('ORGANIZATIONS_PAGE.TEAMS'), // The title for the tab
tabTitle: (_i18n) => _i18n.getTranslation('ORGANIZATIONS_PAGE.TEAMS'), // The title for the tab
tabIcon: 'people-outline', // The icon for the tab
responsive: true, // Whether the tab is responsive
activeLinkOptions: { exact: false }, // The options for the active link
Expand All @@ -93,11 +93,11 @@ export class DashboardComponent extends TranslationBaseComponent implements Afte
) {
// Register the project management tab
this._pageTabRegistryService.registerPageTab({
tabsetId: 'dashboard', // The identifier for the tabset
tabsetId: this.tabsetId, // The identifier for the tabset
tabId: 'project-management', // The identifier for the tab
tabsetType: 'route', // The type of tabset to use
route: this.getRoute('project-management'), // The route for the tab
tabTitle: () => this.getTranslation('DASHBOARD_PAGE.PROJECT_MANAGEMENT'), // The title for the tab
tabTitle: (_i18n) => _i18n.getTranslation('DASHBOARD_PAGE.PROJECT_MANAGEMENT'), // The title for the tab
tabIcon: 'browser-outline', // The icon for the tab
responsive: true, // Whether the tab is responsive
activeLinkOptions: { exact: false }, // The options for the active link
Expand All @@ -111,11 +111,11 @@ export class DashboardComponent extends TranslationBaseComponent implements Afte
) {
// Register the time tracking tab
this._pageTabRegistryService.registerPageTab({
tabsetId: 'dashboard', // The identifier for the tabset
tabsetId: this.tabsetId, // The identifier for the tabset
tabId: 'time-tracking', // The identifier for the tab
tabsetType: 'route', // The type of tabset to use
route: this.getRoute('time-tracking'), // The route for the tab
tabTitle: () => this.getTranslation('TIMESHEET.TIME_TRACKING'), // The title for the tab
tabTitle: (_i18n) => _i18n.getTranslation('TIMESHEET.TIME_TRACKING'), // The title for the tab
tabIcon: 'clock-outline', // The icon for the tab
responsive: true, // Whether the tab is responsive
activeLinkOptions: { exact: false }, // The options for the active link
Expand All @@ -138,11 +138,11 @@ export class DashboardComponent extends TranslationBaseComponent implements Afte
if (!this.selectedEmployee || !this.selectedEmployee.id) {
// Register the accounting tab
this._pageTabRegistryService.registerPageTab({
tabsetId: 'dashboard', // The identifier for the tabset
tabsetId: this.tabsetId, // The identifier for the tabset
tabId: 'accounting', // The identifier for the tab
tabsetType: 'route', // The type of tabset to use
route: this.getRoute('accounting'), // The route for the tab
tabTitle: () => this.getTranslation('DASHBOARD_PAGE.ACCOUNTING'), // The title for the tab
tabTitle: (_i18n) => _i18n.getTranslation('DASHBOARD_PAGE.ACCOUNTING'), // The title for the tab
tabIcon: 'credit-card-outline', // The icon for the tab
responsive: true, // Whether the tab is responsive
activeLinkOptions: { exact: false }, // The options for the active link
Expand All @@ -161,11 +161,11 @@ export class DashboardComponent extends TranslationBaseComponent implements Afte
if (this.selectedEmployee && this.selectedEmployee.id) {
// Register the human resources tab
this._pageTabRegistryService.registerPageTab({
tabsetId: 'dashboard', // The identifier for the tabset
tabsetId: this.tabsetId, // The identifier for the tabset
tabId: 'hr', // The identifier for the tab
tabsetType: 'route', // The type of tabset to use
route: this.getRoute('hr'), // The route for the tab
tabTitle: () => this.getTranslation('DASHBOARD_PAGE.HUMAN_RESOURCES'), // The title for the tab
tabTitle: (_i18n) => _i18n.getTranslation('DASHBOARD_PAGE.HUMAN_RESOURCES'), // The title for the tab
tabIcon: 'person-outline', // The icon for the tab
responsive: true, // Whether the tab is responsive
activeLinkOptions: { exact: false }, // The options for the active link
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,18 @@ <h4>
[buttonTemplate]="actionButtons"
></ngx-gauzy-button-action>
</div>
<nb-tabset (changeTab)="onTabChange($event)" class="mt-4">
<nb-tab [tabTitle]="'JOB_EMPLOYEE.BROWSE' | translate" [tabId]="jobSearchTabsEnum.BROWSE">
<ng-container>
<ng-template [ngTemplateOutlet]="tableLayout"></ng-template>
</ng-container>
</nb-tab>
<nb-tab [tabTitle]="'JOB_EMPLOYEE.SEARCH' | translate" [tabId]="jobSearchTabsEnum.SEARCH">
<ng-template [ngTemplateOutlet]="wip"></ng-template>
</nb-tab>
<nb-tab [tabTitle]="'JOB_EMPLOYEE.HISTORY' | translate" [tabId]="jobSearchTabsEnum.HISTORY">
<ng-template [ngTemplateOutlet]="wip"></ng-template>
</nb-tab>
</nb-tabset>

<!-- Dynamic Tabs -->
<gz-dynamic-tabs [tabsetId]="tabsetId"></gz-dynamic-tabs>
</nb-card-body>
</nb-card>

<!-- Table Layout Template -->
<ng-template #tableLayout>
<!-- Check if the user has the 'ORG_JOB_EMPLOYEE_VIEW' permission -->
<ng-template [ngxPermissionsOnly]="['ORG_JOB_EMPLOYEE_VIEW']">
<div class="table-scroll-container">
<!-- Smart Table Component -->
<angular2-smart-table
style="cursor: pointer"
[settings]="settingsSmartTable"
Expand All @@ -43,17 +37,31 @@ <h4>
</div>
<div class="pagination-container">
<ng-container *ngIf="smartTableSource">
<!-- Pagination Component -->
<ngx-pagination [source]="smartTableSource"></ngx-pagination>
</ng-container>
</div>
</ng-template>

<!-- If the user does not have the 'ORG_JOB_EMPLOYEE_VIEW' permission -->
<ng-template [ngxPermissionsExcept]="['ORG_JOB_EMPLOYEE_VIEW']">
<div>
<!-- Content to display if the user does not have 'canEditComponent' permission -->
<!-- Content to display if the user does not have the 'ORG_JOB_EMPLOYEE_VIEW' permission -->
<!-- Placeholder: Add alternate content here -->
</div>
</ng-template>
</ng-template>

<!-- Coming Soon Template -->
<ng-template #comingSoon>
<div>
<div [style]="{ display: 'flex', 'flex-direction': 'column', 'align-items': 'center', margin: '100px 0px' }">
<nb-icon icon="flash-outline" [style]="{ 'font-size': '50px', color: '#cacaca' }"></nb-icon>
<div>{{ 'COMING_SOON' | translate }}</div>
</div>
</div>
</ng-template>

<ng-template #actionButtons let-buttonSize="buttonSize" let-selectedItem="selectedItem">
<ng-template [ngxPermissionsOnly]="['ORG_JOB_EMPLOYEE_VIEW', 'ORG_EMPLOYEES_EDIT']">
<div class="btn-group actions">
Expand Down Expand Up @@ -107,12 +115,3 @@ <h4>
</button>
</ng-template>
</ng-template>

<ng-template #wip>
<div>
<div [style]="{ display: 'flex', 'flex-direction': 'column', 'align-items': 'center', margin: '100px 0px' }">
<nb-icon icon="flash-outline" [style]="{ 'font-size': '50px', color: '#cacaca' }"></nb-icon>
<div>{{ 'COMING_SOON' | translate }}</div>
</div>
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core';
import { AfterViewInit, Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { CurrencyPipe } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { BehaviorSubject, combineLatest, merge, Subject } from 'rxjs';
import { debounceTime, filter, tap } from 'rxjs/operators';
import { NbTabComponent } from '@nebular/theme';
Expand All @@ -17,7 +17,9 @@ import {
JobService,
ServerDataSource,
Store,
ToastrService
ToastrService,
PageTabsetRegistryId,
PageTabRegistryService
} from '@gauzy/ui-core/core';
import { I18nService } from '@gauzy/ui-core/i18n';
import {
Expand Down Expand Up @@ -45,6 +47,7 @@ export enum JobSearchTabsEnum {
providers: [CurrencyPipe]
})
export class JobEmployeeComponent extends PaginationFilterBaseComponent implements AfterViewInit, OnInit, OnDestroy {
public tabsetId: PageTabsetRegistryId = this._route.snapshot.data.tabsetId; // The identifier for the tabset
public jobSearchTabsEnum = JobSearchTabsEnum;
public loading: boolean = false;
public settingsSmartTable: any;
Expand All @@ -56,33 +59,34 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen
public selectedEmployee: IEmployee;
public disableButton: boolean = true;

// Template References
@ViewChild('tableLayout', { static: true }) tableLayout: TemplateRef<any>; // Template reference for the table layout tab
@ViewChild('comingSoon', { static: true }) comingSoon: TemplateRef<any>; // Template reference for the coming soon tab

constructor(
translateService: TranslateService,
private readonly _http: HttpClient,
private readonly _route: ActivatedRoute,
private readonly _router: Router,
private readonly _ngxPermissionsService: NgxPermissionsService,
private readonly _store: Store,
private readonly _employeesService: EmployeesService,
private readonly _jobService: JobService,
private readonly _toastrService: ToastrService,
private readonly _currencyPipe: CurrencyPipe,
private readonly _ngxPermissionsService: NgxPermissionsService,
private readonly _i18nService: I18nService,
readonly _pageDataTableRegistryService: PageDataTableRegistryService
readonly _pageDataTableRegistryService: PageDataTableRegistryService,
readonly _pageTabRegistryService: PageTabRegistryService
) {
super(translateService);

// Register data table columns
this.registerDataTableColumns(_pageDataTableRegistryService);
}

ngOnInit(): void {
this._applyTranslationOnSmartTable();
this._loadSmartTableSettings();

// Initialize UI permissions
this.initializeUiPermissions();
// Initialize UI languages and Update Locale
this.initializeUiLanguagesAndLocale();
this._applyTranslationOnSmartTable(); //
this._loadSmartTableSettings(); // Load smart table settings
this.initializeUiPermissions(); // Initialize UI permissions
this.initializeUiLanguagesAndLocale(); // Initialize UI languages and Update Locale
this._initializePageElements(); // Register page elements
}

ngAfterViewInit(): void {
Expand Down Expand Up @@ -135,6 +139,59 @@ export class JobEmployeeComponent extends PaginationFilterBaseComponent implemen
.subscribe();
}

/**
* Initializes page elements by registering page tabs and data table columns.
*
* This method centralizes the logic for setting up page-related configurations,
* ensuring that the necessary page tabs and data table columns are registered
* upon initialization.
*/
private _initializePageElements(): void {
// Register page elements
this.registerPageTabs(this._pageTabRegistryService); // Register page tabs
this.registerDataTableColumns(this._pageDataTableRegistryService); // Register data table columns
}

/**
* Register page tabs for the JobEmployee
*
* @param _pageTabRegistryService
*/
registerPageTabs(_pageTabRegistryService: PageTabRegistryService): void {
// Register the browse tab
_pageTabRegistryService.registerPageTab({
tabsetId: this.tabsetId, // The identifier for the tabset
tabId: 'browse', // The identifier for the tab
tabsetType: 'standard', // The type of tabset to use
tabTitle: (_i18n) => _i18n.getTranslation('JOB_EMPLOYEE.BROWSE'), // The title for the tab
order: 1, // The order of the tab,
responsive: true, // Whether the tab is responsive,
template: this.tableLayout // The template to be rendered in the tab
});

// Register the search tab
_pageTabRegistryService.registerPageTab({
tabsetId: this.tabsetId, // The identifier for the tabset
tabId: 'search', // The identifier for the tab
tabsetType: 'standard', // The type of tabset to use
tabTitle: (_i18n) => _i18n.getTranslation('JOB_EMPLOYEE.SEARCH'), // The title for the tab
order: 2, // The order of the tab,
responsive: true, // Whether the tab is responsive,
template: this.comingSoon // The template to be rendered in the tab
});

// Register the history tab
_pageTabRegistryService.registerPageTab({
tabsetId: this.tabsetId, // The identifier for the tabset
tabId: 'history', // The identifier for the tab
tabsetType: 'standard', // The type of tabset to use
tabTitle: (_i18n) => _i18n.getTranslation('JOB_EMPLOYEE.HISTORY'), // The title for the tab
order: 3, // The order of the tab,
responsive: true, // Whether the tab is responsive,
template: this.comingSoon // The template to be rendered in the tab
});
}

/**
* Register data table columns for the JobEmployee
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { NgxPermissionsModule } from 'ngx-permissions';
import { LanguagesEnum } from '@gauzy/contracts';
import { PageRouteRegistryService } from '@gauzy/ui-core/core';
import { HttpLoaderFactory } from '@gauzy/ui-core/i18n';
import { SharedModule, SmartDataViewLayoutModule } from '@gauzy/ui-core/shared';
import { DynamicTabsModule, SharedModule, SmartDataViewLayoutModule } from '@gauzy/ui-core/shared';
import { createJobEmployeeRoutes } from './job-employee.routes';
import { JobEmployeeComponent } from './components/job-employee/job-employee.component';

Expand Down Expand Up @@ -45,7 +45,8 @@ const THIRD_PARTY_MODULES = [
...NB_MODULES,
...THIRD_PARTY_MODULES,
SharedModule,
SmartDataViewLayoutModule
SmartDataViewLayoutModule,
DynamicTabsModule
],
providers: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export const createJobEmployeeRoutes = (_pageRouteRegistryService: PageRouteRegi
component: JobEmployeeComponent,
canActivate: [PermissionsGuard],
data: {
// The tabset identifier for the route
tabsetId: 'job-employee',
// The permission required to access the route
permissions: {
only: [PermissionsEnum.ORG_JOB_EMPLOYEE_VIEW],
redirectTo: '/pages/jobs/search'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable, Type } from '@angular/core';
import { Injectable, TemplateRef, Type } from '@angular/core';
import { PageTabsetRegistryId } from '../../common/component-registry.types';
import { IPageTabRegistry, PageTabRegistryConfig } from './page-tab-registry.types';

Expand Down Expand Up @@ -66,6 +66,7 @@ export class PageTabRegistryService implements IPageTabRegistry {
config.order = config.order ?? 0; // Set the default order to 0 if not provided
config.hide = config.hide ?? false; // Set the default hide to false if not provided
config.responsive = config.responsive ?? true; // Set the default responsive to true if not provided
config.active = config.active ?? false; // Set the default active to false if not provided

// Find the index of an existing tab with the same tabId in the specified tab set
const existing = tabs.findIndex((tab) => tab.tabId === config.tabId);
Expand Down Expand Up @@ -199,17 +200,20 @@ export class PageTabRegistryService implements IPageTabRegistry {

/**
* @description
* Retrieves the component associated with a specific tab ID for a given tabset.
* Retrieves the component or template associated with a specific tab ID for a given tabset.
*
* This method looks up the tabset using the provided `tabsetId`, then searches for the tab
* with the specified `tabId` within that tabset. If the tab is found, it returns the associated
* component; otherwise, it returns `undefined`.
* with the specified `tabId` within that tabset. If the tab is found, it returns either the
* component or the template based on the tab's configuration; otherwise, it returns `undefined`.
*
* @param tabsetId The identifier of the tabset to retrieve tabs from.
* @param tabId The identifier of the tab whose component is to be retrieved.
* @returns The component associated with the specified tab ID, or `undefined` if the tab or component is not found.
* @param tabId The identifier of the tab whose component or template is to be retrieved.
* @returns The component or template associated with the specified tab ID, or `undefined` if neither is found.
*/
public getComponentForTab(tabsetId: PageTabsetRegistryId, tabId: string): Type<any> | undefined {
public getComponentOrTemplateForTab(
tabsetId: PageTabsetRegistryId,
tabId: string
): Type<any> | TemplateRef<any> | undefined {
// Retrieve the list of tabs for the specified tabsetId
const tabs = this.getPageTabset(tabsetId);

Expand All @@ -218,8 +222,8 @@ export class PageTabRegistryService implements IPageTabRegistry {
// Find the tab with the specified tabId
const tab = tabs.find((t) => t.tabId === tabId);

// Return the component associated with the tab ID or undefined if not found
return tab?.component;
// Return the component if it exists, otherwise return the template
return tab?.component || tab?.template;
}

// Return undefined if the tabs could not be retrieved or are not an array
Expand Down
Loading

0 comments on commit e3ecc47

Please sign in to comment.