@vitalyostanin/youtrack-mcp 0.2.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/README-ru.md +283 -0
- package/README.md +290 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +13 -0
- package/dist/src/config.d.ts +10 -0
- package/dist/src/config.js +68 -0
- package/dist/src/server.d.ts +8 -0
- package/dist/src/server.js +48 -0
- package/dist/src/tools/article-search-tools.d.ts +4 -0
- package/dist/src/tools/article-search-tools.js +31 -0
- package/dist/src/tools/article-tools.d.ts +4 -0
- package/dist/src/tools/article-tools.js +98 -0
- package/dist/src/tools/attachment-tools.d.ts +4 -0
- package/dist/src/tools/attachment-tools.js +100 -0
- package/dist/src/tools/issue-search-tools.d.ts +4 -0
- package/dist/src/tools/issue-search-tools.js +56 -0
- package/dist/src/tools/issue-tools.d.ts +4 -0
- package/dist/src/tools/issue-tools.js +190 -0
- package/dist/src/tools/project-tools.d.ts +4 -0
- package/dist/src/tools/project-tools.js +35 -0
- package/dist/src/tools/service-info.d.ts +4 -0
- package/dist/src/tools/service-info.js +61 -0
- package/dist/src/tools/user-tools.d.ts +4 -0
- package/dist/src/tools/user-tools.js +46 -0
- package/dist/src/tools/workitem-report-tools.d.ts +4 -0
- package/dist/src/tools/workitem-report-tools.js +62 -0
- package/dist/src/tools/workitem-tools.d.ts +4 -0
- package/dist/src/tools/workitem-tools.js +247 -0
- package/dist/src/types.d.ts +433 -0
- package/dist/src/types.js +2 -0
- package/dist/src/utils/date.d.ts +34 -0
- package/dist/src/utils/date.js +147 -0
- package/dist/src/utils/mappers.d.ts +76 -0
- package/dist/src/utils/mappers.js +126 -0
- package/dist/src/utils/tool-response.d.ts +4 -0
- package/dist/src/utils/tool-response.js +61 -0
- package/dist/src/youtrack-client.d.ts +86 -0
- package/dist/src/youtrack-client.js +1220 -0
- package/package.json +65 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import type { MappedYoutrackIssue, MappedYoutrackIssueComment, MappedYoutrackIssueDetails, MappedYoutrackWorkItem } from "./utils/mappers.js";
|
|
2
|
+
export interface ServiceInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
version: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export type UserAliasMap = Record<string, string>;
|
|
8
|
+
export interface YoutrackConfig {
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
token: string;
|
|
11
|
+
timezone: string;
|
|
12
|
+
holidays?: string[];
|
|
13
|
+
preHolidays?: string[];
|
|
14
|
+
userAliases?: UserAliasMap;
|
|
15
|
+
}
|
|
16
|
+
export interface DurationValue {
|
|
17
|
+
minutes?: number;
|
|
18
|
+
presentation?: string;
|
|
19
|
+
$type?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface YoutrackProject {
|
|
22
|
+
id: string;
|
|
23
|
+
shortName: string;
|
|
24
|
+
name?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface YoutrackIssue {
|
|
27
|
+
id: string;
|
|
28
|
+
idReadable: string;
|
|
29
|
+
summary?: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
wikifiedDescription?: string;
|
|
32
|
+
usesMarkdown?: boolean;
|
|
33
|
+
project?: YoutrackProject;
|
|
34
|
+
parent?: {
|
|
35
|
+
idReadable: string;
|
|
36
|
+
id?: string;
|
|
37
|
+
} | null;
|
|
38
|
+
assignee?: YoutrackUser | null;
|
|
39
|
+
}
|
|
40
|
+
export interface YoutrackIssueCreateInput {
|
|
41
|
+
project: string;
|
|
42
|
+
summary: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
parentIssueId?: string;
|
|
45
|
+
assigneeLogin?: string;
|
|
46
|
+
usesMarkdown?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface YoutrackIssueUpdateInput {
|
|
49
|
+
issueId: string;
|
|
50
|
+
summary?: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
parentIssueId?: string | null;
|
|
53
|
+
usesMarkdown?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface YoutrackIssueAssignInput {
|
|
56
|
+
issueId: string;
|
|
57
|
+
assigneeLogin: string;
|
|
58
|
+
}
|
|
59
|
+
export interface YoutrackUser {
|
|
60
|
+
id: string;
|
|
61
|
+
login: string;
|
|
62
|
+
name?: string;
|
|
63
|
+
fullName?: string;
|
|
64
|
+
email?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface YoutrackUserListPayload {
|
|
67
|
+
users: YoutrackUser[];
|
|
68
|
+
}
|
|
69
|
+
export interface YoutrackProjectListPayload {
|
|
70
|
+
projects: YoutrackProject[];
|
|
71
|
+
}
|
|
72
|
+
export interface YoutrackWorkItem {
|
|
73
|
+
id: string;
|
|
74
|
+
date: number;
|
|
75
|
+
updated?: number;
|
|
76
|
+
duration: DurationValue;
|
|
77
|
+
text?: string;
|
|
78
|
+
textPreview?: string;
|
|
79
|
+
usesMarkdown?: boolean;
|
|
80
|
+
description?: string;
|
|
81
|
+
issue: {
|
|
82
|
+
idReadable: string;
|
|
83
|
+
id?: string;
|
|
84
|
+
};
|
|
85
|
+
author?: YoutrackUser;
|
|
86
|
+
}
|
|
87
|
+
export interface YoutrackWorkItemCreateInput {
|
|
88
|
+
issueId: string;
|
|
89
|
+
date: string | number | Date;
|
|
90
|
+
minutes: number;
|
|
91
|
+
summary?: string;
|
|
92
|
+
description?: string;
|
|
93
|
+
usesMarkdown?: boolean;
|
|
94
|
+
}
|
|
95
|
+
export interface YoutrackWorkItemUpdateInput {
|
|
96
|
+
issueId: string;
|
|
97
|
+
workItemId: string;
|
|
98
|
+
date?: string | number | Date;
|
|
99
|
+
minutes?: number;
|
|
100
|
+
summary?: string;
|
|
101
|
+
description?: string;
|
|
102
|
+
usesMarkdown?: boolean;
|
|
103
|
+
}
|
|
104
|
+
export interface YoutrackWorkItemPeriodCreateInput {
|
|
105
|
+
issueId: string;
|
|
106
|
+
startDate: string | number | Date;
|
|
107
|
+
endDate: string | number | Date;
|
|
108
|
+
minutes: number;
|
|
109
|
+
summary?: string;
|
|
110
|
+
description?: string;
|
|
111
|
+
usesMarkdown?: boolean;
|
|
112
|
+
excludeWeekends?: boolean;
|
|
113
|
+
excludeHolidays?: boolean;
|
|
114
|
+
holidays?: Array<string | number | Date>;
|
|
115
|
+
preHolidays?: Array<string | number | Date>;
|
|
116
|
+
}
|
|
117
|
+
export interface YoutrackWorkItemIdempotentCreateInput {
|
|
118
|
+
issueId: string;
|
|
119
|
+
date: string | number | Date;
|
|
120
|
+
minutes: number;
|
|
121
|
+
description: string;
|
|
122
|
+
usesMarkdown?: boolean;
|
|
123
|
+
}
|
|
124
|
+
export interface YoutrackWorkItemReportOptions {
|
|
125
|
+
author?: string;
|
|
126
|
+
startDate?: string | number | Date;
|
|
127
|
+
endDate?: string | number | Date;
|
|
128
|
+
issueId?: string;
|
|
129
|
+
expectedDailyMinutes?: number;
|
|
130
|
+
excludeWeekends?: boolean;
|
|
131
|
+
excludeHolidays?: boolean;
|
|
132
|
+
holidays?: Array<string | number | Date>;
|
|
133
|
+
preHolidays?: Array<string | number | Date>;
|
|
134
|
+
allUsers?: boolean;
|
|
135
|
+
}
|
|
136
|
+
export interface ServiceStatusPayload {
|
|
137
|
+
service: ServiceInfo;
|
|
138
|
+
configuration: {
|
|
139
|
+
hasToken: boolean;
|
|
140
|
+
baseUrl: string | null;
|
|
141
|
+
holidays?: string[];
|
|
142
|
+
preHolidays?: string[];
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export interface IssueLookupPayload {
|
|
146
|
+
issue: MappedYoutrackIssue;
|
|
147
|
+
}
|
|
148
|
+
export interface WorkItemsPayload {
|
|
149
|
+
items: MappedYoutrackWorkItem[];
|
|
150
|
+
}
|
|
151
|
+
export interface WorkItemCreatePayload {
|
|
152
|
+
item: MappedYoutrackWorkItem;
|
|
153
|
+
}
|
|
154
|
+
export interface WorkItemUpdatePayload {
|
|
155
|
+
item: MappedYoutrackWorkItem;
|
|
156
|
+
}
|
|
157
|
+
export interface WorkItemDeletePayload {
|
|
158
|
+
issueId: string;
|
|
159
|
+
workItemId: string;
|
|
160
|
+
deleted: true;
|
|
161
|
+
}
|
|
162
|
+
export interface YoutrackIssueDetails extends YoutrackIssue {
|
|
163
|
+
created?: number | null;
|
|
164
|
+
updated?: number | null;
|
|
165
|
+
resolved?: number | null;
|
|
166
|
+
reporter?: YoutrackUser;
|
|
167
|
+
updater?: YoutrackUser;
|
|
168
|
+
}
|
|
169
|
+
export interface IssueDetailsPayload {
|
|
170
|
+
issue: MappedYoutrackIssueDetails;
|
|
171
|
+
}
|
|
172
|
+
export interface YoutrackIssueComment {
|
|
173
|
+
id: string;
|
|
174
|
+
text?: string;
|
|
175
|
+
textPreview?: string;
|
|
176
|
+
usesMarkdown?: boolean;
|
|
177
|
+
author?: YoutrackUser;
|
|
178
|
+
created: number;
|
|
179
|
+
updated?: number;
|
|
180
|
+
}
|
|
181
|
+
export interface IssueCommentsPayload {
|
|
182
|
+
comments: MappedYoutrackIssueComment[];
|
|
183
|
+
}
|
|
184
|
+
export interface IssueCommentCreateInput {
|
|
185
|
+
issueId: string;
|
|
186
|
+
text: string;
|
|
187
|
+
usesMarkdown?: boolean;
|
|
188
|
+
}
|
|
189
|
+
export interface YoutrackActivityItem {
|
|
190
|
+
id: string;
|
|
191
|
+
timestamp: number;
|
|
192
|
+
author?: YoutrackUser;
|
|
193
|
+
category?: {
|
|
194
|
+
id: string;
|
|
195
|
+
};
|
|
196
|
+
target?: {
|
|
197
|
+
text?: string;
|
|
198
|
+
};
|
|
199
|
+
added?: Array<{
|
|
200
|
+
name?: string;
|
|
201
|
+
id?: string;
|
|
202
|
+
login?: string;
|
|
203
|
+
}>;
|
|
204
|
+
removed?: Array<{
|
|
205
|
+
name?: string;
|
|
206
|
+
id?: string;
|
|
207
|
+
login?: string;
|
|
208
|
+
}>;
|
|
209
|
+
$type?: string;
|
|
210
|
+
}
|
|
211
|
+
export interface IssueCommentCreatePayload {
|
|
212
|
+
comment: MappedYoutrackIssueComment;
|
|
213
|
+
}
|
|
214
|
+
export interface WorkItemReportDay {
|
|
215
|
+
date: string;
|
|
216
|
+
expectedMinutes: number;
|
|
217
|
+
actualMinutes: number;
|
|
218
|
+
difference: number;
|
|
219
|
+
percent: number;
|
|
220
|
+
items: MappedYoutrackWorkItem[];
|
|
221
|
+
}
|
|
222
|
+
export interface WorkItemSummary {
|
|
223
|
+
totalMinutes: number;
|
|
224
|
+
totalHours: number;
|
|
225
|
+
expectedMinutes: number;
|
|
226
|
+
expectedHours: number;
|
|
227
|
+
workDays: number;
|
|
228
|
+
averageHoursPerDay: number;
|
|
229
|
+
}
|
|
230
|
+
export interface WorkItemReportPayload {
|
|
231
|
+
summary: WorkItemSummary;
|
|
232
|
+
days: WorkItemReportDay[];
|
|
233
|
+
period: {
|
|
234
|
+
startDate: string;
|
|
235
|
+
endDate: string;
|
|
236
|
+
};
|
|
237
|
+
invalidDays: WorkItemInvalidDay[];
|
|
238
|
+
}
|
|
239
|
+
export interface WorkItemBulkResultPayload {
|
|
240
|
+
created: MappedYoutrackWorkItem[];
|
|
241
|
+
failed: Array<{
|
|
242
|
+
date: string;
|
|
243
|
+
reason: string;
|
|
244
|
+
}>;
|
|
245
|
+
}
|
|
246
|
+
export interface WorkItemInvalidDay {
|
|
247
|
+
date: string;
|
|
248
|
+
expectedMinutes: number;
|
|
249
|
+
actualMinutes: number;
|
|
250
|
+
difference: number;
|
|
251
|
+
percent: number;
|
|
252
|
+
items: MappedYoutrackWorkItem[];
|
|
253
|
+
}
|
|
254
|
+
export interface WorkItemUsersReportPayload {
|
|
255
|
+
reports: Array<{
|
|
256
|
+
userLogin: string;
|
|
257
|
+
summary: WorkItemSummary;
|
|
258
|
+
invalidDays: WorkItemInvalidDay[];
|
|
259
|
+
period: {
|
|
260
|
+
startDate: string;
|
|
261
|
+
endDate: string;
|
|
262
|
+
};
|
|
263
|
+
}>;
|
|
264
|
+
}
|
|
265
|
+
export interface WorkItemsForUsersPayload {
|
|
266
|
+
items: MappedYoutrackWorkItem[];
|
|
267
|
+
users: string[];
|
|
268
|
+
}
|
|
269
|
+
export interface WorkItemsAllUsersPayload {
|
|
270
|
+
items: MappedYoutrackWorkItem[];
|
|
271
|
+
}
|
|
272
|
+
export interface WorkItemIdempotentCreatePayload {
|
|
273
|
+
created: boolean;
|
|
274
|
+
item: MappedYoutrackWorkItem | null;
|
|
275
|
+
}
|
|
276
|
+
export interface YoutrackArticle {
|
|
277
|
+
id: string;
|
|
278
|
+
idReadable: string;
|
|
279
|
+
summary: string;
|
|
280
|
+
content?: string;
|
|
281
|
+
contentPreview?: string;
|
|
282
|
+
usesMarkdown?: boolean;
|
|
283
|
+
parentArticle?: {
|
|
284
|
+
id: string;
|
|
285
|
+
idReadable: string;
|
|
286
|
+
};
|
|
287
|
+
childArticles?: Array<{
|
|
288
|
+
id: string;
|
|
289
|
+
idReadable: string;
|
|
290
|
+
summary: string;
|
|
291
|
+
}>;
|
|
292
|
+
project?: {
|
|
293
|
+
id: string;
|
|
294
|
+
shortName: string;
|
|
295
|
+
name?: string;
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
export interface ArticlePayload {
|
|
299
|
+
article: YoutrackArticle;
|
|
300
|
+
}
|
|
301
|
+
export interface ArticleListPayload {
|
|
302
|
+
articles: YoutrackArticle[];
|
|
303
|
+
}
|
|
304
|
+
export interface ArticleCreateInput {
|
|
305
|
+
summary: string;
|
|
306
|
+
content?: string;
|
|
307
|
+
parentArticleId?: string;
|
|
308
|
+
projectId?: string;
|
|
309
|
+
usesMarkdown?: boolean;
|
|
310
|
+
returnRendered?: boolean;
|
|
311
|
+
}
|
|
312
|
+
export interface ArticleUpdateInput {
|
|
313
|
+
articleId: string;
|
|
314
|
+
summary?: string;
|
|
315
|
+
content?: string;
|
|
316
|
+
usesMarkdown?: boolean;
|
|
317
|
+
returnRendered?: boolean;
|
|
318
|
+
}
|
|
319
|
+
export interface ArticleSearchInput {
|
|
320
|
+
query: string;
|
|
321
|
+
projectId?: string;
|
|
322
|
+
parentArticleId?: string;
|
|
323
|
+
limit?: number;
|
|
324
|
+
returnRendered?: boolean;
|
|
325
|
+
}
|
|
326
|
+
export interface ArticleSearchPayload {
|
|
327
|
+
articles: YoutrackArticle[];
|
|
328
|
+
query: string;
|
|
329
|
+
}
|
|
330
|
+
export interface IssueSearchInput {
|
|
331
|
+
userLogins: string[];
|
|
332
|
+
startDate?: string | number | Date;
|
|
333
|
+
endDate?: string | number | Date;
|
|
334
|
+
dateFilterMode?: "issue_updated" | "user_activity";
|
|
335
|
+
limit?: number;
|
|
336
|
+
skip?: number;
|
|
337
|
+
}
|
|
338
|
+
export interface IssueSearchPayload {
|
|
339
|
+
issues: Array<MappedYoutrackIssue & {
|
|
340
|
+
lastActivityDate?: string;
|
|
341
|
+
}>;
|
|
342
|
+
userLogins: string[];
|
|
343
|
+
period?: {
|
|
344
|
+
startDate?: string;
|
|
345
|
+
endDate?: string;
|
|
346
|
+
};
|
|
347
|
+
pagination: {
|
|
348
|
+
returned: number;
|
|
349
|
+
limit: number;
|
|
350
|
+
skip: number;
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
export interface IssueError {
|
|
354
|
+
issueId: string;
|
|
355
|
+
error: string;
|
|
356
|
+
}
|
|
357
|
+
export interface IssuesLookupPayload {
|
|
358
|
+
issues: MappedYoutrackIssue[];
|
|
359
|
+
errors?: IssueError[];
|
|
360
|
+
}
|
|
361
|
+
export interface IssuesDetailsPayload {
|
|
362
|
+
issues: MappedYoutrackIssueDetails[];
|
|
363
|
+
errors?: IssueError[];
|
|
364
|
+
}
|
|
365
|
+
export interface IssuesCommentsPayload {
|
|
366
|
+
commentsByIssue: Record<string, MappedYoutrackIssueComment[]>;
|
|
367
|
+
errors?: IssueError[];
|
|
368
|
+
}
|
|
369
|
+
export interface YoutrackAttachment {
|
|
370
|
+
id: string;
|
|
371
|
+
name: string;
|
|
372
|
+
author?: YoutrackUser;
|
|
373
|
+
created: number;
|
|
374
|
+
updated?: number;
|
|
375
|
+
size: number;
|
|
376
|
+
mimeType?: string;
|
|
377
|
+
url?: string;
|
|
378
|
+
thumbnailURL?: string;
|
|
379
|
+
extension?: string;
|
|
380
|
+
charset?: string;
|
|
381
|
+
base64Content?: string;
|
|
382
|
+
}
|
|
383
|
+
export interface MappedYoutrackAttachment {
|
|
384
|
+
id: string;
|
|
385
|
+
name: string;
|
|
386
|
+
author?: {
|
|
387
|
+
id: string;
|
|
388
|
+
login: string;
|
|
389
|
+
name?: string;
|
|
390
|
+
};
|
|
391
|
+
created: string;
|
|
392
|
+
updated?: string;
|
|
393
|
+
size: number;
|
|
394
|
+
sizeFormatted: string;
|
|
395
|
+
mimeType?: string;
|
|
396
|
+
extension?: string;
|
|
397
|
+
url?: string;
|
|
398
|
+
thumbnailURL?: string;
|
|
399
|
+
}
|
|
400
|
+
export interface AttachmentsListPayload {
|
|
401
|
+
attachments: MappedYoutrackAttachment[];
|
|
402
|
+
issueId: string;
|
|
403
|
+
}
|
|
404
|
+
export interface AttachmentPayload {
|
|
405
|
+
attachment: MappedYoutrackAttachment;
|
|
406
|
+
issueId: string;
|
|
407
|
+
}
|
|
408
|
+
export interface AttachmentDownloadPayload {
|
|
409
|
+
attachment: MappedYoutrackAttachment;
|
|
410
|
+
downloadUrl: string;
|
|
411
|
+
issueId: string;
|
|
412
|
+
}
|
|
413
|
+
export interface AttachmentUploadInput {
|
|
414
|
+
issueId: string;
|
|
415
|
+
filePaths: string[];
|
|
416
|
+
muteUpdateNotifications?: boolean;
|
|
417
|
+
}
|
|
418
|
+
export interface AttachmentUploadPayload {
|
|
419
|
+
uploaded: MappedYoutrackAttachment[];
|
|
420
|
+
issueId: string;
|
|
421
|
+
}
|
|
422
|
+
export interface AttachmentDeleteInput {
|
|
423
|
+
issueId: string;
|
|
424
|
+
attachmentId: string;
|
|
425
|
+
confirmation: boolean;
|
|
426
|
+
}
|
|
427
|
+
export interface AttachmentDeletePayload {
|
|
428
|
+
deleted: true;
|
|
429
|
+
issueId: string;
|
|
430
|
+
attachmentId: string;
|
|
431
|
+
attachmentName: string;
|
|
432
|
+
}
|
|
433
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare function initializeTimezone(timezone: string): void;
|
|
2
|
+
export declare function getTimezone(): string;
|
|
3
|
+
export declare function parseDateInput(value: string | number | Date): number;
|
|
4
|
+
export declare function toIsoDateString(value: string | number | Date): string;
|
|
5
|
+
export declare function enumerateDateRange(start: string | number | Date, end: string | number | Date): string[];
|
|
6
|
+
export declare function isWeekend(dateIso: string): boolean;
|
|
7
|
+
export declare function isHoliday(date: string | number | Date, holidays?: Array<string | number | Date>): boolean;
|
|
8
|
+
export declare function filterWorkingDays(dates: Array<string | Date | number>, excludeWeekends?: boolean, excludeHolidays?: boolean, holidays?: Array<string | Date | number>): string[];
|
|
9
|
+
export declare function getDayBounds(value: string | number | Date): {
|
|
10
|
+
start: number;
|
|
11
|
+
end: number;
|
|
12
|
+
};
|
|
13
|
+
export declare function minutesToHours(minutes: number): number;
|
|
14
|
+
export declare function hoursToMinutes(hours: number): number;
|
|
15
|
+
export declare function calculateTotalMinutes(items: Array<{
|
|
16
|
+
duration: {
|
|
17
|
+
minutes?: number;
|
|
18
|
+
};
|
|
19
|
+
}>): number;
|
|
20
|
+
export declare function groupWorkItemsByDate<T extends {
|
|
21
|
+
date: number;
|
|
22
|
+
}>(items: T[]): Map<string, T[]>;
|
|
23
|
+
export declare function validateDateRange(start: string | number | Date, end: string | number | Date): void;
|
|
24
|
+
export declare function isWorkingDay(value: string | number | Date): boolean;
|
|
25
|
+
export declare function dateToUnixMs(value: string | Date, timezone?: string): number;
|
|
26
|
+
export declare function unixMsToDate(timestamp: number): Date;
|
|
27
|
+
export declare function formatDate(value: string | number | Date): string;
|
|
28
|
+
export declare function formatDateInTimezone(value: string | number | Date, timezone: string): string;
|
|
29
|
+
export declare function generateDateRange(start: string | number | Date, end: string | number | Date): Date[];
|
|
30
|
+
export declare function filterWorkingDates(dates: Date[], excludeWeekends?: boolean, excludeHolidays?: boolean, holidays?: Date[]): Date[];
|
|
31
|
+
export declare function isSameDay(left: string | number | Date, right: string | number | Date): boolean;
|
|
32
|
+
export declare function getCurrentTimestamp(): number;
|
|
33
|
+
export declare function getCurrentDate(timezone?: string): Date;
|
|
34
|
+
//# sourceMappingURL=date.d.ts.map
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { DateTime, Settings } from "luxon";
|
|
2
|
+
let currentTimezone = "Europe/Moscow";
|
|
3
|
+
export function initializeTimezone(timezone) {
|
|
4
|
+
currentTimezone = timezone;
|
|
5
|
+
Settings.defaultZone = timezone;
|
|
6
|
+
}
|
|
7
|
+
export function getTimezone() {
|
|
8
|
+
return currentTimezone;
|
|
9
|
+
}
|
|
10
|
+
export function parseDateInput(value) {
|
|
11
|
+
if (value instanceof Date) {
|
|
12
|
+
return DateTime.fromJSDate(value).toMillis();
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === "number") {
|
|
15
|
+
if (!Number.isFinite(value)) {
|
|
16
|
+
throw new Error("Date value must be a finite number");
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
const parsed = DateTime.fromISO(value, { zone: currentTimezone });
|
|
21
|
+
if (!parsed.isValid) {
|
|
22
|
+
throw new Error(`Invalid date value: ${value}`);
|
|
23
|
+
}
|
|
24
|
+
return parsed.toMillis();
|
|
25
|
+
}
|
|
26
|
+
export function toIsoDateString(value) {
|
|
27
|
+
const timestamp = parseDateInput(value);
|
|
28
|
+
return DateTime.fromMillis(timestamp).toFormat("yyyy-MM-dd");
|
|
29
|
+
}
|
|
30
|
+
export function enumerateDateRange(start, end) {
|
|
31
|
+
const startTime = DateTime.fromMillis(parseDateInput(start)).startOf("day");
|
|
32
|
+
const endTime = DateTime.fromMillis(parseDateInput(end)).startOf("day");
|
|
33
|
+
if (endTime < startTime) {
|
|
34
|
+
throw new Error("End date cannot be earlier than start date");
|
|
35
|
+
}
|
|
36
|
+
const dates = [];
|
|
37
|
+
for (let current = startTime; current <= endTime; current = current.plus({ days: 1 })) {
|
|
38
|
+
dates.push(current.toFormat("yyyy-MM-dd"));
|
|
39
|
+
}
|
|
40
|
+
return dates;
|
|
41
|
+
}
|
|
42
|
+
export function isWeekend(dateIso) {
|
|
43
|
+
const date = DateTime.fromISO(dateIso);
|
|
44
|
+
return date.weekday === 6 || date.weekday === 7;
|
|
45
|
+
}
|
|
46
|
+
export function isHoliday(date, holidays = []) {
|
|
47
|
+
const target = toIsoDateString(date);
|
|
48
|
+
return holidays.some((holiday) => toIsoDateString(holiday) === target);
|
|
49
|
+
}
|
|
50
|
+
export function filterWorkingDays(dates, excludeWeekends = true, excludeHolidays = true, holidays = []) {
|
|
51
|
+
return dates
|
|
52
|
+
.map((value) => toIsoDateString(value))
|
|
53
|
+
.filter((dateIso) => {
|
|
54
|
+
if (excludeWeekends && isWeekend(dateIso)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (excludeHolidays && isHoliday(dateIso, holidays)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export function getDayBounds(value) {
|
|
64
|
+
const date = DateTime.fromMillis(parseDateInput(value));
|
|
65
|
+
const start = date.startOf("day");
|
|
66
|
+
const end = date.endOf("day");
|
|
67
|
+
return { start: start.toMillis(), end: end.toMillis() };
|
|
68
|
+
}
|
|
69
|
+
export function minutesToHours(minutes) {
|
|
70
|
+
return Math.round((minutes / 60) * 100) / 100;
|
|
71
|
+
}
|
|
72
|
+
export function hoursToMinutes(hours) {
|
|
73
|
+
return Math.round(hours * 60);
|
|
74
|
+
}
|
|
75
|
+
export function calculateTotalMinutes(items) {
|
|
76
|
+
return items.reduce((total, item) => total + (item.duration.minutes ?? 0), 0);
|
|
77
|
+
}
|
|
78
|
+
export function groupWorkItemsByDate(items) {
|
|
79
|
+
const map = new Map();
|
|
80
|
+
for (const item of items) {
|
|
81
|
+
const dateIso = toIsoDateString(item.date);
|
|
82
|
+
const bucket = map.get(dateIso) ?? [];
|
|
83
|
+
bucket.push(item);
|
|
84
|
+
map.set(dateIso, bucket);
|
|
85
|
+
}
|
|
86
|
+
return map;
|
|
87
|
+
}
|
|
88
|
+
export function validateDateRange(start, end) {
|
|
89
|
+
const startTime = DateTime.fromMillis(parseDateInput(start));
|
|
90
|
+
const endTime = DateTime.fromMillis(parseDateInput(end));
|
|
91
|
+
if (endTime < startTime) {
|
|
92
|
+
throw new Error("Start date must be before or equal to end date");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function isWorkingDay(value) {
|
|
96
|
+
return !isWeekend(toIsoDateString(value));
|
|
97
|
+
}
|
|
98
|
+
export function dateToUnixMs(value, timezone = currentTimezone) {
|
|
99
|
+
const source = value instanceof Date ? DateTime.fromJSDate(value) : DateTime.fromISO(value);
|
|
100
|
+
const zoned = source.setZone(timezone);
|
|
101
|
+
const normalized = zoned.set({ hour: 12, minute: 0, second: 0, millisecond: 0 });
|
|
102
|
+
return normalized.toMillis();
|
|
103
|
+
}
|
|
104
|
+
export function unixMsToDate(timestamp) {
|
|
105
|
+
return DateTime.fromMillis(timestamp).toJSDate();
|
|
106
|
+
}
|
|
107
|
+
export function formatDate(value) {
|
|
108
|
+
return toIsoDateString(value);
|
|
109
|
+
}
|
|
110
|
+
export function formatDateInTimezone(value, timezone) {
|
|
111
|
+
const timestamp = parseDateInput(value);
|
|
112
|
+
const formatted = DateTime.fromMillis(timestamp).setZone(timezone).toFormat("yyyy-MM-dd");
|
|
113
|
+
return formatted;
|
|
114
|
+
}
|
|
115
|
+
export function generateDateRange(start, end) {
|
|
116
|
+
const startDate = DateTime.fromMillis(parseDateInput(start)).startOf("day");
|
|
117
|
+
const endDate = DateTime.fromMillis(parseDateInput(end)).startOf("day");
|
|
118
|
+
if (endDate < startDate) {
|
|
119
|
+
throw new Error("End date cannot be earlier than start date");
|
|
120
|
+
}
|
|
121
|
+
const dates = [];
|
|
122
|
+
for (let current = startDate; current <= endDate; current = current.plus({ days: 1 })) {
|
|
123
|
+
dates.push(current.toJSDate());
|
|
124
|
+
}
|
|
125
|
+
return dates;
|
|
126
|
+
}
|
|
127
|
+
export function filterWorkingDates(dates, excludeWeekends = true, excludeHolidays = true, holidays = []) {
|
|
128
|
+
return dates.filter((date) => {
|
|
129
|
+
if (excludeWeekends && !isWorkingDay(date)) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
if (excludeHolidays && holidays.some((holiday) => formatDate(holiday) === formatDate(date))) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
export function isSameDay(left, right) {
|
|
139
|
+
return formatDate(left) === formatDate(right);
|
|
140
|
+
}
|
|
141
|
+
export function getCurrentTimestamp() {
|
|
142
|
+
return DateTime.now().toMillis();
|
|
143
|
+
}
|
|
144
|
+
export function getCurrentDate(timezone = currentTimezone) {
|
|
145
|
+
return DateTime.now().setZone(timezone).toJSDate();
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=date.js.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { YoutrackAttachment, YoutrackIssue, YoutrackIssueComment, YoutrackIssueDetails, YoutrackWorkItem, MappedYoutrackAttachment } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Convert timestamp in milliseconds to ISO date string (YYYY-MM-DD)
|
|
4
|
+
*/
|
|
5
|
+
export declare function timestampToIsoDate(timestamp: number | null | undefined): string | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Convert timestamp in milliseconds to ISO datetime string (YYYY-MM-DDTHH:mm:ss.sssZ)
|
|
8
|
+
*/
|
|
9
|
+
export declare function timestampToIsoDateTime(timestamp: number | null | undefined): string | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Mapped issue with ISO date strings
|
|
12
|
+
* Issue type doesn't have date fields, so it's the same as YoutrackIssue
|
|
13
|
+
*/
|
|
14
|
+
export type MappedYoutrackIssue = YoutrackIssue;
|
|
15
|
+
/**
|
|
16
|
+
* Mapped issue details with ISO date strings
|
|
17
|
+
*/
|
|
18
|
+
export interface MappedYoutrackIssueDetails extends Omit<YoutrackIssueDetails, "created" | "updated" | "resolved"> {
|
|
19
|
+
created?: string;
|
|
20
|
+
updated?: string;
|
|
21
|
+
resolved?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Mapped work item with ISO date strings
|
|
25
|
+
*/
|
|
26
|
+
export interface MappedYoutrackWorkItem extends Omit<YoutrackWorkItem, "date"> {
|
|
27
|
+
date: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Mapped comment with ISO date strings
|
|
31
|
+
*/
|
|
32
|
+
export interface MappedYoutrackIssueComment extends Omit<YoutrackIssueComment, "created" | "updated"> {
|
|
33
|
+
created: string;
|
|
34
|
+
updated?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Map YoutrackIssue to MappedYoutrackIssue
|
|
38
|
+
*/
|
|
39
|
+
export declare function mapIssue(issue: YoutrackIssue): MappedYoutrackIssue;
|
|
40
|
+
/**
|
|
41
|
+
* Map YoutrackIssueDetails to MappedYoutrackIssueDetails
|
|
42
|
+
*/
|
|
43
|
+
export declare function mapIssueDetails(issue: YoutrackIssueDetails): MappedYoutrackIssueDetails;
|
|
44
|
+
/**
|
|
45
|
+
* Map YoutrackWorkItem to MappedYoutrackWorkItem
|
|
46
|
+
*/
|
|
47
|
+
export declare function mapWorkItem(item: YoutrackWorkItem): MappedYoutrackWorkItem;
|
|
48
|
+
/**
|
|
49
|
+
* Map YoutrackIssueComment to MappedYoutrackIssueComment
|
|
50
|
+
*/
|
|
51
|
+
export declare function mapComment(comment: YoutrackIssueComment): MappedYoutrackIssueComment;
|
|
52
|
+
/**
|
|
53
|
+
* Map array of issues
|
|
54
|
+
*/
|
|
55
|
+
export declare function mapIssues(issues: YoutrackIssue[]): MappedYoutrackIssue[];
|
|
56
|
+
/**
|
|
57
|
+
* Map array of work items
|
|
58
|
+
*/
|
|
59
|
+
export declare function mapWorkItems(items: YoutrackWorkItem[]): MappedYoutrackWorkItem[];
|
|
60
|
+
/**
|
|
61
|
+
* Map array of comments
|
|
62
|
+
*/
|
|
63
|
+
export declare function mapComments(comments: YoutrackIssueComment[]): MappedYoutrackIssueComment[];
|
|
64
|
+
/**
|
|
65
|
+
* Format file size in bytes to human-readable format
|
|
66
|
+
*/
|
|
67
|
+
export declare function formatFileSize(bytes: number): string;
|
|
68
|
+
/**
|
|
69
|
+
* Map YoutrackAttachment to MappedYoutrackAttachment
|
|
70
|
+
*/
|
|
71
|
+
export declare function mapAttachment(attachment: YoutrackAttachment): MappedYoutrackAttachment;
|
|
72
|
+
/**
|
|
73
|
+
* Map array of attachments
|
|
74
|
+
*/
|
|
75
|
+
export declare function mapAttachments(attachments: YoutrackAttachment[]): MappedYoutrackAttachment[];
|
|
76
|
+
//# sourceMappingURL=mappers.d.ts.map
|