improvement(templates): make it top-level route and change management/editing process (#1834)

* fix(billing): should allow restoring subscription (#1728)

* fix(already-cancelled-sub): UI should allow restoring subscription

* restore functionality fixed

* fix

* make templates root level url and make it part of deployment system

* separate updating template and deployment versions

* add tags

* add credentials extraction logic + use should import with workflow variables

* fix credential extraction

* add trigger mode indicator

* add starred tracking

* last updated field

* progress on creator profiles

* revert creator profile context type

* progress fix image uploads

* render templates details with creator details

* fix collab rules for workflow edit button

* creator profile perm check improvements

* restore accidental changes

* fix accessibility issues for non logged in users

* remove unused code

* fix type errors

---------

Co-authored-by: Waleed <walif6@gmail.com>
Co-authored-by: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com>
This commit is contained in:
Vikhyath Mondreti
2025-11-07 17:57:53 -08:00
committed by GitHub
parent 6cdee5351c
commit a73e2aaa8b
54 changed files with 13451 additions and 878 deletions

View File

@@ -0,0 +1,47 @@
CREATE TYPE "public"."template_creator_type" AS ENUM('user', 'organization');--> statement-breakpoint
CREATE TYPE "public"."template_status" AS ENUM('pending', 'approved', 'rejected');--> statement-breakpoint
CREATE TABLE "template_creators" (
"id" text PRIMARY KEY NOT NULL,
"reference_type" "template_creator_type" NOT NULL,
"reference_id" text NOT NULL,
"name" text NOT NULL,
"profile_image_url" text,
"details" jsonb,
"created_by" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "templates" DROP CONSTRAINT "templates_user_id_user_id_fk";
--> statement-breakpoint
ALTER TABLE "templates" DROP CONSTRAINT "templates_workflow_id_workflow_id_fk";
--> statement-breakpoint
DROP INDEX "templates_workflow_id_idx";--> statement-breakpoint
DROP INDEX "templates_user_id_idx";--> statement-breakpoint
DROP INDEX "templates_category_idx";--> statement-breakpoint
DROP INDEX "templates_category_views_idx";--> statement-breakpoint
DROP INDEX "templates_category_stars_idx";--> statement-breakpoint
DROP INDEX "templates_user_category_idx";--> statement-breakpoint
ALTER TABLE "settings" ADD COLUMN "super_user_mode_enabled" boolean DEFAULT true NOT NULL;--> statement-breakpoint
ALTER TABLE "templates" ADD COLUMN "details" jsonb;--> statement-breakpoint
ALTER TABLE "templates" ADD COLUMN "creator_id" text;--> statement-breakpoint
ALTER TABLE "templates" ADD COLUMN "status" "template_status" DEFAULT 'pending' NOT NULL;--> statement-breakpoint
ALTER TABLE "templates" ADD COLUMN "tags" text[] DEFAULT '{}'::text[] NOT NULL;--> statement-breakpoint
ALTER TABLE "templates" ADD COLUMN "required_credentials" jsonb DEFAULT '[]' NOT NULL;--> statement-breakpoint
ALTER TABLE "user" ADD COLUMN "is_super_user" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "template_creators" ADD CONSTRAINT "template_creators_created_by_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "template_creators_reference_idx" ON "template_creators" USING btree ("reference_type","reference_id");--> statement-breakpoint
CREATE INDEX "template_creators_reference_id_idx" ON "template_creators" USING btree ("reference_id");--> statement-breakpoint
CREATE INDEX "template_creators_created_by_idx" ON "template_creators" USING btree ("created_by");--> statement-breakpoint
ALTER TABLE "templates" ADD CONSTRAINT "templates_creator_id_template_creators_id_fk" FOREIGN KEY ("creator_id") REFERENCES "public"."template_creators"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "templates" ADD CONSTRAINT "templates_workflow_id_workflow_id_fk" FOREIGN KEY ("workflow_id") REFERENCES "public"."workflow"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "templates_status_idx" ON "templates" USING btree ("status");--> statement-breakpoint
CREATE INDEX "templates_creator_id_idx" ON "templates" USING btree ("creator_id");--> statement-breakpoint
CREATE INDEX "templates_status_views_idx" ON "templates" USING btree ("status","views");--> statement-breakpoint
CREATE INDEX "templates_status_stars_idx" ON "templates" USING btree ("status","stars");--> statement-breakpoint
ALTER TABLE "templates" DROP COLUMN "user_id";--> statement-breakpoint
ALTER TABLE "templates" DROP COLUMN "description";--> statement-breakpoint
ALTER TABLE "templates" DROP COLUMN "author";--> statement-breakpoint
ALTER TABLE "templates" DROP COLUMN "color";--> statement-breakpoint
ALTER TABLE "templates" DROP COLUMN "icon";--> statement-breakpoint
ALTER TABLE "templates" DROP COLUMN "category";

File diff suppressed because it is too large Load Diff

View File

@@ -743,6 +743,13 @@
"when": 1762371130884,
"tag": "0106_bitter_captain_midlands",
"breakpoints": true
},
{
"idx": 107,
"version": "7",
"when": 1762565365042,
"tag": "0107_silky_agent_brand",
"breakpoints": true
}
]
}

