From cc02d4d4d93e7748c6b894e5b55a8bbfa6bb7cfa Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Mon, 3 Nov 2025 22:43:05 +0530 Subject: [PATCH 1/6] fix: folder name sorting --- .../secret-folder/secret-folder-dal.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/backend/src/services/secret-folder/secret-folder-dal.ts b/backend/src/services/secret-folder/secret-folder-dal.ts index 7dfeaddcf..c999b69d2 100644 --- a/backend/src/services/secret-folder/secret-folder-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-dal.ts @@ -419,13 +419,18 @@ export const secretFolderDALFactory = (db: TDbClient) => { .select( selectAllTableCols(TableName.SecretFolder), db.raw( - `DENSE_RANK() OVER (ORDER BY ${TableName.SecretFolder}."name" ${ - orderDirection ?? OrderByDirection.ASC - }) as rank` + `DENSE_RANK() OVER (ORDER BY CASE WHEN ${TableName.SecretFolder}."name" LIKE '\\_%' THEN ${orderDirection === OrderByDirection.ASC ? "0" : "1"} ELSE ${orderDirection === OrderByDirection.ASC ? "1" : "0"} END, + LOWER(${TableName.SecretFolder}."name") ${orderDirection}, + ${TableName.SecretFolder}."name" ${orderDirection} + ) as rank` ), db.ref("slug").withSchema(TableName.Environment).as("environment") ) - .orderBy(`${TableName.SecretFolder}.${orderBy}`, orderDirection); + .orderByRaw( + `CASE WHEN ${TableName.SecretFolder}.${orderBy} LIKE '\\_%' THEN ${orderDirection === OrderByDirection.ASC ? "0" : "1"} ELSE ${orderDirection === OrderByDirection.ASC ? "1" : "0"} END` + ) + .orderByRaw(`LOWER(${TableName.SecretFolder}.${orderBy}) ${orderDirection}`) + .orderByRaw(`${TableName.SecretFolder}.${orderBy} ${orderDirection}`); if (limit) { const rankOffset = offset + 1; // ranks start from 1 @@ -434,7 +439,12 @@ export const secretFolderDALFactory = (db: TDbClient) => { .select("*") .from[number]>("w") .where("w.rank", ">=", rankOffset) - .andWhere("w.rank", "<", rankOffset + limit); + .andWhere("w.rank", "<", rankOffset + limit) + .orderByRaw( + `CASE WHEN "w"."${orderBy}" LIKE '\\_%' THEN ${orderDirection === OrderByDirection.ASC ? "0" : "1"} ELSE ${orderDirection === OrderByDirection.ASC ? "1" : "0"} END` + ) + .orderByRaw(`LOWER("w"."${orderBy}") ${orderDirection}`) + .orderByRaw(`"w"."${orderBy}" ${orderDirection}`); } const folders = await query; From 0d3cb0c0180d672869175a9255b2c1b582febe13 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Mon, 3 Nov 2025 23:46:08 +0530 Subject: [PATCH 2/6] refactor: enhance folder retrieval with dynamic sorting options --- .../secret-folder/secret-folder-dal.ts | 37 +++++++++++++------ .../secret-folder/secret-folder-service.ts | 29 ++++++++------- .../secret-folder/secret-folder-types.ts | 2 + 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/backend/src/services/secret-folder/secret-folder-dal.ts b/backend/src/services/secret-folder/secret-folder-dal.ts index c999b69d2..356de3099 100644 --- a/backend/src/services/secret-folder/secret-folder-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-dal.ts @@ -426,11 +426,13 @@ export const secretFolderDALFactory = (db: TDbClient) => { ), db.ref("slug").withSchema(TableName.Environment).as("environment") ) - .orderByRaw( - `CASE WHEN ${TableName.SecretFolder}.${orderBy} LIKE '\\_%' THEN ${orderDirection === OrderByDirection.ASC ? "0" : "1"} ELSE ${orderDirection === OrderByDirection.ASC ? "1" : "0"} END` - ) - .orderByRaw(`LOWER(${TableName.SecretFolder}.${orderBy}) ${orderDirection}`) - .orderByRaw(`${TableName.SecretFolder}.${orderBy} ${orderDirection}`); + .orderByRaw(`CASE WHEN ${TableName.SecretFolder}.?? LIKE '\\_%' THEN ? ELSE ? END`, [ + orderBy, + orderDirection === OrderByDirection.ASC ? 0 : 1, + orderDirection === OrderByDirection.ASC ? 1 : 0 + ]) + .orderByRaw(`LOWER(${TableName.SecretFolder}.??) ${orderDirection}`, [orderBy]) + .orderByRaw(`${TableName.SecretFolder}.?? ${orderDirection}`, [orderBy]); if (limit) { const rankOffset = offset + 1; // ranks start from 1 @@ -440,11 +442,13 @@ export const secretFolderDALFactory = (db: TDbClient) => { .from[number]>("w") .where("w.rank", ">=", rankOffset) .andWhere("w.rank", "<", rankOffset + limit) - .orderByRaw( - `CASE WHEN "w"."${orderBy}" LIKE '\\_%' THEN ${orderDirection === OrderByDirection.ASC ? "0" : "1"} ELSE ${orderDirection === OrderByDirection.ASC ? "1" : "0"} END` - ) - .orderByRaw(`LOWER("w"."${orderBy}") ${orderDirection}`) - .orderByRaw(`"w"."${orderBy}" ${orderDirection}`); + .orderByRaw(`CASE WHEN "w".?? LIKE '\\_%' THEN ? ELSE ? END`, [ + orderBy, + orderDirection === OrderByDirection.ASC ? 0 : 1, + orderDirection === OrderByDirection.ASC ? 1 : 0 + ]) + .orderByRaw(`LOWER("w".??) ${orderDirection}`, [orderBy]) + .orderByRaw(`"w".?? ${orderDirection}`, [orderBy]); } const folders = await query; @@ -455,7 +459,10 @@ export const secretFolderDALFactory = (db: TDbClient) => { } }; - const findByEnvsDeep = async ({ parentIds }: TFindFoldersDeepByParentIdsDTO, tx?: Knex) => { + const findByEnvsDeep = async ( + { parentIds, orderBy = SecretsOrderBy.Name, orderDirection = OrderByDirection.ASC }: TFindFoldersDeepByParentIdsDTO, + tx?: Knex + ) => { try { const folders = await (tx || db.replicaNode()) .withRecursive("parents", (qb) => @@ -490,7 +497,13 @@ export const secretFolderDALFactory = (db: TDbClient) => { .select<(TSecretFolders & { path: string; depth: number; environment: string })[]>("*") .from("parents") .orderBy("depth") - .orderBy(`name`); + .orderByRaw(`CASE WHEN "parents".?? LIKE '\\_%' THEN ? ELSE ? END`, [ + orderBy, + orderDirection === OrderByDirection.ASC ? 0 : 1, + orderDirection === OrderByDirection.ASC ? 1 : 0 + ]) + .orderByRaw(`LOWER("parents".??) ${orderDirection}`, [orderBy]) + .orderByRaw(`"parents".?? ${orderDirection}`, [orderBy]); return folders; } catch (error) { diff --git a/backend/src/services/secret-folder/secret-folder-service.ts b/backend/src/services/secret-folder/secret-folder-service.ts index c216ea3a8..033efdb14 100644 --- a/backend/src/services/secret-folder/secret-folder-service.ts +++ b/backend/src/services/secret-folder/secret-folder-service.ts @@ -14,6 +14,7 @@ import { PgSqlLock } from "@app/keystore/keystore"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { OrderByDirection, OrgServiceActor } from "@app/lib/types"; import { ActorType } from "@app/services/auth/auth-type"; +import { SecretsOrderBy } from "@app/services/secret/secret-types"; import { buildFolderPath } from "@app/services/secret-folder/secret-folder-fns"; import { @@ -781,7 +782,11 @@ export const secretFolderServiceFactory = ({ if (!parentFolder) return []; if (recursive) { - const recursiveFolders = await folderDAL.findByEnvsDeep({ parentIds: [parentFolder.id] }); + const recursiveFolders = await folderDAL.findByEnvsDeep({ + parentIds: [parentFolder.id], + orderBy: orderBy || SecretsOrderBy.Name, + orderDirection: orderDirection || OrderByDirection.ASC + }); // remove the parent folder return recursiveFolders .filter((folder) => { @@ -800,19 +805,15 @@ export const secretFolderServiceFactory = ({ })); } - const folders = await folderDAL.find( - { - envId: env.id, - parentId: parentFolder.id, - isReserved: false, - $search: search ? { name: `%${search}%` } : undefined - }, - { - sort: orderBy ? [[orderBy, orderDirection ?? OrderByDirection.ASC]] : undefined, - limit, - offset - } - ); + const folders = await folderDAL.findByMultiEnv({ + environmentIds: [env.id], + parentIds: [parentFolder.id], + search, + orderBy: orderBy || SecretsOrderBy.Name, + orderDirection: orderDirection || OrderByDirection.ASC, + limit, + offset + }); if (lastSecretModified) { return folders.filter((el) => el.lastSecretModified ? el.lastSecretModified >= new Date(lastSecretModified) : false diff --git a/backend/src/services/secret-folder/secret-folder-types.ts b/backend/src/services/secret-folder/secret-folder-types.ts index da8be52a0..d220c29d2 100644 --- a/backend/src/services/secret-folder/secret-folder-types.ts +++ b/backend/src/services/secret-folder/secret-folder-types.ts @@ -64,6 +64,8 @@ export type TGetFoldersDeepByEnvsDTO = { export type TFindFoldersDeepByParentIdsDTO = { parentIds: string[]; + orderBy?: SecretsOrderBy; + orderDirection?: OrderByDirection; }; export type TCreateManyFoldersDTO = { From c407acebe4370b89ba1d1b04b8a74ccf6b72fdc0 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Tue, 4 Nov 2025 21:37:29 +0530 Subject: [PATCH 3/6] refactor: simplify folder sorting logic with ICU collation --- .../secret-folder/secret-folder-dal.ts | 29 +++---------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/backend/src/services/secret-folder/secret-folder-dal.ts b/backend/src/services/secret-folder/secret-folder-dal.ts index 356de3099..b8d7e1de0 100644 --- a/backend/src/services/secret-folder/secret-folder-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-dal.ts @@ -419,20 +419,11 @@ export const secretFolderDALFactory = (db: TDbClient) => { .select( selectAllTableCols(TableName.SecretFolder), db.raw( - `DENSE_RANK() OVER (ORDER BY CASE WHEN ${TableName.SecretFolder}."name" LIKE '\\_%' THEN ${orderDirection === OrderByDirection.ASC ? "0" : "1"} ELSE ${orderDirection === OrderByDirection.ASC ? "1" : "0"} END, - LOWER(${TableName.SecretFolder}."name") ${orderDirection}, - ${TableName.SecretFolder}."name" ${orderDirection} - ) as rank` + `DENSE_RANK() OVER (ORDER BY ${TableName.SecretFolder}."name" COLLATE "en-x-icu" ${orderDirection}) as rank` ), db.ref("slug").withSchema(TableName.Environment).as("environment") ) - .orderByRaw(`CASE WHEN ${TableName.SecretFolder}.?? LIKE '\\_%' THEN ? ELSE ? END`, [ - orderBy, - orderDirection === OrderByDirection.ASC ? 0 : 1, - orderDirection === OrderByDirection.ASC ? 1 : 0 - ]) - .orderByRaw(`LOWER(${TableName.SecretFolder}.??) ${orderDirection}`, [orderBy]) - .orderByRaw(`${TableName.SecretFolder}.?? ${orderDirection}`, [orderBy]); + .orderByRaw(`${TableName.SecretFolder}.?? COLLATE "en-x-icu" ${orderDirection}`, [orderBy]); if (limit) { const rankOffset = offset + 1; // ranks start from 1 @@ -442,13 +433,7 @@ export const secretFolderDALFactory = (db: TDbClient) => { .from[number]>("w") .where("w.rank", ">=", rankOffset) .andWhere("w.rank", "<", rankOffset + limit) - .orderByRaw(`CASE WHEN "w".?? LIKE '\\_%' THEN ? ELSE ? END`, [ - orderBy, - orderDirection === OrderByDirection.ASC ? 0 : 1, - orderDirection === OrderByDirection.ASC ? 1 : 0 - ]) - .orderByRaw(`LOWER("w".??) ${orderDirection}`, [orderBy]) - .orderByRaw(`"w".?? ${orderDirection}`, [orderBy]); + .orderByRaw(`"w".?? COLLATE "en-x-icu" ${orderDirection}`, [orderBy]); } const folders = await query; @@ -497,13 +482,7 @@ export const secretFolderDALFactory = (db: TDbClient) => { .select<(TSecretFolders & { path: string; depth: number; environment: string })[]>("*") .from("parents") .orderBy("depth") - .orderByRaw(`CASE WHEN "parents".?? LIKE '\\_%' THEN ? ELSE ? END`, [ - orderBy, - orderDirection === OrderByDirection.ASC ? 0 : 1, - orderDirection === OrderByDirection.ASC ? 1 : 0 - ]) - .orderByRaw(`LOWER("parents".??) ${orderDirection}`, [orderBy]) - .orderByRaw(`"parents".?? ${orderDirection}`, [orderBy]); + .orderByRaw(`"parents".?? COLLATE "en-x-icu" ${orderDirection}`, [orderBy]); return folders; } catch (error) { From 0229732a6c0aca7711d8a1af642b117e5d9ae2c9 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Tue, 4 Nov 2025 23:11:01 +0530 Subject: [PATCH 4/6] refactor: enhance folder sorting logic to use conditional ordering based on direction --- .../src/services/secret-folder/secret-folder-dal.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/src/services/secret-folder/secret-folder-dal.ts b/backend/src/services/secret-folder/secret-folder-dal.ts index b8d7e1de0..1923add8e 100644 --- a/backend/src/services/secret-folder/secret-folder-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-dal.ts @@ -423,7 +423,10 @@ export const secretFolderDALFactory = (db: TDbClient) => { ), db.ref("slug").withSchema(TableName.Environment).as("environment") ) - .orderByRaw(`${TableName.SecretFolder}.?? COLLATE "en-x-icu" ${orderDirection}`, [orderBy]); + .orderByRaw( + `${TableName.SecretFolder}.?? COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"}`, + [orderBy] + ); if (limit) { const rankOffset = offset + 1; // ranks start from 1 @@ -433,7 +436,9 @@ export const secretFolderDALFactory = (db: TDbClient) => { .from[number]>("w") .where("w.rank", ">=", rankOffset) .andWhere("w.rank", "<", rankOffset + limit) - .orderByRaw(`"w".?? COLLATE "en-x-icu" ${orderDirection}`, [orderBy]); + .orderByRaw(`"w".?? COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"}`, [ + orderBy + ]); } const folders = await query; @@ -482,7 +487,9 @@ export const secretFolderDALFactory = (db: TDbClient) => { .select<(TSecretFolders & { path: string; depth: number; environment: string })[]>("*") .from("parents") .orderBy("depth") - .orderByRaw(`"parents".?? COLLATE "en-x-icu" ${orderDirection}`, [orderBy]); + .orderByRaw(`"parents".?? COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"}`, [ + orderBy + ]); return folders; } catch (error) { From eff4bcb886c94835a860ac92fb8c1b5c5742cb5e Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Wed, 5 Nov 2025 03:21:06 +0530 Subject: [PATCH 5/6] refactor: fix conditional ordering logic in folder sorting to ensure correct rank assignment --- backend/src/services/secret-folder/secret-folder-dal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/services/secret-folder/secret-folder-dal.ts b/backend/src/services/secret-folder/secret-folder-dal.ts index 1923add8e..f4bb18005 100644 --- a/backend/src/services/secret-folder/secret-folder-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-dal.ts @@ -419,7 +419,7 @@ export const secretFolderDALFactory = (db: TDbClient) => { .select( selectAllTableCols(TableName.SecretFolder), db.raw( - `DENSE_RANK() OVER (ORDER BY ${TableName.SecretFolder}."name" COLLATE "en-x-icu" ${orderDirection}) as rank` + `DENSE_RANK() OVER (ORDER BY ${TableName.SecretFolder}."name" COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"} as rank` ), db.ref("slug").withSchema(TableName.Environment).as("environment") ) From a19b2d4b0937072f4b21fb7eb3370ee9c275fcff Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Wed, 5 Nov 2025 16:00:21 +0530 Subject: [PATCH 6/6] fix: e2e --- backend/src/services/secret-folder/secret-folder-dal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/services/secret-folder/secret-folder-dal.ts b/backend/src/services/secret-folder/secret-folder-dal.ts index f4bb18005..f2befbe1a 100644 --- a/backend/src/services/secret-folder/secret-folder-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-dal.ts @@ -419,7 +419,7 @@ export const secretFolderDALFactory = (db: TDbClient) => { .select( selectAllTableCols(TableName.SecretFolder), db.raw( - `DENSE_RANK() OVER (ORDER BY ${TableName.SecretFolder}."name" COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"} as rank` + `DENSE_RANK() OVER (ORDER BY ${TableName.SecretFolder}."name" COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"}) as rank` ), db.ref("slug").withSchema(TableName.Environment).as("environment") )