refactor: Simplify click URL resolution logic

This commit is contained in:
gsxdsm
2026-03-02 21:30:49 -08:00
committed by gsxdsm
parent cf3d312eef
commit b2915f4de1
2 changed files with 26 additions and 26 deletions

View File

@@ -588,29 +588,26 @@ export class EventHookService {
eventType: context.eventType, eventType: context.eventType,
}; };
// Build click URL with deep-link if project context is available // Resolve click URL: action-level overrides endpoint default
let clickUrl = action.clickUrl; let clickUrl = action.clickUrl || endpoint.defaultClickUrl;
if (!clickUrl && endpoint.defaultClickUrl) {
clickUrl = endpoint.defaultClickUrl; // Apply deep-link parameters to the resolved click URL
// If we have a project path and the click URL looks like the server URL, if (clickUrl && context.projectPath) {
// append deep-link path try {
if (context.projectPath && clickUrl) { const url = new URL(clickUrl);
try { // Add featureId as query param for deep linking to board with feature output modal
const url = new URL(clickUrl); if (context.featureId) {
// Add featureId as query param for deep linking to board with feature output modal url.pathname = '/board';
if (context.featureId) { url.searchParams.set('featureId', context.featureId);
url.pathname = '/board'; } else {
url.searchParams.set('featureId', context.featureId); url.pathname = '/board';
} else if (context.projectPath) {
url.pathname = '/board';
}
clickUrl = url.toString();
} catch (error) {
// If URL parsing fails, log warning and use as-is
logger.warn(
`Failed to parse defaultClickUrl "${clickUrl}" for deep linking: ${error instanceof Error ? error.message : String(error)}`
);
} }
clickUrl = url.toString();
} catch (error) {
// If URL parsing fails, log warning and use as-is
logger.warn(
`Failed to parse click URL "${clickUrl}" for deep linking: ${error instanceof Error ? error.message : String(error)}`
);
} }
} }

View File

@@ -1246,7 +1246,9 @@ describe('EventHookService', () => {
const options = mockFetch.mock.calls[0][1]; const options = mockFetch.mock.calls[0][1];
// Hook values should override endpoint defaults // Hook values should override endpoint defaults
expect(options.headers['Tags']).toBe('override-emoji,override-tag'); expect(options.headers['Tags']).toBe('override-emoji,override-tag');
expect(options.headers['Click']).toBe('https://override.example.com'); // Click URL uses hook-specific base URL with deep link params applied
expect(options.headers['Click']).toContain('https://override.example.com/board');
expect(options.headers['Click']).toContain('featureId=feat-1');
expect(options.headers['Priority']).toBe('5'); expect(options.headers['Priority']).toBe('5');
}); });
@@ -1359,7 +1361,7 @@ describe('EventHookService', () => {
expect(clickUrl).not.toContain('featureId='); expect(clickUrl).not.toContain('featureId=');
}); });
it('should use hook-specific click URL overriding default with featureId', async () => { it('should apply deep link params to hook-specific click URL', async () => {
mockFetch.mockResolvedValueOnce({ mockFetch.mockResolvedValueOnce({
ok: true, ok: true,
status: 200, status: 200,
@@ -1409,8 +1411,9 @@ describe('EventHookService', () => {
const options = mockFetch.mock.calls[0][1]; const options = mockFetch.mock.calls[0][1];
const clickUrl = options.headers['Click']; const clickUrl = options.headers['Click'];
// Should use the hook-specific click URL (not modified with featureId since it's a custom URL) // Should use the hook-specific click URL with deep link params applied
expect(clickUrl).toBe('https://custom.example.com/custom-page'); expect(clickUrl).toContain('https://custom.example.com/board');
expect(clickUrl).toContain('featureId=feat-789');
}); });
it('should preserve existing query params when adding featureId', async () => { it('should preserve existing query params when adding featureId', async () => {