View File

@@ -37,6 +37,7 @@ export const user = pgTable('user', {
createdAt: timestamp('created_at').notNull(),
updatedAt: timestamp('updated_at').notNull(),
stripeCustomerId: text('stripe_customer_id'),
isSuperUser: boolean('is_super_user').notNull().default(false),
})
export const session = pgTable(
@@ -423,6 +424,7 @@ export const settings = pgTable('settings', {
// UI preferences
showFloatingControls: boolean('show_floating_controls').notNull().default(true),
showTrainingControls: boolean('show_training_controls').notNull().default(false),
superUserModeEnabled: boolean('super_user_mode_enabled').notNull().default(true),
// Copilot preferences - maps model_id to enabled/disabled boolean
copilotEnabledModels: jsonb('copilot_enabled_models').notNull().default('{}'),
@@ -1305,40 +1307,61 @@ export const workflowCheckpoints = pgTable(
})
)
export const templateStatusEnum = pgEnum('template_status', ['pending', 'approved', 'rejected'])
export const templateCreatorTypeEnum = pgEnum('template_creator_type', ['user', 'organization'])
export const templateCreators = pgTable(
'template_creators',
{
id: text('id').primaryKey(),
referenceType: templateCreatorTypeEnum('reference_type').notNull(),
referenceId: text('reference_id').notNull(),
name: text('name').notNull(),
profileImageUrl: text('profile_image_url'),
details: jsonb('details'),
createdBy: text('created_by').references(() => user.id, { onDelete: 'set null' }),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
},
(table) => ({
referenceUniqueIdx: uniqueIndex('template_creators_reference_idx').on(
table.referenceType,
table.referenceId
),
referenceIdIdx: index('template_creators_reference_id_idx').on(table.referenceId),
createdByIdx: index('template_creators_created_by_idx').on(table.createdBy),
})
)
export const templates = pgTable(
'templates',
{
id: text('id').primaryKey(),
workflowId: text('workflow_id').references(() => workflow.id),
userId: text('user_id')
.notNull()
.references(() => user.id, { onDelete: 'cascade' }),
workflowId: text('workflow_id').references(() => workflow.id, { onDelete: 'set null' }),
name: text('name').notNull(),
description: text('description'),
author: text('author').notNull(),
details: jsonb('details'),
creatorId: text('creator_id').references(() => templateCreators.id, { onDelete: 'set null' }),
views: integer('views').notNull().default(0),
stars: integer('stars').notNull().default(0),
color: text('color').notNull().default('#3972F6'),
icon: text('icon').notNull().default('FileText'), // Lucide icon name as string
category: text('category').notNull(),
state: jsonb('state').notNull(), // Using jsonb for better performance
status: templateStatusEnum('status').notNull().default('pending'),
tags: text('tags').array().notNull().default(sql`'{}'::text[]`), // Array of tags
requiredCredentials: jsonb('required_credentials').notNull().default('[]'), // Array of credential requirements
state: jsonb('state').notNull(), // Store the workflow state directly
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
},
(table) => ({
// Primary access patterns
workflowIdIdx: index('templates_workflow_id_idx').on(table.workflowId),
userIdIdx: index('templates_user_id_idx').on(table.userId),
categoryIdx: index('templates_category_idx').on(table.category),
statusIdx: index('templates_status_idx').on(table.status),
creatorIdIdx: index('templates_creator_id_idx').on(table.creatorId),
// Sorting indexes for popular/trending templates
viewsIdx: index('templates_views_idx').on(table.views),
starsIdx: index('templates_stars_idx').on(table.stars),
// Composite indexes for common queries
categoryViewsIdx: index('templates_category_views_idx').on(table.category, table.views),
categoryStarsIdx: index('templates_category_stars_idx').on(table.category, table.stars),
userCategoryIdx: index('templates_user_category_idx').on(table.userId, table.category),
statusViewsIdx: index('templates_status_views_idx').on(table.status, table.views),
statusStarsIdx: index('templates_status_stars_idx').on(table.status, table.stars),
// Temporal indexes
createdAtIdx: index('templates_created_at_idx').on(table.createdAt),