From 80087fb9c34ad8441304a0a5d8fc6a55219ff288 Mon Sep 17 00:00:00 2001 From: Deepak Mardi Date: Fri, 5 Sep 2025 19:23:50 +0530 Subject: [PATCH 1/3] Add section URL logic and tests --- src/TodoistApi.sections.test.ts | 10 +++++++++- src/types/entities.ts | 35 ++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/TodoistApi.sections.test.ts b/src/TodoistApi.sections.test.ts index 11d9ecd..14da58f 100644 --- a/src/TodoistApi.sections.test.ts +++ b/src/TodoistApi.sections.test.ts @@ -2,6 +2,7 @@ import { TodoistApi } from '.' import { DEFAULT_AUTH_TOKEN, DEFAULT_REQUEST_ID, DEFAULT_SECTION } from './testUtils/testDefaults' import { getSyncBaseUri, ENDPOINT_REST_SECTIONS } from './consts/endpoints' import { setupRestClientMock } from './testUtils/mocks' +import { getSectionUrl } from './utils/urlHelpers' function getTarget() { return new TodoistApi(DEFAULT_AUTH_TOKEN) @@ -32,6 +33,8 @@ describe('TodoistApi section endpoints', () => { const section = await api.getSection('123') expect(section).toEqual(DEFAULT_SECTION) + // Check section URL property + expect(section.url).toBe(getSectionUrl(section.id, section.name)) }) }) @@ -124,7 +127,12 @@ describe('TodoistApi section endpoints', () => { }) test('returns success result from rest client', async () => { - const returnedSection = { ...DEFAULT_SECTION, ...DEFAULT_UPDATE_SECTION_ARGS } + const returnedSection = { + ...DEFAULT_SECTION, + ...DEFAULT_UPDATE_SECTION_ARGS, + id: '123', + url: getSectionUrl('123', 'a new name'), + } setupRestClientMock(returnedSection, 204) const api = getTarget() diff --git a/src/types/entities.ts b/src/types/entities.ts index 84f654d..c67d3c4 100644 --- a/src/types/entities.ts +++ b/src/types/entities.ts @@ -1,5 +1,5 @@ import { z } from 'zod' -import { getProjectUrl, getTaskUrl } from '../utils/urlHelpers' +import { getProjectUrl, getTaskUrl, getSectionUrl } from '../utils/urlHelpers' export const DueDateSchema = z .object({ @@ -148,19 +148,26 @@ export type WorkspaceProject = z.infer */ export type ProjectViewStyle = 'list' | 'board' | 'calendar' -export const SectionSchema = z.object({ - id: z.string(), - userId: z.string(), - projectId: z.string(), - addedAt: z.string(), - updatedAt: z.string(), - archivedAt: z.string().nullable(), - name: z.string(), - sectionOrder: z.number().int(), - isArchived: z.boolean(), - isDeleted: z.boolean(), - isCollapsed: z.boolean(), -}) +export const SectionSchema = z + .object({ + id: z.string(), + userId: z.string(), + projectId: z.string(), + addedAt: z.string(), + updatedAt: z.string(), + archivedAt: z.string().nullable(), + name: z.string(), + sectionOrder: z.number().int(), + isArchived: z.boolean(), + isDeleted: z.boolean(), + isCollapsed: z.boolean(), + }) + .transform((data) => { + return { + ...data, + url: getSectionUrl(data.id, data.name), + } + }) /** * Represents a section in a Todoist project. * @see https://todoist.com/api/v1/docs#tag/Sections From fda160064d4aa521498babac40d8ef2128b286f6 Mon Sep 17 00:00:00 2001 From: Deepak Mardi Date: Fri, 5 Sep 2025 19:26:11 +0530 Subject: [PATCH 2/3] Add helpers and tests for section URLs in the SDK --- src/testUtils/testDefaults.ts | 4 +++- src/utils/urlHelpers.ts | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/testUtils/testDefaults.ts b/src/testUtils/testDefaults.ts index 515b28b..0d625ea 100644 --- a/src/testUtils/testDefaults.ts +++ b/src/testUtils/testDefaults.ts @@ -9,7 +9,7 @@ import { RawComment, PersonalProject, } from '../types' -import { getProjectUrl, getTaskUrl } from '../utils/urlHelpers' +import { getProjectUrl, getTaskUrl, getSectionUrl } from '../utils/urlHelpers' export const DEFAULT_TASK_ID = '1234' export const DEFAULT_TASK_CONTENT = 'This is a task' @@ -45,6 +45,7 @@ const DEFAULT_IS_COLLAPSED = false // URL constants using the helper functions const DEFAULT_TASK_URL = getTaskUrl(DEFAULT_TASK_ID, DEFAULT_TASK_CONTENT) const DEFAULT_PROJECT_URL = getProjectUrl(DEFAULT_PROJECT_ID, DEFAULT_PROJECT_NAME) +const DEFAULT_SECTION_URL = getSectionUrl(DEFAULT_SECTION_ID, DEFAULT_SECTION_NAME) export const DEFAULT_AUTH_TOKEN = 'AToken' export const DEFAULT_REQUEST_ID = 'ARequestID' @@ -174,6 +175,7 @@ export const DEFAULT_SECTION: Section = { isArchived: false, isDeleted: false, isCollapsed: false, + url: DEFAULT_SECTION_URL, } export const INVALID_SECTION = { diff --git a/src/utils/urlHelpers.ts b/src/utils/urlHelpers.ts index 039b3cc..36e28e7 100644 --- a/src/utils/urlHelpers.ts +++ b/src/utils/urlHelpers.ts @@ -26,6 +26,19 @@ export function getProjectUrl(projectId: string, name?: string): string { return `${TODOIST_WEB_URI}/project/${path}` } +/** + * Generate the URL for a given section. + * + * @param sectionId The ID of the section. + * @param name The name of the section. + * @returns The URL string for the section view. + */ +export function getSectionUrl(sectionId: string, name?: string): string { + const slug = name ? slugify(name) : undefined + const path = slug ? `${slug}-${sectionId}` : sectionId + return `${TODOIST_WEB_URI}/section/${path}` +} + /** * Slugify function borrowed from Django. * From 342b0501940f45f9d30de3b6b27633b1ec3371de Mon Sep 17 00:00:00 2001 From: Deepak Mardi Date: Fri, 5 Sep 2025 19:36:36 +0530 Subject: [PATCH 3/3] Check that section URL is correct in the test --- src/TodoistApi.sections.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TodoistApi.sections.test.ts b/src/TodoistApi.sections.test.ts index 14da58f..01cd6ce 100644 --- a/src/TodoistApi.sections.test.ts +++ b/src/TodoistApi.sections.test.ts @@ -33,7 +33,6 @@ describe('TodoistApi section endpoints', () => { const section = await api.getSection('123') expect(section).toEqual(DEFAULT_SECTION) - // Check section URL property expect(section.url).toBe(getSectionUrl(section.id, section.name)) }) })