feat: add support to add/edit repositories in collections#1770
feat: add support to add/edit repositories in collections#1770gaspergrom merged 3 commits intomainfrom
Conversation
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
There was a problem hiding this comment.
Pull request overview
Adds repository URL support to community collections so collections can include repositories in addition to insights projects, and returns repository metadata alongside existing collection responses.
Changes:
- Extend collection create/update flows to accept
repositoryUrlsand persist collection↔repository relations. - Include
repositoryUrls/repositoryCountin collection read/query responses. - Include repository data in “liked collections” responses.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| frontend/server/repo/communityCollection.repo.ts | Adds repository association persistence and returns repository URLs/counts in collection reads. |
| frontend/server/repo/collectionLike.repo.ts | Enriches liked-collection results with repository URLs/counts and adjusts featured project selection. |
| frontend/server/api/collection/community/index.post.ts | Accepts and validates repositoryUrls for collection creation. |
| frontend/server/api/collection/community/[id].put.ts | Accepts and validates repositoryUrls for collection updates. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (notFound.length > 0) { | ||
| throw createError({ | ||
| statusCode: 400, | ||
| statusMessage: `Repository URLs not found: ${notFound.join(', ')}`, |
There was a problem hiding this comment.
The error message for missing repositories includes the full list of user-provided URLs in statusMessage (potentially up to 1000 items). This can create extremely large responses/log lines and makes the HTTP error payload noisy. Consider using a short statusMessage (e.g., "Some repository URLs were not found") and move the detailed list (or a capped subset + count) into the error data field.
| statusMessage: `Repository URLs not found: ${notFound.join(', ')}`, | |
| statusMessage: 'Some repository URLs were not found', | |
| data: { | |
| notFoundUrls: notFound, | |
| notFoundCount: notFound.length, | |
| }, |
| if (body.repositoryUrls !== undefined) { | ||
| if ( | ||
| !Array.isArray(body.repositoryUrls) || | ||
| body.repositoryUrls.some((u) => typeof u !== 'string' || !u) | ||
| ) { | ||
| throw createError({ | ||
| statusCode: 400, | ||
| statusMessage: 'repositoryUrls must be an array of non-empty strings', | ||
| }); | ||
| } |
There was a problem hiding this comment.
The validation for repositoryUrls allows whitespace-only strings (e.g., ' '), since it checks !u rather than !u.trim(). This will later fail the repository lookup with a less-direct error. Consider trimming each URL (and validating non-empty post-trim) before passing them to the repository layer.
| if ( | ||
| !Array.isArray(body.repositoryUrls) || | ||
| body.repositoryUrls.some((u) => typeof u !== 'string' || !u) | ||
| ) { | ||
| throw createError({ | ||
| statusCode: 400, | ||
| statusMessage: 'repositoryUrls must be an array of non-empty strings', | ||
| }); | ||
| } | ||
|
|
||
| if (body.repositoryUrls.length > 1000) { | ||
| throw createError({ | ||
| statusCode: 400, | ||
| statusMessage: 'repositoryUrls cannot exceed 1000 items', | ||
| }); | ||
| } |
There was a problem hiding this comment.
The validation for repositoryUrls allows whitespace-only strings (e.g., ' '), since it checks !u rather than !u.trim(). Consider trimming/normalizing each URL (and validating non-empty post-trim) before calling repo.update, so updates don’t silently fail with "not found" errors due to stray whitespace.
| if ( | |
| !Array.isArray(body.repositoryUrls) || | |
| body.repositoryUrls.some((u) => typeof u !== 'string' || !u) | |
| ) { | |
| throw createError({ | |
| statusCode: 400, | |
| statusMessage: 'repositoryUrls must be an array of non-empty strings', | |
| }); | |
| } | |
| if (body.repositoryUrls.length > 1000) { | |
| throw createError({ | |
| statusCode: 400, | |
| statusMessage: 'repositoryUrls cannot exceed 1000 items', | |
| }); | |
| } | |
| if (!Array.isArray(body.repositoryUrls)) { | |
| throw createError({ | |
| statusCode: 400, | |
| statusMessage: 'repositoryUrls must be an array of non-empty strings', | |
| }); | |
| } | |
| const normalizedRepositoryUrls = body.repositoryUrls.map((u) => | |
| typeof u === 'string' ? u.trim() : u, | |
| ); | |
| if (normalizedRepositoryUrls.some((u) => typeof u !== 'string' || !u)) { | |
| throw createError({ | |
| statusCode: 400, | |
| statusMessage: 'repositoryUrls must be an array of non-empty strings', | |
| }); | |
| } | |
| if (normalizedRepositoryUrls.length > 1000) { | |
| throw createError({ | |
| statusCode: 400, | |
| statusMessage: 'repositoryUrls cannot exceed 1000 items', | |
| }); | |
| } | |
| body.repositoryUrls = normalizedRepositoryUrls; |
| featuredProjects: [...allProjects] | ||
| .sort((a, b) => a.name.localeCompare(b.name)) | ||
| .slice(0, 5) | ||
| .map((p) => ({ | ||
| name: p.name, | ||
| slug: p.slug, | ||
| logo: p.logoUrl, | ||
| })), |
There was a problem hiding this comment.
featuredProjects is computed by sorting the full allProjects array for each liked collection and then slicing to 5. If collections can have many projects, this is an avoidable O(n log n) cost per collection per request. Consider ordering in SQL (or using a window function / per-collection limit) so the API only processes the top 5 items needed.
| if (body.projects.length > 1000) { | ||
| throw createError({ statusCode: 400, statusMessage: 'projects cannot exceed 1000 items' }); | ||
| } |
There was a problem hiding this comment.
Do we need this limit?
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
No description provided.