@doist/todoist-sdk 14.0.2 → 14.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/clients/view-options-client.js +25 -0
- package/dist/cjs/todoist-api.js +30 -0
- package/dist/cjs/types/sync/resources/view-options.js +13 -4
- package/dist/cjs/utils/index.js +2 -0
- package/dist/cjs/utils/task-sorting.js +281 -0
- package/dist/cjs/utils/view-options.js +19 -0
- package/dist/esm/clients/view-options-client.js +21 -0
- package/dist/esm/todoist-api.js +30 -0
- package/dist/esm/types/sync/resources/view-options.js +12 -3
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/task-sorting.js +277 -0
- package/dist/esm/utils/view-options.js +15 -0
- package/dist/types/clients/view-options-client.d.ts +8 -0
- package/dist/types/todoist-api.d.ts +24 -1
- package/dist/types/types/sync/commands/project-view-options.d.ts +1 -4
- package/dist/types/types/sync/commands/view-options.d.ts +2 -1
- package/dist/types/types/sync/resources/view-options.d.ts +37 -7
- package/dist/types/types/sync/response.d.ts +24 -5
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/task-sorting.d.ts +38 -0
- package/dist/types/utils/validators.d.ts +24 -6
- package/dist/types/utils/view-options.d.ts +11 -0
- package/package.json +1 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ViewOptionsClient = void 0;
|
|
4
|
+
const sync_request_1 = require("../transport/sync-request");
|
|
5
|
+
const sync_helpers_1 = require("../utils/sync-helpers");
|
|
6
|
+
const view_options_1 = require("../utils/view-options");
|
|
7
|
+
const base_client_1 = require("./base-client");
|
|
8
|
+
/** Internal sub-client for saved view-option reads and writes. */
|
|
9
|
+
class ViewOptionsClient extends base_client_1.BaseClient {
|
|
10
|
+
async getViewOptions() {
|
|
11
|
+
var _a;
|
|
12
|
+
const response = await (0, sync_request_1.performSyncRequest)(this.syncContext, {
|
|
13
|
+
resourceTypes: ['view_options'],
|
|
14
|
+
syncToken: '*',
|
|
15
|
+
});
|
|
16
|
+
return ((_a = response.viewOptions) !== null && _a !== void 0 ? _a : []).filter(view_options_1.isActiveViewOption);
|
|
17
|
+
}
|
|
18
|
+
async setViewOptions(args, requestId) {
|
|
19
|
+
await (0, sync_request_1.performSyncRequest)(this.syncContext, { commands: [(0, sync_helpers_1.createCommand)('view_options_set', args)] }, { requestId, hasSyncCommands: true });
|
|
20
|
+
}
|
|
21
|
+
async deleteViewOptions(args, requestId) {
|
|
22
|
+
await (0, sync_request_1.performSyncRequest)(this.syncContext, { commands: [(0, sync_helpers_1.createCommand)('view_options_delete', args)] }, { requestId, hasSyncCommands: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.ViewOptionsClient = ViewOptionsClient;
|
package/dist/cjs/todoist-api.js
CHANGED
|
@@ -19,6 +19,7 @@ const task_client_1 = require("./clients/task-client");
|
|
|
19
19
|
const template_client_1 = require("./clients/template-client");
|
|
20
20
|
const ui_extension_client_1 = require("./clients/ui-extension-client");
|
|
21
21
|
const upload_client_1 = require("./clients/upload-client");
|
|
22
|
+
const view_options_client_1 = require("./clients/view-options-client");
|
|
22
23
|
const workspace_client_1 = require("./clients/workspace-client");
|
|
23
24
|
const endpoints_1 = require("./consts/endpoints");
|
|
24
25
|
const http_client_1 = require("./transport/http-client");
|
|
@@ -65,6 +66,7 @@ class TodoistApi {
|
|
|
65
66
|
this.billingClient = new billing_client_1.BillingClient(clientDeps);
|
|
66
67
|
this.appClient = new app_client_1.AppClient(clientDeps);
|
|
67
68
|
this.uiExtensionClient = new ui_extension_client_1.UiExtensionClient(clientDeps);
|
|
69
|
+
this.viewOptionsClient = new view_options_client_1.ViewOptionsClient(clientDeps);
|
|
68
70
|
}
|
|
69
71
|
/**
|
|
70
72
|
* Executes a raw Sync API request.
|
|
@@ -98,6 +100,34 @@ class TodoistApi {
|
|
|
98
100
|
customFetch: this.customFetch,
|
|
99
101
|
}, syncRequest, { requestId, hasSyncCommands: Boolean((_a = syncRequest.commands) === null || _a === void 0 ? void 0 : _a.length) });
|
|
100
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Retrieves the authenticated user's active saved view options.
|
|
105
|
+
*
|
|
106
|
+
* @returns A promise that resolves to the active saved view options.
|
|
107
|
+
*/
|
|
108
|
+
async getViewOptions() {
|
|
109
|
+
return this.viewOptionsClient.getViewOptions();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Sets saved options for a view.
|
|
113
|
+
*
|
|
114
|
+
* @param args - The saved view options to set.
|
|
115
|
+
* @param requestId - Optional custom identifier for the request.
|
|
116
|
+
* @returns A promise that resolves when the view options are saved.
|
|
117
|
+
*/
|
|
118
|
+
async setViewOptions(args, requestId) {
|
|
119
|
+
return this.viewOptionsClient.setViewOptions(args, requestId);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Deletes the saved options for a view.
|
|
123
|
+
*
|
|
124
|
+
* @param args - The view whose saved options to delete.
|
|
125
|
+
* @param requestId - Optional custom identifier for the request.
|
|
126
|
+
* @returns A promise that resolves when the view options are deleted.
|
|
127
|
+
*/
|
|
128
|
+
async deleteViewOptions(args, requestId) {
|
|
129
|
+
return this.viewOptionsClient.deleteViewOptions(args, requestId);
|
|
130
|
+
}
|
|
101
131
|
/**
|
|
102
132
|
* Retrieves information about the authenticated user.
|
|
103
133
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ProjectViewOptionsDefaultsSchema = exports.ViewOptionsSchema = exports.CalendarSettingsSchema = exports.CALENDAR_LAYOUTS = exports.SortOrderSchema = exports.SORT_ORDERS = exports.SortedBySchema = exports.SORTED_BY_OPTIONS = exports.GroupedBySchema = exports.GROUPED_BY_OPTIONS = exports.ViewModeSchema = exports.VIEW_MODES = exports.ViewTypeSchema = exports.VIEW_TYPES = void 0;
|
|
3
|
+
exports.ProjectViewOptionsDefaultsSchema = exports.ViewOptionsSchema = exports.CalendarSettingsSchema = exports.CALENDAR_COLORS = exports.CALENDAR_LAYOUTS = exports.SortOrderSchema = exports.SORT_ORDERS = exports.SortedBySchema = exports.SORTED_BY_OPTIONS = exports.GroupedBySchema = exports.GROUPED_BY_OPTIONS = exports.ViewModeSchema = exports.VIEW_MODES = exports.ViewTypeSchema = exports.VIEW_TYPES = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
/** Available view types. */
|
|
6
6
|
exports.VIEW_TYPES = [
|
|
@@ -52,18 +52,27 @@ exports.SORT_ORDERS = ['ASC', 'DESC'];
|
|
|
52
52
|
exports.SortOrderSchema = zod_1.z.enum(exports.SORT_ORDERS).nullable();
|
|
53
53
|
/** Available calendar layout modes. */
|
|
54
54
|
exports.CALENDAR_LAYOUTS = ['WEEK', 'MONTH'];
|
|
55
|
+
/** Available task color sources for calendar views. */
|
|
56
|
+
exports.CALENDAR_COLORS = ['PRIORITY', 'LABEL', 'PROJECT'];
|
|
55
57
|
exports.CalendarSettingsSchema = zod_1.z.looseObject({
|
|
56
|
-
layout: zod_1.z.enum(exports.CALENDAR_LAYOUTS).optional(),
|
|
58
|
+
layout: zod_1.z.enum(exports.CALENDAR_LAYOUTS).nullable().optional(),
|
|
59
|
+
visibleDayCount: zod_1.z
|
|
60
|
+
.union([zod_1.z.literal(1), zod_1.z.literal(3), zod_1.z.literal(7)])
|
|
61
|
+
.nullable()
|
|
62
|
+
.optional(),
|
|
63
|
+
color: zod_1.z.enum(exports.CALENDAR_COLORS).nullable().optional(),
|
|
57
64
|
});
|
|
58
65
|
exports.ViewOptionsSchema = zod_1.z.looseObject({
|
|
59
66
|
viewType: exports.ViewTypeSchema,
|
|
60
|
-
objectId: zod_1.z.string().optional(),
|
|
67
|
+
objectId: zod_1.z.string().nullable().optional(),
|
|
61
68
|
groupedBy: exports.GroupedBySchema.optional(),
|
|
62
69
|
filteredBy: zod_1.z.string().nullable().optional(),
|
|
63
|
-
viewMode: exports.ViewModeSchema.optional(),
|
|
70
|
+
viewMode: exports.ViewModeSchema.nullable().optional(),
|
|
64
71
|
showCompletedTasks: zod_1.z.boolean().optional(),
|
|
65
72
|
sortedBy: exports.SortedBySchema.optional(),
|
|
66
73
|
sortOrder: exports.SortOrderSchema.optional(),
|
|
74
|
+
calendarSettings: exports.CalendarSettingsSchema.nullable().optional(),
|
|
75
|
+
isDeleted: zod_1.z.boolean().optional(),
|
|
67
76
|
});
|
|
68
77
|
exports.ProjectViewOptionsDefaultsSchema = zod_1.z.looseObject({
|
|
69
78
|
projectId: zod_1.z.string(),
|
package/dist/cjs/utils/index.js
CHANGED
|
@@ -24,6 +24,8 @@ Object.defineProperty(exports, "getSectionUrl", { enumerable: true, get: functio
|
|
|
24
24
|
var sync_helpers_1 = require("./sync-helpers");
|
|
25
25
|
Object.defineProperty(exports, "createCommand", { enumerable: true, get: function () { return sync_helpers_1.createCommand; } });
|
|
26
26
|
__exportStar(require("./project-helpers"), exports);
|
|
27
|
+
__exportStar(require("./task-sorting"), exports);
|
|
28
|
+
__exportStar(require("./view-options"), exports);
|
|
27
29
|
var webhook_parser_1 = require("./webhook-parser");
|
|
28
30
|
Object.defineProperty(exports, "parseWebhookPayload", { enumerable: true, get: function () { return webhook_parser_1.parseWebhookPayload; } });
|
|
29
31
|
Object.defineProperty(exports, "verifyWebhookSignature", { enumerable: true, get: function () { return webhook_parser_1.verifyWebhookSignature; } });
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_TASK_ORDERS = void 0;
|
|
4
|
+
exports.sortTasks = sortTasks;
|
|
5
|
+
/** Todoist's default task-ordering hierarchies. */
|
|
6
|
+
exports.DEFAULT_TASK_ORDERS = ['PRIORITY_FIRST', 'DATE_FIRST'];
|
|
7
|
+
const DEFAULT_TIMEZONE = 'UTC';
|
|
8
|
+
const DEFAULT_LOCALE = 'en';
|
|
9
|
+
const DATE_ONLY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
10
|
+
const DATE_TIME_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?$/;
|
|
11
|
+
const EXPLICIT_TIMEZONE_PATTERN = /(?:Z|[+-]\d{2}:?\d{2})$/i;
|
|
12
|
+
const DATE_TIME_FORMATTERS = new Map();
|
|
13
|
+
function compareNumber(a, b) {
|
|
14
|
+
if (a === b)
|
|
15
|
+
return 0;
|
|
16
|
+
return a < b ? -1 : 1;
|
|
17
|
+
}
|
|
18
|
+
function isValidDateParts(year, month, day) {
|
|
19
|
+
const date = new Date(0);
|
|
20
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
21
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
22
|
+
return (date.getUTCFullYear() === year &&
|
|
23
|
+
date.getUTCMonth() === month - 1 &&
|
|
24
|
+
date.getUTCDate() === day);
|
|
25
|
+
}
|
|
26
|
+
function dateSortValue({ year, month, day, hour = 0, minute = 0, second = 0, millisecond = 0, isAllDay = false, }) {
|
|
27
|
+
if (!isValidDateParts(year, month, day) ||
|
|
28
|
+
hour < 0 ||
|
|
29
|
+
hour > 23 ||
|
|
30
|
+
minute < 0 ||
|
|
31
|
+
minute > 59 ||
|
|
32
|
+
second < 0 ||
|
|
33
|
+
second > 59 ||
|
|
34
|
+
millisecond < 0 ||
|
|
35
|
+
millisecond > 999) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
day: year * 10000 + month * 100 + day,
|
|
40
|
+
kind: isAllDay ? 0 : 1,
|
|
41
|
+
time: ((hour * 60 + minute) * 60 + second) * 1000 + millisecond,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function parseDateOnly(value) {
|
|
45
|
+
const match = DATE_ONLY_PATTERN.exec(value);
|
|
46
|
+
if (!match)
|
|
47
|
+
return null;
|
|
48
|
+
return dateSortValue({
|
|
49
|
+
year: Number(match[1]),
|
|
50
|
+
month: Number(match[2]),
|
|
51
|
+
day: Number(match[3]),
|
|
52
|
+
isAllDay: true,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function parseDateTimeComponents(value) {
|
|
56
|
+
var _a, _b;
|
|
57
|
+
const match = DATE_TIME_PATTERN.exec(value);
|
|
58
|
+
if (!match)
|
|
59
|
+
return null;
|
|
60
|
+
const milliseconds = Number(((_a = match[7]) !== null && _a !== void 0 ? _a : '').padEnd(3, '0').slice(0, 3));
|
|
61
|
+
const components = {
|
|
62
|
+
year: Number(match[1]),
|
|
63
|
+
month: Number(match[2]),
|
|
64
|
+
day: Number(match[3]),
|
|
65
|
+
hour: Number(match[4]),
|
|
66
|
+
minute: Number(match[5]),
|
|
67
|
+
second: Number((_b = match[6]) !== null && _b !== void 0 ? _b : 0),
|
|
68
|
+
millisecond: milliseconds,
|
|
69
|
+
};
|
|
70
|
+
return dateSortValue(components) === null ? null : components;
|
|
71
|
+
}
|
|
72
|
+
function createDateTimeFormatter(timezone, fallback) {
|
|
73
|
+
const cached = DATE_TIME_FORMATTERS.get(timezone);
|
|
74
|
+
if (cached)
|
|
75
|
+
return cached;
|
|
76
|
+
try {
|
|
77
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
78
|
+
timeZone: timezone,
|
|
79
|
+
calendar: 'iso8601',
|
|
80
|
+
numberingSystem: 'latn',
|
|
81
|
+
year: 'numeric',
|
|
82
|
+
month: '2-digit',
|
|
83
|
+
day: '2-digit',
|
|
84
|
+
hour: '2-digit',
|
|
85
|
+
minute: '2-digit',
|
|
86
|
+
second: '2-digit',
|
|
87
|
+
hourCycle: 'h23',
|
|
88
|
+
});
|
|
89
|
+
DATE_TIME_FORMATTERS.set(timezone, formatter);
|
|
90
|
+
return formatter;
|
|
91
|
+
}
|
|
92
|
+
catch (_a) {
|
|
93
|
+
return fallback !== null && fallback !== void 0 ? fallback : createDateTimeFormatter(DEFAULT_TIMEZONE);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function componentsAt(timestamp, formatter) {
|
|
97
|
+
const parts = formatter.formatToParts(new Date(timestamp));
|
|
98
|
+
function part(type) {
|
|
99
|
+
var _a;
|
|
100
|
+
return Number((_a = parts.find((entry) => entry.type === type)) === null || _a === void 0 ? void 0 : _a.value);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
year: part('year'),
|
|
104
|
+
month: part('month'),
|
|
105
|
+
day: part('day'),
|
|
106
|
+
hour: part('hour'),
|
|
107
|
+
minute: part('minute'),
|
|
108
|
+
second: part('second'),
|
|
109
|
+
millisecond: new Date(timestamp).getUTCMilliseconds(),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function componentsAsUtcTimestamp({ year, month, day, hour = 0, minute = 0, second = 0, millisecond = 0, }) {
|
|
113
|
+
const date = new Date(0);
|
|
114
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
115
|
+
date.setUTCHours(hour, minute, second, millisecond);
|
|
116
|
+
return date.getTime();
|
|
117
|
+
}
|
|
118
|
+
/** Resolves a zoned wall clock to an instant, including daylight-saving offsets. */
|
|
119
|
+
function timestampForWallClock(components, formatter) {
|
|
120
|
+
const target = componentsAsUtcTimestamp(components);
|
|
121
|
+
let timestamp = target;
|
|
122
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
123
|
+
const adjustment = target - componentsAsUtcTimestamp(componentsAt(timestamp, formatter));
|
|
124
|
+
if (adjustment === 0)
|
|
125
|
+
return timestamp;
|
|
126
|
+
timestamp += adjustment;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
function dateSortValueAt(timestamp, formatter) {
|
|
131
|
+
const value = dateSortValue(componentsAt(timestamp, formatter));
|
|
132
|
+
return value ? Object.assign(Object.assign({}, value), { time: timestamp }) : null;
|
|
133
|
+
}
|
|
134
|
+
function parseFixedDateTime(value, formatter) {
|
|
135
|
+
if (parseDateTimeComponents(value.replace(EXPLICIT_TIMEZONE_PATTERN, '')) === null)
|
|
136
|
+
return null;
|
|
137
|
+
const timestamp = Date.parse(value);
|
|
138
|
+
return Number.isNaN(timestamp) ? null : dateSortValueAt(timestamp, formatter);
|
|
139
|
+
}
|
|
140
|
+
function parseZonedFloatingDateTime(value, sourceFormatter, accountFormatter) {
|
|
141
|
+
const components = parseDateTimeComponents(value);
|
|
142
|
+
if (!components)
|
|
143
|
+
return null;
|
|
144
|
+
const timestamp = timestampForWallClock(components, sourceFormatter);
|
|
145
|
+
return timestamp === null ? null : dateSortValueAt(timestamp, accountFormatter);
|
|
146
|
+
}
|
|
147
|
+
function parseTaskDate(value, formatter, timezone) {
|
|
148
|
+
var _a;
|
|
149
|
+
return ((_a = parseDateOnly(value)) !== null && _a !== void 0 ? _a : (EXPLICIT_TIMEZONE_PATTERN.test(value)
|
|
150
|
+
? parseFixedDateTime(value, formatter)
|
|
151
|
+
: parseZonedFloatingDateTime(value, timezone ? createDateTimeFormatter(timezone, formatter) : formatter, formatter)));
|
|
152
|
+
}
|
|
153
|
+
function compareNullable(a, b, compare) {
|
|
154
|
+
if (a === null || b === null) {
|
|
155
|
+
if (a === b)
|
|
156
|
+
return 0;
|
|
157
|
+
return a === null ? 1 : -1;
|
|
158
|
+
}
|
|
159
|
+
return compare(a, b);
|
|
160
|
+
}
|
|
161
|
+
function compareDateValues(left, right) {
|
|
162
|
+
return (compareNumber(left.day, right.day) ||
|
|
163
|
+
compareNumber(left.kind, right.kind) ||
|
|
164
|
+
compareNumber(left.time, right.time));
|
|
165
|
+
}
|
|
166
|
+
function compareDate(a, b) {
|
|
167
|
+
return compareNullable(a, b, compareDateValues);
|
|
168
|
+
}
|
|
169
|
+
function compareOptionalNumber(a, b) {
|
|
170
|
+
return compareNullable(a, b, compareNumber);
|
|
171
|
+
}
|
|
172
|
+
function compareOptionalText(a, b, collator) {
|
|
173
|
+
return compareNullable(a, b, (left, right) => collator.compare(left, right));
|
|
174
|
+
}
|
|
175
|
+
function prepareTasks(tasks, context, { formatter, resolveAssignee }) {
|
|
176
|
+
return tasks.map((task, index) => {
|
|
177
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
178
|
+
const due = task.due
|
|
179
|
+
? parseTaskDate((_a = task.due.datetime) !== null && _a !== void 0 ? _a : task.due.date, formatter, task.due.timezone)
|
|
180
|
+
: null;
|
|
181
|
+
const deadline = task.deadline ? parseTaskDate(task.deadline.date, formatter) : null;
|
|
182
|
+
return {
|
|
183
|
+
task,
|
|
184
|
+
index,
|
|
185
|
+
due,
|
|
186
|
+
deadline,
|
|
187
|
+
schedule: due !== null && due !== void 0 ? due : deadline,
|
|
188
|
+
added: task.addedAt && !Number.isNaN(task.addedAt.getTime())
|
|
189
|
+
? task.addedAt.getTime()
|
|
190
|
+
: null,
|
|
191
|
+
project: (_c = (_b = context.projectOrder) === null || _b === void 0 ? void 0 : _b.get(task.projectId)) !== null && _c !== void 0 ? _c : null,
|
|
192
|
+
workspace: (_e = (_d = context.workspaceOrder) === null || _d === void 0 ? void 0 : _d.get(task.projectId)) !== null && _e !== void 0 ? _e : null,
|
|
193
|
+
assignee: resolveAssignee ? ((_g = (_f = context.assigneeName) === null || _f === void 0 ? void 0 : _f.call(context, task)) !== null && _g !== void 0 ? _g : null) : null,
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function comparePriorityFirst(a, b) {
|
|
198
|
+
const common = compareNumber(b.task.priority, a.task.priority) ||
|
|
199
|
+
compareDate(a.due, b.due) ||
|
|
200
|
+
compareDate(a.deadline, b.deadline);
|
|
201
|
+
if (common !== 0)
|
|
202
|
+
return common;
|
|
203
|
+
const project = compareOptionalNumber(a.project, b.project);
|
|
204
|
+
if (project !== 0)
|
|
205
|
+
return project;
|
|
206
|
+
if (a.task.projectId === b.task.projectId) {
|
|
207
|
+
return compareNumber(a.task.childOrder, b.task.childOrder);
|
|
208
|
+
}
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
function compareDateFirst(a, b) {
|
|
212
|
+
return (compareDate(a.schedule, b.schedule) ||
|
|
213
|
+
compareNumber(b.task.priority, a.task.priority) ||
|
|
214
|
+
compareDate(a.deadline, b.deadline) ||
|
|
215
|
+
compareNumber(a.task.dayOrder, b.task.dayOrder) ||
|
|
216
|
+
compareOptionalNumber(a.added, b.added));
|
|
217
|
+
}
|
|
218
|
+
function compareDefault(a, b, defaultOrder) {
|
|
219
|
+
return defaultOrder === 'DATE_FIRST' ? compareDateFirst(a, b) : comparePriorityFirst(a, b);
|
|
220
|
+
}
|
|
221
|
+
function comparePrimary({ sortedBy, a, b, collator, }) {
|
|
222
|
+
switch (sortedBy) {
|
|
223
|
+
case 'ALPHABETICALLY':
|
|
224
|
+
return collator.compare(a.task.content, b.task.content);
|
|
225
|
+
case 'ASSIGNEE':
|
|
226
|
+
return compareOptionalText(a.assignee, b.assignee, collator);
|
|
227
|
+
case 'DUE_DATE':
|
|
228
|
+
return compareDate(a.due, b.due);
|
|
229
|
+
case 'DEADLINE':
|
|
230
|
+
return compareDate(a.deadline, b.deadline);
|
|
231
|
+
case 'ADDED_DATE':
|
|
232
|
+
return compareOptionalNumber(a.added, b.added);
|
|
233
|
+
case 'PRIORITY':
|
|
234
|
+
return compareNumber(a.task.priority, b.task.priority);
|
|
235
|
+
case 'PROJECT':
|
|
236
|
+
return compareOptionalNumber(a.project, b.project);
|
|
237
|
+
case 'WORKSPACE':
|
|
238
|
+
return compareOptionalNumber(a.workspace, b.workspace);
|
|
239
|
+
case 'MANUAL':
|
|
240
|
+
return 0;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function defaultSortOrder(sortedBy) {
|
|
244
|
+
return sortedBy === 'PRIORITY' ? 'DESC' : 'ASC';
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Sorts the supplied tasks using Todoist view-ordering rules.
|
|
248
|
+
*
|
|
249
|
+
* The function performs no I/O and always returns a new array. Exact project,
|
|
250
|
+
* workspace, assignee, localized text, and due-time ordering requires the
|
|
251
|
+
* corresponding context. Callers must sort each independent view section or
|
|
252
|
+
* group separately and preserve any subtask structure they render.
|
|
253
|
+
*
|
|
254
|
+
* This function sorts only the tasks supplied to it. Fetch every page first
|
|
255
|
+
* when globally correct ordering is required for a paginated query.
|
|
256
|
+
*/
|
|
257
|
+
function sortTasks(tasks, options, context = {}) {
|
|
258
|
+
var _a, _b, _c;
|
|
259
|
+
const locale = Array.isArray(context.locale)
|
|
260
|
+
? [...context.locale]
|
|
261
|
+
: ((_a = context.locale) !== null && _a !== void 0 ? _a : DEFAULT_LOCALE);
|
|
262
|
+
const collator = new Intl.Collator(locale, { sensitivity: 'base', numeric: true });
|
|
263
|
+
const formatter = createDateTimeFormatter((_b = context.timezone) !== null && _b !== void 0 ? _b : DEFAULT_TIMEZONE);
|
|
264
|
+
const sortedBy = options.sortedBy;
|
|
265
|
+
const prepared = prepareTasks(tasks, context, {
|
|
266
|
+
formatter,
|
|
267
|
+
resolveAssignee: sortedBy === 'ASSIGNEE',
|
|
268
|
+
});
|
|
269
|
+
const direction = sortedBy && sortedBy !== 'MANUAL' ? ((_c = options.sortOrder) !== null && _c !== void 0 ? _c : defaultSortOrder(sortedBy)) : null;
|
|
270
|
+
const directionMultiplier = direction === 'DESC' ? -1 : 1;
|
|
271
|
+
return prepared
|
|
272
|
+
.sort((a, b) => {
|
|
273
|
+
if (sortedBy && sortedBy !== 'MANUAL') {
|
|
274
|
+
const primary = comparePrimary({ sortedBy, a, b, collator }) * directionMultiplier;
|
|
275
|
+
if (primary !== 0)
|
|
276
|
+
return primary;
|
|
277
|
+
}
|
|
278
|
+
return compareDefault(a, b, options.defaultOrder) || compareNumber(a.index, b.index);
|
|
279
|
+
})
|
|
280
|
+
.map(({ task }) => task);
|
|
281
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isActiveViewOption = isActiveViewOption;
|
|
4
|
+
exports.findViewOptions = findViewOptions;
|
|
5
|
+
/** Returns whether saved view options are active rather than a deletion tombstone. */
|
|
6
|
+
function isActiveViewOption(options) {
|
|
7
|
+
return options.isDeleted !== true;
|
|
8
|
+
}
|
|
9
|
+
/** Finds the active saved options for one logical view. */
|
|
10
|
+
function findViewOptions(options, args) {
|
|
11
|
+
var _a;
|
|
12
|
+
const targetObjectId = (_a = args.objectId) !== null && _a !== void 0 ? _a : null;
|
|
13
|
+
return options.find((entry) => {
|
|
14
|
+
var _a;
|
|
15
|
+
return isActiveViewOption(entry) &&
|
|
16
|
+
((_a = entry.objectId) !== null && _a !== void 0 ? _a : null) === targetObjectId &&
|
|
17
|
+
args.viewTypes.includes(entry.viewType);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { performSyncRequest } from '../transport/sync-request.js';
|
|
2
|
+
import { createCommand } from '../utils/sync-helpers.js';
|
|
3
|
+
import { isActiveViewOption } from '../utils/view-options.js';
|
|
4
|
+
import { BaseClient } from './base-client.js';
|
|
5
|
+
/** Internal sub-client for saved view-option reads and writes. */
|
|
6
|
+
export class ViewOptionsClient extends BaseClient {
|
|
7
|
+
async getViewOptions() {
|
|
8
|
+
var _a;
|
|
9
|
+
const response = await performSyncRequest(this.syncContext, {
|
|
10
|
+
resourceTypes: ['view_options'],
|
|
11
|
+
syncToken: '*',
|
|
12
|
+
});
|
|
13
|
+
return ((_a = response.viewOptions) !== null && _a !== void 0 ? _a : []).filter(isActiveViewOption);
|
|
14
|
+
}
|
|
15
|
+
async setViewOptions(args, requestId) {
|
|
16
|
+
await performSyncRequest(this.syncContext, { commands: [createCommand('view_options_set', args)] }, { requestId, hasSyncCommands: true });
|
|
17
|
+
}
|
|
18
|
+
async deleteViewOptions(args, requestId) {
|
|
19
|
+
await performSyncRequest(this.syncContext, { commands: [createCommand('view_options_delete', args)] }, { requestId, hasSyncCommands: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
package/dist/esm/todoist-api.js
CHANGED
|
@@ -16,6 +16,7 @@ import { TaskClient } from './clients/task-client.js';
|
|
|
16
16
|
import { TemplateClient } from './clients/template-client.js';
|
|
17
17
|
import { UiExtensionClient } from './clients/ui-extension-client.js';
|
|
18
18
|
import { UploadClient } from './clients/upload-client.js';
|
|
19
|
+
import { ViewOptionsClient } from './clients/view-options-client.js';
|
|
19
20
|
import { WorkspaceClient } from './clients/workspace-client.js';
|
|
20
21
|
import { ENDPOINT_REST_USER, getSyncBaseUri } from './consts/endpoints.js';
|
|
21
22
|
import { request } from './transport/http-client.js';
|
|
@@ -62,6 +63,7 @@ export class TodoistApi {
|
|
|
62
63
|
this.billingClient = new BillingClient(clientDeps);
|
|
63
64
|
this.appClient = new AppClient(clientDeps);
|
|
64
65
|
this.uiExtensionClient = new UiExtensionClient(clientDeps);
|
|
66
|
+
this.viewOptionsClient = new ViewOptionsClient(clientDeps);
|
|
65
67
|
}
|
|
66
68
|
/**
|
|
67
69
|
* Executes a raw Sync API request.
|
|
@@ -95,6 +97,34 @@ export class TodoistApi {
|
|
|
95
97
|
customFetch: this.customFetch,
|
|
96
98
|
}, syncRequest, { requestId, hasSyncCommands: Boolean((_a = syncRequest.commands) === null || _a === void 0 ? void 0 : _a.length) });
|
|
97
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Retrieves the authenticated user's active saved view options.
|
|
102
|
+
*
|
|
103
|
+
* @returns A promise that resolves to the active saved view options.
|
|
104
|
+
*/
|
|
105
|
+
async getViewOptions() {
|
|
106
|
+
return this.viewOptionsClient.getViewOptions();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Sets saved options for a view.
|
|
110
|
+
*
|
|
111
|
+
* @param args - The saved view options to set.
|
|
112
|
+
* @param requestId - Optional custom identifier for the request.
|
|
113
|
+
* @returns A promise that resolves when the view options are saved.
|
|
114
|
+
*/
|
|
115
|
+
async setViewOptions(args, requestId) {
|
|
116
|
+
return this.viewOptionsClient.setViewOptions(args, requestId);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Deletes the saved options for a view.
|
|
120
|
+
*
|
|
121
|
+
* @param args - The view whose saved options to delete.
|
|
122
|
+
* @param requestId - Optional custom identifier for the request.
|
|
123
|
+
* @returns A promise that resolves when the view options are deleted.
|
|
124
|
+
*/
|
|
125
|
+
async deleteViewOptions(args, requestId) {
|
|
126
|
+
return this.viewOptionsClient.deleteViewOptions(args, requestId);
|
|
127
|
+
}
|
|
98
128
|
/**
|
|
99
129
|
* Retrieves information about the authenticated user.
|
|
100
130
|
*
|
|
@@ -49,18 +49,27 @@ export const SORT_ORDERS = ['ASC', 'DESC'];
|
|
|
49
49
|
export const SortOrderSchema = z.enum(SORT_ORDERS).nullable();
|
|
50
50
|
/** Available calendar layout modes. */
|
|
51
51
|
export const CALENDAR_LAYOUTS = ['WEEK', 'MONTH'];
|
|
52
|
+
/** Available task color sources for calendar views. */
|
|
53
|
+
export const CALENDAR_COLORS = ['PRIORITY', 'LABEL', 'PROJECT'];
|
|
52
54
|
export const CalendarSettingsSchema = z.looseObject({
|
|
53
|
-
layout: z.enum(CALENDAR_LAYOUTS).optional(),
|
|
55
|
+
layout: z.enum(CALENDAR_LAYOUTS).nullable().optional(),
|
|
56
|
+
visibleDayCount: z
|
|
57
|
+
.union([z.literal(1), z.literal(3), z.literal(7)])
|
|
58
|
+
.nullable()
|
|
59
|
+
.optional(),
|
|
60
|
+
color: z.enum(CALENDAR_COLORS).nullable().optional(),
|
|
54
61
|
});
|
|
55
62
|
export const ViewOptionsSchema = z.looseObject({
|
|
56
63
|
viewType: ViewTypeSchema,
|
|
57
|
-
objectId: z.string().optional(),
|
|
64
|
+
objectId: z.string().nullable().optional(),
|
|
58
65
|
groupedBy: GroupedBySchema.optional(),
|
|
59
66
|
filteredBy: z.string().nullable().optional(),
|
|
60
|
-
viewMode: ViewModeSchema.optional(),
|
|
67
|
+
viewMode: ViewModeSchema.nullable().optional(),
|
|
61
68
|
showCompletedTasks: z.boolean().optional(),
|
|
62
69
|
sortedBy: SortedBySchema.optional(),
|
|
63
70
|
sortOrder: SortOrderSchema.optional(),
|
|
71
|
+
calendarSettings: CalendarSettingsSchema.nullable().optional(),
|
|
72
|
+
isDeleted: z.boolean().optional(),
|
|
64
73
|
});
|
|
65
74
|
export const ProjectViewOptionsDefaultsSchema = z.looseObject({
|
|
66
75
|
projectId: z.string(),
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -3,4 +3,6 @@ export * from './sanitization.js';
|
|
|
3
3
|
export { getTaskUrl, getProjectUrl, getSectionUrl } from './url-helpers.js';
|
|
4
4
|
export { createCommand } from './sync-helpers.js';
|
|
5
5
|
export * from './project-helpers.js';
|
|
6
|
+
export * from './task-sorting.js';
|
|
7
|
+
export * from './view-options.js';
|
|
6
8
|
export { parseWebhookPayload, verifyWebhookSignature } from './webhook-parser.js';
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/** Todoist's default task-ordering hierarchies. */
|
|
2
|
+
export const DEFAULT_TASK_ORDERS = ['PRIORITY_FIRST', 'DATE_FIRST'];
|
|
3
|
+
const DEFAULT_TIMEZONE = 'UTC';
|
|
4
|
+
const DEFAULT_LOCALE = 'en';
|
|
5
|
+
const DATE_ONLY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
6
|
+
const DATE_TIME_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?$/;
|
|
7
|
+
const EXPLICIT_TIMEZONE_PATTERN = /(?:Z|[+-]\d{2}:?\d{2})$/i;
|
|
8
|
+
const DATE_TIME_FORMATTERS = new Map();
|
|
9
|
+
function compareNumber(a, b) {
|
|
10
|
+
if (a === b)
|
|
11
|
+
return 0;
|
|
12
|
+
return a < b ? -1 : 1;
|
|
13
|
+
}
|
|
14
|
+
function isValidDateParts(year, month, day) {
|
|
15
|
+
const date = new Date(0);
|
|
16
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
17
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
18
|
+
return (date.getUTCFullYear() === year &&
|
|
19
|
+
date.getUTCMonth() === month - 1 &&
|
|
20
|
+
date.getUTCDate() === day);
|
|
21
|
+
}
|
|
22
|
+
function dateSortValue({ year, month, day, hour = 0, minute = 0, second = 0, millisecond = 0, isAllDay = false, }) {
|
|
23
|
+
if (!isValidDateParts(year, month, day) ||
|
|
24
|
+
hour < 0 ||
|
|
25
|
+
hour > 23 ||
|
|
26
|
+
minute < 0 ||
|
|
27
|
+
minute > 59 ||
|
|
28
|
+
second < 0 ||
|
|
29
|
+
second > 59 ||
|
|
30
|
+
millisecond < 0 ||
|
|
31
|
+
millisecond > 999) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
day: year * 10000 + month * 100 + day,
|
|
36
|
+
kind: isAllDay ? 0 : 1,
|
|
37
|
+
time: ((hour * 60 + minute) * 60 + second) * 1000 + millisecond,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function parseDateOnly(value) {
|
|
41
|
+
const match = DATE_ONLY_PATTERN.exec(value);
|
|
42
|
+
if (!match)
|
|
43
|
+
return null;
|
|
44
|
+
return dateSortValue({
|
|
45
|
+
year: Number(match[1]),
|
|
46
|
+
month: Number(match[2]),
|
|
47
|
+
day: Number(match[3]),
|
|
48
|
+
isAllDay: true,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function parseDateTimeComponents(value) {
|
|
52
|
+
var _a, _b;
|
|
53
|
+
const match = DATE_TIME_PATTERN.exec(value);
|
|
54
|
+
if (!match)
|
|
55
|
+
return null;
|
|
56
|
+
const milliseconds = Number(((_a = match[7]) !== null && _a !== void 0 ? _a : '').padEnd(3, '0').slice(0, 3));
|
|
57
|
+
const components = {
|
|
58
|
+
year: Number(match[1]),
|
|
59
|
+
month: Number(match[2]),
|
|
60
|
+
day: Number(match[3]),
|
|
61
|
+
hour: Number(match[4]),
|
|
62
|
+
minute: Number(match[5]),
|
|
63
|
+
second: Number((_b = match[6]) !== null && _b !== void 0 ? _b : 0),
|
|
64
|
+
millisecond: milliseconds,
|
|
65
|
+
};
|
|
66
|
+
return dateSortValue(components) === null ? null : components;
|
|
67
|
+
}
|
|
68
|
+
function createDateTimeFormatter(timezone, fallback) {
|
|
69
|
+
const cached = DATE_TIME_FORMATTERS.get(timezone);
|
|
70
|
+
if (cached)
|
|
71
|
+
return cached;
|
|
72
|
+
try {
|
|
73
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
74
|
+
timeZone: timezone,
|
|
75
|
+
calendar: 'iso8601',
|
|
76
|
+
numberingSystem: 'latn',
|
|
77
|
+
year: 'numeric',
|
|
78
|
+
month: '2-digit',
|
|
79
|
+
day: '2-digit',
|
|
80
|
+
hour: '2-digit',
|
|
81
|
+
minute: '2-digit',
|
|
82
|
+
second: '2-digit',
|
|
83
|
+
hourCycle: 'h23',
|
|
84
|
+
});
|
|
85
|
+
DATE_TIME_FORMATTERS.set(timezone, formatter);
|
|
86
|
+
return formatter;
|
|
87
|
+
}
|
|
88
|
+
catch (_a) {
|
|
89
|
+
return fallback !== null && fallback !== void 0 ? fallback : createDateTimeFormatter(DEFAULT_TIMEZONE);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function componentsAt(timestamp, formatter) {
|
|
93
|
+
const parts = formatter.formatToParts(new Date(timestamp));
|
|
94
|
+
function part(type) {
|
|
95
|
+
var _a;
|
|
96
|
+
return Number((_a = parts.find((entry) => entry.type === type)) === null || _a === void 0 ? void 0 : _a.value);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
year: part('year'),
|
|
100
|
+
month: part('month'),
|
|
101
|
+
day: part('day'),
|
|
102
|
+
hour: part('hour'),
|
|
103
|
+
minute: part('minute'),
|
|
104
|
+
second: part('second'),
|
|
105
|
+
millisecond: new Date(timestamp).getUTCMilliseconds(),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function componentsAsUtcTimestamp({ year, month, day, hour = 0, minute = 0, second = 0, millisecond = 0, }) {
|
|
109
|
+
const date = new Date(0);
|
|
110
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
111
|
+
date.setUTCHours(hour, minute, second, millisecond);
|
|
112
|
+
return date.getTime();
|
|
113
|
+
}
|
|
114
|
+
/** Resolves a zoned wall clock to an instant, including daylight-saving offsets. */
|
|
115
|
+
function timestampForWallClock(components, formatter) {
|
|
116
|
+
const target = componentsAsUtcTimestamp(components);
|
|
117
|
+
let timestamp = target;
|
|
118
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
119
|
+
const adjustment = target - componentsAsUtcTimestamp(componentsAt(timestamp, formatter));
|
|
120
|
+
if (adjustment === 0)
|
|
121
|
+
return timestamp;
|
|
122
|
+
timestamp += adjustment;
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
function dateSortValueAt(timestamp, formatter) {
|
|
127
|
+
const value = dateSortValue(componentsAt(timestamp, formatter));
|
|
128
|
+
return value ? Object.assign(Object.assign({}, value), { time: timestamp }) : null;
|
|
129
|
+
}
|
|
130
|
+
function parseFixedDateTime(value, formatter) {
|
|
131
|
+
if (parseDateTimeComponents(value.replace(EXPLICIT_TIMEZONE_PATTERN, '')) === null)
|
|
132
|
+
return null;
|
|
133
|
+
const timestamp = Date.parse(value);
|
|
134
|
+
return Number.isNaN(timestamp) ? null : dateSortValueAt(timestamp, formatter);
|
|
135
|
+
}
|
|
136
|
+
function parseZonedFloatingDateTime(value, sourceFormatter, accountFormatter) {
|
|
137
|
+
const components = parseDateTimeComponents(value);
|
|
138
|
+
if (!components)
|
|
139
|
+
return null;
|
|
140
|
+
const timestamp = timestampForWallClock(components, sourceFormatter);
|
|
141
|
+
return timestamp === null ? null : dateSortValueAt(timestamp, accountFormatter);
|
|
142
|
+
}
|
|
143
|
+
function parseTaskDate(value, formatter, timezone) {
|
|
144
|
+
var _a;
|
|
145
|
+
return ((_a = parseDateOnly(value)) !== null && _a !== void 0 ? _a : (EXPLICIT_TIMEZONE_PATTERN.test(value)
|
|
146
|
+
? parseFixedDateTime(value, formatter)
|
|
147
|
+
: parseZonedFloatingDateTime(value, timezone ? createDateTimeFormatter(timezone, formatter) : formatter, formatter)));
|
|
148
|
+
}
|
|
149
|
+
function compareNullable(a, b, compare) {
|
|
150
|
+
if (a === null || b === null) {
|
|
151
|
+
if (a === b)
|
|
152
|
+
return 0;
|
|
153
|
+
return a === null ? 1 : -1;
|
|
154
|
+
}
|
|
155
|
+
return compare(a, b);
|
|
156
|
+
}
|
|
157
|
+
function compareDateValues(left, right) {
|
|
158
|
+
return (compareNumber(left.day, right.day) ||
|
|
159
|
+
compareNumber(left.kind, right.kind) ||
|
|
160
|
+
compareNumber(left.time, right.time));
|
|
161
|
+
}
|
|
162
|
+
function compareDate(a, b) {
|
|
163
|
+
return compareNullable(a, b, compareDateValues);
|
|
164
|
+
}
|
|
165
|
+
function compareOptionalNumber(a, b) {
|
|
166
|
+
return compareNullable(a, b, compareNumber);
|
|
167
|
+
}
|
|
168
|
+
function compareOptionalText(a, b, collator) {
|
|
169
|
+
return compareNullable(a, b, (left, right) => collator.compare(left, right));
|
|
170
|
+
}
|
|
171
|
+
function prepareTasks(tasks, context, { formatter, resolveAssignee }) {
|
|
172
|
+
return tasks.map((task, index) => {
|
|
173
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
174
|
+
const due = task.due
|
|
175
|
+
? parseTaskDate((_a = task.due.datetime) !== null && _a !== void 0 ? _a : task.due.date, formatter, task.due.timezone)
|
|
176
|
+
: null;
|
|
177
|
+
const deadline = task.deadline ? parseTaskDate(task.deadline.date, formatter) : null;
|
|
178
|
+
return {
|
|
179
|
+
task,
|
|
180
|
+
index,
|
|
181
|
+
due,
|
|
182
|
+
deadline,
|
|
183
|
+
schedule: due !== null && due !== void 0 ? due : deadline,
|
|
184
|
+
added: task.addedAt && !Number.isNaN(task.addedAt.getTime())
|
|
185
|
+
? task.addedAt.getTime()
|
|
186
|
+
: null,
|
|
187
|
+
project: (_c = (_b = context.projectOrder) === null || _b === void 0 ? void 0 : _b.get(task.projectId)) !== null && _c !== void 0 ? _c : null,
|
|
188
|
+
workspace: (_e = (_d = context.workspaceOrder) === null || _d === void 0 ? void 0 : _d.get(task.projectId)) !== null && _e !== void 0 ? _e : null,
|
|
189
|
+
assignee: resolveAssignee ? ((_g = (_f = context.assigneeName) === null || _f === void 0 ? void 0 : _f.call(context, task)) !== null && _g !== void 0 ? _g : null) : null,
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function comparePriorityFirst(a, b) {
|
|
194
|
+
const common = compareNumber(b.task.priority, a.task.priority) ||
|
|
195
|
+
compareDate(a.due, b.due) ||
|
|
196
|
+
compareDate(a.deadline, b.deadline);
|
|
197
|
+
if (common !== 0)
|
|
198
|
+
return common;
|
|
199
|
+
const project = compareOptionalNumber(a.project, b.project);
|
|
200
|
+
if (project !== 0)
|
|
201
|
+
return project;
|
|
202
|
+
if (a.task.projectId === b.task.projectId) {
|
|
203
|
+
return compareNumber(a.task.childOrder, b.task.childOrder);
|
|
204
|
+
}
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
function compareDateFirst(a, b) {
|
|
208
|
+
return (compareDate(a.schedule, b.schedule) ||
|
|
209
|
+
compareNumber(b.task.priority, a.task.priority) ||
|
|
210
|
+
compareDate(a.deadline, b.deadline) ||
|
|
211
|
+
compareNumber(a.task.dayOrder, b.task.dayOrder) ||
|
|
212
|
+
compareOptionalNumber(a.added, b.added));
|
|
213
|
+
}
|
|
214
|
+
function compareDefault(a, b, defaultOrder) {
|
|
215
|
+
return defaultOrder === 'DATE_FIRST' ? compareDateFirst(a, b) : comparePriorityFirst(a, b);
|
|
216
|
+
}
|
|
217
|
+
function comparePrimary({ sortedBy, a, b, collator, }) {
|
|
218
|
+
switch (sortedBy) {
|
|
219
|
+
case 'ALPHABETICALLY':
|
|
220
|
+
return collator.compare(a.task.content, b.task.content);
|
|
221
|
+
case 'ASSIGNEE':
|
|
222
|
+
return compareOptionalText(a.assignee, b.assignee, collator);
|
|
223
|
+
case 'DUE_DATE':
|
|
224
|
+
return compareDate(a.due, b.due);
|
|
225
|
+
case 'DEADLINE':
|
|
226
|
+
return compareDate(a.deadline, b.deadline);
|
|
227
|
+
case 'ADDED_DATE':
|
|
228
|
+
return compareOptionalNumber(a.added, b.added);
|
|
229
|
+
case 'PRIORITY':
|
|
230
|
+
return compareNumber(a.task.priority, b.task.priority);
|
|
231
|
+
case 'PROJECT':
|
|
232
|
+
return compareOptionalNumber(a.project, b.project);
|
|
233
|
+
case 'WORKSPACE':
|
|
234
|
+
return compareOptionalNumber(a.workspace, b.workspace);
|
|
235
|
+
case 'MANUAL':
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function defaultSortOrder(sortedBy) {
|
|
240
|
+
return sortedBy === 'PRIORITY' ? 'DESC' : 'ASC';
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Sorts the supplied tasks using Todoist view-ordering rules.
|
|
244
|
+
*
|
|
245
|
+
* The function performs no I/O and always returns a new array. Exact project,
|
|
246
|
+
* workspace, assignee, localized text, and due-time ordering requires the
|
|
247
|
+
* corresponding context. Callers must sort each independent view section or
|
|
248
|
+
* group separately and preserve any subtask structure they render.
|
|
249
|
+
*
|
|
250
|
+
* This function sorts only the tasks supplied to it. Fetch every page first
|
|
251
|
+
* when globally correct ordering is required for a paginated query.
|
|
252
|
+
*/
|
|
253
|
+
export function sortTasks(tasks, options, context = {}) {
|
|
254
|
+
var _a, _b, _c;
|
|
255
|
+
const locale = Array.isArray(context.locale)
|
|
256
|
+
? [...context.locale]
|
|
257
|
+
: ((_a = context.locale) !== null && _a !== void 0 ? _a : DEFAULT_LOCALE);
|
|
258
|
+
const collator = new Intl.Collator(locale, { sensitivity: 'base', numeric: true });
|
|
259
|
+
const formatter = createDateTimeFormatter((_b = context.timezone) !== null && _b !== void 0 ? _b : DEFAULT_TIMEZONE);
|
|
260
|
+
const sortedBy = options.sortedBy;
|
|
261
|
+
const prepared = prepareTasks(tasks, context, {
|
|
262
|
+
formatter,
|
|
263
|
+
resolveAssignee: sortedBy === 'ASSIGNEE',
|
|
264
|
+
});
|
|
265
|
+
const direction = sortedBy && sortedBy !== 'MANUAL' ? ((_c = options.sortOrder) !== null && _c !== void 0 ? _c : defaultSortOrder(sortedBy)) : null;
|
|
266
|
+
const directionMultiplier = direction === 'DESC' ? -1 : 1;
|
|
267
|
+
return prepared
|
|
268
|
+
.sort((a, b) => {
|
|
269
|
+
if (sortedBy && sortedBy !== 'MANUAL') {
|
|
270
|
+
const primary = comparePrimary({ sortedBy, a, b, collator }) * directionMultiplier;
|
|
271
|
+
if (primary !== 0)
|
|
272
|
+
return primary;
|
|
273
|
+
}
|
|
274
|
+
return compareDefault(a, b, options.defaultOrder) || compareNumber(a.index, b.index);
|
|
275
|
+
})
|
|
276
|
+
.map(({ task }) => task);
|
|
277
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Returns whether saved view options are active rather than a deletion tombstone. */
|
|
2
|
+
export function isActiveViewOption(options) {
|
|
3
|
+
return options.isDeleted !== true;
|
|
4
|
+
}
|
|
5
|
+
/** Finds the active saved options for one logical view. */
|
|
6
|
+
export function findViewOptions(options, args) {
|
|
7
|
+
var _a;
|
|
8
|
+
const targetObjectId = (_a = args.objectId) !== null && _a !== void 0 ? _a : null;
|
|
9
|
+
return options.find((entry) => {
|
|
10
|
+
var _a;
|
|
11
|
+
return isActiveViewOption(entry) &&
|
|
12
|
+
((_a = entry.objectId) !== null && _a !== void 0 ? _a : null) === targetObjectId &&
|
|
13
|
+
args.viewTypes.includes(entry.viewType);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ViewOptions, ViewOptionsDeleteArgs, ViewOptionsSetArgs } from '../types/sync/index.js';
|
|
2
|
+
import { BaseClient } from './base-client.js';
|
|
3
|
+
/** Internal sub-client for saved view-option reads and writes. */
|
|
4
|
+
export declare class ViewOptionsClient extends BaseClient {
|
|
5
|
+
getViewOptions(): Promise<ViewOptions[]>;
|
|
6
|
+
setViewOptions(args: ViewOptionsSetArgs, requestId?: string): Promise<void>;
|
|
7
|
+
deleteViewOptions(args: ViewOptionsDeleteArgs, requestId?: string): Promise<void>;
|
|
8
|
+
}
|
|
@@ -14,6 +14,7 @@ import { ProductivityStats } from './types/productivity/index.js';
|
|
|
14
14
|
import { PersonalProject, WorkspaceProject, AddProjectArgs, UpdateProjectArgs, GetProjectsArgs, SearchProjectsArgs, GetProjectCollaboratorsArgs, GetProjectsResponse, GetProjectCollaboratorsResponse, GetArchivedProjectsArgs, GetArchivedProjectsResponse, MoveProjectToWorkspaceArgs, MoveProjectToPersonalArgs, GetArchivedProjectsCountArgs, GetArchivedProjectsCountResponse, GetProjectPermissionsResponse, GetFullProjectArgs, GetFullProjectResponse, JoinProjectResponse } from './types/projects/index.js';
|
|
15
15
|
import { AddReminderArgs, UpdateReminderArgs, AddLocationReminderArgs, UpdateLocationReminderArgs, GetRemindersArgs, GetRemindersResponse, GetLocationRemindersArgs, GetLocationRemindersResponse } from './types/reminders/index.js';
|
|
16
16
|
import { Section, AddSectionArgs, UpdateSectionArgs, GetSectionsArgs, SearchSectionsArgs, GetSectionsResponse } from './types/sections/index.js';
|
|
17
|
+
import type { SyncRequest, SyncResponse, ViewOptions, ViewOptionsDeleteArgs, ViewOptionsSetArgs } from './types/sync/index.js';
|
|
17
18
|
import type { Folder } from './types/sync/resources/folders.js';
|
|
18
19
|
import { Task, AddTaskArgs, GetTasksArgs, GetTasksByFilterArgs, UpdateTaskArgs, QuickAddTaskArgs, type MoveTaskArgs, GetCompletedTasksByCompletionDateArgs, GetCompletedTasksByDueDateArgs, GetCompletedTasksResponse, SearchCompletedTasksArgs, GetTasksResponse, GetAllCompletedTasksArgs, GetAllCompletedTasksResponse } from './types/tasks/index.js';
|
|
19
20
|
import { ExportTemplateFileArgs, ExportTemplateUrlArgs, ExportTemplateUrlResponse, CreateProjectFromTemplateArgs, CreateProjectFromTemplateResponse, ImportTemplateIntoProjectArgs, ImportTemplateFromIdArgs, ImportTemplateResponse } from './types/templates/index.js';
|
|
@@ -21,7 +22,6 @@ import type { AddUiExtensionArgs, UiExtension, UpdateUiExtensionArgs, UploadUiEx
|
|
|
21
22
|
import { UploadFileArgs, DeleteUploadArgs } from './types/uploads/index.js';
|
|
22
23
|
import { CurrentUser } from './types/users/index.js';
|
|
23
24
|
import { WorkspaceInvitation, WorkspacePlanDetails, JoinWorkspaceResult, Workspace, AddWorkspaceArgs, UpdateWorkspaceArgs, GetWorkspaceMembersActivityArgs, GetWorkspaceMembersActivityResponse, GetWorkspaceUserTasksArgs, GetWorkspaceUserTasksResponse, InviteWorkspaceUsersArgs, InviteWorkspaceUsersResponse, UpdateWorkspaceUserArgs, RemoveWorkspaceUserArgs, GetWorkspaceInvitationsArgs, DeleteWorkspaceInvitationArgs, WorkspaceInvitationActionArgs, JoinWorkspaceArgs, WorkspaceLogoArgs, GetWorkspacePlanDetailsArgs, GetWorkspaceUsersArgs, GetWorkspaceUsersResponse, GetWorkspaceProjectsArgs, WorkspaceInvitationsResponse, AllWorkspaceInvitationsResponse, WorkspaceLogoResponse } from './types/workspaces/index.js';
|
|
24
|
-
import { type SyncResponse, type SyncRequest } from './types/sync/index.js';
|
|
25
25
|
/**
|
|
26
26
|
* A client for interacting with the Todoist API v1.
|
|
27
27
|
* This class provides methods to manage tasks, projects, sections, labels, and comments in Todoist.
|
|
@@ -79,6 +79,7 @@ export declare class TodoistApi {
|
|
|
79
79
|
private readonly billingClient;
|
|
80
80
|
private readonly appClient;
|
|
81
81
|
private readonly uiExtensionClient;
|
|
82
|
+
private readonly viewOptionsClient;
|
|
82
83
|
constructor(
|
|
83
84
|
/**
|
|
84
85
|
* Your Todoist API token.
|
|
@@ -113,6 +114,28 @@ export declare class TodoistApi {
|
|
|
113
114
|
* ```
|
|
114
115
|
*/
|
|
115
116
|
sync(syncRequest: SyncRequest, requestId?: string): Promise<SyncResponse>;
|
|
117
|
+
/**
|
|
118
|
+
* Retrieves the authenticated user's active saved view options.
|
|
119
|
+
*
|
|
120
|
+
* @returns A promise that resolves to the active saved view options.
|
|
121
|
+
*/
|
|
122
|
+
getViewOptions(): Promise<ViewOptions[]>;
|
|
123
|
+
/**
|
|
124
|
+
* Sets saved options for a view.
|
|
125
|
+
*
|
|
126
|
+
* @param args - The saved view options to set.
|
|
127
|
+
* @param requestId - Optional custom identifier for the request.
|
|
128
|
+
* @returns A promise that resolves when the view options are saved.
|
|
129
|
+
*/
|
|
130
|
+
setViewOptions(args: ViewOptionsSetArgs, requestId?: string): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Deletes the saved options for a view.
|
|
133
|
+
*
|
|
134
|
+
* @param args - The view whose saved options to delete.
|
|
135
|
+
* @param requestId - Optional custom identifier for the request.
|
|
136
|
+
* @returns A promise that resolves when the view options are deleted.
|
|
137
|
+
*/
|
|
138
|
+
deleteViewOptions(args: ViewOptionsDeleteArgs, requestId?: string): Promise<void>;
|
|
116
139
|
/**
|
|
117
140
|
* Retrieves information about the authenticated user.
|
|
118
141
|
*
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type { ViewMode, GroupedBy, SortedBy, SortOrder
|
|
2
|
-
export type CalendarSettings = {
|
|
3
|
-
layout?: CalendarLayout;
|
|
4
|
-
};
|
|
1
|
+
import type { CalendarSettings, ViewMode, GroupedBy, SortedBy, SortOrder } from '../resources/view-options.js';
|
|
5
2
|
export type ProjectViewOptionsDefaultsSetArgs = {
|
|
6
3
|
projectId: string;
|
|
7
4
|
viewMode?: ViewMode | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CalendarSettings, GroupedBy, SortedBy, SortOrder, ViewMode, ViewType } from '../resources/view-options.js';
|
|
2
2
|
export type ViewOptionsSetArgs = {
|
|
3
3
|
viewType: ViewType;
|
|
4
4
|
objectId?: string;
|
|
@@ -8,6 +8,7 @@ export type ViewOptionsSetArgs = {
|
|
|
8
8
|
showCompletedTasks?: boolean;
|
|
9
9
|
sortedBy?: SortedBy | null;
|
|
10
10
|
sortOrder?: SortOrder | null;
|
|
11
|
+
calendarSettings?: CalendarSettings | null;
|
|
11
12
|
};
|
|
12
13
|
export type ViewOptionsDeleteArgs = {
|
|
13
14
|
viewType: ViewType;
|
|
@@ -68,12 +68,23 @@ export declare const SortOrderSchema: z.ZodNullable<z.ZodEnum<{
|
|
|
68
68
|
export declare const CALENDAR_LAYOUTS: readonly ["WEEK", "MONTH"];
|
|
69
69
|
/** Calendar layout mode. */
|
|
70
70
|
export type CalendarLayout = (typeof CALENDAR_LAYOUTS)[number];
|
|
71
|
+
/** Available task color sources for calendar views. */
|
|
72
|
+
export declare const CALENDAR_COLORS: readonly ["PRIORITY", "LABEL", "PROJECT"];
|
|
73
|
+
/** Task color source for a calendar view. */
|
|
74
|
+
export type CalendarColor = (typeof CALENDAR_COLORS)[number];
|
|
71
75
|
export declare const CalendarSettingsSchema: z.ZodObject<{
|
|
72
|
-
layout: z.ZodOptional<z.ZodEnum<{
|
|
76
|
+
layout: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
73
77
|
WEEK: "WEEK";
|
|
74
78
|
MONTH: "MONTH";
|
|
75
|
-
}
|
|
79
|
+
}>>>;
|
|
80
|
+
visibleDayCount: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<3>, z.ZodLiteral<7>]>>>;
|
|
81
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
82
|
+
PROJECT: "PROJECT";
|
|
83
|
+
LABEL: "LABEL";
|
|
84
|
+
PRIORITY: "PRIORITY";
|
|
85
|
+
}>>>;
|
|
76
86
|
}, z.core.$loose>;
|
|
87
|
+
export type CalendarSettings = z.infer<typeof CalendarSettingsSchema>;
|
|
77
88
|
export declare const ViewOptionsSchema: z.ZodObject<{
|
|
78
89
|
viewType: z.ZodEnum<{
|
|
79
90
|
PROJECT: "PROJECT";
|
|
@@ -90,7 +101,7 @@ export declare const ViewOptionsSchema: z.ZodObject<{
|
|
|
90
101
|
OVERDUE: "OVERDUE";
|
|
91
102
|
WORKSPACE_OVERVIEW: "WORKSPACE_OVERVIEW";
|
|
92
103
|
}>;
|
|
93
|
-
objectId: z.ZodOptional<z.ZodString
|
|
104
|
+
objectId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
94
105
|
groupedBy: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
95
106
|
PROJECT: "PROJECT";
|
|
96
107
|
LABEL: "LABEL";
|
|
@@ -102,11 +113,11 @@ export declare const ViewOptionsSchema: z.ZodObject<{
|
|
|
102
113
|
WORKSPACE: "WORKSPACE";
|
|
103
114
|
}>>>;
|
|
104
115
|
filteredBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
105
|
-
viewMode: z.ZodOptional<z.ZodEnum<{
|
|
116
|
+
viewMode: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
106
117
|
LIST: "LIST";
|
|
107
118
|
BOARD: "BOARD";
|
|
108
119
|
CALENDAR: "CALENDAR";
|
|
109
|
-
}
|
|
120
|
+
}>>>;
|
|
110
121
|
showCompletedTasks: z.ZodOptional<z.ZodBoolean>;
|
|
111
122
|
sortedBy: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
112
123
|
PROJECT: "PROJECT";
|
|
@@ -123,6 +134,19 @@ export declare const ViewOptionsSchema: z.ZodObject<{
|
|
|
123
134
|
ASC: "ASC";
|
|
124
135
|
DESC: "DESC";
|
|
125
136
|
}>>>;
|
|
137
|
+
calendarSettings: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
138
|
+
layout: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
139
|
+
WEEK: "WEEK";
|
|
140
|
+
MONTH: "MONTH";
|
|
141
|
+
}>>>;
|
|
142
|
+
visibleDayCount: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<3>, z.ZodLiteral<7>]>>>;
|
|
143
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
144
|
+
PROJECT: "PROJECT";
|
|
145
|
+
LABEL: "LABEL";
|
|
146
|
+
PRIORITY: "PRIORITY";
|
|
147
|
+
}>>>;
|
|
148
|
+
}, z.core.$loose>>>;
|
|
149
|
+
isDeleted: z.ZodOptional<z.ZodBoolean>;
|
|
126
150
|
}, z.core.$loose>;
|
|
127
151
|
export type ViewOptions = z.infer<typeof ViewOptionsSchema>;
|
|
128
152
|
export declare const ProjectViewOptionsDefaultsSchema: z.ZodObject<{
|
|
@@ -160,10 +184,16 @@ export declare const ProjectViewOptionsDefaultsSchema: z.ZodObject<{
|
|
|
160
184
|
showCompletedTasks: z.ZodOptional<z.ZodBoolean>;
|
|
161
185
|
filteredBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
162
186
|
calendarSettings: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
163
|
-
layout: z.ZodOptional<z.ZodEnum<{
|
|
187
|
+
layout: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
164
188
|
WEEK: "WEEK";
|
|
165
189
|
MONTH: "MONTH";
|
|
166
|
-
}
|
|
190
|
+
}>>>;
|
|
191
|
+
visibleDayCount: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<3>, z.ZodLiteral<7>]>>>;
|
|
192
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
193
|
+
PROJECT: "PROJECT";
|
|
194
|
+
LABEL: "LABEL";
|
|
195
|
+
PRIORITY: "PRIORITY";
|
|
196
|
+
}>>>;
|
|
167
197
|
}, z.core.$loose>>>;
|
|
168
198
|
}, z.core.$loose>;
|
|
169
199
|
export type ProjectViewOptionsDefaults = z.infer<typeof ProjectViewOptionsDefaultsSchema>;
|
|
@@ -751,7 +751,7 @@ export declare const SyncResponseSchema: z.ZodObject<{
|
|
|
751
751
|
OVERDUE: "OVERDUE";
|
|
752
752
|
WORKSPACE_OVERVIEW: "WORKSPACE_OVERVIEW";
|
|
753
753
|
}>;
|
|
754
|
-
objectId: z.ZodOptional<z.ZodString
|
|
754
|
+
objectId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
755
755
|
groupedBy: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
756
756
|
PROJECT: "PROJECT";
|
|
757
757
|
LABEL: "LABEL";
|
|
@@ -763,11 +763,11 @@ export declare const SyncResponseSchema: z.ZodObject<{
|
|
|
763
763
|
WORKSPACE: "WORKSPACE";
|
|
764
764
|
}>>>;
|
|
765
765
|
filteredBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
766
|
-
viewMode: z.ZodOptional<z.ZodEnum<{
|
|
766
|
+
viewMode: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
767
767
|
LIST: "LIST";
|
|
768
768
|
BOARD: "BOARD";
|
|
769
769
|
CALENDAR: "CALENDAR";
|
|
770
|
-
}
|
|
770
|
+
}>>>;
|
|
771
771
|
showCompletedTasks: z.ZodOptional<z.ZodBoolean>;
|
|
772
772
|
sortedBy: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
773
773
|
PROJECT: "PROJECT";
|
|
@@ -784,6 +784,19 @@ export declare const SyncResponseSchema: z.ZodObject<{
|
|
|
784
784
|
ASC: "ASC";
|
|
785
785
|
DESC: "DESC";
|
|
786
786
|
}>>>;
|
|
787
|
+
calendarSettings: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
788
|
+
layout: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
789
|
+
WEEK: "WEEK";
|
|
790
|
+
MONTH: "MONTH";
|
|
791
|
+
}>>>;
|
|
792
|
+
visibleDayCount: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<3>, z.ZodLiteral<7>]>>>;
|
|
793
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
794
|
+
PROJECT: "PROJECT";
|
|
795
|
+
LABEL: "LABEL";
|
|
796
|
+
PRIORITY: "PRIORITY";
|
|
797
|
+
}>>>;
|
|
798
|
+
}, z.core.$loose>>>;
|
|
799
|
+
isDeleted: z.ZodOptional<z.ZodBoolean>;
|
|
787
800
|
}, z.core.$loose>>>;
|
|
788
801
|
projectViewOptionsDefaults: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
789
802
|
projectId: z.ZodString;
|
|
@@ -820,10 +833,16 @@ export declare const SyncResponseSchema: z.ZodObject<{
|
|
|
820
833
|
showCompletedTasks: z.ZodOptional<z.ZodBoolean>;
|
|
821
834
|
filteredBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
822
835
|
calendarSettings: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
823
|
-
layout: z.ZodOptional<z.ZodEnum<{
|
|
836
|
+
layout: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
824
837
|
WEEK: "WEEK";
|
|
825
838
|
MONTH: "MONTH";
|
|
826
|
-
}
|
|
839
|
+
}>>>;
|
|
840
|
+
visibleDayCount: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<3>, z.ZodLiteral<7>]>>>;
|
|
841
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
842
|
+
PROJECT: "PROJECT";
|
|
843
|
+
LABEL: "LABEL";
|
|
844
|
+
PRIORITY: "PRIORITY";
|
|
845
|
+
}>>>;
|
|
827
846
|
}, z.core.$loose>>>;
|
|
828
847
|
}, z.core.$loose>>>;
|
|
829
848
|
roleActions: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
@@ -3,5 +3,7 @@ export * from './sanitization.js';
|
|
|
3
3
|
export { getTaskUrl, getProjectUrl, getSectionUrl } from './url-helpers.js';
|
|
4
4
|
export { createCommand } from './sync-helpers.js';
|
|
5
5
|
export * from './project-helpers.js';
|
|
6
|
+
export * from './task-sorting.js';
|
|
7
|
+
export * from './view-options.js';
|
|
6
8
|
export { parseWebhookPayload, verifyWebhookSignature } from './webhook-parser.js';
|
|
7
9
|
export type { VerifyWebhookSignatureArgs } from './webhook-parser.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { SortOrder, SortedBy } from '../types/sync/index.js';
|
|
2
|
+
import type { Task } from '../types/tasks/index.js';
|
|
3
|
+
/** Todoist's default task-ordering hierarchies. */
|
|
4
|
+
export declare const DEFAULT_TASK_ORDERS: readonly ["PRIORITY_FIRST", "DATE_FIRST"];
|
|
5
|
+
/** Default hierarchy used when a view has no named sorting. */
|
|
6
|
+
export type DefaultTaskOrder = (typeof DEFAULT_TASK_ORDERS)[number];
|
|
7
|
+
export type TaskSortOptions = {
|
|
8
|
+
/** Saved or requested sort field. Null and MANUAL use defaultOrder. */
|
|
9
|
+
sortedBy?: SortedBy | null;
|
|
10
|
+
/** Saved or requested direction. Defaults by field when absent. */
|
|
11
|
+
sortOrder?: SortOrder | null;
|
|
12
|
+
/** Default hierarchy for this view or filter query. */
|
|
13
|
+
defaultOrder: DefaultTaskOrder;
|
|
14
|
+
};
|
|
15
|
+
export type TaskSortContext = {
|
|
16
|
+
/** Project ID to its visible order. */
|
|
17
|
+
projectOrder?: ReadonlyMap<string, number>;
|
|
18
|
+
/** Project ID to the visible order of its workspace bucket. */
|
|
19
|
+
workspaceOrder?: ReadonlyMap<string, number>;
|
|
20
|
+
/** Resolves the display name used for assignee sorting. */
|
|
21
|
+
assigneeName?: (task: Task) => string | null | undefined;
|
|
22
|
+
/** Account IANA timezone. Defaults to UTC for deterministic behavior. */
|
|
23
|
+
timezone?: string;
|
|
24
|
+
/** Locale used for text comparisons. Defaults to English. */
|
|
25
|
+
locale?: string | readonly string[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Sorts the supplied tasks using Todoist view-ordering rules.
|
|
29
|
+
*
|
|
30
|
+
* The function performs no I/O and always returns a new array. Exact project,
|
|
31
|
+
* workspace, assignee, localized text, and due-time ordering requires the
|
|
32
|
+
* corresponding context. Callers must sort each independent view section or
|
|
33
|
+
* group separately and preserve any subtask structure they render.
|
|
34
|
+
*
|
|
35
|
+
* This function sorts only the tasks supplied to it. Fetch every page first
|
|
36
|
+
* when globally correct ordering is required for a paginated query.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sortTasks(tasks: readonly Task[], options: TaskSortOptions, context?: TaskSortContext): Task[];
|
|
@@ -1153,23 +1153,37 @@ export declare const validateCompletedInfo: (input: unknown) => {
|
|
|
1153
1153
|
export declare const validateViewOptions: (input: unknown) => {
|
|
1154
1154
|
[x: string]: unknown;
|
|
1155
1155
|
viewType: "PROJECT" | "TODAY" | "UPCOMING" | "LABEL" | "FILTER" | "WORKSPACE_FILTER" | "SEARCH" | "TEMPLATE_PREVIEW" | "TASK_DETAIL" | "AUTOMATION" | "ASSIGNED" | "OVERDUE" | "WORKSPACE_OVERVIEW";
|
|
1156
|
-
objectId?: string | undefined;
|
|
1156
|
+
objectId?: string | null | undefined;
|
|
1157
1157
|
groupedBy?: "PROJECT" | "LABEL" | "ASSIGNEE" | "ADDED_DATE" | "DUE_DATE" | "DEADLINE" | "PRIORITY" | "WORKSPACE" | null | undefined;
|
|
1158
1158
|
filteredBy?: string | null | undefined;
|
|
1159
|
-
viewMode?: "LIST" | "BOARD" | "CALENDAR" | undefined;
|
|
1159
|
+
viewMode?: "LIST" | "BOARD" | "CALENDAR" | null | undefined;
|
|
1160
1160
|
showCompletedTasks?: boolean | undefined;
|
|
1161
1161
|
sortedBy?: "PROJECT" | "ASSIGNEE" | "ADDED_DATE" | "DUE_DATE" | "DEADLINE" | "PRIORITY" | "WORKSPACE" | "MANUAL" | "ALPHABETICALLY" | null | undefined;
|
|
1162
1162
|
sortOrder?: "ASC" | "DESC" | null | undefined;
|
|
1163
|
+
calendarSettings?: {
|
|
1164
|
+
[x: string]: unknown;
|
|
1165
|
+
layout?: "WEEK" | "MONTH" | null | undefined;
|
|
1166
|
+
visibleDayCount?: 3 | 1 | 7 | null | undefined;
|
|
1167
|
+
color?: "PROJECT" | "LABEL" | "PRIORITY" | null | undefined;
|
|
1168
|
+
} | null | undefined;
|
|
1169
|
+
isDeleted?: boolean | undefined;
|
|
1163
1170
|
}, validateViewOptionsArray: (input: unknown) => {
|
|
1164
1171
|
[x: string]: unknown;
|
|
1165
1172
|
viewType: "PROJECT" | "TODAY" | "UPCOMING" | "LABEL" | "FILTER" | "WORKSPACE_FILTER" | "SEARCH" | "TEMPLATE_PREVIEW" | "TASK_DETAIL" | "AUTOMATION" | "ASSIGNED" | "OVERDUE" | "WORKSPACE_OVERVIEW";
|
|
1166
|
-
objectId?: string | undefined;
|
|
1173
|
+
objectId?: string | null | undefined;
|
|
1167
1174
|
groupedBy?: "PROJECT" | "LABEL" | "ASSIGNEE" | "ADDED_DATE" | "DUE_DATE" | "DEADLINE" | "PRIORITY" | "WORKSPACE" | null | undefined;
|
|
1168
1175
|
filteredBy?: string | null | undefined;
|
|
1169
|
-
viewMode?: "LIST" | "BOARD" | "CALENDAR" | undefined;
|
|
1176
|
+
viewMode?: "LIST" | "BOARD" | "CALENDAR" | null | undefined;
|
|
1170
1177
|
showCompletedTasks?: boolean | undefined;
|
|
1171
1178
|
sortedBy?: "PROJECT" | "ASSIGNEE" | "ADDED_DATE" | "DUE_DATE" | "DEADLINE" | "PRIORITY" | "WORKSPACE" | "MANUAL" | "ALPHABETICALLY" | null | undefined;
|
|
1172
1179
|
sortOrder?: "ASC" | "DESC" | null | undefined;
|
|
1180
|
+
calendarSettings?: {
|
|
1181
|
+
[x: string]: unknown;
|
|
1182
|
+
layout?: "WEEK" | "MONTH" | null | undefined;
|
|
1183
|
+
visibleDayCount?: 3 | 1 | 7 | null | undefined;
|
|
1184
|
+
color?: "PROJECT" | "LABEL" | "PRIORITY" | null | undefined;
|
|
1185
|
+
} | null | undefined;
|
|
1186
|
+
isDeleted?: boolean | undefined;
|
|
1173
1187
|
}[];
|
|
1174
1188
|
export declare const validateProjectViewOptionsDefaults: (input: unknown) => {
|
|
1175
1189
|
[x: string]: unknown;
|
|
@@ -1182,7 +1196,9 @@ export declare const validateProjectViewOptionsDefaults: (input: unknown) => {
|
|
|
1182
1196
|
filteredBy?: string | null | undefined;
|
|
1183
1197
|
calendarSettings?: {
|
|
1184
1198
|
[x: string]: unknown;
|
|
1185
|
-
layout?: "WEEK" | "MONTH" | undefined;
|
|
1199
|
+
layout?: "WEEK" | "MONTH" | null | undefined;
|
|
1200
|
+
visibleDayCount?: 3 | 1 | 7 | null | undefined;
|
|
1201
|
+
color?: "PROJECT" | "LABEL" | "PRIORITY" | null | undefined;
|
|
1186
1202
|
} | null | undefined;
|
|
1187
1203
|
}, validateProjectViewOptionsDefaultsArray: (input: unknown) => {
|
|
1188
1204
|
[x: string]: unknown;
|
|
@@ -1195,7 +1211,9 @@ export declare const validateProjectViewOptionsDefaults: (input: unknown) => {
|
|
|
1195
1211
|
filteredBy?: string | null | undefined;
|
|
1196
1212
|
calendarSettings?: {
|
|
1197
1213
|
[x: string]: unknown;
|
|
1198
|
-
layout?: "WEEK" | "MONTH" | undefined;
|
|
1214
|
+
layout?: "WEEK" | "MONTH" | null | undefined;
|
|
1215
|
+
visibleDayCount?: 3 | 1 | 7 | null | undefined;
|
|
1216
|
+
color?: "PROJECT" | "LABEL" | "PRIORITY" | null | undefined;
|
|
1199
1217
|
} | null | undefined;
|
|
1200
1218
|
}[];
|
|
1201
1219
|
export declare const validateUserPlanLimits: (input: unknown) => {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ViewOptions, ViewType } from '../types/sync/index.js';
|
|
2
|
+
export type FindViewOptionsArgs = {
|
|
3
|
+
/** View types that identify the logical view. */
|
|
4
|
+
viewTypes: readonly ViewType[];
|
|
5
|
+
/** Object ID for object-backed views. Omit for singleton views. */
|
|
6
|
+
objectId?: string | null;
|
|
7
|
+
};
|
|
8
|
+
/** Returns whether saved view options are active rather than a deletion tombstone. */
|
|
9
|
+
export declare function isActiveViewOption(options: ViewOptions): boolean;
|
|
10
|
+
/** Finds the active saved options for one logical view. */
|
|
11
|
+
export declare function findViewOptions(options: readonly ViewOptions[], args: FindViewOptionsArgs): ViewOptions | undefined;
|
package/package.json
CHANGED