feat: payload cms
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Failing after 1m13s
Build & Deploy / 🏗️ Build (push) Failing after 5m53s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Smoke Test (push) Has been skipped
Build & Deploy / ⚡ Lighthouse (push) Has been skipped
Build & Deploy / ♿ WCAG (push) Has been skipped
Build & Deploy / 🛡️ Quality Gates (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 4s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Failing after 1m13s
Build & Deploy / 🏗️ Build (push) Failing after 5m53s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Smoke Test (push) Has been skipped
Build & Deploy / ⚡ Lighthouse (push) Has been skipped
Build & Deploy / ♿ WCAG (push) Has been skipped
Build & Deploy / 🛡️ Quality Gates (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 4s
This commit is contained in:
2621
src/migrations/20260223_195005_products_collection.json
Normal file
2621
src/migrations/20260223_195005_products_collection.json
Normal file
File diff suppressed because it is too large
Load Diff
356
src/migrations/20260223_195005_products_collection.ts
Normal file
356
src/migrations/20260223_195005_products_collection.ts
Normal file
@@ -0,0 +1,356 @@
|
||||
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres';
|
||||
|
||||
export async function up({ db }: MigrateUpArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
CREATE TYPE "public"."enum_posts_locale" AS ENUM('en', 'de');
|
||||
CREATE TYPE "public"."enum_posts_status" AS ENUM('draft', 'published');
|
||||
CREATE TYPE "public"."enum__posts_v_version_locale" AS ENUM('en', 'de');
|
||||
CREATE TYPE "public"."enum__posts_v_version_status" AS ENUM('draft', 'published');
|
||||
CREATE TYPE "public"."enum_form_submissions_type" AS ENUM('contact', 'product_quote');
|
||||
CREATE TYPE "public"."enum_products_locale" AS ENUM('en', 'de');
|
||||
CREATE TYPE "public"."enum_products_status" AS ENUM('draft', 'published');
|
||||
CREATE TYPE "public"."enum__products_v_version_locale" AS ENUM('en', 'de');
|
||||
CREATE TYPE "public"."enum__products_v_version_status" AS ENUM('draft', 'published');
|
||||
CREATE TABLE "users_sessions" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"id" varchar PRIMARY KEY NOT NULL,
|
||||
"created_at" timestamp(3) with time zone,
|
||||
"expires_at" timestamp(3) with time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "users" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"email" varchar NOT NULL,
|
||||
"reset_password_token" varchar,
|
||||
"reset_password_expiration" timestamp(3) with time zone,
|
||||
"salt" varchar,
|
||||
"hash" varchar,
|
||||
"login_attempts" numeric DEFAULT 0,
|
||||
"lock_until" timestamp(3) with time zone
|
||||
);
|
||||
|
||||
CREATE TABLE "media" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"alt" varchar NOT NULL,
|
||||
"caption" varchar,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"url" varchar,
|
||||
"thumbnail_u_r_l" varchar,
|
||||
"filename" varchar,
|
||||
"mime_type" varchar,
|
||||
"filesize" numeric,
|
||||
"width" numeric,
|
||||
"height" numeric,
|
||||
"focal_x" numeric,
|
||||
"focal_y" numeric,
|
||||
"sizes_thumbnail_url" varchar,
|
||||
"sizes_thumbnail_width" numeric,
|
||||
"sizes_thumbnail_height" numeric,
|
||||
"sizes_thumbnail_mime_type" varchar,
|
||||
"sizes_thumbnail_filesize" numeric,
|
||||
"sizes_thumbnail_filename" varchar,
|
||||
"sizes_card_url" varchar,
|
||||
"sizes_card_width" numeric,
|
||||
"sizes_card_height" numeric,
|
||||
"sizes_card_mime_type" varchar,
|
||||
"sizes_card_filesize" numeric,
|
||||
"sizes_card_filename" varchar,
|
||||
"sizes_hero_url" varchar,
|
||||
"sizes_hero_width" numeric,
|
||||
"sizes_hero_height" numeric,
|
||||
"sizes_hero_mime_type" varchar,
|
||||
"sizes_hero_filesize" numeric,
|
||||
"sizes_hero_filename" varchar,
|
||||
"sizes_hero_mobile_url" varchar,
|
||||
"sizes_hero_mobile_width" numeric,
|
||||
"sizes_hero_mobile_height" numeric,
|
||||
"sizes_hero_mobile_mime_type" varchar,
|
||||
"sizes_hero_mobile_filesize" numeric,
|
||||
"sizes_hero_mobile_filename" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "posts" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"title" varchar,
|
||||
"slug" varchar,
|
||||
"excerpt" varchar,
|
||||
"date" timestamp(3) with time zone,
|
||||
"featured_image_id" integer,
|
||||
"locale" "enum_posts_locale" DEFAULT 'en',
|
||||
"category" varchar,
|
||||
"content" jsonb,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"_status" "enum_posts_status" DEFAULT 'draft'
|
||||
);
|
||||
|
||||
CREATE TABLE "_posts_v" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"parent_id" integer,
|
||||
"version_title" varchar,
|
||||
"version_slug" varchar,
|
||||
"version_excerpt" varchar,
|
||||
"version_date" timestamp(3) with time zone,
|
||||
"version_featured_image_id" integer,
|
||||
"version_locale" "enum__posts_v_version_locale" DEFAULT 'en',
|
||||
"version_category" varchar,
|
||||
"version_content" jsonb,
|
||||
"version_updated_at" timestamp(3) with time zone,
|
||||
"version_created_at" timestamp(3) with time zone,
|
||||
"version__status" "enum__posts_v_version_status" DEFAULT 'draft',
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"latest" boolean
|
||||
);
|
||||
|
||||
CREATE TABLE "form_submissions" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" varchar NOT NULL,
|
||||
"email" varchar NOT NULL,
|
||||
"type" "enum_form_submissions_type" NOT NULL,
|
||||
"product_name" varchar,
|
||||
"message" varchar NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "products_categories" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"id" varchar PRIMARY KEY NOT NULL,
|
||||
"category" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "products" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"title" varchar,
|
||||
"sku" varchar,
|
||||
"slug" varchar,
|
||||
"description" varchar,
|
||||
"locale" "enum_products_locale" DEFAULT 'de',
|
||||
"application" jsonb,
|
||||
"content" jsonb,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"_status" "enum_products_status" DEFAULT 'draft'
|
||||
);
|
||||
|
||||
CREATE TABLE "products_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"media_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE "_products_v_version_categories" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"category" varchar,
|
||||
"_uuid" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "_products_v" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"parent_id" integer,
|
||||
"version_title" varchar,
|
||||
"version_sku" varchar,
|
||||
"version_slug" varchar,
|
||||
"version_description" varchar,
|
||||
"version_locale" "enum__products_v_version_locale" DEFAULT 'de',
|
||||
"version_application" jsonb,
|
||||
"version_content" jsonb,
|
||||
"version_updated_at" timestamp(3) with time zone,
|
||||
"version_created_at" timestamp(3) with time zone,
|
||||
"version__status" "enum__products_v_version_status" DEFAULT 'draft',
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"latest" boolean
|
||||
);
|
||||
|
||||
CREATE TABLE "_products_v_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"media_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE "payload_kv" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"key" varchar NOT NULL,
|
||||
"data" jsonb NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "payload_locked_documents" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"global_slug" varchar,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "payload_locked_documents_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"users_id" integer,
|
||||
"media_id" integer,
|
||||
"posts_id" integer,
|
||||
"form_submissions_id" integer,
|
||||
"products_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE "payload_preferences" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"key" varchar,
|
||||
"value" jsonb,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "payload_preferences_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"users_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE "payload_migrations" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" varchar,
|
||||
"batch" numeric,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "posts" ADD CONSTRAINT "posts_featured_image_id_media_id_fk" FOREIGN KEY ("featured_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_posts_v" ADD CONSTRAINT "_posts_v_parent_id_posts_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."posts"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_posts_v" ADD CONSTRAINT "_posts_v_version_featured_image_id_media_id_fk" FOREIGN KEY ("version_featured_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "products_categories" ADD CONSTRAINT "products_categories_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "products_rels" ADD CONSTRAINT "products_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "products_rels" ADD CONSTRAINT "products_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_products_v_version_categories" ADD CONSTRAINT "_products_v_version_categories_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_products_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_products_v" ADD CONSTRAINT "_products_v_parent_id_products_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."products"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_products_v_rels" ADD CONSTRAINT "_products_v_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."_products_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_products_v_rels" ADD CONSTRAINT "_products_v_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_posts_fk" FOREIGN KEY ("posts_id") REFERENCES "public"."posts"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_form_submissions_fk" FOREIGN KEY ("form_submissions_id") REFERENCES "public"."form_submissions"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_products_fk" FOREIGN KEY ("products_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
CREATE INDEX "users_sessions_order_idx" ON "users_sessions" USING btree ("_order");
|
||||
CREATE INDEX "users_sessions_parent_id_idx" ON "users_sessions" USING btree ("_parent_id");
|
||||
CREATE INDEX "users_updated_at_idx" ON "users" USING btree ("updated_at");
|
||||
CREATE INDEX "users_created_at_idx" ON "users" USING btree ("created_at");
|
||||
CREATE UNIQUE INDEX "users_email_idx" ON "users" USING btree ("email");
|
||||
CREATE INDEX "media_updated_at_idx" ON "media" USING btree ("updated_at");
|
||||
CREATE INDEX "media_created_at_idx" ON "media" USING btree ("created_at");
|
||||
CREATE UNIQUE INDEX "media_filename_idx" ON "media" USING btree ("filename");
|
||||
CREATE INDEX "media_sizes_thumbnail_sizes_thumbnail_filename_idx" ON "media" USING btree ("sizes_thumbnail_filename");
|
||||
CREATE INDEX "media_sizes_card_sizes_card_filename_idx" ON "media" USING btree ("sizes_card_filename");
|
||||
CREATE INDEX "media_sizes_hero_sizes_hero_filename_idx" ON "media" USING btree ("sizes_hero_filename");
|
||||
CREATE INDEX "media_sizes_hero_mobile_sizes_hero_mobile_filename_idx" ON "media" USING btree ("sizes_hero_mobile_filename");
|
||||
CREATE UNIQUE INDEX "posts_slug_idx" ON "posts" USING btree ("slug");
|
||||
CREATE INDEX "posts_featured_image_idx" ON "posts" USING btree ("featured_image_id");
|
||||
CREATE INDEX "posts_updated_at_idx" ON "posts" USING btree ("updated_at");
|
||||
CREATE INDEX "posts_created_at_idx" ON "posts" USING btree ("created_at");
|
||||
CREATE INDEX "posts__status_idx" ON "posts" USING btree ("_status");
|
||||
CREATE INDEX "_posts_v_parent_idx" ON "_posts_v" USING btree ("parent_id");
|
||||
CREATE INDEX "_posts_v_version_version_slug_idx" ON "_posts_v" USING btree ("version_slug");
|
||||
CREATE INDEX "_posts_v_version_version_featured_image_idx" ON "_posts_v" USING btree ("version_featured_image_id");
|
||||
CREATE INDEX "_posts_v_version_version_updated_at_idx" ON "_posts_v" USING btree ("version_updated_at");
|
||||
CREATE INDEX "_posts_v_version_version_created_at_idx" ON "_posts_v" USING btree ("version_created_at");
|
||||
CREATE INDEX "_posts_v_version_version__status_idx" ON "_posts_v" USING btree ("version__status");
|
||||
CREATE INDEX "_posts_v_created_at_idx" ON "_posts_v" USING btree ("created_at");
|
||||
CREATE INDEX "_posts_v_updated_at_idx" ON "_posts_v" USING btree ("updated_at");
|
||||
CREATE INDEX "_posts_v_latest_idx" ON "_posts_v" USING btree ("latest");
|
||||
CREATE INDEX "form_submissions_updated_at_idx" ON "form_submissions" USING btree ("updated_at");
|
||||
CREATE INDEX "form_submissions_created_at_idx" ON "form_submissions" USING btree ("created_at");
|
||||
CREATE INDEX "products_categories_order_idx" ON "products_categories" USING btree ("_order");
|
||||
CREATE INDEX "products_categories_parent_id_idx" ON "products_categories" USING btree ("_parent_id");
|
||||
CREATE UNIQUE INDEX "products_sku_idx" ON "products" USING btree ("sku");
|
||||
CREATE INDEX "products_updated_at_idx" ON "products" USING btree ("updated_at");
|
||||
CREATE INDEX "products_created_at_idx" ON "products" USING btree ("created_at");
|
||||
CREATE INDEX "products__status_idx" ON "products" USING btree ("_status");
|
||||
CREATE INDEX "products_rels_order_idx" ON "products_rels" USING btree ("order");
|
||||
CREATE INDEX "products_rels_parent_idx" ON "products_rels" USING btree ("parent_id");
|
||||
CREATE INDEX "products_rels_path_idx" ON "products_rels" USING btree ("path");
|
||||
CREATE INDEX "products_rels_media_id_idx" ON "products_rels" USING btree ("media_id");
|
||||
CREATE INDEX "_products_v_version_categories_order_idx" ON "_products_v_version_categories" USING btree ("_order");
|
||||
CREATE INDEX "_products_v_version_categories_parent_id_idx" ON "_products_v_version_categories" USING btree ("_parent_id");
|
||||
CREATE INDEX "_products_v_parent_idx" ON "_products_v" USING btree ("parent_id");
|
||||
CREATE INDEX "_products_v_version_version_sku_idx" ON "_products_v" USING btree ("version_sku");
|
||||
CREATE INDEX "_products_v_version_version_updated_at_idx" ON "_products_v" USING btree ("version_updated_at");
|
||||
CREATE INDEX "_products_v_version_version_created_at_idx" ON "_products_v" USING btree ("version_created_at");
|
||||
CREATE INDEX "_products_v_version_version__status_idx" ON "_products_v" USING btree ("version__status");
|
||||
CREATE INDEX "_products_v_created_at_idx" ON "_products_v" USING btree ("created_at");
|
||||
CREATE INDEX "_products_v_updated_at_idx" ON "_products_v" USING btree ("updated_at");
|
||||
CREATE INDEX "_products_v_latest_idx" ON "_products_v" USING btree ("latest");
|
||||
CREATE INDEX "_products_v_rels_order_idx" ON "_products_v_rels" USING btree ("order");
|
||||
CREATE INDEX "_products_v_rels_parent_idx" ON "_products_v_rels" USING btree ("parent_id");
|
||||
CREATE INDEX "_products_v_rels_path_idx" ON "_products_v_rels" USING btree ("path");
|
||||
CREATE INDEX "_products_v_rels_media_id_idx" ON "_products_v_rels" USING btree ("media_id");
|
||||
CREATE UNIQUE INDEX "payload_kv_key_idx" ON "payload_kv" USING btree ("key");
|
||||
CREATE INDEX "payload_locked_documents_global_slug_idx" ON "payload_locked_documents" USING btree ("global_slug");
|
||||
CREATE INDEX "payload_locked_documents_updated_at_idx" ON "payload_locked_documents" USING btree ("updated_at");
|
||||
CREATE INDEX "payload_locked_documents_created_at_idx" ON "payload_locked_documents" USING btree ("created_at");
|
||||
CREATE INDEX "payload_locked_documents_rels_order_idx" ON "payload_locked_documents_rels" USING btree ("order");
|
||||
CREATE INDEX "payload_locked_documents_rels_parent_idx" ON "payload_locked_documents_rels" USING btree ("parent_id");
|
||||
CREATE INDEX "payload_locked_documents_rels_path_idx" ON "payload_locked_documents_rels" USING btree ("path");
|
||||
CREATE INDEX "payload_locked_documents_rels_users_id_idx" ON "payload_locked_documents_rels" USING btree ("users_id");
|
||||
CREATE INDEX "payload_locked_documents_rels_media_id_idx" ON "payload_locked_documents_rels" USING btree ("media_id");
|
||||
CREATE INDEX "payload_locked_documents_rels_posts_id_idx" ON "payload_locked_documents_rels" USING btree ("posts_id");
|
||||
CREATE INDEX "payload_locked_documents_rels_form_submissions_id_idx" ON "payload_locked_documents_rels" USING btree ("form_submissions_id");
|
||||
CREATE INDEX "payload_locked_documents_rels_products_id_idx" ON "payload_locked_documents_rels" USING btree ("products_id");
|
||||
CREATE INDEX "payload_preferences_key_idx" ON "payload_preferences" USING btree ("key");
|
||||
CREATE INDEX "payload_preferences_updated_at_idx" ON "payload_preferences" USING btree ("updated_at");
|
||||
CREATE INDEX "payload_preferences_created_at_idx" ON "payload_preferences" USING btree ("created_at");
|
||||
CREATE INDEX "payload_preferences_rels_order_idx" ON "payload_preferences_rels" USING btree ("order");
|
||||
CREATE INDEX "payload_preferences_rels_parent_idx" ON "payload_preferences_rels" USING btree ("parent_id");
|
||||
CREATE INDEX "payload_preferences_rels_path_idx" ON "payload_preferences_rels" USING btree ("path");
|
||||
CREATE INDEX "payload_preferences_rels_users_id_idx" ON "payload_preferences_rels" USING btree ("users_id");
|
||||
CREATE INDEX "payload_migrations_updated_at_idx" ON "payload_migrations" USING btree ("updated_at");
|
||||
CREATE INDEX "payload_migrations_created_at_idx" ON "payload_migrations" USING btree ("created_at");`);
|
||||
}
|
||||
|
||||
export async function down({ db }: MigrateDownArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
DROP TABLE "users_sessions" CASCADE;
|
||||
DROP TABLE "users" CASCADE;
|
||||
DROP TABLE "media" CASCADE;
|
||||
DROP TABLE "posts" CASCADE;
|
||||
DROP TABLE "_posts_v" CASCADE;
|
||||
DROP TABLE "form_submissions" CASCADE;
|
||||
DROP TABLE "products_categories" CASCADE;
|
||||
DROP TABLE "products" CASCADE;
|
||||
DROP TABLE "products_rels" CASCADE;
|
||||
DROP TABLE "_products_v_version_categories" CASCADE;
|
||||
DROP TABLE "_products_v" CASCADE;
|
||||
DROP TABLE "_products_v_rels" CASCADE;
|
||||
DROP TABLE "payload_kv" CASCADE;
|
||||
DROP TABLE "payload_locked_documents" CASCADE;
|
||||
DROP TABLE "payload_locked_documents_rels" CASCADE;
|
||||
DROP TABLE "payload_preferences" CASCADE;
|
||||
DROP TABLE "payload_preferences_rels" CASCADE;
|
||||
DROP TABLE "payload_migrations" CASCADE;
|
||||
DROP TYPE "public"."enum_posts_locale";
|
||||
DROP TYPE "public"."enum_posts_status";
|
||||
DROP TYPE "public"."enum__posts_v_version_locale";
|
||||
DROP TYPE "public"."enum__posts_v_version_status";
|
||||
DROP TYPE "public"."enum_form_submissions_type";
|
||||
DROP TYPE "public"."enum_products_locale";
|
||||
DROP TYPE "public"."enum_products_status";
|
||||
DROP TYPE "public"."enum__products_v_version_locale";
|
||||
DROP TYPE "public"."enum__products_v_version_status";`);
|
||||
}
|
||||
2591
src/migrations/20260223_195151_remove_sku_unique.json
Normal file
2591
src/migrations/20260223_195151_remove_sku_unique.json
Normal file
File diff suppressed because it is too large
Load Diff
13
src/migrations/20260223_195151_remove_sku_unique.ts
Normal file
13
src/migrations/20260223_195151_remove_sku_unique.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres';
|
||||
|
||||
export async function up({ db }: MigrateUpArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
DROP INDEX "products_sku_idx";
|
||||
DROP INDEX "_products_v_version_version_sku_idx";`);
|
||||
}
|
||||
|
||||
export async function down({ db }: MigrateDownArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
CREATE UNIQUE INDEX "products_sku_idx" ON "products" USING btree ("sku");
|
||||
CREATE INDEX "_products_v_version_version_sku_idx" ON "_products_v" USING btree ("version_sku");`);
|
||||
}
|
||||
15
src/migrations/index.ts
Normal file
15
src/migrations/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as migration_20260223_195005_products_collection from './20260223_195005_products_collection';
|
||||
import * as migration_20260223_195151_remove_sku_unique from './20260223_195151_remove_sku_unique';
|
||||
|
||||
export const migrations = [
|
||||
{
|
||||
up: migration_20260223_195005_products_collection.up,
|
||||
down: migration_20260223_195005_products_collection.down,
|
||||
name: '20260223_195005_products_collection',
|
||||
},
|
||||
{
|
||||
up: migration_20260223_195151_remove_sku_unique.up,
|
||||
down: migration_20260223_195151_remove_sku_unique.down,
|
||||
name: '20260223_195151_remove_sku_unique',
|
||||
},
|
||||
];
|
||||
793
src/payload-generated-schema.ts
Normal file
793
src/payload-generated-schema.ts
Normal file
@@ -0,0 +1,793 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* This file was automatically generated by Payload.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||
* and re-run `payload generate:db-schema` to regenerate this file.
|
||||
*/
|
||||
|
||||
import type {} from '@payloadcms/db-postgres';
|
||||
import {
|
||||
pgTable,
|
||||
index,
|
||||
uniqueIndex,
|
||||
foreignKey,
|
||||
integer,
|
||||
varchar,
|
||||
timestamp,
|
||||
serial,
|
||||
numeric,
|
||||
jsonb,
|
||||
boolean,
|
||||
pgEnum,
|
||||
} from '@payloadcms/db-postgres/drizzle/pg-core';
|
||||
import { sql, relations } from '@payloadcms/db-postgres/drizzle';
|
||||
export const enum_posts_locale = pgEnum('enum_posts_locale', ['en', 'de']);
|
||||
export const enum_posts_status = pgEnum('enum_posts_status', ['draft', 'published']);
|
||||
export const enum__posts_v_version_locale = pgEnum('enum__posts_v_version_locale', ['en', 'de']);
|
||||
export const enum__posts_v_version_status = pgEnum('enum__posts_v_version_status', [
|
||||
'draft',
|
||||
'published',
|
||||
]);
|
||||
export const enum_form_submissions_type = pgEnum('enum_form_submissions_type', [
|
||||
'contact',
|
||||
'product_quote',
|
||||
]);
|
||||
export const enum_products_locale = pgEnum('enum_products_locale', ['en', 'de']);
|
||||
export const enum_products_status = pgEnum('enum_products_status', ['draft', 'published']);
|
||||
export const enum__products_v_version_locale = pgEnum('enum__products_v_version_locale', [
|
||||
'en',
|
||||
'de',
|
||||
]);
|
||||
export const enum__products_v_version_status = pgEnum('enum__products_v_version_status', [
|
||||
'draft',
|
||||
'published',
|
||||
]);
|
||||
|
||||
export const users_sessions = pgTable(
|
||||
'users_sessions',
|
||||
{
|
||||
_order: integer('_order').notNull(),
|
||||
_parentID: integer('_parent_id').notNull(),
|
||||
id: varchar('id').primaryKey(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 }),
|
||||
expiresAt: timestamp('expires_at', {
|
||||
mode: 'string',
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}).notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index('users_sessions_order_idx').on(columns._order),
|
||||
index('users_sessions_parent_id_idx').on(columns._parentID),
|
||||
foreignKey({
|
||||
columns: [columns['_parentID']],
|
||||
foreignColumns: [users.id],
|
||||
name: 'users_sessions_parent_id_fk',
|
||||
}).onDelete('cascade'),
|
||||
],
|
||||
);
|
||||
|
||||
export const users = pgTable(
|
||||
'users',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
email: varchar('email').notNull(),
|
||||
resetPasswordToken: varchar('reset_password_token'),
|
||||
resetPasswordExpiration: timestamp('reset_password_expiration', {
|
||||
mode: 'string',
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
salt: varchar('salt'),
|
||||
hash: varchar('hash'),
|
||||
loginAttempts: numeric('login_attempts', { mode: 'number' }).default(0),
|
||||
lockUntil: timestamp('lock_until', { mode: 'string', withTimezone: true, precision: 3 }),
|
||||
},
|
||||
(columns) => [
|
||||
index('users_updated_at_idx').on(columns.updatedAt),
|
||||
index('users_created_at_idx').on(columns.createdAt),
|
||||
uniqueIndex('users_email_idx').on(columns.email),
|
||||
],
|
||||
);
|
||||
|
||||
export const media = pgTable(
|
||||
'media',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
alt: varchar('alt').notNull(),
|
||||
caption: varchar('caption'),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
url: varchar('url'),
|
||||
thumbnailURL: varchar('thumbnail_u_r_l'),
|
||||
filename: varchar('filename'),
|
||||
mimeType: varchar('mime_type'),
|
||||
filesize: numeric('filesize', { mode: 'number' }),
|
||||
width: numeric('width', { mode: 'number' }),
|
||||
height: numeric('height', { mode: 'number' }),
|
||||
focalX: numeric('focal_x', { mode: 'number' }),
|
||||
focalY: numeric('focal_y', { mode: 'number' }),
|
||||
sizes_thumbnail_url: varchar('sizes_thumbnail_url'),
|
||||
sizes_thumbnail_width: numeric('sizes_thumbnail_width', { mode: 'number' }),
|
||||
sizes_thumbnail_height: numeric('sizes_thumbnail_height', { mode: 'number' }),
|
||||
sizes_thumbnail_mimeType: varchar('sizes_thumbnail_mime_type'),
|
||||
sizes_thumbnail_filesize: numeric('sizes_thumbnail_filesize', { mode: 'number' }),
|
||||
sizes_thumbnail_filename: varchar('sizes_thumbnail_filename'),
|
||||
sizes_card_url: varchar('sizes_card_url'),
|
||||
sizes_card_width: numeric('sizes_card_width', { mode: 'number' }),
|
||||
sizes_card_height: numeric('sizes_card_height', { mode: 'number' }),
|
||||
sizes_card_mimeType: varchar('sizes_card_mime_type'),
|
||||
sizes_card_filesize: numeric('sizes_card_filesize', { mode: 'number' }),
|
||||
sizes_card_filename: varchar('sizes_card_filename'),
|
||||
sizes_hero_url: varchar('sizes_hero_url'),
|
||||
sizes_hero_width: numeric('sizes_hero_width', { mode: 'number' }),
|
||||
sizes_hero_height: numeric('sizes_hero_height', { mode: 'number' }),
|
||||
sizes_hero_mimeType: varchar('sizes_hero_mime_type'),
|
||||
sizes_hero_filesize: numeric('sizes_hero_filesize', { mode: 'number' }),
|
||||
sizes_hero_filename: varchar('sizes_hero_filename'),
|
||||
sizes_hero_mobile_url: varchar('sizes_hero_mobile_url'),
|
||||
sizes_hero_mobile_width: numeric('sizes_hero_mobile_width', { mode: 'number' }),
|
||||
sizes_hero_mobile_height: numeric('sizes_hero_mobile_height', { mode: 'number' }),
|
||||
sizes_hero_mobile_mimeType: varchar('sizes_hero_mobile_mime_type'),
|
||||
sizes_hero_mobile_filesize: numeric('sizes_hero_mobile_filesize', { mode: 'number' }),
|
||||
sizes_hero_mobile_filename: varchar('sizes_hero_mobile_filename'),
|
||||
},
|
||||
(columns) => [
|
||||
index('media_updated_at_idx').on(columns.updatedAt),
|
||||
index('media_created_at_idx').on(columns.createdAt),
|
||||
uniqueIndex('media_filename_idx').on(columns.filename),
|
||||
index('media_sizes_thumbnail_sizes_thumbnail_filename_idx').on(
|
||||
columns.sizes_thumbnail_filename,
|
||||
),
|
||||
index('media_sizes_card_sizes_card_filename_idx').on(columns.sizes_card_filename),
|
||||
index('media_sizes_hero_sizes_hero_filename_idx').on(columns.sizes_hero_filename),
|
||||
index('media_sizes_hero_mobile_sizes_hero_mobile_filename_idx').on(
|
||||
columns.sizes_hero_mobile_filename,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
export const posts = pgTable(
|
||||
'posts',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
title: varchar('title'),
|
||||
slug: varchar('slug'),
|
||||
excerpt: varchar('excerpt'),
|
||||
date: timestamp('date', { mode: 'string', withTimezone: true, precision: 3 }),
|
||||
featuredImage: integer('featured_image_id').references(() => media.id, {
|
||||
onDelete: 'set null',
|
||||
}),
|
||||
locale: enum_posts_locale('locale').default('en'),
|
||||
category: varchar('category'),
|
||||
content: jsonb('content'),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
_status: enum_posts_status('_status').default('draft'),
|
||||
},
|
||||
(columns) => [
|
||||
uniqueIndex('posts_slug_idx').on(columns.slug),
|
||||
index('posts_featured_image_idx').on(columns.featuredImage),
|
||||
index('posts_updated_at_idx').on(columns.updatedAt),
|
||||
index('posts_created_at_idx').on(columns.createdAt),
|
||||
index('posts__status_idx').on(columns._status),
|
||||
],
|
||||
);
|
||||
|
||||
export const _posts_v = pgTable(
|
||||
'_posts_v',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
parent: integer('parent_id').references(() => posts.id, {
|
||||
onDelete: 'set null',
|
||||
}),
|
||||
version_title: varchar('version_title'),
|
||||
version_slug: varchar('version_slug'),
|
||||
version_excerpt: varchar('version_excerpt'),
|
||||
version_date: timestamp('version_date', { mode: 'string', withTimezone: true, precision: 3 }),
|
||||
version_featuredImage: integer('version_featured_image_id').references(() => media.id, {
|
||||
onDelete: 'set null',
|
||||
}),
|
||||
version_locale: enum__posts_v_version_locale('version_locale').default('en'),
|
||||
version_category: varchar('version_category'),
|
||||
version_content: jsonb('version_content'),
|
||||
version_updatedAt: timestamp('version_updated_at', {
|
||||
mode: 'string',
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
version_createdAt: timestamp('version_created_at', {
|
||||
mode: 'string',
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
version__status: enum__posts_v_version_status('version__status').default('draft'),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
latest: boolean('latest'),
|
||||
},
|
||||
(columns) => [
|
||||
index('_posts_v_parent_idx').on(columns.parent),
|
||||
index('_posts_v_version_version_slug_idx').on(columns.version_slug),
|
||||
index('_posts_v_version_version_featured_image_idx').on(columns.version_featuredImage),
|
||||
index('_posts_v_version_version_updated_at_idx').on(columns.version_updatedAt),
|
||||
index('_posts_v_version_version_created_at_idx').on(columns.version_createdAt),
|
||||
index('_posts_v_version_version__status_idx').on(columns.version__status),
|
||||
index('_posts_v_created_at_idx').on(columns.createdAt),
|
||||
index('_posts_v_updated_at_idx').on(columns.updatedAt),
|
||||
index('_posts_v_latest_idx').on(columns.latest),
|
||||
],
|
||||
);
|
||||
|
||||
export const form_submissions = pgTable(
|
||||
'form_submissions',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
name: varchar('name').notNull(),
|
||||
email: varchar('email').notNull(),
|
||||
type: enum_form_submissions_type('type').notNull(),
|
||||
productName: varchar('product_name'),
|
||||
message: varchar('message').notNull(),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index('form_submissions_updated_at_idx').on(columns.updatedAt),
|
||||
index('form_submissions_created_at_idx').on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const products_categories = pgTable(
|
||||
'products_categories',
|
||||
{
|
||||
_order: integer('_order').notNull(),
|
||||
_parentID: integer('_parent_id').notNull(),
|
||||
id: varchar('id').primaryKey(),
|
||||
category: varchar('category'),
|
||||
},
|
||||
(columns) => [
|
||||
index('products_categories_order_idx').on(columns._order),
|
||||
index('products_categories_parent_id_idx').on(columns._parentID),
|
||||
foreignKey({
|
||||
columns: [columns['_parentID']],
|
||||
foreignColumns: [products.id],
|
||||
name: 'products_categories_parent_id_fk',
|
||||
}).onDelete('cascade'),
|
||||
],
|
||||
);
|
||||
|
||||
export const products = pgTable(
|
||||
'products',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
title: varchar('title'),
|
||||
sku: varchar('sku'),
|
||||
slug: varchar('slug'),
|
||||
description: varchar('description'),
|
||||
locale: enum_products_locale('locale').default('de'),
|
||||
application: jsonb('application'),
|
||||
content: jsonb('content'),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
_status: enum_products_status('_status').default('draft'),
|
||||
},
|
||||
(columns) => [
|
||||
uniqueIndex('products_sku_idx').on(columns.sku),
|
||||
index('products_updated_at_idx').on(columns.updatedAt),
|
||||
index('products_created_at_idx').on(columns.createdAt),
|
||||
index('products__status_idx').on(columns._status),
|
||||
],
|
||||
);
|
||||
|
||||
export const products_rels = pgTable(
|
||||
'products_rels',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
order: integer('order'),
|
||||
parent: integer('parent_id').notNull(),
|
||||
path: varchar('path').notNull(),
|
||||
mediaID: integer('media_id'),
|
||||
},
|
||||
(columns) => [
|
||||
index('products_rels_order_idx').on(columns.order),
|
||||
index('products_rels_parent_idx').on(columns.parent),
|
||||
index('products_rels_path_idx').on(columns.path),
|
||||
index('products_rels_media_id_idx').on(columns.mediaID),
|
||||
foreignKey({
|
||||
columns: [columns['parent']],
|
||||
foreignColumns: [products.id],
|
||||
name: 'products_rels_parent_fk',
|
||||
}).onDelete('cascade'),
|
||||
foreignKey({
|
||||
columns: [columns['mediaID']],
|
||||
foreignColumns: [media.id],
|
||||
name: 'products_rels_media_fk',
|
||||
}).onDelete('cascade'),
|
||||
],
|
||||
);
|
||||
|
||||
export const _products_v_version_categories = pgTable(
|
||||
'_products_v_version_categories',
|
||||
{
|
||||
_order: integer('_order').notNull(),
|
||||
_parentID: integer('_parent_id').notNull(),
|
||||
id: serial('id').primaryKey(),
|
||||
category: varchar('category'),
|
||||
_uuid: varchar('_uuid'),
|
||||
},
|
||||
(columns) => [
|
||||
index('_products_v_version_categories_order_idx').on(columns._order),
|
||||
index('_products_v_version_categories_parent_id_idx').on(columns._parentID),
|
||||
foreignKey({
|
||||
columns: [columns['_parentID']],
|
||||
foreignColumns: [_products_v.id],
|
||||
name: '_products_v_version_categories_parent_id_fk',
|
||||
}).onDelete('cascade'),
|
||||
],
|
||||
);
|
||||
|
||||
export const _products_v = pgTable(
|
||||
'_products_v',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
parent: integer('parent_id').references(() => products.id, {
|
||||
onDelete: 'set null',
|
||||
}),
|
||||
version_title: varchar('version_title'),
|
||||
version_sku: varchar('version_sku'),
|
||||
version_slug: varchar('version_slug'),
|
||||
version_description: varchar('version_description'),
|
||||
version_locale: enum__products_v_version_locale('version_locale').default('de'),
|
||||
version_application: jsonb('version_application'),
|
||||
version_content: jsonb('version_content'),
|
||||
version_updatedAt: timestamp('version_updated_at', {
|
||||
mode: 'string',
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
version_createdAt: timestamp('version_created_at', {
|
||||
mode: 'string',
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
version__status: enum__products_v_version_status('version__status').default('draft'),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
latest: boolean('latest'),
|
||||
},
|
||||
(columns) => [
|
||||
index('_products_v_parent_idx').on(columns.parent),
|
||||
index('_products_v_version_version_sku_idx').on(columns.version_sku),
|
||||
index('_products_v_version_version_updated_at_idx').on(columns.version_updatedAt),
|
||||
index('_products_v_version_version_created_at_idx').on(columns.version_createdAt),
|
||||
index('_products_v_version_version__status_idx').on(columns.version__status),
|
||||
index('_products_v_created_at_idx').on(columns.createdAt),
|
||||
index('_products_v_updated_at_idx').on(columns.updatedAt),
|
||||
index('_products_v_latest_idx').on(columns.latest),
|
||||
],
|
||||
);
|
||||
|
||||
export const _products_v_rels = pgTable(
|
||||
'_products_v_rels',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
order: integer('order'),
|
||||
parent: integer('parent_id').notNull(),
|
||||
path: varchar('path').notNull(),
|
||||
mediaID: integer('media_id'),
|
||||
},
|
||||
(columns) => [
|
||||
index('_products_v_rels_order_idx').on(columns.order),
|
||||
index('_products_v_rels_parent_idx').on(columns.parent),
|
||||
index('_products_v_rels_path_idx').on(columns.path),
|
||||
index('_products_v_rels_media_id_idx').on(columns.mediaID),
|
||||
foreignKey({
|
||||
columns: [columns['parent']],
|
||||
foreignColumns: [_products_v.id],
|
||||
name: '_products_v_rels_parent_fk',
|
||||
}).onDelete('cascade'),
|
||||
foreignKey({
|
||||
columns: [columns['mediaID']],
|
||||
foreignColumns: [media.id],
|
||||
name: '_products_v_rels_media_fk',
|
||||
}).onDelete('cascade'),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_kv = pgTable(
|
||||
'payload_kv',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
key: varchar('key').notNull(),
|
||||
data: jsonb('data').notNull(),
|
||||
},
|
||||
(columns) => [uniqueIndex('payload_kv_key_idx').on(columns.key)],
|
||||
);
|
||||
|
||||
export const payload_locked_documents = pgTable(
|
||||
'payload_locked_documents',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
globalSlug: varchar('global_slug'),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index('payload_locked_documents_global_slug_idx').on(columns.globalSlug),
|
||||
index('payload_locked_documents_updated_at_idx').on(columns.updatedAt),
|
||||
index('payload_locked_documents_created_at_idx').on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_locked_documents_rels = pgTable(
|
||||
'payload_locked_documents_rels',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
order: integer('order'),
|
||||
parent: integer('parent_id').notNull(),
|
||||
path: varchar('path').notNull(),
|
||||
usersID: integer('users_id'),
|
||||
mediaID: integer('media_id'),
|
||||
postsID: integer('posts_id'),
|
||||
'form-submissionsID': integer('form_submissions_id'),
|
||||
productsID: integer('products_id'),
|
||||
},
|
||||
(columns) => [
|
||||
index('payload_locked_documents_rels_order_idx').on(columns.order),
|
||||
index('payload_locked_documents_rels_parent_idx').on(columns.parent),
|
||||
index('payload_locked_documents_rels_path_idx').on(columns.path),
|
||||
index('payload_locked_documents_rels_users_id_idx').on(columns.usersID),
|
||||
index('payload_locked_documents_rels_media_id_idx').on(columns.mediaID),
|
||||
index('payload_locked_documents_rels_posts_id_idx').on(columns.postsID),
|
||||
index('payload_locked_documents_rels_form_submissions_id_idx').on(
|
||||
columns['form-submissionsID'],
|
||||
),
|
||||
index('payload_locked_documents_rels_products_id_idx').on(columns.productsID),
|
||||
foreignKey({
|
||||
columns: [columns['parent']],
|
||||
foreignColumns: [payload_locked_documents.id],
|
||||
name: 'payload_locked_documents_rels_parent_fk',
|
||||
}).onDelete('cascade'),
|
||||
foreignKey({
|
||||
columns: [columns['usersID']],
|
||||
foreignColumns: [users.id],
|
||||
name: 'payload_locked_documents_rels_users_fk',
|
||||
}).onDelete('cascade'),
|
||||
foreignKey({
|
||||
columns: [columns['mediaID']],
|
||||
foreignColumns: [media.id],
|
||||
name: 'payload_locked_documents_rels_media_fk',
|
||||
}).onDelete('cascade'),
|
||||
foreignKey({
|
||||
columns: [columns['postsID']],
|
||||
foreignColumns: [posts.id],
|
||||
name: 'payload_locked_documents_rels_posts_fk',
|
||||
}).onDelete('cascade'),
|
||||
foreignKey({
|
||||
columns: [columns['form-submissionsID']],
|
||||
foreignColumns: [form_submissions.id],
|
||||
name: 'payload_locked_documents_rels_form_submissions_fk',
|
||||
}).onDelete('cascade'),
|
||||
foreignKey({
|
||||
columns: [columns['productsID']],
|
||||
foreignColumns: [products.id],
|
||||
name: 'payload_locked_documents_rels_products_fk',
|
||||
}).onDelete('cascade'),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_preferences = pgTable(
|
||||
'payload_preferences',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
key: varchar('key'),
|
||||
value: jsonb('value'),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index('payload_preferences_key_idx').on(columns.key),
|
||||
index('payload_preferences_updated_at_idx').on(columns.updatedAt),
|
||||
index('payload_preferences_created_at_idx').on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_preferences_rels = pgTable(
|
||||
'payload_preferences_rels',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
order: integer('order'),
|
||||
parent: integer('parent_id').notNull(),
|
||||
path: varchar('path').notNull(),
|
||||
usersID: integer('users_id'),
|
||||
},
|
||||
(columns) => [
|
||||
index('payload_preferences_rels_order_idx').on(columns.order),
|
||||
index('payload_preferences_rels_parent_idx').on(columns.parent),
|
||||
index('payload_preferences_rels_path_idx').on(columns.path),
|
||||
index('payload_preferences_rels_users_id_idx').on(columns.usersID),
|
||||
foreignKey({
|
||||
columns: [columns['parent']],
|
||||
foreignColumns: [payload_preferences.id],
|
||||
name: 'payload_preferences_rels_parent_fk',
|
||||
}).onDelete('cascade'),
|
||||
foreignKey({
|
||||
columns: [columns['usersID']],
|
||||
foreignColumns: [users.id],
|
||||
name: 'payload_preferences_rels_users_fk',
|
||||
}).onDelete('cascade'),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_migrations = pgTable(
|
||||
'payload_migrations',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
name: varchar('name'),
|
||||
batch: numeric('batch', { mode: 'number' }),
|
||||
updatedAt: timestamp('updated_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp('created_at', { mode: 'string', withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index('payload_migrations_updated_at_idx').on(columns.updatedAt),
|
||||
index('payload_migrations_created_at_idx').on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const relations_users_sessions = relations(users_sessions, ({ one }) => ({
|
||||
_parentID: one(users, {
|
||||
fields: [users_sessions._parentID],
|
||||
references: [users.id],
|
||||
relationName: 'sessions',
|
||||
}),
|
||||
}));
|
||||
export const relations_users = relations(users, ({ many }) => ({
|
||||
sessions: many(users_sessions, {
|
||||
relationName: 'sessions',
|
||||
}),
|
||||
}));
|
||||
export const relations_media = relations(media, () => ({}));
|
||||
export const relations_posts = relations(posts, ({ one }) => ({
|
||||
featuredImage: one(media, {
|
||||
fields: [posts.featuredImage],
|
||||
references: [media.id],
|
||||
relationName: 'featuredImage',
|
||||
}),
|
||||
}));
|
||||
export const relations__posts_v = relations(_posts_v, ({ one }) => ({
|
||||
parent: one(posts, {
|
||||
fields: [_posts_v.parent],
|
||||
references: [posts.id],
|
||||
relationName: 'parent',
|
||||
}),
|
||||
version_featuredImage: one(media, {
|
||||
fields: [_posts_v.version_featuredImage],
|
||||
references: [media.id],
|
||||
relationName: 'version_featuredImage',
|
||||
}),
|
||||
}));
|
||||
export const relations_form_submissions = relations(form_submissions, () => ({}));
|
||||
export const relations_products_categories = relations(products_categories, ({ one }) => ({
|
||||
_parentID: one(products, {
|
||||
fields: [products_categories._parentID],
|
||||
references: [products.id],
|
||||
relationName: 'categories',
|
||||
}),
|
||||
}));
|
||||
export const relations_products_rels = relations(products_rels, ({ one }) => ({
|
||||
parent: one(products, {
|
||||
fields: [products_rels.parent],
|
||||
references: [products.id],
|
||||
relationName: '_rels',
|
||||
}),
|
||||
mediaID: one(media, {
|
||||
fields: [products_rels.mediaID],
|
||||
references: [media.id],
|
||||
relationName: 'media',
|
||||
}),
|
||||
}));
|
||||
export const relations_products = relations(products, ({ many }) => ({
|
||||
categories: many(products_categories, {
|
||||
relationName: 'categories',
|
||||
}),
|
||||
_rels: many(products_rels, {
|
||||
relationName: '_rels',
|
||||
}),
|
||||
}));
|
||||
export const relations__products_v_version_categories = relations(
|
||||
_products_v_version_categories,
|
||||
({ one }) => ({
|
||||
_parentID: one(_products_v, {
|
||||
fields: [_products_v_version_categories._parentID],
|
||||
references: [_products_v.id],
|
||||
relationName: 'version_categories',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations__products_v_rels = relations(_products_v_rels, ({ one }) => ({
|
||||
parent: one(_products_v, {
|
||||
fields: [_products_v_rels.parent],
|
||||
references: [_products_v.id],
|
||||
relationName: '_rels',
|
||||
}),
|
||||
mediaID: one(media, {
|
||||
fields: [_products_v_rels.mediaID],
|
||||
references: [media.id],
|
||||
relationName: 'media',
|
||||
}),
|
||||
}));
|
||||
export const relations__products_v = relations(_products_v, ({ one, many }) => ({
|
||||
parent: one(products, {
|
||||
fields: [_products_v.parent],
|
||||
references: [products.id],
|
||||
relationName: 'parent',
|
||||
}),
|
||||
version_categories: many(_products_v_version_categories, {
|
||||
relationName: 'version_categories',
|
||||
}),
|
||||
_rels: many(_products_v_rels, {
|
||||
relationName: '_rels',
|
||||
}),
|
||||
}));
|
||||
export const relations_payload_kv = relations(payload_kv, () => ({}));
|
||||
export const relations_payload_locked_documents_rels = relations(
|
||||
payload_locked_documents_rels,
|
||||
({ one }) => ({
|
||||
parent: one(payload_locked_documents, {
|
||||
fields: [payload_locked_documents_rels.parent],
|
||||
references: [payload_locked_documents.id],
|
||||
relationName: '_rels',
|
||||
}),
|
||||
usersID: one(users, {
|
||||
fields: [payload_locked_documents_rels.usersID],
|
||||
references: [users.id],
|
||||
relationName: 'users',
|
||||
}),
|
||||
mediaID: one(media, {
|
||||
fields: [payload_locked_documents_rels.mediaID],
|
||||
references: [media.id],
|
||||
relationName: 'media',
|
||||
}),
|
||||
postsID: one(posts, {
|
||||
fields: [payload_locked_documents_rels.postsID],
|
||||
references: [posts.id],
|
||||
relationName: 'posts',
|
||||
}),
|
||||
'form-submissionsID': one(form_submissions, {
|
||||
fields: [payload_locked_documents_rels['form-submissionsID']],
|
||||
references: [form_submissions.id],
|
||||
relationName: 'form-submissions',
|
||||
}),
|
||||
productsID: one(products, {
|
||||
fields: [payload_locked_documents_rels.productsID],
|
||||
references: [products.id],
|
||||
relationName: 'products',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations_payload_locked_documents = relations(
|
||||
payload_locked_documents,
|
||||
({ many }) => ({
|
||||
_rels: many(payload_locked_documents_rels, {
|
||||
relationName: '_rels',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations_payload_preferences_rels = relations(
|
||||
payload_preferences_rels,
|
||||
({ one }) => ({
|
||||
parent: one(payload_preferences, {
|
||||
fields: [payload_preferences_rels.parent],
|
||||
references: [payload_preferences.id],
|
||||
relationName: '_rels',
|
||||
}),
|
||||
usersID: one(users, {
|
||||
fields: [payload_preferences_rels.usersID],
|
||||
references: [users.id],
|
||||
relationName: 'users',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations_payload_preferences = relations(payload_preferences, ({ many }) => ({
|
||||
_rels: many(payload_preferences_rels, {
|
||||
relationName: '_rels',
|
||||
}),
|
||||
}));
|
||||
export const relations_payload_migrations = relations(payload_migrations, () => ({}));
|
||||
|
||||
type DatabaseSchema = {
|
||||
enum_posts_locale: typeof enum_posts_locale;
|
||||
enum_posts_status: typeof enum_posts_status;
|
||||
enum__posts_v_version_locale: typeof enum__posts_v_version_locale;
|
||||
enum__posts_v_version_status: typeof enum__posts_v_version_status;
|
||||
enum_form_submissions_type: typeof enum_form_submissions_type;
|
||||
enum_products_locale: typeof enum_products_locale;
|
||||
enum_products_status: typeof enum_products_status;
|
||||
enum__products_v_version_locale: typeof enum__products_v_version_locale;
|
||||
enum__products_v_version_status: typeof enum__products_v_version_status;
|
||||
users_sessions: typeof users_sessions;
|
||||
users: typeof users;
|
||||
media: typeof media;
|
||||
posts: typeof posts;
|
||||
_posts_v: typeof _posts_v;
|
||||
form_submissions: typeof form_submissions;
|
||||
products_categories: typeof products_categories;
|
||||
products: typeof products;
|
||||
products_rels: typeof products_rels;
|
||||
_products_v_version_categories: typeof _products_v_version_categories;
|
||||
_products_v: typeof _products_v;
|
||||
_products_v_rels: typeof _products_v_rels;
|
||||
payload_kv: typeof payload_kv;
|
||||
payload_locked_documents: typeof payload_locked_documents;
|
||||
payload_locked_documents_rels: typeof payload_locked_documents_rels;
|
||||
payload_preferences: typeof payload_preferences;
|
||||
payload_preferences_rels: typeof payload_preferences_rels;
|
||||
payload_migrations: typeof payload_migrations;
|
||||
relations_users_sessions: typeof relations_users_sessions;
|
||||
relations_users: typeof relations_users;
|
||||
relations_media: typeof relations_media;
|
||||
relations_posts: typeof relations_posts;
|
||||
relations__posts_v: typeof relations__posts_v;
|
||||
relations_form_submissions: typeof relations_form_submissions;
|
||||
relations_products_categories: typeof relations_products_categories;
|
||||
relations_products_rels: typeof relations_products_rels;
|
||||
relations_products: typeof relations_products;
|
||||
relations__products_v_version_categories: typeof relations__products_v_version_categories;
|
||||
relations__products_v_rels: typeof relations__products_v_rels;
|
||||
relations__products_v: typeof relations__products_v;
|
||||
relations_payload_kv: typeof relations_payload_kv;
|
||||
relations_payload_locked_documents_rels: typeof relations_payload_locked_documents_rels;
|
||||
relations_payload_locked_documents: typeof relations_payload_locked_documents;
|
||||
relations_payload_preferences_rels: typeof relations_payload_preferences_rels;
|
||||
relations_payload_preferences: typeof relations_payload_preferences;
|
||||
relations_payload_migrations: typeof relations_payload_migrations;
|
||||
};
|
||||
|
||||
declare module '@payloadcms/db-postgres' {
|
||||
export interface GeneratedDatabaseSchema {
|
||||
schema: DatabaseSchema;
|
||||
}
|
||||
}
|
||||
25
src/payload/blocks/AnimatedImage.ts
Normal file
25
src/payload/blocks/AnimatedImage.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const AnimatedImage: Block = {
|
||||
slug: 'animatedImage',
|
||||
fields: [
|
||||
{
|
||||
name: 'src',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'alt',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'width',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'height',
|
||||
type: 'number',
|
||||
},
|
||||
],
|
||||
};
|
||||
20
src/payload/blocks/Callout.ts
Normal file
20
src/payload/blocks/Callout.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Block } from 'payload';
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical';
|
||||
|
||||
export const Callout: Block = {
|
||||
slug: 'callout',
|
||||
fields: [
|
||||
{
|
||||
name: 'type',
|
||||
type: 'select',
|
||||
options: ['info', 'warning', 'important', 'tip', 'caution'],
|
||||
defaultValue: 'info',
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({}),
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
34
src/payload/blocks/ChatBubble.ts
Normal file
34
src/payload/blocks/ChatBubble.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Block } from 'payload';
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical';
|
||||
|
||||
export const ChatBubble: Block = {
|
||||
slug: 'chatBubble',
|
||||
fields: [
|
||||
{
|
||||
name: 'author',
|
||||
type: 'text',
|
||||
defaultValue: 'KLZ Team',
|
||||
},
|
||||
{
|
||||
name: 'avatar',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'role',
|
||||
type: 'text',
|
||||
defaultValue: 'Assistant',
|
||||
},
|
||||
{
|
||||
name: 'align',
|
||||
type: 'select',
|
||||
options: ['left', 'right'],
|
||||
defaultValue: 'left',
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({}),
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
47
src/payload/blocks/ComparisonGrid.ts
Normal file
47
src/payload/blocks/ComparisonGrid.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const ComparisonGrid: Block = {
|
||||
slug: 'comparisonGrid',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Main Heading',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'leftLabel',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'rightLabel',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'items',
|
||||
type: 'array',
|
||||
required: true,
|
||||
minRows: 1,
|
||||
fields: [
|
||||
{
|
||||
name: 'label',
|
||||
label: 'Row Label',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'leftValue',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'rightValue',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
20
src/payload/blocks/HighlightBox.ts
Normal file
20
src/payload/blocks/HighlightBox.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Block } from 'payload';
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical';
|
||||
|
||||
export const HighlightBox: Block = {
|
||||
slug: 'highlightBox',
|
||||
fields: [
|
||||
{
|
||||
name: 'type',
|
||||
type: 'select',
|
||||
options: ['info', 'warning', 'success', 'error', 'neutral'],
|
||||
defaultValue: 'neutral',
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({}),
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
12
src/payload/blocks/PowerCTA.ts
Normal file
12
src/payload/blocks/PowerCTA.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const PowerCTA: Block = {
|
||||
slug: 'powerCTA',
|
||||
fields: [
|
||||
{
|
||||
name: 'locale',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
96
src/payload/blocks/ProductTabs.ts
Normal file
96
src/payload/blocks/ProductTabs.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const ProductTabs: Block = {
|
||||
slug: 'productTabs',
|
||||
interfaceName: 'ProductTabsBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'technicalItems',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'label',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'unit',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'voltageTables',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'voltageLabel',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'metaItems',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'label',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'unit',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'columns',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'key',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'label',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'rows',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'configuration',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'cells',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
23
src/payload/blocks/SplitHeading.ts
Normal file
23
src/payload/blocks/SplitHeading.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const SplitHeading: Block = {
|
||||
slug: 'splitHeading',
|
||||
interfaceName: 'SplitHeadingBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'id',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'level',
|
||||
type: 'select',
|
||||
options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
|
||||
defaultValue: 'h2',
|
||||
},
|
||||
],
|
||||
};
|
||||
25
src/payload/blocks/Stats.ts
Normal file
25
src/payload/blocks/Stats.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const Stats: Block = {
|
||||
slug: 'stats',
|
||||
interfaceName: 'StatsBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'stats',
|
||||
type: 'array',
|
||||
required: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'label',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
31
src/payload/blocks/StickyNarrative.ts
Normal file
31
src/payload/blocks/StickyNarrative.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const StickyNarrative: Block = {
|
||||
slug: 'stickyNarrative',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Main Heading',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'items',
|
||||
type: 'array',
|
||||
required: true,
|
||||
minRows: 1,
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
30
src/payload/blocks/TechnicalGrid.ts
Normal file
30
src/payload/blocks/TechnicalGrid.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const TechnicalGrid: Block = {
|
||||
slug: 'technicalGrid',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Main Heading',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'items',
|
||||
type: 'array',
|
||||
required: true,
|
||||
minRows: 1,
|
||||
fields: [
|
||||
{
|
||||
name: 'label',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
30
src/payload/blocks/VisualLinkPreview.ts
Normal file
30
src/payload/blocks/VisualLinkPreview.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Block } from 'payload';
|
||||
|
||||
export const VisualLinkPreview: Block = {
|
||||
slug: 'visualLinkPreview',
|
||||
fields: [
|
||||
{
|
||||
name: 'url',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'summary',
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Legacy HTTP string from the old hardcoded images.',
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
27
src/payload/blocks/allBlocks.ts
Normal file
27
src/payload/blocks/allBlocks.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { AnimatedImage } from './AnimatedImage';
|
||||
import { Callout } from './Callout';
|
||||
import { ChatBubble } from './ChatBubble';
|
||||
import { ComparisonGrid } from './ComparisonGrid';
|
||||
import { HighlightBox } from './HighlightBox';
|
||||
import { PowerCTA } from './PowerCTA';
|
||||
import { ProductTabs } from './ProductTabs';
|
||||
import { SplitHeading } from './SplitHeading';
|
||||
import { Stats } from './Stats';
|
||||
import { StickyNarrative } from './StickyNarrative';
|
||||
import { TechnicalGrid } from './TechnicalGrid';
|
||||
import { VisualLinkPreview } from './VisualLinkPreview';
|
||||
|
||||
export const payloadBlocks = [
|
||||
AnimatedImage,
|
||||
Callout,
|
||||
ChatBubble,
|
||||
ComparisonGrid,
|
||||
HighlightBox,
|
||||
PowerCTA,
|
||||
ProductTabs,
|
||||
SplitHeading,
|
||||
Stats,
|
||||
StickyNarrative,
|
||||
TechnicalGrid,
|
||||
VisualLinkPreview,
|
||||
];
|
||||
67
src/payload/collections/FormSubmissions.ts
Normal file
67
src/payload/collections/FormSubmissions.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import type { CollectionConfig } from 'payload';
|
||||
|
||||
export const FormSubmissions: CollectionConfig = {
|
||||
slug: 'form-submissions',
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
defaultColumns: ['name', 'email', 'type', 'createdAt'],
|
||||
description: 'Captured leads from Contact and Product Quote forms.',
|
||||
},
|
||||
access: {
|
||||
// Only Admins can view and delete leads via dashboard.
|
||||
read: ({ req: { user } }) => Boolean(user) || process.env.NODE_ENV === 'development',
|
||||
update: ({ req: { user } }) => Boolean(user) || process.env.NODE_ENV === 'development',
|
||||
delete: ({ req: { user } }) => Boolean(user) || process.env.NODE_ENV === 'development',
|
||||
// Next.js server actions handle secure inserts natively. No public client create access.
|
||||
create: () => false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
required: true,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
required: true,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: 'General Contact', value: 'contact' },
|
||||
{ label: 'Product Quote', value: 'product_quote' },
|
||||
],
|
||||
required: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'productName',
|
||||
type: 'text',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
readOnly: true,
|
||||
condition: (data) => data.type === 'product_quote',
|
||||
description: 'The specific KLZ product the user requested a quote for.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
48
src/payload/collections/Media.ts
Normal file
48
src/payload/collections/Media.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { CollectionConfig } from 'payload';
|
||||
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: 'alt',
|
||||
defaultColumns: ['filename', 'alt', 'updatedAt'],
|
||||
},
|
||||
upload: {
|
||||
staticDir: 'public/media',
|
||||
adminThumbnail: 'thumbnail',
|
||||
imageSizes: [
|
||||
{
|
||||
name: 'thumbnail',
|
||||
width: 600,
|
||||
// height: undefined allows wide 5:1 aspect ratios to be preserved without cropping
|
||||
height: undefined,
|
||||
position: 'centre',
|
||||
},
|
||||
{
|
||||
name: 'card',
|
||||
width: 768,
|
||||
height: undefined,
|
||||
position: 'centre',
|
||||
},
|
||||
{
|
||||
name: 'tablet',
|
||||
width: 1024,
|
||||
height: undefined,
|
||||
position: 'centre',
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'alt',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'caption',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
};
|
||||
61
src/payload/collections/Pages.ts
Normal file
61
src/payload/collections/Pages.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { CollectionConfig } from 'payload';
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical';
|
||||
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
defaultColumns: ['title', 'slug', 'locale', 'updatedAt'],
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'text',
|
||||
required: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'locale',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: 'English', value: 'en' },
|
||||
{ label: 'German', value: 'de' },
|
||||
],
|
||||
required: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'excerpt',
|
||||
type: 'textarea',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'featuredImage',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({}),
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
154
src/payload/collections/Posts.ts
Normal file
154
src/payload/collections/Posts.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import type { CollectionConfig } from 'payload';
|
||||
import { lexicalEditor, BlocksFeature } from '@payloadcms/richtext-lexical';
|
||||
|
||||
import { StickyNarrative } from '../blocks/StickyNarrative';
|
||||
import { ComparisonGrid } from '../blocks/ComparisonGrid';
|
||||
import { VisualLinkPreview } from '../blocks/VisualLinkPreview';
|
||||
import { TechnicalGrid } from '../blocks/TechnicalGrid';
|
||||
import { HighlightBox } from '../blocks/HighlightBox';
|
||||
import { AnimatedImage } from '../blocks/AnimatedImage';
|
||||
import { ChatBubble } from '../blocks/ChatBubble';
|
||||
import { PowerCTA } from '../blocks/PowerCTA';
|
||||
import { Callout } from '../blocks/Callout';
|
||||
import { Stats } from '../blocks/Stats';
|
||||
import { SplitHeading } from '../blocks/SplitHeading';
|
||||
|
||||
export const Posts: CollectionConfig = {
|
||||
slug: 'posts',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
defaultColumns: ['featuredImage', 'title', 'date', 'updatedAt', '_status'],
|
||||
},
|
||||
versions: {
|
||||
drafts: true, // Enables Draft/Published workflows
|
||||
},
|
||||
access: {
|
||||
read: ({ req: { user } }) => {
|
||||
// In local development, always show everything (including Drafts and scheduled future posts)
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If an Admin user is logged in, they can view everything
|
||||
if (user) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For public unauthenticated visitors in PROD/STAGING contexts:
|
||||
// Only serve Posts where Status = "published" AND the publish Date is in the past!
|
||||
return {
|
||||
and: [
|
||||
{
|
||||
_status: {
|
||||
equals: 'published',
|
||||
},
|
||||
},
|
||||
{
|
||||
date: {
|
||||
less_than_equal: new Date().toISOString(),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'text',
|
||||
required: true,
|
||||
unique: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
hooks: {
|
||||
beforeValidate: [
|
||||
({ value, data }) => {
|
||||
// Auto-generate slug from title if left blank
|
||||
if (value || !data?.title) return value;
|
||||
return data.title
|
||||
.toLowerCase()
|
||||
.replace(/ /g, '-')
|
||||
.replace(/[^\w-]+/g, '');
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'excerpt',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'A short summary for blog feed cards and SEO.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
type: 'date',
|
||||
required: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
description: 'Future dates will schedule the post to publish automatically.',
|
||||
},
|
||||
defaultValue: () => new Date().toISOString(),
|
||||
},
|
||||
{
|
||||
name: 'featuredImage',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
description: 'The primary Hero image used for headers and OpenGraph previews.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'locale',
|
||||
type: 'select',
|
||||
required: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
options: [
|
||||
{ label: 'English', value: 'en' },
|
||||
{ label: 'German', value: 'de' },
|
||||
],
|
||||
defaultValue: 'en',
|
||||
},
|
||||
{
|
||||
name: 'category',
|
||||
type: 'text',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
description: 'Used for tag bucketing (e.g. "Kabel Technologie").',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({
|
||||
features: ({ defaultFeatures }) => [
|
||||
...defaultFeatures,
|
||||
BlocksFeature({
|
||||
blocks: [
|
||||
StickyNarrative,
|
||||
ComparisonGrid,
|
||||
VisualLinkPreview,
|
||||
TechnicalGrid,
|
||||
HighlightBox,
|
||||
AnimatedImage,
|
||||
ChatBubble,
|
||||
PowerCTA,
|
||||
Callout,
|
||||
Stats,
|
||||
SplitHeading,
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
144
src/payload/collections/Products.ts
Normal file
144
src/payload/collections/Products.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import type { CollectionConfig } from 'payload';
|
||||
import { lexicalEditor, BlocksFeature } from '@payloadcms/richtext-lexical';
|
||||
|
||||
import { StickyNarrative } from '../blocks/StickyNarrative';
|
||||
import { ComparisonGrid } from '../blocks/ComparisonGrid';
|
||||
import { VisualLinkPreview } from '../blocks/VisualLinkPreview';
|
||||
import { TechnicalGrid } from '../blocks/TechnicalGrid';
|
||||
import { HighlightBox } from '../blocks/HighlightBox';
|
||||
import { AnimatedImage } from '../blocks/AnimatedImage';
|
||||
import { ChatBubble } from '../blocks/ChatBubble';
|
||||
import { PowerCTA } from '../blocks/PowerCTA';
|
||||
import { Callout } from '../blocks/Callout';
|
||||
import { Stats } from '../blocks/Stats';
|
||||
import { SplitHeading } from '../blocks/SplitHeading';
|
||||
import { ProductTabs } from '../blocks/ProductTabs';
|
||||
|
||||
export const Products: CollectionConfig = {
|
||||
slug: 'products',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
defaultColumns: ['featuredImage', 'title', 'sku', 'locale', 'updatedAt', '_status'],
|
||||
},
|
||||
versions: {
|
||||
drafts: true,
|
||||
},
|
||||
access: {
|
||||
read: ({ req: { user } }) => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return true;
|
||||
}
|
||||
if (user) {
|
||||
return true;
|
||||
}
|
||||
return {
|
||||
_status: {
|
||||
equals: 'published',
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'sku',
|
||||
type: 'text',
|
||||
required: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'text',
|
||||
required: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'locale',
|
||||
type: 'select',
|
||||
required: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
options: [
|
||||
{ label: 'English', value: 'en' },
|
||||
{ label: 'German', value: 'de' },
|
||||
],
|
||||
defaultValue: 'de',
|
||||
},
|
||||
{
|
||||
name: 'categories',
|
||||
type: 'array',
|
||||
required: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'category',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'featuredImage',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
description: 'The primary thumbnail used in list views.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'images',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
hasMany: true,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'application',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({}),
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({
|
||||
features: ({ defaultFeatures }) => [
|
||||
...defaultFeatures,
|
||||
BlocksFeature({
|
||||
blocks: [
|
||||
StickyNarrative,
|
||||
ComparisonGrid,
|
||||
VisualLinkPreview,
|
||||
TechnicalGrid,
|
||||
HighlightBox,
|
||||
AnimatedImage,
|
||||
ChatBubble,
|
||||
PowerCTA,
|
||||
Callout,
|
||||
Stats,
|
||||
SplitHeading,
|
||||
ProductTabs,
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
12
src/payload/collections/Users.ts
Normal file
12
src/payload/collections/Users.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { CollectionConfig } from 'payload';
|
||||
|
||||
export const Users: CollectionConfig = {
|
||||
slug: 'users',
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
auth: true,
|
||||
fields: [
|
||||
// Email added by default
|
||||
],
|
||||
};
|
||||
296
src/payload/utils/lexicalParser.ts
Normal file
296
src/payload/utils/lexicalParser.ts
Normal file
@@ -0,0 +1,296 @@
|
||||
/**
|
||||
* Converts a Markdown+JSX string into a Lexical AST node array.
|
||||
* Specifically adapted for klz-cables.com custom Component Blocks.
|
||||
*/
|
||||
|
||||
function propValue(chunk: string, prop: string): string {
|
||||
// Match prop="value" or prop='value' or prop={value}
|
||||
// and also multiline props like prop={\n [\n {...}\n ]\n}
|
||||
// For arrays or complex objects passed as props, basic regex might fail,
|
||||
// but the MDX in klz-cables usually uses simpler props or children.
|
||||
const match =
|
||||
chunk.match(new RegExp(`${prop}=["']([^"']+)["']`)) ||
|
||||
chunk.match(new RegExp(`${prop}=\\{([^}]+)\\}`));
|
||||
return match ? match[1] : '';
|
||||
}
|
||||
|
||||
function extractItemsProp(chunk: string, startTag: string): any[] {
|
||||
// Match items={ [ ... ] } robustly without stopping at inner object braces
|
||||
const itemsMatch = chunk.match(/items=\{\s*(\[[\s\S]*?\])\s*\}/);
|
||||
if (itemsMatch) {
|
||||
try {
|
||||
const arrayString = itemsMatch[1].trim();
|
||||
// Since klz-cables MDX passes pure JS object arrays like `items={[{title: 'A', content: 'B'}]}`,
|
||||
// parsing it via Regex to JSON is extremely brittle due to unquoted keys and trailing commas.
|
||||
// Using `new Function` safely evaluates the array AST directly in this Node script environment.
|
||||
const fn = new Function(`return ${arrayString};`);
|
||||
return fn();
|
||||
} catch (_e: any) {
|
||||
console.warn(`Could not parse items array for block ${startTag}:`, _e.message);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function blockNode(blockType: string, fields: Record<string, any>) {
|
||||
return { type: 'block', format: '', version: 2, fields: { blockType, ...fields } };
|
||||
}
|
||||
|
||||
function ensureChildren(parsedNodes: any[]): any[] {
|
||||
// Lexical root nodes require at least one child node, or validation fails
|
||||
if (parsedNodes.length === 0) {
|
||||
return [
|
||||
{
|
||||
type: 'paragraph',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
children: [{ mode: 'normal', type: 'text', text: ' ', version: 1 }],
|
||||
},
|
||||
];
|
||||
}
|
||||
return parsedNodes;
|
||||
}
|
||||
|
||||
export function parseMarkdownToLexical(markdown: string): any[] {
|
||||
const textNode = (text: string) => ({
|
||||
type: 'paragraph',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
children: [{ mode: 'normal', type: 'text', text, version: 1 }],
|
||||
});
|
||||
|
||||
const nodes: any[] = [];
|
||||
let content = markdown;
|
||||
|
||||
// Strip frontmatter
|
||||
const fm = content.match(/^---\s*\n[\s\S]*?\n---/);
|
||||
if (fm) content = content.replace(fm[0], '').trim();
|
||||
|
||||
// 1. EXTRACT MULTILINE WRAPPERS BEFORE CHUNKING
|
||||
// This allows nested newlines inside components without breaking them.
|
||||
const extractBlocks = [
|
||||
{
|
||||
tag: 'HighlightBox',
|
||||
regex: /<HighlightBox([^>]*)>([\s\S]*?)<\/HighlightBox>/g,
|
||||
build: (props: string, inner: string) =>
|
||||
blockNode('highlightBox', {
|
||||
title: propValue(`<Tag ${props}>`, 'title'),
|
||||
color: propValue(`<Tag ${props}>`, 'color') || 'primary',
|
||||
content: {
|
||||
root: {
|
||||
type: 'root',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
direction: 'ltr',
|
||||
children: ensureChildren(parseMarkdownToLexical(inner.trim())),
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
tag: 'ChatBubble',
|
||||
regex: /<ChatBubble([^>]*)>([\s\S]*?)<\/ChatBubble>/g,
|
||||
build: (props: string, inner: string) =>
|
||||
blockNode('chatBubble', {
|
||||
author: propValue(`<Tag ${props}>`, 'author') || 'KLZ Team',
|
||||
avatar: propValue(`<Tag ${props}>`, 'avatar'),
|
||||
role: propValue(`<Tag ${props}>`, 'role') || 'Assistant',
|
||||
align: propValue(`<Tag ${props}>`, 'align') || 'left',
|
||||
content: {
|
||||
root: {
|
||||
type: 'root',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
direction: 'ltr',
|
||||
children: ensureChildren(parseMarkdownToLexical(inner.trim())),
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
tag: 'Callout',
|
||||
regex: /<Callout([^>]*)>([\s\S]*?)<\/Callout>/g,
|
||||
build: (props: string, inner: string) =>
|
||||
blockNode('callout', {
|
||||
type: propValue(`<Tag ${props}>`, 'type') || 'info',
|
||||
title: propValue(`<Tag ${props}>`, 'title'),
|
||||
content: {
|
||||
root: {
|
||||
type: 'root',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
direction: 'ltr',
|
||||
children: ensureChildren(parseMarkdownToLexical(inner.trim())),
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
// Placeholder map to temporarily store extracted multi-line blocks
|
||||
const placeholders = new Map<string, any>();
|
||||
let placeholderIdx = 0;
|
||||
|
||||
for (const block of extractBlocks) {
|
||||
content = content.replace(block.regex, (match, propsMatch, innerMatch) => {
|
||||
const id = `__BLOCK_PLACEHOLDER_${placeholderIdx++}__`;
|
||||
placeholders.set(id, block.build(propsMatch, innerMatch));
|
||||
return `\n\n${id}\n\n`; // Pad with newlines so it becomes its own chunk
|
||||
});
|
||||
}
|
||||
|
||||
// 2. CHUNK THE REST (Paragraphs, Single-line Components)
|
||||
const rawChunks = content.split(/\n\s*\n/);
|
||||
|
||||
for (let chunk of rawChunks) {
|
||||
chunk = chunk.trim();
|
||||
if (!chunk) continue;
|
||||
|
||||
// Has Placeholder?
|
||||
if (chunk.startsWith('__BLOCK_PLACEHOLDER_')) {
|
||||
nodes.push(placeholders.get(chunk));
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Custom Component: ProductTabs ---
|
||||
if (chunk.includes('<ProductTabs')) {
|
||||
const dataMatch = chunk.match(/data=\{({[\s\S]*?})\}\s*\/>/);
|
||||
if (dataMatch) {
|
||||
try {
|
||||
const parsedData = JSON.parse(dataMatch[1]);
|
||||
|
||||
// Normalize String Arrays to Payload Object Arrays { value: "string" }
|
||||
if (parsedData.voltageTables) {
|
||||
parsedData.voltageTables.forEach((vt: any) => {
|
||||
if (vt.rows) {
|
||||
vt.rows.forEach((row: any) => {
|
||||
if (row.cells && Array.isArray(row.cells)) {
|
||||
row.cells = row.cells.map((cell: any) =>
|
||||
typeof cell !== 'object' || cell === null ? { value: String(cell) } : cell,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
nodes.push(
|
||||
blockNode('productTabs', {
|
||||
technicalItems: parsedData.technicalItems || [],
|
||||
voltageTables: parsedData.voltageTables || [],
|
||||
}),
|
||||
);
|
||||
} catch (e: any) {
|
||||
console.warn(`Could not parse JSON payload for ProductTabs:`, e.message);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Custom Component: StickyNarrative ---
|
||||
if (chunk.includes('<StickyNarrative')) {
|
||||
nodes.push(
|
||||
blockNode('stickyNarrative', {
|
||||
title: propValue(chunk, 'title'),
|
||||
items: extractItemsProp(chunk, 'StickyNarrative'),
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Custom Component: ComparisonGrid ---
|
||||
if (chunk.includes('<ComparisonGrid')) {
|
||||
nodes.push(
|
||||
blockNode('comparisonGrid', {
|
||||
title: propValue(chunk, 'title'),
|
||||
leftLabel: propValue(chunk, 'leftLabel'),
|
||||
rightLabel: propValue(chunk, 'rightLabel'),
|
||||
items: extractItemsProp(chunk, 'ComparisonGrid'),
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Custom Component: VisualLinkPreview ---
|
||||
if (chunk.includes('<VisualLinkPreview')) {
|
||||
nodes.push(
|
||||
blockNode('visualLinkPreview', {
|
||||
url: propValue(chunk, 'url'),
|
||||
title: propValue(chunk, 'title'),
|
||||
summary: propValue(chunk, 'summary'),
|
||||
image: propValue(chunk, 'image'),
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Custom Component: TechnicalGrid ---
|
||||
if (chunk.includes('<TechnicalGrid')) {
|
||||
nodes.push(
|
||||
blockNode('technicalGrid', {
|
||||
title: propValue(chunk, 'title'),
|
||||
items: extractItemsProp(chunk, 'TechnicalGrid'),
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Custom Component: AnimatedImage ---
|
||||
if (chunk.includes('<AnimatedImage')) {
|
||||
const widthMatch = chunk.match(/width=\{?(\d+)\}?/);
|
||||
const heightMatch = chunk.match(/height=\{?(\d+)\}?/);
|
||||
nodes.push(
|
||||
blockNode('animatedImage', {
|
||||
src: propValue(chunk, 'src'),
|
||||
alt: propValue(chunk, 'alt'),
|
||||
width: widthMatch ? parseInt(widthMatch[1], 10) : undefined,
|
||||
height: heightMatch ? parseInt(heightMatch[1], 10) : undefined,
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Custom Component: PowerCTA ---
|
||||
if (chunk.includes('<PowerCTA')) {
|
||||
nodes.push(
|
||||
blockNode('powerCTA', {
|
||||
locale: propValue(chunk, 'locale') || 'de',
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Standard Markdown: Headings ---
|
||||
const headingMatch = chunk.match(/^(#{1,6})\s+(.*)/);
|
||||
if (headingMatch) {
|
||||
nodes.push({
|
||||
type: 'heading',
|
||||
tag: `h${headingMatch[1].length}`,
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
direction: 'ltr',
|
||||
children: [{ mode: 'normal', type: 'text', text: headingMatch[2], version: 1 }],
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Standard Markdown: Images ---
|
||||
const imageMatch = chunk.match(/^!\[([^\]]*)\]\(([^)]+)\)$/);
|
||||
if (imageMatch) {
|
||||
nodes.push(textNode(chunk));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Default: plain text paragraph
|
||||
nodes.push(textNode(chunk));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
Reference in New Issue
Block a user