Skip to content

Commit ac36e04

Browse files
committed
Add Task Manager integration mutations and types
Introduces GraphQL types and mutations for managing Task Manager integration in projects, including disconnecting and updating settings. Updates the project model to support partial updates, extends resolvers for new mutations, and adds comprehensive tests for these features.
1 parent e0845cf commit ac36e04

File tree

7 files changed

+762
-3
lines changed

7 files changed

+762
-3
lines changed

src/models/project.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,9 +465,16 @@ export default class ProjectModel extends AbstractModel<ProjectDBScheme> impleme
465465

466466
/**
467467
* Updates project data in DataBase
468-
* @param projectData - projectData to save
469-
*/
470-
public async updateProject(projectData: ProjectDBScheme): Promise<ProjectDBScheme> {
468+
* Performs partial update - can update one or several properties without requiring full project object
469+
*
470+
* @param projectData - partial project data containing one or more properties to update.
471+
* Only provided properties will be updated; others will remain unchanged.
472+
* Example: `{ name: 'New Name' }` will update only the name field.
473+
* Example: `{ taskManager: null }` will remove the taskManager field.
474+
* @returns {Promise<ProjectDBScheme>} Updated project data
475+
* @throws {Error} If project update fails or project not found
476+
*/
477+
public async updateProject(projectData: Partial<ProjectDBScheme>): Promise<ProjectDBScheme> {
471478
let result;
472479

473480
try {

src/resolvers/project.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,102 @@ module.exports = {
391391

392392
return userModel.updateLastProjectVisit(projectId);
393393
},
394+
395+
/**
396+
* Disconnect Task Manager integration from project
397+
*
398+
* @param {ResolverObj} _obj
399+
* @param {string} projectId - project ID to disconnect Task Manager from
400+
* @param {UserInContext} user - current authorized user {@see ../index.js}
401+
* @param {ContextFactories} factories - factories for working with models
402+
*
403+
* @returns {Project}
404+
*/
405+
async disconnectTaskManager(_obj, { projectId }, { user, factories }) {
406+
const project = await factories.projectsFactory.findById(projectId);
407+
408+
if (!project) {
409+
throw new ApolloError('There is no project with that id');
410+
}
411+
412+
if (project.workspaceId.toString() === '6213b6a01e6281087467cc7a') {
413+
throw new ApolloError('Unable to update demo project');
414+
}
415+
416+
try {
417+
/**
418+
* Remove taskManager field from project
419+
* Set updatedAt to current date
420+
*/
421+
return await project.updateProject({
422+
taskManager: null,
423+
});
424+
} catch (err) {
425+
throw new ApolloError('Failed to disconnect Task Manager', { originalError: err });
426+
}
427+
},
428+
429+
/**
430+
* Update Task Manager settings for project
431+
*
432+
* @param {ResolverObj} _obj
433+
* @param {Object} input - Task Manager settings input
434+
* @param {string} input.projectId - project ID to update
435+
* @param {boolean} input.autoTaskEnabled - enable automatic task creation
436+
* @param {number} input.taskThresholdTotalCount - threshold for auto task creation
437+
* @param {boolean} input.assignAgent - assign agent (e.g. Copilot) to tasks
438+
* @param {UserInContext} user - current authorized user {@see ../index.js}
439+
* @param {ContextFactories} factories - factories for working with models
440+
*
441+
* @returns {Project}
442+
*/
443+
async updateTaskManagerSettings(_obj, { input }, { user, factories }) {
444+
const { projectId, autoTaskEnabled, taskThresholdTotalCount, assignAgent } = input;
445+
446+
const project = await factories.projectsFactory.findById(projectId);
447+
448+
if (!project) {
449+
throw new ApolloError('There is no project with that id');
450+
}
451+
452+
if (project.workspaceId.toString() === '6213b6a01e6281087467cc7a') {
453+
throw new ApolloError('Unable to update demo project');
454+
}
455+
456+
/**
457+
* Check if taskManager is configured
458+
*/
459+
if (!project.taskManager) {
460+
throw new UserInputError('Task Manager is not configured for this project');
461+
}
462+
463+
/**
464+
* Validate taskThresholdTotalCount
465+
*/
466+
if (typeof taskThresholdTotalCount !== 'number' || taskThresholdTotalCount <= 0) {
467+
throw new UserInputError('taskThresholdTotalCount must be a positive integer greater than 0');
468+
}
469+
470+
try {
471+
/**
472+
* Update taskManager settings
473+
* Keep existing config and usage, update only settings
474+
*/
475+
const updatedTaskManager = {
476+
...project.taskManager,
477+
autoTaskEnabled,
478+
taskThresholdTotalCount,
479+
assignAgent,
480+
updatedAt: new Date(),
481+
};
482+
483+
return await project.updateProject({
484+
taskManager: updatedTaskManager,
485+
});
486+
} catch (err) {
487+
throw new ApolloError('Failed to update Task Manager settings', { originalError: err });
488+
}
489+
},
394490
},
395491
Project: {
396492
/**

src/typeDefs/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import projectNotificationsMutations from './projectNotificationsMutations';
99
import projectEventGroupingPattern from './projectEventGroupingPattern';
1010
import projectEventGroupingPatternMutations from './projectEventGroupingPatternMutations';
1111
import project from './project';
12+
import taskManager from './taskManager';
13+
import projectTaskManagerMutations from './projectTaskManagerMutations';
1214
import user from './user';
1315
import userNotifications from './userNotifications';
1416
import userNotificationsMutations from './userNotificationsMutations';
@@ -93,6 +95,8 @@ const typeDefinitions = [
9395
projectNotifications,
9496
projectNotificationsMutations,
9597
project,
98+
taskManager,
99+
projectTaskManagerMutations,
96100
user,
97101
userNotifications,
98102
userNotificationsMutations,

src/typeDefs/project.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,11 @@ type Project {
402402
Detailed info for a specific release
403403
"""
404404
releaseDetails(release: String!): ProjectReleaseDetails!
405+
406+
"""
407+
Task Manager integration configuration
408+
"""
409+
taskManager: TaskManager
405410
}
406411
407412
extend type Query {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { gql } from 'apollo-server-express';
2+
3+
export default gql`
4+
"""
5+
Input type for updating task manager settings
6+
"""
7+
input UpdateTaskManagerSettingsInput {
8+
"""
9+
Project ID to update
10+
"""
11+
projectId: ID!
12+
13+
"""
14+
Enable automatic task creation by scheduled worker
15+
"""
16+
autoTaskEnabled: Boolean!
17+
18+
"""
19+
Threshold for auto task creation (minimum totalCount)
20+
"""
21+
taskThresholdTotalCount: Int!
22+
23+
"""
24+
Assign agent (e.g. Copilot) to newly created tasks
25+
"""
26+
assignAgent: Boolean!
27+
}
28+
29+
extend type Mutation {
30+
"""
31+
Disconnect Task Manager integration from project
32+
"""
33+
disconnectTaskManager(
34+
"""
35+
Project ID to disconnect Task Manager from
36+
"""
37+
projectId: ID!
38+
): Project! @requireAdmin
39+
40+
"""
41+
Update Task Manager settings for project
42+
"""
43+
updateTaskManagerSettings(
44+
"""
45+
Task Manager settings input
46+
"""
47+
input: UpdateTaskManagerSettingsInput!
48+
): Project! @requireAdmin
49+
}
50+
`;

src/typeDefs/taskManager.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { gql } from 'apollo-server-express';
2+
3+
export default gql`
4+
"""
5+
Task Manager usage tracking for daily auto-task budget
6+
"""
7+
type TaskManagerUsage {
8+
"""
9+
UTC day boundary (e.g. 2026-01-17T00:00:00.000Z)
10+
"""
11+
dayStartUtc: DateTime!
12+
13+
"""
14+
Number of auto-created tasks since dayStartUtc
15+
"""
16+
autoTasksCreated: Int!
17+
}
18+
19+
"""
20+
GitHub Task Manager specific configuration
21+
"""
22+
type GitHubTaskManagerConfig {
23+
"""
24+
GitHub App installation ID
25+
"""
26+
installationId: String!
27+
28+
"""
29+
Repository ID
30+
"""
31+
repoId: String!
32+
33+
"""
34+
Repository full name (owner/repo)
35+
"""
36+
repoFullName: String!
37+
}
38+
39+
"""
40+
Task Manager configuration for project
41+
"""
42+
type TaskManager {
43+
"""
44+
Type of task manager (currently only 'github' is supported)
45+
"""
46+
type: String!
47+
48+
"""
49+
Enable automatic task creation by scheduled worker
50+
"""
51+
autoTaskEnabled: Boolean!
52+
53+
"""
54+
Threshold for auto task creation (minimum totalCount)
55+
"""
56+
taskThresholdTotalCount: Int!
57+
58+
"""
59+
Assign agent (e.g. Copilot) to newly created tasks
60+
"""
61+
assignAgent: Boolean!
62+
63+
"""
64+
Usage tracking for daily auto-task budget
65+
"""
66+
usage: TaskManagerUsage
67+
68+
"""
69+
Date when integration was connected
70+
"""
71+
connectedAt: DateTime!
72+
73+
"""
74+
Date when configuration was last updated
75+
"""
76+
updatedAt: DateTime!
77+
78+
"""
79+
Task manager specific configuration (typed by type)
80+
"""
81+
config: GitHubTaskManagerConfig!
82+
}
83+
`;

0 commit comments

Comments
 (0)