mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
⚡ Add tags to GET /workflows
This commit is contained in:
parent
be7ec2d3e7
commit
ffea0a01f6
|
@ -23,6 +23,7 @@ import { Repository } from 'typeorm';
|
||||||
import { ChildProcess } from 'child_process';
|
import { ChildProcess } from 'child_process';
|
||||||
import { Url } from 'url';
|
import { Url } from 'url';
|
||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
|
import { TagEntity } from './databases/entities/TagEntity';
|
||||||
|
|
||||||
export interface IActivationError {
|
export interface IActivationError {
|
||||||
time: number;
|
time: number;
|
||||||
|
@ -80,13 +81,13 @@ export interface ITagBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITagDb extends ITagBase {
|
export interface ITagDb extends ITagBase {
|
||||||
id: number;
|
id: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Almost identical to editor-ui.Interfaces.ts
|
// Almost identical to editor-ui.Interfaces.ts
|
||||||
export interface IWorkflowDb extends IWorkflowBase {
|
export interface IWorkflowDb extends IWorkflowBase {
|
||||||
id: number | string;
|
id: number | string;
|
||||||
tags: Array<{ id: number; name: string }>;
|
tags: TagEntity[] | Array<{ id: string; name: string }>; // TODO: Unify
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWorkflowResponse extends IWorkflowBase {
|
export interface IWorkflowResponse extends IWorkflowBase {
|
||||||
|
|
|
@ -502,7 +502,7 @@ class App {
|
||||||
const { tags } = req.body as { tags: string };
|
const { tags } = req.body as { tags: string };
|
||||||
|
|
||||||
if (tags) {
|
if (tags) {
|
||||||
const tagIds = tags.split(',').map(Number);
|
const tagIds = tags.split(',');
|
||||||
await TagHelpers.createTagWorkflowRelations(result.id as string, tagIds);
|
await TagHelpers.createTagWorkflowRelations(result.id as string, tagIds);
|
||||||
result.tags = await TagHelpers.getTagsForResponseData(tagIds);
|
result.tags = await TagHelpers.getTagsForResponseData(tagIds);
|
||||||
}
|
}
|
||||||
|
@ -554,6 +554,19 @@ class App {
|
||||||
|
|
||||||
const results = await Db.collections.Workflow!.find(findQuery);
|
const results = await Db.collections.Workflow!.find(findQuery);
|
||||||
|
|
||||||
|
const tagsPerWorkflow = await TagHelpers.getTagsByWorkflowIds(results.map(({ id }) => id.toString()));
|
||||||
|
|
||||||
|
// TODO: Improve
|
||||||
|
tagsPerWorkflow.forEach(({ workflowId, id, name }) => {
|
||||||
|
results.forEach(result => {
|
||||||
|
if (result.id !== workflowId) return;
|
||||||
|
// @ts-ignore
|
||||||
|
result.tags = result.tags
|
||||||
|
? [...result.tags, { id, name }]
|
||||||
|
: [{ id, name }];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
for (const entry of results) {
|
for (const entry of results) {
|
||||||
(entry as unknown as IWorkflowShortResponse).id = entry.id.toString();
|
(entry as unknown as IWorkflowShortResponse).id = entry.id.toString();
|
||||||
}
|
}
|
||||||
|
@ -654,7 +667,7 @@ class App {
|
||||||
if (tags) {
|
if (tags) {
|
||||||
await TagHelpers.deleteAllTagsForWorkflow(id);
|
await TagHelpers.deleteAllTagsForWorkflow(id);
|
||||||
|
|
||||||
const tagIds = tags.split(',').map(Number);
|
const tagIds = tags.split(',');
|
||||||
|
|
||||||
for (const tagId of tagIds) {
|
for (const tagId of tagIds) {
|
||||||
await TagHelpers.validateId(tagId);
|
await TagHelpers.validateId(tagId);
|
||||||
|
@ -745,7 +758,7 @@ class App {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Creates a tag
|
// Creates a tag
|
||||||
this.app.post(`/${this.restEndpoint}/tags`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<{ id: number, name: string }> => {
|
this.app.post(`/${this.restEndpoint}/tags`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<{ id: string, name: string }> => {
|
||||||
TagHelpers.validateRequestBody(req.body);
|
TagHelpers.validateRequestBody(req.body);
|
||||||
|
|
||||||
const { name } = req.body;
|
const { name } = req.body;
|
||||||
|
@ -758,28 +771,28 @@ class App {
|
||||||
updatedAt: this.getCurrentDate(),
|
updatedAt: this.getCurrentDate(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const { id } = await Db.collections.Tag!.save(newTag);
|
const { id } = await Db.collections.Tag!.save(newTag) as { id: string };
|
||||||
|
|
||||||
return { id, name };
|
return { id, name };
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Deletes a tag
|
// Deletes a tag
|
||||||
this.app.delete(`/${this.restEndpoint}/tags/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
|
this.app.delete(`/${this.restEndpoint}/tags/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
|
||||||
const id = Number(req.params.id);
|
const { id } = req.params;
|
||||||
await TagHelpers.validateId(id);
|
await TagHelpers.validateId(id);
|
||||||
await Db.collections.Tag!.delete({ id });
|
await Db.collections.Tag!.delete({ id });
|
||||||
return true;
|
return true;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Updates an existing tag
|
// Updates an existing tag
|
||||||
this.app.patch(`/${this.restEndpoint}/tags/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<{ id: number, name: string }> => {
|
this.app.patch(`/${this.restEndpoint}/tags/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<{ id: string, name: string }> => {
|
||||||
TagHelpers.validateRequestBody(req.body);
|
TagHelpers.validateRequestBody(req.body);
|
||||||
|
|
||||||
const { name } = req.body;
|
const { name } = req.body;
|
||||||
await TagHelpers.validateName(name);
|
await TagHelpers.validateName(name);
|
||||||
TagHelpers.validateLength(name);
|
TagHelpers.validateLength(name);
|
||||||
|
|
||||||
const id = Number(req.params.id);
|
const { id } = req.params;
|
||||||
await TagHelpers.validateId(id);
|
await TagHelpers.validateId(id);
|
||||||
|
|
||||||
const updatedTag: Partial<ITagDb> = {
|
const updatedTag: Partial<ITagDb> = {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
/**
|
/**
|
||||||
* Validate whether a tag ID exists so that it can be used for a workflow create or tag update operation.
|
* Validate whether a tag ID exists so that it can be used for a workflow create or tag update operation.
|
||||||
*/
|
*/
|
||||||
export async function validateId(id: number): Promise<void> | never {
|
export async function validateId(id: string): Promise<void> | never {
|
||||||
const findQuery = { where: { id } } as FindOneOptions;
|
const findQuery = { where: { id } } as FindOneOptions;
|
||||||
const tag = await Db.collections.Tag!.findOne(findQuery);
|
const tag = await Db.collections.Tag!.findOne(findQuery);
|
||||||
|
|
||||||
|
@ -116,15 +116,34 @@ export async function getAllTagsWithUsageCount(): Promise<Array<{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve tag IDs and names, to be used in an API response.
|
* Retrieve tag IDs and names, to be used in an API response
|
||||||
|
* for a workflow create/update operation.
|
||||||
|
*/
|
||||||
|
export async function getTagsByWorkflowIds(
|
||||||
|
workflowIds: string[]
|
||||||
|
): Promise<Array<{ workflowId: number; id: string; name: string }>> {
|
||||||
|
return await getConnection().createQueryBuilder()
|
||||||
|
.select('workflows_tags.workflowId', 'workflowId')
|
||||||
|
.addSelect('tag_entity.id', 'id')
|
||||||
|
.addSelect('tag_entity.name', 'name')
|
||||||
|
.from('workflows_tags', 'workflows_tags')
|
||||||
|
.leftJoin('tag_entity', 'tag_entity', 'tag_entity.id = workflows_tags.tagId')
|
||||||
|
.where('workflows_tags.workflowId IN (:...workflowIds)', { workflowIds })
|
||||||
|
.getRawMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve tag IDs and names, to be used in an API response
|
||||||
|
* for a workflow create/update operation.
|
||||||
*/
|
*/
|
||||||
export async function getTagsForResponseData(
|
export async function getTagsForResponseData(
|
||||||
tagIds: number[]
|
tagIds: string[]
|
||||||
): Promise<Array<{ id: number; name: string }>> {
|
): Promise<Array<{ id: string; name: string }>> {
|
||||||
return await Db.collections.Tag!.find({
|
return await Db.collections.Tag!.find({
|
||||||
select: ['id', 'name'],
|
select: ['id', 'name'],
|
||||||
where: { id: In(tagIds) },
|
where: { id: In(tagIds) },
|
||||||
});
|
}) as Array<{ id: string; name: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -146,7 +165,7 @@ async function findRelations(
|
||||||
*/
|
*/
|
||||||
export async function getWorkflowTags(
|
export async function getWorkflowTags(
|
||||||
workflowId: string
|
workflowId: string
|
||||||
): Promise<Array<{ id: number; name: string }>> {
|
): Promise<Array<{ id: string; name: string }>> {
|
||||||
return await getConnection().createQueryBuilder()
|
return await getConnection().createQueryBuilder()
|
||||||
.select('tag_entity.id', 'id')
|
.select('tag_entity.id', 'id')
|
||||||
.addSelect('tag_entity.name', 'name')
|
.addSelect('tag_entity.name', 'name')
|
||||||
|
@ -170,7 +189,7 @@ export async function getWorkflowTags(
|
||||||
/**
|
/**
|
||||||
* Link a workflow to one or more tags.
|
* Link a workflow to one or more tags.
|
||||||
*/
|
*/
|
||||||
export async function createTagWorkflowRelations(workflowId: string, tagIds: number[]) {
|
export async function createTagWorkflowRelations(workflowId: string, tagIds: string[]) {
|
||||||
await getConnection().createQueryBuilder()
|
await getConnection().createQueryBuilder()
|
||||||
.insert()
|
.insert()
|
||||||
.into('workflows_tags')
|
.into('workflows_tags')
|
||||||
|
|
Loading…
Reference in a new issue