Repository navigation
Release 6.10.2025 #576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release 6.10.2025 #576
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,20 +4,15 @@ export class AddUniqueConstraintDefaultChatflows1753000000001 implements Migrati | |
| name = 'AddUniqueConstraintDefaultChatflows1753000000001' | ||
|
|
||
| public async up(queryRunner: QueryRunner): Promise<void> { | ||
| // NOTE: Before running this migration, you should manually clean up duplicate chatflows | ||
| // using the SQL scripts provided: | ||
| // 1. Run 1-analyze-duplicate-chatflows.sql to see duplicates | ||
| // 2. Run 2-generate-cleanup-statements.sql to get DELETE statements | ||
| // 3. Manually execute the DELETE statements after reviewing them | ||
| // 4. Then run this migration to add the unique constraint | ||
|
|
||
| // Check if there are any remaining duplicates before adding the constraint | ||
| // Automatically clean up duplicate chatflows, keeping the most recently updated one | ||
|
|
||
| // First, check if there are any duplicates | ||
| const duplicateCheck = await queryRunner.query(` | ||
| SELECT COUNT(*) as duplicate_count | ||
| FROM ( | ||
| SELECT "userId", "parentChatflowId" | ||
| FROM "chat_flow" | ||
| WHERE "parentChatflowId" IS NOT NULL | ||
| WHERE "parentChatflowId" IS NOT NULL | ||
| AND "deletedDate" IS NULL | ||
| GROUP BY "userId", "parentChatflowId" | ||
| HAVING COUNT(*) > 1 | ||
|
|
@@ -27,21 +22,40 @@ export class AddUniqueConstraintDefaultChatflows1753000000001 implements Migrati | |
| const duplicateCount = parseInt(duplicateCheck[0]?.duplicate_count || '0') | ||
|
|
||
| if (duplicateCount > 0) { | ||
| throw new Error( | ||
| `Cannot add unique constraint: ${duplicateCount} duplicate chatflow groups still exist. ` + | ||
| `Please run the manual cleanup scripts first:\n` + | ||
| `1. 1-analyze-duplicate-chatflows.sql\n` + | ||
| `2. 2-generate-cleanup-statements.sql\n` + | ||
| `3. Manually execute the DELETE statements\n` + | ||
| `4. Then re-run this migration` | ||
| ) | ||
| console.log(`Found ${duplicateCount} duplicate chatflow groups. Cleaning up automatically...`) | ||
|
|
||
| // Delete duplicate chatflows, keeping only the most recently updated one for each group | ||
| const deleteResult = await queryRunner.query(` | ||
| DELETE FROM "chat_flow" | ||
| WHERE id IN ( | ||
| SELECT cf.id | ||
| FROM "chat_flow" cf | ||
| INNER JOIN ( | ||
| SELECT | ||
| "userId", | ||
| "parentChatflowId", | ||
| MAX("updatedDate") as max_updated_date | ||
| FROM "chat_flow" | ||
| WHERE "parentChatflowId" IS NOT NULL | ||
| AND "deletedDate" IS NULL | ||
| GROUP BY "userId", "parentChatflowId" | ||
| HAVING COUNT(*) > 1 | ||
| ) duplicates | ||
| ON cf."userId" = duplicates."userId" | ||
| AND cf."parentChatflowId" = duplicates."parentChatflowId" | ||
| WHERE cf."deletedDate" IS NULL | ||
| AND cf."updatedDate" < duplicates.max_updated_date | ||
| ) | ||
|
Comment on lines
+27
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new automatic cleanup deletes duplicates only when Useful? React with 👍 / 👎. |
||
| `) | ||
|
|
||
| console.log(`Deleted ${deleteResult[1]} duplicate chatflow records`) | ||
| } | ||
|
|
||
| // Add the unique constraint | ||
| // This prevents multiple default chatflows from the same template for the same user | ||
| await queryRunner.query(` | ||
| CREATE UNIQUE INDEX "idx_unique_user_parent_chatflow" | ||
| ON "chat_flow" ("userId", "parentChatflowId") | ||
| CREATE UNIQUE INDEX "idx_unique_user_parent_chatflow" | ||
| ON "chat_flow" ("userId", "parentChatflowId") | ||
| WHERE "parentChatflowId" IS NOT NULL AND "deletedDate" IS NULL | ||
| `) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously the layout applied
padding-top: 54pxto thebodyto push all content below the fixed webinar banner. The change now only offsets.navbar, so the main content still starts at the top of the viewport while the banner remains fixed attop: 0, leaving the first ~54 px of content hidden under the banner when it is active. Consider preserving the body offset (or adding equivalent margin to the main wrapper) so the banner doesn’t obscure page content.Useful? React with 👍 / 👎.