-
-
Notifications
You must be signed in to change notification settings - Fork 210
feat: Link to project using name and version #1425
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
base: master
Are you sure you want to change the base?
feat: Link to project using name and version #1425
Conversation
Signed-off-by: Tobias Trumm <tobias@tobiastrumm.de>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
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.
Pull request overview
This PR implements a feature to allow linking to projects using their name and version instead of requiring the UUID. It adds two new Vue Router routes that perform a lookup of the project UUID via a new API endpoint and redirect to the existing UUID-based project routes.
Changes:
- Added
URL_PROJECT_LOOKUPAPI endpoint constant for project lookup by name and version - Added
projects/:name/:version/*route with navigation guard that looks up UUID and redirects to UUID-based routes - Added
projects/:name/:versionroute that redirects to the wildcard variant with a trailing slash
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| src/shared/api.json | Adds the URL constant for the new project lookup API endpoint |
| src/router/index.js | Implements two new routes to support name/version-based project linking with UUID lookup and redirection logic |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }, | ||
| { | ||
| path: 'projects/:name/:version', | ||
| redirect: 'projects/:name/:version/', |
Copilot
AI
Jan 19, 2026
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.
The redirect path should be absolute (starting with '/') or use a function-based redirect. The current relative path may not work as expected. Consider changing to redirect: (to) => ({ path: /projects/${to.params.name}/${to.params.version}/ }) to ensure proper route resolution.
| redirect: 'projects/:name/:version/', | |
| redirect: (to) => ({ | |
| path: `/projects/${to.params.name}/${to.params.version}/`, | |
| }), |
| ? `/${to.params.pathMatch}` | ||
| : ''; | ||
| next({ | ||
| path: `projects/${result.data.uuid}${trailingPathSegments}`, |
Copilot
AI
Jan 19, 2026
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.
The navigation redirect should include leading slash to make the path absolute. Change path: projects/${result.data.uuid}${trailingPathSegments} to `path: `/projects/${result.data.uuid}${trailingPathSegments} to ensure proper path resolution.
| path: `projects/${result.data.uuid}${trailingPathSegments}`, | |
| path: `/projects/${result.data.uuid}${trailingPathSegments}`, |
| path: `projects/${result.data.uuid}${trailingPathSegments}`, | ||
| replace: true, | ||
| }); | ||
| }) | ||
| .catch(() => { | ||
| next({ | ||
| name: '404', |
Copilot
AI
Jan 19, 2026
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.
Query parameters from the original URL are not preserved during the redirect. If the original URL contains query parameters (e.g., for filtering or sorting), they will be lost. Consider preserving them by including query: to.query in the next() object alongside the path.
| path: `projects/${result.data.uuid}${trailingPathSegments}`, | |
| replace: true, | |
| }); | |
| }) | |
| .catch(() => { | |
| next({ | |
| name: '404', | |
| path: `projects/${result.data.uuid}${trailingPathSegments}`, | |
| query: to.query, | |
| replace: true, | |
| }); | |
| }) | |
| .catch(() => { | |
| next({ | |
| name: '404', | |
| query: to.query, |
| .catch(() => { | ||
| next({ | ||
| name: '404', | ||
| replace: true, | ||
| }); |
Copilot
AI
Jan 19, 2026
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.
The error handling catches all errors uniformly, but different error types should potentially be handled differently. For example, a 404 (not found) is different from a 401 (unauthorized) or 500 (server error). Consider checking the error response status to provide more appropriate error handling, especially for authorization errors which might need different treatment than simple "not found" scenarios.
| .catch(() => { | |
| next({ | |
| name: '404', | |
| replace: true, | |
| }); | |
| .catch((error) => { | |
| const status = error && error.response && error.response.status; | |
| if (status === 404) { | |
| next({ | |
| name: '404', | |
| replace: true, | |
| }); | |
| } else if (status === 401 || status === 403) { | |
| next({ | |
| name: 'Login', | |
| replace: true, | |
| }); | |
| } else { | |
| // Cancel navigation on unexpected errors to avoid misreporting them as "not found" | |
| next(false); | |
| } |
| const searchParams = new URLSearchParams({ | ||
| name: to.params.name, | ||
| version: to.params.version, |
Copilot
AI
Jan 19, 2026
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.
Project names and versions may contain special characters that need URL encoding. The current implementation doesn't decode these parameters before sending them to the API. If a project name contains special characters (e.g., spaces, slashes), the URL parameters extracted from to.params will already be decoded by Vue Router, but this should be verified. Additionally, consider validating that the name and version parameters don't contain path separators or other invalid characters that could cause routing issues.
| const searchParams = new URLSearchParams({ | |
| name: to.params.name, | |
| version: to.params.version, | |
| const decodeParam = (value) => { | |
| if (typeof value !== 'string') { | |
| return ''; | |
| } | |
| try { | |
| return decodeURIComponent(value); | |
| } catch (e) { | |
| // If decoding fails (malformed escape sequences), fall back to the original value | |
| return value; | |
| } | |
| }; | |
| const isValidSegment = (value) => | |
| typeof value === 'string' && !/[\\/]/.test(value); | |
| const name = decodeParam(to.params.name); | |
| const version = decodeParam(to.params.version); | |
| if (!isValidSegment(name) || !isValidSegment(version)) { | |
| next({ | |
| name: '404', | |
| replace: true, | |
| }); | |
| return; | |
| } | |
| const searchParams = new URLSearchParams({ | |
| name, | |
| version, |
| path: `projects/${result.data.uuid}${trailingPathSegments}`, | ||
| replace: true, | ||
| }); | ||
| }) | ||
| .catch(() => { | ||
| next({ | ||
| name: '404', |
Copilot
AI
Jan 19, 2026
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.
URL hash fragments are not preserved during the redirect. If the original URL contains a hash (e.g., for in-page navigation or state), it will be lost. Consider preserving the hash by including hash: to.hash in the next() object alongside the path.
| path: `projects/${result.data.uuid}${trailingPathSegments}`, | |
| replace: true, | |
| }); | |
| }) | |
| .catch(() => { | |
| next({ | |
| name: '404', | |
| path: `projects/${result.data.uuid}${trailingPathSegments}`, | |
| hash: to.hash, | |
| replace: true, | |
| }); | |
| }) | |
| .catch(() => { | |
| next({ | |
| name: '404', | |
| hash: to.hash, |
Description
This is another try to implement project links that use
nameandversionand do not requireuuid. The previous try at #45 seems to be abandoned.Addressed Issue
resolves #41
Additional Details
This PR adds two additional vue routes:
projects/:name/:version/*Its
beforeEachnavigation guard tries to lookup theuuidof the project using the/v1/project/lookupAPI endpoint. If auuidwas found, it redirects toprojects/:uuid. If not, it redirects to the 404 page.The
/*at the end is used to keep trailing subpaths.projects/MyProject/1.2.3/->projects/:uuidprojects/MyProject/1.2.3/components->projects/:uuid/componentsprojects/:name/:versionThe
projects/:name/:version/*route will not matchprojects/MyProject/1.2.3because it does not end with a/. That's whyprojects/:name/:versionwill redirect toprojects/:name/:version/.projects/:name/:version->projects/:name/:version/->projects/:uuidChecklist