Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions apps/api/openapi/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@
},
"name": {
"type": "string"
},
"slug": {
"description": "URL-safe identifier unique within the workspace. Derived from name if omitted.",
"type": "string"
}
},
"required": [
Expand Down Expand Up @@ -2679,6 +2683,10 @@
},
"name": {
"type": "string"
},
"slug": {
"description": "URL-safe identifier unique within the workspace.",
"type": "string"
}
},
"required": [
Expand Down Expand Up @@ -3417,11 +3425,15 @@
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
}
},
"required": [
"id",
"name",
"slug",
"inputs",
"jobAgents"
],
Expand Down
5 changes: 4 additions & 1 deletion apps/api/openapi/schemas/workflows.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ local openapi = import '../lib/openapi.libsonnet';
required: ['name', 'inputs', 'jobAgents'],
properties: {
name: { type: 'string' },
slug: { type: 'string', description: 'URL-safe identifier unique within the workspace. Derived from name if omitted.' },
inputs: {
type: 'array',
items: openapi.schemaRef('WorkflowInput'),
Expand All @@ -131,6 +132,7 @@ local openapi = import '../lib/openapi.libsonnet';
required: ['name', 'inputs', 'jobAgents'],
properties: {
name: { type: 'string' },
slug: { type: 'string', description: 'URL-safe identifier unique within the workspace.' },
inputs: {
type: 'array',
items: openapi.schemaRef('WorkflowInput'),
Expand All @@ -144,10 +146,11 @@ local openapi = import '../lib/openapi.libsonnet';

Workflow: {
type: 'object',
required: ['id', 'name', 'inputs', 'jobAgents'],
required: ['id', 'name', 'slug', 'inputs', 'jobAgents'],
properties: {
id: { type: 'string' },
name: { type: 'string' },
slug: { type: 'string' },
inputs: {
type: 'array',
items: openapi.schemaRef('WorkflowInput'),
Expand Down
26 changes: 17 additions & 9 deletions apps/api/src/routes/v1/workspaces/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import { db } from "@ctrlplane/db/client";
import * as schema from "@ctrlplane/db/schema";
import { getClientFor } from "@ctrlplane/workspace-engine-sdk";

const slugifyWorkflowName = (name: string) =>
name
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");

const listWorkflows: AsyncTypedHandler<
"/v1/workspaces/{workspaceId}/workflows",
"get"
Expand All @@ -29,9 +35,10 @@ const listWorkflows: AsyncTypedHandler<
.limit(limit)
.offset(offset);

const items = rows.map(({ id, name, inputs, jobAgents }) => ({
const items = rows.map(({ id, name, slug, inputs, jobAgents }) => ({
id,
name,
slug,
inputs,
jobAgents,
}));
Expand All @@ -44,14 +51,15 @@ const createWorkflow: AsyncTypedHandler<
"post"
> = async (req, res) => {
const { workspaceId } = req.params;
const slug = req.body.slug ?? slugifyWorkflowName(req.body.name);
const created = await db
.insert(schema.workflow)
.values({ ...req.body, workspaceId })
.values({ ...req.body, slug, workspaceId })
.returning()
.then(takeFirst);

const { id, name, inputs, jobAgents } = created;
res.status(201).json({ id, name, inputs, jobAgents });
res.status(201).json({ id, name, slug, inputs, jobAgents });
};

const getWorkflow: AsyncTypedHandler<
Expand All @@ -72,8 +80,8 @@ const getWorkflow: AsyncTypedHandler<

if (workflow == null) throw new NotFoundError("Workflow not found");

const { id, name, inputs, jobAgents } = workflow;
res.json({ id, name, inputs, jobAgents });
const { id, name, slug, inputs, jobAgents } = workflow;
res.json({ id, name, slug, inputs, jobAgents });
};

const updateWorkflow: AsyncTypedHandler<
Expand All @@ -95,8 +103,8 @@ const updateWorkflow: AsyncTypedHandler<

if (updated == null) throw new NotFoundError("Workflow not found");

const { id, name, inputs, jobAgents } = updated;
res.status(202).json({ id, name, inputs, jobAgents });
const { id, name, slug, inputs, jobAgents } = updated;
res.status(202).json({ id, name, slug, inputs, jobAgents });
};

const deleteWorkflow: AsyncTypedHandler<
Expand All @@ -117,8 +125,8 @@ const deleteWorkflow: AsyncTypedHandler<

if (deleted == null) throw new NotFoundError("Workflow not found");

const { id, name, inputs, jobAgents } = deleted;
res.status(202).json({ id, name, inputs, jobAgents });
const { id, name, slug, inputs, jobAgents } = deleted;
res.status(202).json({ id, name, slug, inputs, jobAgents });
};

const createWorkflowRun: AsyncTypedHandler<
Expand Down
5 changes: 5 additions & 0 deletions apps/api/src/types/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,8 @@ export interface components {
inputs: components["schemas"]["WorkflowInput"][];
jobAgents: components["schemas"]["CreateWorkflowJobAgent"][];
name: string;
/** @description URL-safe identifier unique within the workspace. Derived from name if omitted. */
slug?: string;
};
CreateWorkflowJobAgent: {
/** @description Configuration for the job agent */
Expand Down Expand Up @@ -2069,6 +2071,8 @@ export interface components {
inputs: components["schemas"]["WorkflowInput"][];
jobAgents: components["schemas"]["CreateWorkflowJobAgent"][];
name: string;
/** @description URL-safe identifier unique within the workspace. */
slug?: string;
};
UpdateWorkspaceRequest: {
/** @description Display name of the workspace */
Expand Down Expand Up @@ -2334,6 +2338,7 @@ export interface components {
inputs: components["schemas"]["WorkflowInput"][];
jobAgents: components["schemas"]["WorkflowJobAgent"][];
name: string;
slug: string;
};
WorkflowArrayInput: components["schemas"]["WorkflowManualArrayInput"] | components["schemas"]["WorkflowSelectorArrayInput"];
WorkflowBooleanInput: {
Expand Down
4 changes: 4 additions & 0 deletions apps/workspace-engine/oapi/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3035,11 +3035,15 @@
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
}
},
"required": [
"id",
"name",
"slug",
"inputs",
"jobs"
],
Expand Down
3 changes: 2 additions & 1 deletion apps/workspace-engine/oapi/spec/schemas/workflows.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ local openapi = import '../lib/openapi.libsonnet';

Workflow: {
type: 'object',
required: ['id', 'name', 'inputs', 'jobs'],
required: ['id', 'name', 'slug', 'inputs', 'jobs'],
properties: {
id: { type: 'string' },
name: { type: 'string' },
slug: { type: 'string' },
inputs: {
type: 'array',
items: openapi.schemaRef('WorkflowInput'),
Expand Down
1 change: 1 addition & 0 deletions apps/workspace-engine/pkg/db/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion apps/workspace-engine/pkg/db/queries/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,11 @@ CREATE TABLE user_approval_record (
CREATE TABLE workflow (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
slug TEXT NOT NULL,
inputs JSONB NOT NULL DEFAULT '[]',
job_agents JSONB NOT NULL DEFAULT '[]',
workspace_id UUID NOT NULL REFERENCES workspace(id) ON DELETE CASCADE
workspace_id UUID NOT NULL REFERENCES workspace(id) ON DELETE CASCADE,
UNIQUE (workspace_id, slug)
);

CREATE TABLE workflow_run (
Expand Down
3 changes: 2 additions & 1 deletion apps/workspace-engine/pkg/db/workflows.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apps/workspace-engine/pkg/oapi/oapi.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func (g *PostgresGetter) GetWorkflowByID(
return &oapi.Workflow{
Id: workflowRow.ID.String(),
Name: workflowRow.Name,
Slug: workflowRow.Slug,
Inputs: inputs,
Jobs: jobs,
}, nil
Expand Down
5 changes: 5 additions & 0 deletions e2e/api/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,8 @@ export interface components {
inputs: components["schemas"]["WorkflowInput"][];
jobAgents: components["schemas"]["CreateWorkflowJobAgent"][];
name: string;
/** @description URL-safe identifier unique within the workspace. Derived from name if omitted. */
slug?: string;
};
CreateWorkflowJobAgent: {
/** @description Configuration for the job agent */
Expand Down Expand Up @@ -2069,6 +2071,8 @@ export interface components {
inputs: components["schemas"]["WorkflowInput"][];
jobAgents: components["schemas"]["CreateWorkflowJobAgent"][];
name: string;
/** @description URL-safe identifier unique within the workspace. */
slug?: string;
};
UpdateWorkspaceRequest: {
/** @description Display name of the workspace */
Expand Down Expand Up @@ -2334,6 +2338,7 @@ export interface components {
inputs: components["schemas"]["WorkflowInput"][];
jobAgents: components["schemas"]["WorkflowJobAgent"][];
name: string;
slug: string;
};
WorkflowArrayInput: components["schemas"]["WorkflowManualArrayInput"] | components["schemas"]["WorkflowSelectorArrayInput"];
WorkflowBooleanInput: {
Expand Down
Loading
Loading