mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
⚡ Add execution resource
This commit is contained in:
parent
e8ab7d5468
commit
ffdce3b1a2
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -134,7 +134,7 @@
|
|||
"eslint-plugin-vue": "^7.16.0",
|
||||
"eventsource": "^1.0.7",
|
||||
"express": "^4.16.4",
|
||||
"express-openapi-validator": "^4.13.7",
|
||||
"express-openapi-validator": "^4.13.6",
|
||||
"fast-glob": "^3.2.5",
|
||||
"fflate": "^0.7.0",
|
||||
"file-saver": "^2.0.2",
|
||||
|
|
66
packages/cli/src/PublicApi/Services/execution.ts
Normal file
66
packages/cli/src/PublicApi/Services/execution.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { In, Equal, Not, ObjectLiteral, MoreThan, LessThan } from 'typeorm';
|
||||
import { Db, IExecutionFlattedDb } from '../..';
|
||||
import { ExecutionStatus } from '../publicApiRequest';
|
||||
|
||||
function getStatusCondition(status: ExecutionStatus): ObjectLiteral {
|
||||
const condition: ObjectLiteral = {};
|
||||
|
||||
if (status === 'success') {
|
||||
condition.finished = true;
|
||||
} else if (status === 'running') {
|
||||
condition.stoppedAt = Equal(null);
|
||||
} else if (status === 'waiting') {
|
||||
condition.waitTill = Not(null);
|
||||
} else if (status === 'error') {
|
||||
condition.stoppedAt = Not(null);
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
export async function getExecutions(data: {
|
||||
limit: number;
|
||||
lastId?: number;
|
||||
workflowIds?: number[];
|
||||
status?: ExecutionStatus;
|
||||
}): Promise<IExecutionFlattedDb[]> {
|
||||
const executions = await Db.collections.Execution.find({
|
||||
where: {
|
||||
...(data.lastId && { id: LessThan(data.lastId) }),
|
||||
...(data.status && { ...getStatusCondition(data.status) }),
|
||||
...(data.workflowIds && { workflowId: In(data.workflowIds) }),
|
||||
},
|
||||
order: { id: 'DESC' },
|
||||
take: data.limit,
|
||||
});
|
||||
return executions;
|
||||
}
|
||||
|
||||
export async function getExecutionsCount(data: {
|
||||
limit: number;
|
||||
lastId?: number;
|
||||
workflowIds?: number[];
|
||||
status?: ExecutionStatus;
|
||||
}): Promise<number> {
|
||||
const executions = await Db.collections.Execution.count({
|
||||
where: {
|
||||
id: LessThan(data.lastId),
|
||||
...(data.status && { ...getStatusCondition(data.status) }),
|
||||
...(data.workflowIds && { workflowId: In(data.workflowIds) }),
|
||||
},
|
||||
take: data.limit,
|
||||
});
|
||||
return executions;
|
||||
}
|
||||
|
||||
export async function getExecution(id: number): Promise<IExecutionFlattedDb | undefined> {
|
||||
const execution = await Db.collections.Execution.findOne({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
return execution;
|
||||
}
|
||||
|
||||
export async function deleteExecution(execution: IExecutionFlattedDb): Promise<void> {
|
||||
await Db.collections.Execution.remove(execution);
|
||||
}
|
24
packages/cli/src/PublicApi/Services/workflow.ts
Normal file
24
packages/cli/src/PublicApi/Services/workflow.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { User } from '../../databases/entities/User';
|
||||
import { Db } from '../..';
|
||||
|
||||
export async function getSharedWorkflowIds(user: User): Promise<number[]> {
|
||||
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
||||
where: {
|
||||
user,
|
||||
},
|
||||
});
|
||||
return sharedWorkflows.map((workflow) => workflow.workflowId);
|
||||
}
|
||||
|
||||
export async function getWorkflowAccess(
|
||||
user: User,
|
||||
workflowId: string | undefined,
|
||||
): Promise<boolean> {
|
||||
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
||||
where: {
|
||||
user,
|
||||
workflow: { id: workflowId },
|
||||
},
|
||||
});
|
||||
return !!sharedWorkflows.length;
|
||||
}
|
|
@ -4,11 +4,11 @@
|
|||
/* eslint-disable import/no-cycle */
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { pick } from 'lodash';
|
||||
import { In } from 'typeorm';
|
||||
import { validate as uuidValidate } from 'uuid';
|
||||
import { OpenAPIV3, Format } from 'express-openapi-validator/dist/framework/types';
|
||||
import express = require('express');
|
||||
import validator from 'validator';
|
||||
import { In } from 'typeorm';
|
||||
import { User } from '../databases/entities/User';
|
||||
import type { Role } from '../databases/entities/Role';
|
||||
import { ActiveWorkflowRunner, Db, InternalHooksManager, ITelemetryUserDeletionData } from '..';
|
||||
|
@ -18,39 +18,57 @@ import { SharedWorkflow } from '../databases/entities/SharedWorkflow';
|
|||
import { SharedCredentials } from '../databases/entities/SharedCredentials';
|
||||
import { WorkflowEntity } from '../databases/entities/WorkflowEntity';
|
||||
|
||||
interface IPaginationOffsetDecoded {
|
||||
offset: number;
|
||||
limit: number;
|
||||
}
|
||||
export type OperationID = 'getUsers' | 'getUser';
|
||||
|
||||
export const decodeCursor = (cursor: string): IPaginationOffsetDecoded => {
|
||||
const { offset, limit } = JSON.parse(Buffer.from(cursor, 'base64').toString());
|
||||
return {
|
||||
offset,
|
||||
limit,
|
||||
};
|
||||
type PaginationBase = { limit: number };
|
||||
|
||||
type PaginationOffsetDecoded = PaginationBase & { offset: number };
|
||||
|
||||
type PaginationCursorDecoded = PaginationBase & { lastId: number };
|
||||
|
||||
type OffsetPagination = PaginationBase & { offset: number; numberOfTotalRecords: number };
|
||||
|
||||
type CursorPagination = PaginationBase & { lastId: number; numberOfNextRecords: number };
|
||||
|
||||
export const decodeCursor = (cursor: string): PaginationOffsetDecoded | PaginationCursorDecoded => {
|
||||
return JSON.parse(Buffer.from(cursor, 'base64').toString()) as
|
||||
| PaginationCursorDecoded
|
||||
| PaginationOffsetDecoded;
|
||||
};
|
||||
|
||||
export const encodeNextCursor = (
|
||||
offset: number,
|
||||
limit: number,
|
||||
numberOfRecords: number,
|
||||
): string | null => {
|
||||
const retrieveRecordsLength = offset + limit;
|
||||
|
||||
if (retrieveRecordsLength < numberOfRecords) {
|
||||
const encodeOffSetPagination = (pagination: OffsetPagination): string | null => {
|
||||
if (pagination.numberOfTotalRecords > pagination.offset + pagination.limit) {
|
||||
return Buffer.from(
|
||||
JSON.stringify({
|
||||
limit,
|
||||
offset: offset + limit,
|
||||
limit: pagination.limit,
|
||||
offset: pagination.offset + pagination.limit,
|
||||
}),
|
||||
).toString('base64');
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const encodeCursoPagination = (pagination: CursorPagination): string | null => {
|
||||
if (pagination.numberOfNextRecords) {
|
||||
return Buffer.from(
|
||||
JSON.stringify({
|
||||
lastId: pagination.lastId,
|
||||
limit: pagination.limit,
|
||||
}),
|
||||
).toString('base64');
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const encodeNextCursor = (
|
||||
pagination: OffsetPagination | CursorPagination,
|
||||
): string | null => {
|
||||
if ('offset' in pagination) {
|
||||
return encodeOffSetPagination(pagination);
|
||||
}
|
||||
return encodeCursoPagination(pagination);
|
||||
};
|
||||
|
||||
export const getSelectableProperties = (table: 'user' | 'role'): string[] => {
|
||||
return {
|
||||
user: ['id', 'email', 'firstName', 'lastName', 'createdAt', 'updatedAt', 'isPending'],
|
||||
|
@ -193,13 +211,13 @@ export async function getAllUsersAndCount(data: {
|
|||
limit?: number;
|
||||
offset?: number;
|
||||
}): Promise<[User[], number]> {
|
||||
const users = await Db.collections.User!.find({
|
||||
const users = await Db.collections.User.find({
|
||||
where: {},
|
||||
relations: data?.includeRole ? ['globalRole'] : undefined,
|
||||
skip: data.offset,
|
||||
take: data.limit,
|
||||
});
|
||||
const count = await Db.collections.User!.count();
|
||||
const count = await Db.collections.User.count();
|
||||
return [users, count];
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,9 @@ import type { UserRequest } from '../requests';
|
|||
import * as UserManagementMailer from '../UserManagement/email/UserManagementMailer';
|
||||
|
||||
import { decodeCursor, getGlobalMemberRole } from './helpers';
|
||||
import { Role, PaginatatedRequest } from './publicApiRequest';
|
||||
|
||||
type Role = 'owner' | 'member';
|
||||
|
||||
const instanceOwnerSetup = (
|
||||
export const instanceOwnerSetup = (
|
||||
req: express.Request,
|
||||
res: express.Response,
|
||||
next: express.NextFunction,
|
||||
|
@ -36,8 +35,8 @@ const emailSetup = (
|
|||
next();
|
||||
};
|
||||
|
||||
const authorize =
|
||||
(role: [Role]) =>
|
||||
export const authorize =
|
||||
(role: Role[]) =>
|
||||
(req: express.Request, res: express.Response, next: express.NextFunction): any => {
|
||||
const {
|
||||
globalRole: { name: userRole },
|
||||
|
@ -76,17 +75,22 @@ const transferingToDeletedUser = (
|
|||
next();
|
||||
};
|
||||
|
||||
const validCursor = (
|
||||
req: UserRequest.Get,
|
||||
export const validCursor = (
|
||||
req: PaginatatedRequest,
|
||||
res: express.Response,
|
||||
next: express.NextFunction,
|
||||
): any => {
|
||||
if (req.query.cursor) {
|
||||
const { cursor } = req.query;
|
||||
try {
|
||||
const { offset, limit } = decodeCursor(cursor);
|
||||
req.query.offset = offset;
|
||||
req.query.limit = limit;
|
||||
const paginationData = decodeCursor(cursor);
|
||||
if ('offset' in paginationData) {
|
||||
req.query.offset = paginationData.offset;
|
||||
req.query.limit = paginationData.limit;
|
||||
} else {
|
||||
req.query.lastId = paginationData.lastId;
|
||||
req.query.limit = paginationData.limit;
|
||||
}
|
||||
} catch (error) {
|
||||
return res.status(400).json({
|
||||
message: 'An invalid cursor was used',
|
||||
|
|
54
packages/cli/src/PublicApi/publicApiRequest.ts
Normal file
54
packages/cli/src/PublicApi/publicApiRequest.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* eslint-disable import/no-cycle */
|
||||
import express from 'express';
|
||||
|
||||
import type { User } from '../databases/entities/User';
|
||||
|
||||
export type ExecutionStatus = 'error' | 'running' | 'success' | 'waiting' | null;
|
||||
|
||||
export type Role = 'owner' | 'member';
|
||||
|
||||
export type AuthlessRequest<
|
||||
RouteParams = {},
|
||||
ResponseBody = {},
|
||||
RequestBody = {},
|
||||
RequestQuery = {},
|
||||
> = express.Request<RouteParams, ResponseBody, RequestBody, RequestQuery>;
|
||||
|
||||
export type AuthenticatedRequest<
|
||||
RouteParams = {},
|
||||
ResponseBody = {},
|
||||
RequestBody = {},
|
||||
RequestQuery = {},
|
||||
> = express.Request<RouteParams, ResponseBody, RequestBody, RequestQuery> & {
|
||||
user: User;
|
||||
};
|
||||
|
||||
export type PaginatatedRequest = AuthenticatedRequest<
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
limit?: number;
|
||||
cursor?: string;
|
||||
offset?: number;
|
||||
lastId?: number;
|
||||
}
|
||||
>;
|
||||
export declare namespace ExecutionRequest {
|
||||
type GetAll = AuthenticatedRequest<
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
status?: ExecutionStatus;
|
||||
limit?: number;
|
||||
cursor?: string;
|
||||
offset?: number;
|
||||
workflowId?: number;
|
||||
lastId?: number;
|
||||
}
|
||||
>;
|
||||
|
||||
type Get = AuthenticatedRequest<{ executionId: number }, {}, {}, {}>;
|
||||
type Delete = Get;
|
||||
}
|
129
packages/cli/src/PublicApi/v1/handlers/Executions.ts
Normal file
129
packages/cli/src/PublicApi/v1/handlers/Executions.ts
Normal file
|
@ -0,0 +1,129 @@
|
|||
import express = require('express');
|
||||
|
||||
import { ExecutionRequest } from '../../publicApiRequest';
|
||||
import { encodeNextCursor } from '../../helpers';
|
||||
import { authorize, instanceOwnerSetup, validCursor } from '../../middlewares';
|
||||
import {
|
||||
getExecutions,
|
||||
getExecution,
|
||||
deleteExecution,
|
||||
getExecutionsCount,
|
||||
} from '../../Services/execution';
|
||||
import { getSharedWorkflowIds, getWorkflowAccess } from '../../Services/workflow';
|
||||
|
||||
export = {
|
||||
deleteExecution: [
|
||||
instanceOwnerSetup,
|
||||
authorize(['owner', 'member']),
|
||||
async (req: ExecutionRequest.Delete, res: express.Response): Promise<express.Response> => {
|
||||
const { executionId } = req.params;
|
||||
|
||||
const execution = await getExecution(executionId);
|
||||
if (execution === undefined) {
|
||||
return res.status(404).json({
|
||||
message: 'Execution not found.',
|
||||
});
|
||||
}
|
||||
|
||||
if (req.user.globalRole.name === 'owner') {
|
||||
await deleteExecution(execution);
|
||||
return res.json(execution);
|
||||
}
|
||||
|
||||
const userHasAccessToWorkflow = await getWorkflowAccess(req.user, execution.workflowId);
|
||||
|
||||
if (userHasAccessToWorkflow) {
|
||||
await deleteExecution(execution);
|
||||
return res.json(execution);
|
||||
}
|
||||
|
||||
return res.status(404).json({
|
||||
message: 'Execution not found.',
|
||||
});
|
||||
},
|
||||
],
|
||||
getExecution: [
|
||||
instanceOwnerSetup,
|
||||
authorize(['owner', 'member']),
|
||||
async (req: ExecutionRequest.Get, res: express.Response): Promise<express.Response> => {
|
||||
const { executionId } = req.params;
|
||||
|
||||
const execution = await getExecution(executionId);
|
||||
if (execution === undefined) {
|
||||
return res.status(404).json({
|
||||
message: 'Execution not found.',
|
||||
});
|
||||
}
|
||||
|
||||
if (req.user.globalRole.name === 'owner') {
|
||||
return res.json(execution);
|
||||
}
|
||||
|
||||
const userHasAccessToWorkflow = await getWorkflowAccess(req.user, execution.workflowId);
|
||||
|
||||
if (userHasAccessToWorkflow) {
|
||||
return res.json(execution);
|
||||
}
|
||||
return res.status(404).json({
|
||||
message: 'Execution not found.',
|
||||
});
|
||||
},
|
||||
],
|
||||
getExecutions: [
|
||||
instanceOwnerSetup,
|
||||
authorize(['owner', 'member']),
|
||||
validCursor,
|
||||
async (req: ExecutionRequest.GetAll, res: express.Response): Promise<express.Response> => {
|
||||
const {
|
||||
lastId = undefined,
|
||||
limit = 100,
|
||||
status = undefined,
|
||||
workflowId = undefined,
|
||||
} = req.query;
|
||||
|
||||
const filters = {
|
||||
status,
|
||||
limit,
|
||||
lastId,
|
||||
...(workflowId && { workflowIds: [workflowId] }),
|
||||
};
|
||||
|
||||
if (req.user.globalRole.name === 'owner') {
|
||||
const executions = await getExecutions(filters);
|
||||
|
||||
filters.lastId = executions.slice(-1)[0].id as number;
|
||||
|
||||
const count = await getExecutionsCount(filters);
|
||||
|
||||
return res.json({
|
||||
data: executions,
|
||||
nextCursor: encodeNextCursor({
|
||||
lastId: filters.lastId,
|
||||
limit,
|
||||
numberOfNextRecords: count,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
const sharedWorkflowsIds = [];
|
||||
|
||||
if (!workflowId) {
|
||||
const sharedWorkflows = await getSharedWorkflowIds(req.user);
|
||||
sharedWorkflowsIds.push(...sharedWorkflows);
|
||||
}
|
||||
|
||||
const executions = await getExecutions(filters);
|
||||
|
||||
const count = await getExecutionsCount(filters);
|
||||
|
||||
return res.json({
|
||||
data: executions,
|
||||
nextCursor: encodeNextCursor({
|
||||
lastId: executions.slice(-1)[0].id as number,
|
||||
limit,
|
||||
numberOfNextRecords: count,
|
||||
}),
|
||||
});
|
||||
},
|
||||
],
|
||||
};
|
|
@ -135,7 +135,11 @@ export = {
|
|||
|
||||
return res.json({
|
||||
data: clean(users, { includeRole }),
|
||||
nextCursor: encodeNextCursor(offset, limit, count),
|
||||
nextCursor: encodeNextCursor({
|
||||
offset,
|
||||
limit,
|
||||
numberOfTotalRecords: count,
|
||||
}),
|
||||
});
|
||||
},
|
||||
],
|
||||
|
|
|
@ -18,8 +18,43 @@ servers:
|
|||
tags:
|
||||
- name: User
|
||||
description: Operations about user
|
||||
- name: Execution
|
||||
description: Operations about execution
|
||||
paths:
|
||||
/users:
|
||||
post:
|
||||
x-eov-operation-id: createUsers
|
||||
x-eov-operation-handler: v1/handlers/Users
|
||||
tags:
|
||||
- User
|
||||
summary: Invite a user
|
||||
description: Invites a user to your instance. Only available for the instance owner.
|
||||
operationId: createUser
|
||||
requestBody:
|
||||
description: Created user object.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UserInformation'
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: A User object
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UserInformation'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
get:
|
||||
x-eov-operation-id: getUsers
|
||||
x-eov-operation-handler: v1/handlers/Users
|
||||
|
@ -66,38 +101,6 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
post:
|
||||
x-eov-operation-id: createUsers
|
||||
x-eov-operation-handler: v1/handlers/Users
|
||||
tags:
|
||||
- User
|
||||
summary: Invite a user
|
||||
description: Invites a user to your instance. Only available for the instance owner.
|
||||
operationId: createUser
|
||||
requestBody:
|
||||
description: Created user object.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UserInformation'
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: A User object
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UserInformation'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/users/{identifier}:
|
||||
get:
|
||||
x-eov-operation-id: getUser
|
||||
|
@ -177,6 +180,121 @@ paths:
|
|||
$ref: '#/components/schemas/Error'
|
||||
"404":
|
||||
description: User not found
|
||||
/executions:
|
||||
get:
|
||||
x-eov-operation-id: getExecutions
|
||||
x-eov-operation-handler: v1/handlers/Executions
|
||||
tags:
|
||||
- Execution
|
||||
summary: Retrieve all executions
|
||||
description: Retrieve all executions from your instance.
|
||||
parameters:
|
||||
- name: status
|
||||
in: query
|
||||
description: Status to filter the executions by.
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: ['error', 'running', 'success', 'waiting']
|
||||
default: 'any'
|
||||
- name: workflowId
|
||||
in: query
|
||||
description: Workflow to filter the executions by.
|
||||
required: false
|
||||
schema:
|
||||
type: number
|
||||
example: 1000
|
||||
- name: limit
|
||||
in: query
|
||||
description: The maximum number of items to return.
|
||||
required: false
|
||||
schema:
|
||||
type: number
|
||||
example: 100
|
||||
default: 100
|
||||
- name: cursor
|
||||
in: query
|
||||
description: Paginate through users by setting the cursor parameter to a nextCursor attribute returned by a previous request's response. Default value fetches the first "page" of the collection. See pagination for more detail.
|
||||
required: false
|
||||
style: form
|
||||
schema:
|
||||
type: string
|
||||
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
|
||||
responses:
|
||||
"200":
|
||||
description: Operation successful.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ExecutionDetailsResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
"404":
|
||||
description: User not found
|
||||
/executions/{executionId}:
|
||||
get:
|
||||
x-eov-operation-id: getExecution
|
||||
x-eov-operation-handler: v1/handlers/Executions
|
||||
tags:
|
||||
- Execution
|
||||
summary: Retrieve an execution
|
||||
description: Retrieve an execution from you instance.
|
||||
parameters:
|
||||
- name: executionId
|
||||
in: path
|
||||
description: The ID of the execution.
|
||||
required: true
|
||||
schema:
|
||||
type: number
|
||||
responses:
|
||||
"200":
|
||||
description: Operation successful.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ExecutionInformation'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
"404":
|
||||
description: User not found
|
||||
delete:
|
||||
x-eov-operation-id: deleteExecution
|
||||
x-eov-operation-handler: v1/handlers/Executions
|
||||
tags:
|
||||
- Execution
|
||||
summary: Delete an execution
|
||||
description: Deletes an execution from your instance.
|
||||
parameters:
|
||||
- name: executionId
|
||||
in: path
|
||||
description: The ID of the execution to be deleted.
|
||||
required: true
|
||||
schema:
|
||||
type: number
|
||||
responses:
|
||||
"200":
|
||||
description: Operation successful.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ExecutionInformation'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
"404":
|
||||
description: User not found
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Error:
|
||||
|
@ -233,6 +351,18 @@ components:
|
|||
readOnly: true
|
||||
globalRole:
|
||||
$ref: '#/components/schemas/RoleInformation'
|
||||
ExecutionDetailsResponse:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ExecutionInformation'
|
||||
nextCursor:
|
||||
type: string
|
||||
description: Paginate through users by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
|
||||
nullable: true
|
||||
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
|
||||
UserDetailsResponse:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -245,6 +375,39 @@ components:
|
|||
description: Paginate through users by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
|
||||
nullable: true
|
||||
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
|
||||
ExecutionInformation:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: number
|
||||
example: 1000
|
||||
data:
|
||||
type: string
|
||||
finished:
|
||||
type: boolean
|
||||
example: true
|
||||
mode:
|
||||
type: string
|
||||
enum: ['cli', 'error', 'integrated', 'internal', 'manual', 'retry', 'trigger', 'webhook']
|
||||
retryOf:
|
||||
type: string
|
||||
nullable: true
|
||||
retrySuccessId:
|
||||
type: string
|
||||
nullable: true
|
||||
startedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
stoppedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
workflowId:
|
||||
type: string
|
||||
example: 1000
|
||||
waitTill:
|
||||
type: string
|
||||
nullable: true
|
||||
format: date-time
|
||||
RoleInformation:
|
||||
type: object
|
||||
properties:
|
||||
|
|
Loading…
Reference in a new issue