mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 13:27:31 -08:00
refactor(core): Move remaining tags logic to service (no-changelog) (#6920)
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
parent
9e3e298aca
commit
9b9b891e68
|
@ -8,7 +8,7 @@ import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
|||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import config from '@/config';
|
||||
import { TagRepository } from '@/databases/repositories';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import Container from 'typedi';
|
||||
|
||||
function insertIf(condition: boolean, elements: string[]): string[] {
|
||||
|
@ -64,7 +64,7 @@ export async function getWorkflowById(id: string): Promise<WorkflowEntity | null
|
|||
* Intersection! e.g. workflow needs to have all provided tags.
|
||||
*/
|
||||
export async function getWorkflowIdsViaTags(tags: string[]): Promise<string[]> {
|
||||
const dbTags = await Container.get(TagRepository).find({
|
||||
const dbTags = await Container.get(TagService).findMany({
|
||||
where: { name: In(tags) },
|
||||
relations: ['workflows'],
|
||||
});
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
import type { EntityManager } from 'typeorm';
|
||||
import type { TagEntity } from '@db/entities/TagEntity';
|
||||
import type { ITagToImport, IWorkflowToImport } from '@/Interfaces';
|
||||
import { TagRepository } from './databases/repositories';
|
||||
import Container from 'typedi';
|
||||
|
||||
// ----------------------------------
|
||||
// utils
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* Sort tags based on the order of the tag IDs in the request.
|
||||
*/
|
||||
export function sortByRequestOrder(
|
||||
tags: TagEntity[],
|
||||
{ requestOrder }: { requestOrder: string[] },
|
||||
) {
|
||||
const tagMap = tags.reduce<Record<string, TagEntity>>((acc, tag) => {
|
||||
acc[tag.id] = tag;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return requestOrder.map((tagId) => tagMap[tagId]);
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// mutations
|
||||
// ----------------------------------
|
||||
|
||||
const createTag = async (transactionManager: EntityManager, name: string): Promise<TagEntity> => {
|
||||
const tag = Container.get(TagRepository).create({ name: name.trim() });
|
||||
return transactionManager.save<TagEntity>(tag);
|
||||
};
|
||||
|
||||
const findOrCreateTag = async (
|
||||
transactionManager: EntityManager,
|
||||
importTag: ITagToImport,
|
||||
tagsEntities: TagEntity[],
|
||||
): Promise<TagEntity> => {
|
||||
// Assume tag is identical if createdAt date is the same to preserve a changed tag name
|
||||
const identicalMatch = tagsEntities.find(
|
||||
(existingTag) =>
|
||||
existingTag.id === importTag.id &&
|
||||
existingTag.createdAt &&
|
||||
importTag.createdAt &&
|
||||
existingTag.createdAt.getTime() === new Date(importTag.createdAt).getTime(),
|
||||
);
|
||||
if (identicalMatch) {
|
||||
return identicalMatch;
|
||||
}
|
||||
|
||||
const nameMatch = tagsEntities.find((existingTag) => existingTag.name === importTag.name);
|
||||
if (nameMatch) {
|
||||
return nameMatch;
|
||||
}
|
||||
|
||||
const created = await createTag(transactionManager, importTag.name);
|
||||
tagsEntities.push(created);
|
||||
return created;
|
||||
};
|
||||
|
||||
const hasTags = (workflow: IWorkflowToImport) =>
|
||||
'tags' in workflow && Array.isArray(workflow.tags) && workflow.tags.length > 0;
|
||||
|
||||
/**
|
||||
* Set tag IDs to use existing tags, creates a new tag if no matching tag could be found
|
||||
*/
|
||||
export async function setTagsForImport(
|
||||
transactionManager: EntityManager,
|
||||
workflow: IWorkflowToImport,
|
||||
tags: TagEntity[],
|
||||
): Promise<void> {
|
||||
if (!hasTags(workflow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workflowTags = workflow.tags;
|
||||
const tagLookupPromises = [];
|
||||
for (let i = 0; i < workflowTags.length; i++) {
|
||||
if (workflowTags[i]?.name) {
|
||||
const lookupPromise = findOrCreateTag(transactionManager, workflowTags[i], tags).then(
|
||||
(tag) => {
|
||||
workflowTags[i] = {
|
||||
id: tag.id,
|
||||
name: tag.name,
|
||||
};
|
||||
},
|
||||
);
|
||||
tagLookupPromises.push(lookupPromise);
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(tagLookupPromises);
|
||||
}
|
|
@ -11,14 +11,13 @@ import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
|||
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { setTagsForImport } from '@/TagHelpers';
|
||||
import { disableAutoGeneratedIds } from '@db/utils/commandHelpers';
|
||||
import type { ICredentialsDb, IWorkflowToImport } from '@/Interfaces';
|
||||
import { replaceInvalidCredentials } from '@/WorkflowHelpers';
|
||||
import { BaseCommand, UM_FIX_INSTRUCTION } from '../BaseCommand';
|
||||
import { generateNanoId } from '@db/utils/generators';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { TagRepository } from '@/databases/repositories';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
|
||||
function assertHasWorkflowsToImport(workflows: unknown): asserts workflows is IWorkflowToImport[] {
|
||||
if (!Array.isArray(workflows)) {
|
||||
|
@ -66,6 +65,8 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
|
||||
private transactionManager: EntityManager;
|
||||
|
||||
private tagService = Container.get(TagService);
|
||||
|
||||
async init() {
|
||||
disableAutoGeneratedIds(WorkflowEntity);
|
||||
await super.init();
|
||||
|
@ -93,7 +94,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
const user = flags.userId ? await this.getAssignee(flags.userId) : await this.getOwner();
|
||||
|
||||
const credentials = await Db.collections.Credentials.find();
|
||||
const tags = await Container.get(TagRepository).find();
|
||||
const tags = await this.tagService.getAll();
|
||||
|
||||
let totalImported = 0;
|
||||
|
||||
|
@ -133,7 +134,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(workflow, 'tags')) {
|
||||
await setTagsForImport(transactionManager, workflow, tags);
|
||||
await this.tagService.setTagsForImport(transactionManager, workflow, tags);
|
||||
}
|
||||
|
||||
if (workflow.active) {
|
||||
|
@ -183,7 +184,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
}
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(workflow, 'tags')) {
|
||||
await setTagsForImport(transactionManager, workflow, tags);
|
||||
await this.tagService.setTagsForImport(transactionManager, workflow, tags);
|
||||
}
|
||||
if (workflow.active) {
|
||||
this.logger.info(
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
import { Request, Response, NextFunction } from 'express';
|
||||
import config from '@/config';
|
||||
import { Authorized, Delete, Get, Middleware, Patch, Post, RestController } from '@/decorators';
|
||||
import { type ITagWithCountDb } from '@/Interfaces';
|
||||
import type { TagEntity } from '@db/entities/TagEntity';
|
||||
import { TagRepository } from '@db/repositories';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { TagsRequest } from '@/requests';
|
||||
import { Service } from 'typedi';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
|
||||
@Authorized()
|
||||
@RestController('/tags')
|
||||
|
@ -16,10 +12,7 @@ import { ExternalHooks } from '@/ExternalHooks';
|
|||
export class TagsController {
|
||||
private config = config;
|
||||
|
||||
constructor(
|
||||
private tagsRepository: TagRepository,
|
||||
private externalHooks: ExternalHooks,
|
||||
) {}
|
||||
constructor(private tagService: TagService) {}
|
||||
|
||||
// TODO: move this into a new decorator `@IfEnabled('workflowTagsDisabled')`
|
||||
@Middleware()
|
||||
|
@ -29,61 +22,32 @@ export class TagsController {
|
|||
next();
|
||||
}
|
||||
|
||||
// Retrieves all tags, with or without usage count
|
||||
@Get('/')
|
||||
async getAll(req: TagsRequest.GetAll): Promise<TagEntity[] | ITagWithCountDb[]> {
|
||||
const { withUsageCount } = req.query;
|
||||
if (withUsageCount === 'true') {
|
||||
return this.tagsRepository
|
||||
.find({
|
||||
select: ['id', 'name', 'createdAt', 'updatedAt'],
|
||||
relations: ['workflowMappings'],
|
||||
})
|
||||
.then((tags) =>
|
||||
tags.map(({ workflowMappings, ...rest }) => ({
|
||||
...rest,
|
||||
usageCount: workflowMappings.length,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
return this.tagsRepository.find({ select: ['id', 'name', 'createdAt', 'updatedAt'] });
|
||||
async getAll(req: TagsRequest.GetAll) {
|
||||
return this.tagService.getAll({ withUsageCount: req.query.withUsageCount === 'true' });
|
||||
}
|
||||
|
||||
// Creates a tag
|
||||
@Post('/')
|
||||
async createTag(req: TagsRequest.Create): Promise<TagEntity> {
|
||||
const newTag = this.tagsRepository.create({ name: req.body.name.trim() });
|
||||
async createTag(req: TagsRequest.Create) {
|
||||
const tag = this.tagService.toEntity({ name: req.body.name });
|
||||
|
||||
await this.externalHooks.run('tag.beforeCreate', [newTag]);
|
||||
await validateEntity(newTag);
|
||||
|
||||
const tag = await this.tagsRepository.save(newTag);
|
||||
await this.externalHooks.run('tag.afterCreate', [tag]);
|
||||
return tag;
|
||||
return this.tagService.save(tag, 'create');
|
||||
}
|
||||
|
||||
// Updates a tag
|
||||
@Patch('/:id(\\w+)')
|
||||
async updateTag(req: TagsRequest.Update): Promise<TagEntity> {
|
||||
const newTag = this.tagsRepository.create({ id: req.params.id, name: req.body.name.trim() });
|
||||
async updateTag(req: TagsRequest.Update) {
|
||||
const newTag = this.tagService.toEntity({ id: req.params.id, name: req.body.name.trim() });
|
||||
|
||||
await this.externalHooks.run('tag.beforeUpdate', [newTag]);
|
||||
await validateEntity(newTag);
|
||||
|
||||
const tag = await this.tagsRepository.save(newTag);
|
||||
await this.externalHooks.run('tag.afterUpdate', [tag]);
|
||||
return tag;
|
||||
return this.tagService.save(newTag, 'update');
|
||||
}
|
||||
|
||||
@Authorized(['global', 'owner'])
|
||||
@Delete('/:id(\\w+)')
|
||||
async deleteTag(req: TagsRequest.Delete) {
|
||||
const { id } = req.params;
|
||||
await this.externalHooks.run('tag.beforeDelete', [id]);
|
||||
|
||||
await this.tagsRepository.delete({ id });
|
||||
await this.externalHooks.run('tag.afterDelete', [id]);
|
||||
await this.tagService.delete(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import type { SourceControlWorkflowVersionId } from './types/sourceControlWorkfl
|
|||
import type { ExportableCredential } from './types/exportableCredential';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { TagRepository } from '@/databases/repositories';
|
||||
|
||||
@Service()
|
||||
export class SourceControlService {
|
||||
private sshKeyName: string;
|
||||
|
|
|
@ -492,15 +492,12 @@ export class SourceControlImportService {
|
|||
`A tag with the name <strong>${tag.name}</strong> already exists locally.<br />Please either rename the local tag, or the remote one with the id <strong>${tag.id}</strong> in the tags.json file.`,
|
||||
);
|
||||
}
|
||||
await this.tagRepository.upsert(
|
||||
{
|
||||
...tag,
|
||||
},
|
||||
{
|
||||
skipUpdateIfNoValuesChanged: true,
|
||||
conflictPaths: { id: true },
|
||||
},
|
||||
);
|
||||
|
||||
const tagCopy = this.tagRepository.create(tag);
|
||||
await this.tagRepository.upsert(tagCopy, {
|
||||
skipUpdateIfNoValuesChanged: true,
|
||||
conflictPaths: { id: true },
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
157
packages/cli/src/services/tag.service.ts
Normal file
157
packages/cli/src/services/tag.service.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
import { TagRepository } from '@/databases/repositories';
|
||||
import { Service } from 'typedi';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import type { ITagToImport, ITagWithCountDb, IWorkflowToImport } from '@/Interfaces';
|
||||
import type { TagEntity } from '@/databases/entities/TagEntity';
|
||||
import type { EntityManager, FindManyOptions, FindOneOptions } from 'typeorm';
|
||||
import type { UpsertOptions } from 'typeorm/repository/UpsertOptions';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
|
||||
type GetAllResult<T> = T extends { withUsageCount: true } ? ITagWithCountDb[] : TagEntity[];
|
||||
|
||||
@Service()
|
||||
export class TagService {
|
||||
constructor(
|
||||
private externalHooks: ExternalHooks,
|
||||
private tagRepository: TagRepository,
|
||||
) {}
|
||||
|
||||
toEntity(attrs: { name: string; id?: string }) {
|
||||
attrs.name = attrs.name.trim();
|
||||
|
||||
return this.tagRepository.create(attrs);
|
||||
}
|
||||
|
||||
async save(tag: TagEntity, actionKind: 'create' | 'update') {
|
||||
await validateEntity(tag);
|
||||
|
||||
const action = actionKind[0].toUpperCase() + actionKind.slice(1);
|
||||
|
||||
await this.externalHooks.run(`tag.before${action}`, [tag]);
|
||||
|
||||
const savedTag = this.tagRepository.save(tag);
|
||||
|
||||
await this.externalHooks.run(`tag.after${action}`, [tag]);
|
||||
|
||||
return savedTag;
|
||||
}
|
||||
|
||||
async delete(id: string) {
|
||||
await this.externalHooks.run('tag.beforeDelete', [id]);
|
||||
|
||||
const deleteResult = this.tagRepository.delete(id);
|
||||
|
||||
await this.externalHooks.run('tag.afterDelete', [id]);
|
||||
|
||||
return deleteResult;
|
||||
}
|
||||
|
||||
async findOne(options: FindOneOptions<TagEntity>) {
|
||||
return this.tagRepository.findOne(options);
|
||||
}
|
||||
|
||||
async findMany(options: FindManyOptions<TagEntity>) {
|
||||
return this.tagRepository.find(options);
|
||||
}
|
||||
|
||||
async upsert(tag: TagEntity, options: UpsertOptions<TagEntity>) {
|
||||
return this.tagRepository.upsert(tag, options);
|
||||
}
|
||||
|
||||
async getAll<T extends { withUsageCount: boolean }>(options?: T): Promise<GetAllResult<T>> {
|
||||
if (options?.withUsageCount) {
|
||||
const allTags = await this.tagRepository.find({
|
||||
select: ['id', 'name', 'createdAt', 'updatedAt'],
|
||||
relations: ['workflowMappings'],
|
||||
});
|
||||
|
||||
return allTags.map(({ workflowMappings, ...rest }) => {
|
||||
return {
|
||||
...rest,
|
||||
usageCount: workflowMappings.length,
|
||||
} as ITagWithCountDb;
|
||||
}) as GetAllResult<T>;
|
||||
}
|
||||
|
||||
return this.tagRepository.find({
|
||||
select: ['id', 'name', 'createdAt', 'updatedAt'],
|
||||
}) as Promise<GetAllResult<T>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort tags based on the order of the tag IDs in the request.
|
||||
*/
|
||||
sortByRequestOrder(tags: TagEntity[], { requestOrder }: { requestOrder: string[] }) {
|
||||
const tagMap = tags.reduce<Record<string, TagEntity>>((acc, tag) => {
|
||||
acc[tag.id] = tag;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return requestOrder.map((tagId) => tagMap[tagId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tag IDs to use existing tags, creates a new tag if no matching tag could be found
|
||||
*/
|
||||
async setTagsForImport(
|
||||
transactionManager: EntityManager,
|
||||
workflow: IWorkflowToImport,
|
||||
tags: TagEntity[],
|
||||
) {
|
||||
if (!this.hasTags(workflow)) return;
|
||||
|
||||
const workflowTags = workflow.tags;
|
||||
const tagLookupPromises = [];
|
||||
for (let i = 0; i < workflowTags.length; i++) {
|
||||
if (workflowTags[i]?.name) {
|
||||
const lookupPromise = this.findOrCreateTag(transactionManager, workflowTags[i], tags).then(
|
||||
(tag) => {
|
||||
workflowTags[i] = {
|
||||
id: tag.id,
|
||||
name: tag.name,
|
||||
};
|
||||
},
|
||||
);
|
||||
tagLookupPromises.push(lookupPromise);
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(tagLookupPromises);
|
||||
}
|
||||
|
||||
private hasTags(workflow: IWorkflowToImport) {
|
||||
return 'tags' in workflow && Array.isArray(workflow.tags) && workflow.tags.length > 0;
|
||||
}
|
||||
|
||||
private async findOrCreateTag(
|
||||
transactionManager: EntityManager,
|
||||
importTag: ITagToImport,
|
||||
tagsEntities: TagEntity[],
|
||||
) {
|
||||
// Assume tag is identical if createdAt date is the same to preserve a changed tag name
|
||||
const identicalMatch = tagsEntities.find(
|
||||
(existingTag) =>
|
||||
existingTag.id === importTag.id &&
|
||||
existingTag.createdAt &&
|
||||
importTag.createdAt &&
|
||||
existingTag.createdAt.getTime() === new Date(importTag.createdAt).getTime(),
|
||||
);
|
||||
if (identicalMatch) {
|
||||
return identicalMatch;
|
||||
}
|
||||
|
||||
const nameMatch = tagsEntities.find((existingTag) => existingTag.name === importTag.name);
|
||||
if (nameMatch) {
|
||||
return nameMatch;
|
||||
}
|
||||
|
||||
const created = await this.txCreateTag(transactionManager, importTag.name);
|
||||
tagsEntities.push(created);
|
||||
return created;
|
||||
}
|
||||
|
||||
private async txCreateTag(transactionManager: EntityManager, name: string) {
|
||||
const tag = this.tagRepository.create({ name: name.trim() });
|
||||
return transactionManager.save<TagEntity>(tag);
|
||||
}
|
||||
}
|
|
@ -12,7 +12,6 @@ import { EEWorkflowsService as EEWorkflows } from './workflows.services.ee';
|
|||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { LoggerProxy } from 'n8n-workflow';
|
||||
import * as TagHelpers from '@/TagHelpers';
|
||||
import { EECredentialsService as EECredentials } from '../credentials/credentials.service.ee';
|
||||
import type { IExecutionPushResponse } from '@/Interfaces';
|
||||
import * as GenericHelpers from '@/GenericHelpers';
|
||||
|
@ -22,7 +21,7 @@ import { InternalHooks } from '@/InternalHooks';
|
|||
import { RoleService } from '@/services/role.service';
|
||||
import * as utils from '@/utils';
|
||||
import { listQueryMiddleware } from '@/middlewares';
|
||||
import { TagRepository } from '@/databases/repositories';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const EEWorkflowController = express.Router();
|
||||
|
@ -137,7 +136,7 @@ EEWorkflowController.post(
|
|||
const { tags: tagIds } = req.body;
|
||||
|
||||
if (tagIds?.length && !config.getEnv('workflowTagsDisabled')) {
|
||||
newWorkflow.tags = await Container.get(TagRepository).find({
|
||||
newWorkflow.tags = await Container.get(TagService).findMany({
|
||||
select: ['id', 'name'],
|
||||
where: {
|
||||
id: In(tagIds),
|
||||
|
@ -188,7 +187,7 @@ EEWorkflowController.post(
|
|||
}
|
||||
|
||||
if (tagIds && !config.getEnv('workflowTagsDisabled') && savedWorkflow.tags) {
|
||||
savedWorkflow.tags = TagHelpers.sortByRequestOrder(savedWorkflow.tags, {
|
||||
savedWorkflow.tags = Container.get(TagService).sortByRequestOrder(savedWorkflow.tags, {
|
||||
requestOrder: tagIds,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import * as ResponseHelper from '@/ResponseHelper';
|
|||
import * as WorkflowHelpers from '@/WorkflowHelpers';
|
||||
import type { IWorkflowResponse, IExecutionPushResponse } from '@/Interfaces';
|
||||
import config from '@/config';
|
||||
import * as TagHelpers from '@/TagHelpers';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
|
@ -26,7 +25,7 @@ import { InternalHooks } from '@/InternalHooks';
|
|||
import { RoleService } from '@/services/role.service';
|
||||
import * as utils from '@/utils';
|
||||
import { listQueryMiddleware } from '@/middlewares';
|
||||
import { TagRepository } from '@/databases/repositories';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
|
||||
export const workflowsController = express.Router();
|
||||
|
||||
|
@ -65,7 +64,7 @@ workflowsController.post(
|
|||
const { tags: tagIds } = req.body;
|
||||
|
||||
if (tagIds?.length && !config.getEnv('workflowTagsDisabled')) {
|
||||
newWorkflow.tags = await Container.get(TagRepository).find({
|
||||
newWorkflow.tags = await Container.get(TagService).findMany({
|
||||
select: ['id', 'name'],
|
||||
where: {
|
||||
id: In(tagIds),
|
||||
|
@ -101,7 +100,7 @@ workflowsController.post(
|
|||
}
|
||||
|
||||
if (tagIds && !config.getEnv('workflowTagsDisabled') && savedWorkflow.tags) {
|
||||
savedWorkflow.tags = TagHelpers.sortByRequestOrder(savedWorkflow.tags, {
|
||||
savedWorkflow.tags = Container.get(TagService).sortByRequestOrder(savedWorkflow.tags, {
|
||||
requestOrder: tagIds,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import type { User } from '@db/entities/User';
|
|||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import * as TagHelpers from '@/TagHelpers';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import type { ListQueryOptions, WorkflowRequest } from '@/requests';
|
||||
import type { IWorkflowDb, IWorkflowExecutionDataProcess } from '@/Interfaces';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
|
@ -299,7 +299,7 @@ export class WorkflowsService {
|
|||
}
|
||||
|
||||
if (updatedWorkflow.tags?.length && tagIds?.length) {
|
||||
updatedWorkflow.tags = TagHelpers.sortByRequestOrder(updatedWorkflow.tags, {
|
||||
updatedWorkflow.tags = Container.get(TagService).sortByRequestOrder(updatedWorkflow.tags, {
|
||||
requestOrder: tagIds,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue