diff --git a/apps/gauzy/src/app/pages/tags/tags.component.html b/apps/gauzy/src/app/pages/tags/tags.component.html index f5c62c88441..9b1ed209cce 100644 --- a/apps/gauzy/src/app/pages/tags/tags.component.html +++ b/apps/gauzy/src/app/pages/tags/tags.component.html @@ -11,7 +11,7 @@ {{ option.displayName }} diff --git a/apps/gauzy/src/app/pages/tags/tags.component.ts b/apps/gauzy/src/app/pages/tags/tags.component.ts index 25d69384171..9d2dfc81a4f 100644 --- a/apps/gauzy/src/app/pages/tags/tags.component.ts +++ b/apps/gauzy/src/app/pages/tags/tags.component.ts @@ -6,9 +6,9 @@ import { debounceTime, filter, tap } from 'rxjs/operators'; import { Subject, firstValueFrom } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; -import { ITag, IOrganization, ComponentLayoutStyleEnum } from '@gauzy/contracts'; -import { ComponentEnum, distinctUntilChange, splitCamelCase } from '@gauzy/ui-core/common'; -import { Store, TagsService, ToastrService } from '@gauzy/ui-core/core'; +import { ITag, IOrganization, ComponentLayoutStyleEnum, ITagType } from '@gauzy/contracts'; +import { ComponentEnum, distinctUntilChange } from '@gauzy/ui-core/common'; +import { Store, TagsService, TagTypesService, ToastrService } from '@gauzy/ui-core/core'; import { DeleteConfirmationComponent, IPaginationBase, @@ -35,6 +35,7 @@ export class TagsComponent extends PaginationFilterBaseComponent implements Afte dataLayoutStyle = ComponentLayoutStyleEnum.TABLE; componentLayoutStyleEnum = ComponentLayoutStyleEnum; tags: ITag[] = []; + tagTypes: ITagType[] = []; private organization: IOrganization; tags$: Subject = this.subject$; @@ -44,6 +45,7 @@ export class TagsComponent extends PaginationFilterBaseComponent implements Afte constructor( private readonly dialogService: NbDialogService, private readonly tagsService: TagsService, + private readonly tagTypesService: TagTypesService, public readonly translateService: TranslateService, private readonly toastrService: ToastrService, private readonly store: Store, @@ -61,6 +63,7 @@ export class TagsComponent extends PaginationFilterBaseComponent implements Afte debounceTime(300), tap(() => (this.loading = true)), tap(() => this.getTags()), + tap(() => this.getTagTypes()), tap(() => this.clearItem()), untilDestroyed(this) ) @@ -232,10 +235,17 @@ export class TagsComponent extends PaginationFilterBaseComponent implements Afte instance.value = cell.getValue(); } }, + tagTypeName: { + title: this.getTranslation('TAGS_PAGE.TAGS_TYPE'), + type: 'string', + width: '20%', + isFilterable: false + }, description: { title: this.getTranslation('TAGS_PAGE.TAGS_DESCRIPTION'), type: 'string', - width: '70%' + width: '70%', + isFilterable: false }, counter: { title: this.getTranslation('Counter'), @@ -277,23 +287,53 @@ export class TagsComponent extends PaginationFilterBaseComponent implements Afte return counter; }; + async getTagTypes() { + this.loading = true; + const { tenantId } = this.store.user; + const { id: organizationId } = this.organization; + + try { + const { items } = await this.tagTypesService.getTagTypes({ + tenantId, + organizationId + }); + + this.tagTypes = items; + + this.filterOptions.push( + ...this.tagTypes.map((tagType) => { + return { + value: tagType.id, + displayName: tagType.type + }; + }) + ); + this.loading = false; + } catch (error) { + this.loading = false; + this.toastrService.danger('TAGS_PAGE.TAGS_FETCH_FAILED', 'Error fetching tag types'); + } + } + async getTags() { this.allTags = []; - this.filterOptions = [{ property: 'all', displayName: 'All' }]; + this.filterOptions = [{ value: '', displayName: 'All' }]; const { tenantId } = this.store.user; const { id: organizationId } = this.organization; - const { items } = await this.tagsService.getTags({ - tenantId, - organizationId - }); + const { items } = await this.tagsService.getTags( + { + tenantId, + organizationId + }, + ['tagType'] + ); const { activePage, itemsPerPage } = this.getPagination(); this.allTags = items; - this._generateUniqueTags(this.allTags); this.smartTableSource.setPaging(activePage, itemsPerPage, false); if (!this._isFiltered) { this.smartTableSource.load(this.allTags); @@ -327,14 +367,14 @@ export class TagsComponent extends PaginationFilterBaseComponent implements Afte * @returns */ selectedFilterOption(value: string) { - if (value === 'all') { + if (value === '') { this._isFiltered = false; this._refresh$.next(true); this.tags$.next(true); return; } if (value) { - const tags = this.allTags.filter((tag) => tag[value] && parseInt(tag[value]) > 0); + const tags = this.allTags.filter((tag) => tag.tagTypeId === value); this._isFiltered = true; this._refresh$.next(true); this.smartTableSource.load(tags); @@ -342,28 +382,6 @@ export class TagsComponent extends PaginationFilterBaseComponent implements Afte } } - /** - * Generate Unique Tags - * - * @param tags - */ - private _generateUniqueTags(tags: any[]) { - tags.forEach((tag) => { - for (const property in tag) { - const substring = '_counter'; - if (property.includes(substring) && parseInt(tag[property]) > 0) { - const options = this.filterOptions.find((option) => option.property === property); - if (!options) { - this.filterOptions.push({ - property, - displayName: splitCamelCase(property.replace(substring, '')) - }); - } - } - } - }); - } - private _applyTranslationOnSmartTable() { this.translateService.onLangChange .pipe( diff --git a/packages/contracts/src/lib/tag.model.ts b/packages/contracts/src/lib/tag.model.ts index 6bf74ccd58d..2000c46188c 100644 --- a/packages/contracts/src/lib/tag.model.ts +++ b/packages/contracts/src/lib/tag.model.ts @@ -25,9 +25,11 @@ export interface ITag extends IBasePerTenantAndOrganizationEntityModel, IRelatio /** * Input interface for finding tags with optional filters. */ -export interface ITagFindInput extends IBasePerTenantAndOrganizationEntityModel, Partial< - Pick -> {} +export interface ITagFindInput + extends IBasePerTenantAndOrganizationEntityModel, + Partial< + Pick + > {} /** * Input interface for creating a tag. @@ -56,6 +58,11 @@ export interface ITagTypeCreateInput extends Omit {} +/** + * Input interface for finding tag Type with optional filters. + */ +export interface ITagTypesFindInput extends IBasePerTenantAndOrganizationEntityModel, Partial> {} + /** * Enum for default task tags. */ diff --git a/packages/core/src/lib/app/app.module.ts b/packages/core/src/lib/app/app.module.ts index 92963eed3d5..3f59188f482 100644 --- a/packages/core/src/lib/app/app.module.ts +++ b/packages/core/src/lib/app/app.module.ts @@ -158,6 +158,7 @@ import { SubscriptionModule } from '../subscription/subscription.module'; import { DashboardModule } from '../dashboard/dashboard.module'; import { DashboardWidgetModule } from '../dashboard/dashboard-widget/dashboard-widget.module'; import { TenantApiKeyModule } from '../tenant-api-key/tenant-api-key.module'; +import { TagTypeModule } from '../tag-type'; const { unleashConfig } = environment; @@ -389,6 +390,7 @@ if (environment.THROTTLE_ENABLED) { TenantModule, TenantSettingModule, TagModule, + TagTypeModule, SkillModule, LanguageModule, InvoiceModule, diff --git a/packages/core/src/lib/core/seeds/seed-data.service.ts b/packages/core/src/lib/core/seeds/seed-data.service.ts index e99ccbb3075..023ccbb73a3 100644 --- a/packages/core/src/lib/core/seeds/seed-data.service.ts +++ b/packages/core/src/lib/core/seeds/seed-data.service.ts @@ -210,6 +210,7 @@ import { createDefaultPriorities } from './../../tasks/priorities/priority.seed' import { createDefaultSizes } from './../../tasks/sizes/size.seed'; import { createDefaultIssueTypes } from './../../tasks/issue-type/issue-type.seed'; import { getDBType } from './../../core/utils'; +import { createRandomOrganizationTagTypes, createTagTypes } from '../../tag-type/tag-type.seed'; export enum SeederTypeEnum { ALL = 'all', @@ -574,6 +575,8 @@ export class SeedDataService { await this.tryExecute('Default Tags', createDefaultTags(this.dataSource, this.tenant, this.organizations)); + await this.tryExecute('Default Tag Types', createTagTypes(this.dataSource, this.tenant, this.organizations)); + // Organization level inserts which need connection, tenant, role, organizations const categories = await this.tryExecute( 'Default Expense Categories', @@ -1010,6 +1013,11 @@ export class SeedDataService { createRandomOrganizationTags(this.dataSource, this.randomTenants, this.randomTenantOrganizationsMap) ); + await this.tryExecute( + 'Random Organization Tag Types', + createRandomOrganizationTagTypes(this.dataSource, this.randomTenants, this.randomTenantOrganizationsMap) + ); + await this.tryExecute( 'Random Organization Documents', createRandomOrganizationDocuments(this.dataSource, this.randomTenants, this.randomTenantOrganizationsMap) diff --git a/packages/core/src/lib/tag-type/tag-type.controller.ts b/packages/core/src/lib/tag-type/tag-type.controller.ts index a13d837b079..4362765f9b6 100644 --- a/packages/core/src/lib/tag-type/tag-type.controller.ts +++ b/packages/core/src/lib/tag-type/tag-type.controller.ts @@ -71,9 +71,7 @@ export class TagTypeController extends CrudController { }) @Permissions(PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_TAG_TYPES_VIEW) @Get('/') - async findAll( - @Query(new ValidationPipe()) options: PaginationParams - ): Promise> { + async findAll(@Query(new ValidationPipe()) options: PaginationParams): Promise> { return await this.tagTypesService.findAll(options); } diff --git a/packages/core/src/lib/tag-type/tag-type.seed.ts b/packages/core/src/lib/tag-type/tag-type.seed.ts index ca8e116fe1d..4382ec10e9d 100644 --- a/packages/core/src/lib/tag-type/tag-type.seed.ts +++ b/packages/core/src/lib/tag-type/tag-type.seed.ts @@ -55,6 +55,61 @@ export const createTagTypes = async ( return insertTagTypes(dataSource, tagTypes); }; +/** + * Creates random organization tag types for given tenants and their organizations. + * + * @function createRandomOrganizationTagTypes + * @async + * @param {DataSource} dataSource - The TypeORM `DataSource` instance used for database operations. + * @param {ITenant[]} tenants - An array of tenant entities for which random tag types are being created. + * @param {Map} tenantOrganizationsMap - A map linking each tenant to its associated organizations. + * @returns {Promise} - A promise that resolves to an array of created and saved `ITagType` entities. + * + * @description + * This function generates random tag types for multiple tenants and their organizations. + * For each tenant, it retrieves the associated organizations from the `tenantOrganizationsMap`. + * It iterates over the organizations and creates `TagType` entities based on predefined + * `DEFAULT_TAG_TYPES`. The generated entities are saved in bulk into the database. + * + * If a tenant does not have any organizations, the function logs a warning and skips the tenant. + * + * @throws Will throw an error if the database save operation fails. + */ +export const createRandomOrganizationTagTypes = async ( + dataSource: DataSource, + tenants: ITenant[], + tenantOrganizationsMap: Map +): Promise => { + let tagTypes: TagType[] = []; + + for (const tenant of tenants) { + // Fetch organizations for the current tenant + const organizations = tenantOrganizationsMap.get(tenant); + + if (!organizations || organizations.length === 0) { + console.warn(`No organizations found for tenant ID: ${tenant.id}`); + continue; // Skip to the next tenant if no organizations are found + } + + for (const organization of organizations) { + // Create TagType instances for the current organization + const organizationTagTypes: TagType[] = DEFAULT_TAG_TYPES.map(({ type }) => { + const tagType = new TagType(); + tagType.type = type; + tagType.organization = organization; + tagType.tenantId = tenant.id; + return tagType; + }); + + // Add the new TagType entities to the tagTypes array + tagTypes.push(...organizationTagTypes); + } + } + + // Bulk save all created tag types into the database + return await dataSource.manager.save(tagTypes); +}; + /** * Inserts an array of tag types into the database. * diff --git a/packages/core/src/lib/tags/commands/tag.list.command.ts b/packages/core/src/lib/tags/commands/tag.list.command.ts index ac7326d9f5c..949b052ee06 100644 --- a/packages/core/src/lib/tags/commands/tag.list.command.ts +++ b/packages/core/src/lib/tags/commands/tag.list.command.ts @@ -7,6 +7,6 @@ export class TagListCommand implements ICommand { constructor( public readonly input: FindOptionsWhere, - public readonly relations: string[] | FindOptionsRelations, - ) { } + public readonly relations: string[] | FindOptionsRelations + ) {} } diff --git a/packages/core/src/lib/tags/dto/create-tag.dto.ts b/packages/core/src/lib/tags/dto/create-tag.dto.ts index 663db93d794..1aeae4a854f 100644 --- a/packages/core/src/lib/tags/dto/create-tag.dto.ts +++ b/packages/core/src/lib/tags/dto/create-tag.dto.ts @@ -3,7 +3,9 @@ import { ITagCreateInput } from '@gauzy/contracts'; import { TenantOrganizationBaseDTO } from './../../core/dto'; import { Tag } from './../tag.entity'; -export class CreateTagDTO extends IntersectionType( - PartialType(TenantOrganizationBaseDTO), - PickType(Tag, ['name', 'description', 'color', 'textColor', 'icon', 'organizationTeamId']) -) implements ITagCreateInput { } +export class CreateTagDTO + extends IntersectionType( + PartialType(TenantOrganizationBaseDTO), + PickType(Tag, ['name', 'description', 'color', 'textColor', 'icon', 'organizationTeamId', 'tagTypeId']) + ) + implements ITagCreateInput {} diff --git a/packages/core/src/lib/tags/dto/update-tag.dto.ts b/packages/core/src/lib/tags/dto/update-tag.dto.ts index c1433adf805..0a06628b0a1 100644 --- a/packages/core/src/lib/tags/dto/update-tag.dto.ts +++ b/packages/core/src/lib/tags/dto/update-tag.dto.ts @@ -3,7 +3,11 @@ import { ITagUpdateInput } from '@gauzy/contracts'; import { TenantOrganizationBaseDTO } from './../../core/dto'; import { Tag } from './../tag.entity'; -export class UpdateTagDTO extends IntersectionType( - PartialType(TenantOrganizationBaseDTO), - PartialType(PickType(Tag, ['name', 'description', 'color', 'textColor', 'icon', 'organizationTeamId'])), -) implements ITagUpdateInput { } +export class UpdateTagDTO + extends IntersectionType( + PartialType(TenantOrganizationBaseDTO), + PartialType( + PickType(Tag, ['name', 'description', 'color', 'textColor', 'icon', 'organizationTeamId', 'tagTypeId']) + ) + ) + implements ITagUpdateInput {} diff --git a/packages/core/src/lib/tags/tag.service.ts b/packages/core/src/lib/tags/tag.service.ts index 7f558414886..59fed9438fe 100644 --- a/packages/core/src/lib/tags/tag.service.ts +++ b/packages/core/src/lib/tags/tag.service.ts @@ -62,7 +62,9 @@ export class TagService extends TenantAwareCrudService { query.setFindOptions({ ...(relations ? { relations: relations } : {}) }); + // Left join all relational tables with tag table + query.leftJoin(`${query.alias}.tagType`, 'tagType'); query.leftJoin(`${query.alias}.candidates`, 'candidate'); query.leftJoin(`${query.alias}.employees`, 'employee'); query.leftJoin(`${query.alias}.employeeLevels`, 'employeeLevel'); @@ -100,6 +102,8 @@ export class TagService extends TenantAwareCrudService { // Add new selection to the SELECT query query.select(`${query.alias}.*`); + + query.addSelect(p(`"tagType"."type"`), `tagTypeName`); // Add the select statement for counting, and cast it to integer query.addSelect(p(`CAST(COUNT("candidate"."id") AS INTEGER)`), `candidate_counter`); query.addSelect(p(`CAST(COUNT("employee"."id") AS INTEGER)`), `employee_counter`); @@ -145,6 +149,7 @@ export class TagService extends TenantAwareCrudService { // Adds GROUP BY condition in the query builder. query.addGroupBy(`${query.alias}.id`); + query.addGroupBy(`tagType.type`); // Additionally you can add parameters used in where expression. query.where((qb: SelectQueryBuilder) => { this.getFilterTagQuery(qb, input); @@ -184,7 +189,10 @@ export class TagService extends TenantAwareCrudService { // Optional organization filter query.andWhere( new Brackets((qb) => { - qb.where(`${query.alias}.organizationId IS NULL`).orWhere(`${query.alias}.organizationId = :organizationId`, { organizationId }); + qb.where(`${query.alias}.organizationId IS NULL`).orWhere( + `${query.alias}.organizationId = :organizationId`, + { organizationId } + ); }) ); diff --git a/packages/ui-core/core/src/lib/services/index.ts b/packages/ui-core/core/src/lib/services/index.ts index 13ff52edc71..ae7de292897 100644 --- a/packages/ui-core/core/src/lib/services/index.ts +++ b/packages/ui-core/core/src/lib/services/index.ts @@ -57,6 +57,7 @@ export * from './server-connection'; export * from './skill'; export * from './state'; export * from './tag'; +export * from './tag-type'; export * from './tasks'; export * from './tenant'; export * from './time-off'; diff --git a/packages/ui-core/core/src/lib/services/tag-type/index.ts b/packages/ui-core/core/src/lib/services/tag-type/index.ts new file mode 100644 index 00000000000..cdbbb47ac6a --- /dev/null +++ b/packages/ui-core/core/src/lib/services/tag-type/index.ts @@ -0,0 +1 @@ +export * from './tag-types.service'; diff --git a/packages/ui-core/core/src/lib/services/tag-type/tag-types.service.ts b/packages/ui-core/core/src/lib/services/tag-type/tag-types.service.ts new file mode 100644 index 00000000000..bcb09c424c1 --- /dev/null +++ b/packages/ui-core/core/src/lib/services/tag-type/tag-types.service.ts @@ -0,0 +1,65 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { firstValueFrom } from 'rxjs'; +import { IPagination, ITagType, ITagTypesFindInput } from '@gauzy/contracts'; +import { API_PREFIX, toParams } from '@gauzy/ui-core/common'; +import { CrudService } from '../crud/crud.service'; + +@Injectable({ providedIn: 'root' }) +export class TagTypesService extends CrudService { + static readonly API_URL = `${API_PREFIX}/tag-types`; + + constructor(http: HttpClient) { + super(http, TagTypesService.API_URL); + } + + /** + * Get all tag types with pagination and filter options + * + * @param where - Filtering options + * @param relations - Optional relations to include in the response + * @returns A promise resolving to a paginated list of tag types + */ + getTagTypes(where: ITagTypesFindInput, relations: string[] = []): Promise> { + return firstValueFrom( + this.http.get>(`${TagTypesService.API_URL}`, { + params: toParams({ where, relations }) + }) + ); + } + + /** + * Get the count of tag types + * + * @param where - Optional filter criteria + * @returns A promise resolving to the count of tag types + */ + getTagTypesCount(where: ITagTypesFindInput): Promise { + return firstValueFrom( + this.http.get(`${TagTypesService.API_URL}/count`, { + params: toParams({ where }) + }) + ); + } + + /** + * Create a new tag type + * + * @param tagType - The tag type data to create + * @returns A promise resolving to the created tag type + */ + createTagType(tagType: ITagType): Promise { + return firstValueFrom(this.http.post(`${TagTypesService.API_URL}`, tagType)); + } + + /** + * Update an existing tag type by its ID + * + * @param id - The ID of the tag type to update + * @param tagType - The new data for the tag type + * @returns A promise resolving to the updated tag type + */ + updateTagType(id: string, tagType: ITagType): Promise { + return firstValueFrom(this.http.put(`${TagTypesService.API_URL}/${id}`, tagType)); + } +} diff --git a/packages/ui-core/i18n/assets/i18n/ach.json b/packages/ui-core/i18n/assets/i18n/ach.json index 489558d3ea0..f6869b8b36d 100644 --- a/packages/ui-core/i18n/assets/i18n/ach.json +++ b/packages/ui-core/i18n/assets/i18n/ach.json @@ -2155,7 +2155,8 @@ "TAGS_SELECT_DESCRIPTION": "crwdns3166:0crwdne3166:0", "ADD_NEW_TAG": "crwdns4306:0crwdne4306:0", "TENANT_LEVEL": "crwdns4726:0crwdne4726:0", - "TAGS_TYPE": "crwdns10274:0crwdne10274:0" + "TAGS_TYPE": "crwdns10274:0crwdne10274:0", + "TAGS_SELECT_TYPE": "Yeny tags kikome" }, "SKILLS_PAGE": { "HEADER": "crwdns3920:0crwdne3920:0" @@ -3455,7 +3456,6 @@ "REMOVE_EMPLOYEE_LEVEL": "crwdns8952:0{{ name }}crwdne8952:0", "INVALID_EMPLOYEE_LEVEL": "crwdns3490:0crwdne3490:0", "ALREADY_EXISTS": "Kombedi me Employee tye ka bino." - }, "EDIT_ORGANIZATIONS_VENDOR": { "ADD_VENDOR": "crwdns8954:0{{ name }}crwdne8954:0", @@ -3475,7 +3475,6 @@ "REMOVE_POSITION": "crwdns8970:0{{ name }}crwdne8970:0", "INVALID_POSITION_NAME": "crwdns2825:0crwdne2825:0", "ALREADY_EXISTS": "Kombedi me Position tye ka bino." - }, "EDIT_ORGANIZATIONS_DEPARTMENTS": { "ADD_DEPARTMENT": "crwdns8972:0{{ name }}crwdne8972:0", diff --git a/packages/ui-core/i18n/assets/i18n/ar.json b/packages/ui-core/i18n/assets/i18n/ar.json index 840a465f085..3e008102d0b 100644 --- a/packages/ui-core/i18n/assets/i18n/ar.json +++ b/packages/ui-core/i18n/assets/i18n/ar.json @@ -2355,7 +2355,8 @@ "TAGS_SELECT_DESCRIPTION": "وصف العلامة", "ADD_NEW_TAG": "إضافة وسم جديد", "TENANT_LEVEL": "مستوى المستأجر", - "TAGS_TYPE": "نوع العلامات" + "TAGS_TYPE": "نوع العلامات", + "TAGS_SELECT_TYPE": "اختر نوع العلامات" }, "SKILLS_PAGE": { "HEADER": "مهارات" diff --git a/packages/ui-core/i18n/assets/i18n/bg.json b/packages/ui-core/i18n/assets/i18n/bg.json index 01c62f2b80a..58b4142d913 100644 --- a/packages/ui-core/i18n/assets/i18n/bg.json +++ b/packages/ui-core/i18n/assets/i18n/bg.json @@ -2416,7 +2416,8 @@ "TAGS_SELECT_DESCRIPTION": "Tag description", "ADD_NEW_TAG": "Add new Tag", "TENANT_LEVEL": "Tenant level", - "TAGS_TYPE": "Tags type" + "TAGS_TYPE": "Tags type", + "TAGS_SELECT_TYPE": "Изберете тип на етикетите" }, "SKILLS_PAGE": { "HEADER": "Skills" diff --git a/packages/ui-core/i18n/assets/i18n/de.json b/packages/ui-core/i18n/assets/i18n/de.json index f586d3f0201..7a965a3c89d 100644 --- a/packages/ui-core/i18n/assets/i18n/de.json +++ b/packages/ui-core/i18n/assets/i18n/de.json @@ -2353,7 +2353,8 @@ "TAGS_SELECT_DESCRIPTION": "Tag Beschreibung", "ADD_NEW_TAG": "Neuen Tag hinzufügen", "TENANT_LEVEL": "Mieterstufe", - "TAGS_TYPE": "Tags-Typ" + "TAGS_TYPE": "Tags-Typ", + "TAGS_SELECT_TYPE": "Tag-Typ auswählen" }, "SKILLS_PAGE": { "HEADER": "Fähigkeiten" diff --git a/packages/ui-core/i18n/assets/i18n/en.json b/packages/ui-core/i18n/assets/i18n/en.json index 8bab1dfae24..52bb5062554 100644 --- a/packages/ui-core/i18n/assets/i18n/en.json +++ b/packages/ui-core/i18n/assets/i18n/en.json @@ -2480,7 +2480,8 @@ "TAGS_SELECT_DESCRIPTION": "Tag description", "ADD_NEW_TAG": "Add new Tag", "TENANT_LEVEL": "Tenant level", - "TAGS_TYPE": "Tags type" + "TAGS_TYPE": "Tags type", + "TAGS_SELECT_TYPE": "Select tag type" }, "SKILLS_PAGE": { "HEADER": "Skills" diff --git a/packages/ui-core/i18n/assets/i18n/es.json b/packages/ui-core/i18n/assets/i18n/es.json index a416e8c82c5..4b95d029ad3 100644 --- a/packages/ui-core/i18n/assets/i18n/es.json +++ b/packages/ui-core/i18n/assets/i18n/es.json @@ -2359,7 +2359,8 @@ "TAGS_SELECT_DESCRIPTION": "Descripción de etiqueta", "ADD_NEW_TAG": "Agregar nueva etiqueta.", "TENANT_LEVEL": "Nivel de inquilino", - "TAGS_TYPE": "Tipo de etiquetas" + "TAGS_TYPE": "Tipo de etiquetas", + "TAGS_SELECT_TYPE": "Seleccionar tipo de etiqueta" }, "SKILLS_PAGE": { "HEADER": "Habilidades." diff --git a/packages/ui-core/i18n/assets/i18n/fr.json b/packages/ui-core/i18n/assets/i18n/fr.json index a7984153aa7..7240dadfaa0 100644 --- a/packages/ui-core/i18n/assets/i18n/fr.json +++ b/packages/ui-core/i18n/assets/i18n/fr.json @@ -2358,7 +2358,8 @@ "TAGS_SELECT_DESCRIPTION": "Description du tag", "ADD_NEW_TAG": "Ajouter un nouveau Tag", "TENANT_LEVEL": "Niveau du locataire", - "TAGS_TYPE": "Catégories de balises" + "TAGS_TYPE": "Catégories de balises", + "TAGS_SELECT_TYPE": "Sélectionnez le type de balise" }, "SKILLS_PAGE": { "HEADER": "Compétences" diff --git a/packages/ui-core/i18n/assets/i18n/he.json b/packages/ui-core/i18n/assets/i18n/he.json index 24107f61ff9..c585639a29d 100644 --- a/packages/ui-core/i18n/assets/i18n/he.json +++ b/packages/ui-core/i18n/assets/i18n/he.json @@ -2382,7 +2382,9 @@ "TAGS_SELECT_DESCRIPTION": "Tag description", "ADD_NEW_TAG": "Add new Tag", "TENANT_LEVEL": "Tenant level", - "TAGS_TYPE": "Tags type" + "TAGS_TYPE": "Tags type", + "TAGS_SELECT_TYPE": "בחר סוג תג" + }, "SKILLS_PAGE": { "HEADER": "Skills" diff --git a/packages/ui-core/i18n/assets/i18n/it.json b/packages/ui-core/i18n/assets/i18n/it.json index 35ce980145b..6edb6a68fc3 100644 --- a/packages/ui-core/i18n/assets/i18n/it.json +++ b/packages/ui-core/i18n/assets/i18n/it.json @@ -2357,7 +2357,8 @@ "TAGS_SELECT_DESCRIPTION": "Descrizione del tag", "ADD_NEW_TAG": "Aggiungi nuovo Tag", "TENANT_LEVEL": "Livello dell'inquilino", - "TAGS_TYPE": "Tipo di tag" + "TAGS_TYPE": "Tipo di tag", + "TAGS_SELECT_TYPE": "Seleziona il tipo di tag" }, "SKILLS_PAGE": { "HEADER": "Abilità" diff --git a/packages/ui-core/i18n/assets/i18n/nl.json b/packages/ui-core/i18n/assets/i18n/nl.json index f97833e36f7..3a9339804d0 100644 --- a/packages/ui-core/i18n/assets/i18n/nl.json +++ b/packages/ui-core/i18n/assets/i18n/nl.json @@ -2357,7 +2357,8 @@ "TAGS_SELECT_DESCRIPTION": "Tagbeschrijving", "ADD_NEW_TAG": "Voeg nieuwe tag toe", "TENANT_LEVEL": "Huurdersniveau", - "TAGS_TYPE": "Tagstype" + "TAGS_TYPE": "Tagstype", + "TAGS_SELECT_TYPE": "Selecteer tagtype" }, "SKILLS_PAGE": { "HEADER": "Vaardigheden" diff --git a/packages/ui-core/i18n/assets/i18n/pl.json b/packages/ui-core/i18n/assets/i18n/pl.json index aafa03e3ae7..0d90e6fb9f7 100644 --- a/packages/ui-core/i18n/assets/i18n/pl.json +++ b/packages/ui-core/i18n/assets/i18n/pl.json @@ -2357,7 +2357,8 @@ "TAGS_SELECT_DESCRIPTION": "Opis tagu", "ADD_NEW_TAG": "Dodaj nową etykietę", "TENANT_LEVEL": "Poziom najemcy", - "TAGS_TYPE": "Typy tagów" + "TAGS_TYPE": "Typy tagów", + "TAGS_SELECT_TYPE": "Wybierz typ tagu" }, "SKILLS_PAGE": { "HEADER": "Umiejętności" diff --git a/packages/ui-core/i18n/assets/i18n/pt.json b/packages/ui-core/i18n/assets/i18n/pt.json index f913de5dc21..7545809b9d0 100644 --- a/packages/ui-core/i18n/assets/i18n/pt.json +++ b/packages/ui-core/i18n/assets/i18n/pt.json @@ -2357,7 +2357,8 @@ "TAGS_SELECT_DESCRIPTION": "Descrição da tag", "ADD_NEW_TAG": "Adicionar nova Tag", "TENANT_LEVEL": "Nível do inquilino", - "TAGS_TYPE": "Tipo de etiquetas" + "TAGS_TYPE": "Tipo de etiquetas", + "TAGS_SELECT_TYPE": "Selecionar tipo de tag" }, "SKILLS_PAGE": { "HEADER": "Habilidades" diff --git a/packages/ui-core/i18n/assets/i18n/ru.json b/packages/ui-core/i18n/assets/i18n/ru.json index a1309bc4224..20b844905b6 100644 --- a/packages/ui-core/i18n/assets/i18n/ru.json +++ b/packages/ui-core/i18n/assets/i18n/ru.json @@ -2388,7 +2388,8 @@ "TAGS_SELECT_DESCRIPTION": "Описание метки", "ADD_NEW_TAG": "Добавить новый тег", "TENANT_LEVEL": "Уровень владельца", - "TAGS_TYPE": "Тип тегов" + "TAGS_TYPE": "Тип тегов", + "TAGS_SELECT_TYPE": "Выберите тип тега" }, "SKILLS_PAGE": { "HEADER": "Навыки" diff --git a/packages/ui-core/i18n/assets/i18n/zh.json b/packages/ui-core/i18n/assets/i18n/zh.json index 01886616a4d..f394e8b1f8c 100644 --- a/packages/ui-core/i18n/assets/i18n/zh.json +++ b/packages/ui-core/i18n/assets/i18n/zh.json @@ -2357,7 +2357,8 @@ "TAGS_SELECT_DESCRIPTION": "标签描述", "ADD_NEW_TAG": "添加新标签", "TENANT_LEVEL": "租户级别", - "TAGS_TYPE": "标签类型" + "TAGS_TYPE": "标签类型", + "TAGS_SELECT_TYPE": "选择标签类型" }, "SKILLS_PAGE": { "HEADER": "技能 (Jìnéng)" diff --git a/packages/ui-core/shared/src/lib/tags/tags-mutation.component.html b/packages/ui-core/shared/src/lib/tags/tags-mutation.component.html index 275da7f7b46..063551cd825 100644 --- a/packages/ui-core/shared/src/lib/tags/tags-mutation.component.html +++ b/packages/ui-core/shared/src/lib/tags/tags-mutation.component.html @@ -4,9 +4,7 @@
- {{ - (tag ? 'TAGS_PAGE.EDIT_TAGS' : 'TAGS_PAGE.ADD_TAGS') | translate - }} + {{ (tag ? 'TAGS_PAGE.EDIT_TAGS' : 'TAGS_PAGE.ADD_TAGS') | translate }}
@@ -22,9 +20,7 @@
class="select-name" type="text" nbInput - [placeholder]=" - 'TAGS_PAGE.TAGS_SELECT_NAME' | translate - " + [placeholder]="'TAGS_PAGE.TAGS_SELECT_NAME' | translate" id="inputName" fullWidth /> @@ -78,24 +74,32 @@
+
+
+
+ + + + {{ tagType.type }} + + +
+
+
- - diff --git a/packages/ui-core/shared/src/lib/tags/tags-mutation.component.ts b/packages/ui-core/shared/src/lib/tags/tags-mutation.component.ts index 410e5f508a2..9f27518fa92 100644 --- a/packages/ui-core/shared/src/lib/tags/tags-mutation.component.ts +++ b/packages/ui-core/shared/src/lib/tags/tags-mutation.component.ts @@ -3,8 +3,8 @@ import { UntypedFormGroup, UntypedFormBuilder, Validators } from '@angular/forms import { NbDialogRef, NbThemeService } from '@nebular/theme'; import { firstValueFrom } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; -import { ITag } from '@gauzy/contracts'; -import { Store } from '@gauzy/ui-core/core'; +import { ITag, ITagType } from '@gauzy/contracts'; +import { Store, TagTypesService, ToastrService } from '@gauzy/ui-core/core'; import { TagsService } from '@gauzy/ui-core/core'; import { NotesWithTagsComponent } from '../table-components'; @@ -23,10 +23,16 @@ export class TagsMutationComponent extends NotesWithTagsComponent implements OnI name: [null, Validators.required], color: [null, Validators.required], isTenantLevel: [false], - description: [] + description: [], + tagTypeId: [] }); } + /** + * List of tag types + */ + public tagTypes: ITagType[] = []; + /* * Getter & Setter for tag to edit */ @@ -40,7 +46,8 @@ export class TagsMutationComponent extends NotesWithTagsComponent implements OnI } /** - * Getter for color form control + * Getter fr + * or color form control */ get color() { return this.form.get('color').value || ''; @@ -49,15 +56,40 @@ export class TagsMutationComponent extends NotesWithTagsComponent implements OnI constructor( protected readonly dialogRef: NbDialogRef, private readonly tagsService: TagsService, + private readonly tagTypeService: TagTypesService, private readonly fb: UntypedFormBuilder, public readonly translateService: TranslateService, public readonly themeService: NbThemeService, - private readonly store: Store + private readonly store: Store, + private readonly toastrService: ToastrService ) { super(themeService, translateService); } - ngOnInit(): void {} + ngOnInit(): void { + this._loadTagTypes(); + } + + /** + * Fetch all tag types from the TagTypeService + */ + private async _loadTagTypes() { + const { tenantId } = this.store.user; + const organizationId = this.store.organizationId; + + try { + const { items } = await this.tagTypeService.getTagTypes({ + tenantId, + organizationId + }); + + this.tagTypes = items; + } catch (error) { + console.log(error); + + this.toastrService.danger('TAGS_PAGE.TAGS_FETCH_FAILED', 'Error fetching tag types'); + } + } async addTag() { if (!this.store.selectedOrganization) { @@ -65,7 +97,7 @@ export class TagsMutationComponent extends NotesWithTagsComponent implements OnI } const { tenantId } = this.store.user; const { id: organizationId } = this.store.selectedOrganization; - const { name, description, color, isTenantLevel } = this.form.getRawValue(); + const { name, description, color, isTenantLevel, tagTypeId } = this.form.getRawValue(); const tag = await firstValueFrom( this.tagsService.create({ @@ -73,6 +105,7 @@ export class TagsMutationComponent extends NotesWithTagsComponent implements OnI description, color, tenantId, + tagTypeId, ...(isTenantLevel ? { organizationId: null @@ -93,7 +126,7 @@ export class TagsMutationComponent extends NotesWithTagsComponent implements OnI const { tenantId } = this.store.user; const { id: organizationId } = this.store.selectedOrganization; - const { name, description, color, isTenantLevel } = this.form.getRawValue(); + const { name, description, color, isTenantLevel, tagTypeId } = this.form.getRawValue(); const tag = await firstValueFrom( this.tagsService.update(this.tag.id, { @@ -101,6 +134,7 @@ export class TagsMutationComponent extends NotesWithTagsComponent implements OnI description, color, tenantId, + tagTypeId, ...(isTenantLevel ? { organizationId: null @@ -119,12 +153,13 @@ export class TagsMutationComponent extends NotesWithTagsComponent implements OnI private _patchFormValue() { if (this.tag) { - const { name, color, description, organizationId } = this.tag; + const { name, color, description, organizationId, tagTypeId } = this.tag; this.form.patchValue({ name, color, description, - isTenantLevel: organizationId ? false : true + isTenantLevel: organizationId ? false : true, + tagTypeId }); } }