-
Notifications
You must be signed in to change notification settings - Fork 14.8k
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
feat(core): Add endpoint GET /projects/:projectId/folders
(no-changelog)
#13519
base: master
Are you sure you want to change the base?
Conversation
…ved' into ado-3168-be-add-endpoint-to-rename-folder
…be-add-endpoint-to-update-folder-tags
ae7b4ca
to
1c6bb55
Compare
1c6bb55
to
754a8d2
Compare
…be-add-endpoint-to-list-folders
/projects/:projectId/folders
(no-changelog)
/projects/:projectId/folders
(no-changelog) /projects/:projectId/folders
/projects/:projectId/folders
/projects/:projectId/folders
(no-changelog)
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.
Some suggestions on how to simplify the schema validation on DTOs :D
}); | ||
|
||
// SortBy parameter validation | ||
const sortByValidator = z |
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.
You could use z.enum
instead (which also has a nice default message that could be used if the exact message isn't important)
const sortByValidator = z | |
const sortByValidator = z | |
.enum(VALID_SORT_OPTIONS, { message: `sortBy must be one of: ${VALID_SORT_OPTIONS.join(', ')}` }) | |
.optional(); |
// --------------------- | ||
|
||
// Filter parameter validation | ||
const filterValidator = z |
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.
Instead of using superRefine
and transform
what if we just did this on a single transform
, it also can set issues via ctx
?
const filterValidator = z | |
const filterValidator = z | |
.string() | |
.optional() | |
.transform((val, ctx) => { | |
if (!val) return undefined; | |
try { | |
const parsed: unknown = JSON.parse(val); | |
try { | |
return filterSchema.parse(parsed); | |
} catch (e) { | |
ctx.addIssue({ | |
code: z.ZodIssueCode.custom, | |
message: 'Invalid filter fields', | |
path: ['filter'], | |
}); | |
return z.NEVER; | |
} | |
} catch (e) { | |
ctx.addIssue({ | |
code: z.ZodIssueCode.custom, | |
message: 'Invalid filter format', | |
path: ['filter'], | |
}); | |
return z.NEVER; | |
} | |
}); |
.refine((val) => val === undefined || !isNaN(val), { | ||
message: 'Skip must be a valid number', | ||
}); |
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.
refine doesn't need to check for undefined here
.refine((val) => val === undefined || !isNaN(val), { | |
message: 'Skip must be a valid number', | |
}); | |
.refine((val) => !isNaN(val), { | |
message: 'Skip must be a valid number', | |
}); |
.string() | ||
.optional() | ||
.transform((val) => (val ? parseInt(val, 10) : 10)) | ||
.refine((val) => val === undefined || !isNaN(val), { |
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.
Same here
.refine((val) => val === undefined || !isNaN(val), { | |
.refine((val) => !isNaN(val), { | |
message: 'Take must be a valid number', | |
}); |
@@ -0,0 +1,181 @@ | |||
import { ApplicationError, jsonParse } from 'n8n-workflow'; |
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.
How necessary is using jsonParse
here, as we're using it without the extra features. Now using it brings extra production dependency.
.strict(); | ||
|
||
// Common transformers | ||
const parseJsonArray = (val: string): unknown => { |
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.
With the suggestions this and isArrayOfStrings
become unnecessary
}); | ||
|
||
// Select parameter validation | ||
const selectValidator = z |
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.
This could written utilizing zod more as
const selectValidator = z | |
// Select parameter validation | |
const selectFieldsValidator = z.array(z.enum(VALID_SELECT_FIELDS)); | |
const selectValidator = z | |
.string() | |
.optional() | |
.transform((val, ctx) => { | |
if (!val) return undefined; | |
try { | |
const parsed: unknown = JSON.parse(val); | |
try { | |
const selectFields = selectFieldsValidator.parse(parsed); | |
if (selectFields.length === 0) return undefined; | |
type SelectField = (typeof VALID_SELECT_FIELDS)[number]; | |
return selectFields.reduce<Record<SelectField, true>>( | |
(acc, field) => ({ ...acc, [field]: true }), | |
{} as Record<SelectField, true>, | |
); | |
} catch (e) { | |
ctx.addIssue({ | |
code: z.ZodIssueCode.custom, | |
message: `Invalid select fields. Valid fields are: ${VALID_SELECT_FIELDS.join(', ')}`, | |
path: ['select'], | |
}); | |
return z.NEVER; | |
} | |
} catch (e) { | |
ctx.addIssue({ | |
code: z.ZodIssueCode.custom, | |
message: 'Invalid select format', | |
path: ['select'], | |
}); | |
return z.NEVER; | |
} | |
}); |
Note that this suggestion slightly changes the error messages, if they are important and shown on UI or something please adjust
}, | ||
])('should validate $name', ({ request }) => { | ||
const result = ListFolderQueryDto.safeParse(request); | ||
expect(result.success).toBe(true); |
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.
We don't have any tests here testing that what these DTOs produce are what we expect, and as there's some amount of logic in there I feel like we maybe should have some.
Based on PR #13516
Chain of upstream PRs as of 2025-02-25
PR feat(core): Add endpoint PATCH
/projects/:projectId/folders/:folderId
(no-changelog) #13454:master
←ado-3168-be-add-endpoint-to-rename-folder
PR feat(core): Update PATCH
/projects/:projectId/folders/:folderId
to support tags (no-changelog) #13456:ado-3168-be-add-endpoint-to-rename-folder
←ado-3170-be-add-endpoint-to-update-folder-tags
PR feat(core): Add endpoint DELETE
/projects/:projectId/folders/:folderId
(no-changelog) #13516:ado-3170-be-add-endpoint-to-update-folder-tags
←ado-3167-be-add-endpoint-to-delete-folder
/projects/:projectId/folders
(no-changelog) #13519 (THIS ONE):ado-3167-be-add-endpoint-to-delete-folder
←ado-3270-be-add-endpoint-to-list-folders
Summary
This endpoint retrieves a list of available folders where the user can move the contents of a deleted folder.
Related Linear tickets, Github issues, and Community forum posts
https://linear.app/n8n/issue/ADO-3270/[be]-add-endpoint-to-list-folders
Review / Merge checklist
release/backport
(if the PR is an urgent fix that needs to be backported)