@transcend-io/mcp-server-assessment 0.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/README.md +96 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +17 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/graphql-BVBi59RV.mjs +1017 -0
- package/dist/graphql-BVBi59RV.mjs.map +1 -0
- package/dist/index.d.mts +204 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/package.json +56 -0
|
@@ -0,0 +1,1017 @@
|
|
|
1
|
+
import { PaginationSchema, TranscendGraphQLBase, createListResult, createToolResult, defineTool, z } from "@transcend-io/mcp-server-base";
|
|
2
|
+
import { AssessmentFormStatus, AssessmentFormTemplateStatus } from "@transcend-io/privacy-types";
|
|
3
|
+
//#region src/tools/assessments_add_section.ts
|
|
4
|
+
const AddSectionSchema = z.object({
|
|
5
|
+
template_id: z.string().describe("ID of the assessment form template to add the section to"),
|
|
6
|
+
title: z.string().describe("Title of the new section"),
|
|
7
|
+
questions: z.array(z.record(z.string(), z.unknown())).optional().describe("Array of question objects: [{title, type, subType?, description?, placeholder?, isRequired?, referenceId?, answerOptions?: [{value}], allowSelectOther?, requireRiskEvaluation?}]")
|
|
8
|
+
});
|
|
9
|
+
function createAssessmentsAddSectionTool(clients) {
|
|
10
|
+
const graphql = clients.graphql;
|
|
11
|
+
return defineTool({
|
|
12
|
+
name: "assessments_add_section",
|
|
13
|
+
description: "Add a new section (with optional inline questions) to an existing assessment form template. Useful for building templates incrementally or adding sections to imported templates. Same auto-corrections as assessments_create_template apply to questions.",
|
|
14
|
+
category: "Assessments",
|
|
15
|
+
readOnly: false,
|
|
16
|
+
confirmationHint: "Adds a section to the assessment template",
|
|
17
|
+
annotations: {
|
|
18
|
+
readOnlyHint: false,
|
|
19
|
+
destructiveHint: false,
|
|
20
|
+
idempotentHint: false
|
|
21
|
+
},
|
|
22
|
+
zodSchema: AddSectionSchema,
|
|
23
|
+
handler: async ({ template_id, title, questions }) => {
|
|
24
|
+
return createToolResult(true, {
|
|
25
|
+
section: await graphql.createAssessmentSection({
|
|
26
|
+
assessmentFormTemplateId: template_id,
|
|
27
|
+
title,
|
|
28
|
+
questions
|
|
29
|
+
}),
|
|
30
|
+
message: `Section "${title}" added to template successfully`
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/tools/assessments_answer_question.ts
|
|
37
|
+
const AnswerQuestionValueSchema = z.object({
|
|
38
|
+
value: z.string(),
|
|
39
|
+
isUserCreated: z.boolean()
|
|
40
|
+
});
|
|
41
|
+
const AnswerQuestionSchema = z.object({
|
|
42
|
+
assessment_question_id: z.string().describe("ID of the assessment question to answer"),
|
|
43
|
+
assessment_answer_ids: z.array(z.string()).optional().describe("IDs of existing answer options to select (for SINGLE_SELECT/MULTI_SELECT questions)"),
|
|
44
|
+
assessment_answer_values: z.array(AnswerQuestionValueSchema).optional().describe("Free-text answer values to create and select (for text questions). Each item: {value: string, isUserCreated: boolean}")
|
|
45
|
+
});
|
|
46
|
+
function createAssessmentsAnswerQuestionTool(clients) {
|
|
47
|
+
const graphql = clients.graphql;
|
|
48
|
+
return defineTool({
|
|
49
|
+
name: "assessments_answer_question",
|
|
50
|
+
description: "Answer an assessment question by selecting existing answer options or providing free-text values. For SINGLE_SELECT/MULTI_SELECT questions, provide assessmentAnswerIds from the answerOptions. For SHORT_ANSWER_TEXT/LONG_ANSWER_TEXT, provide assessmentAnswerValues with {value, isUserCreated: true}.",
|
|
51
|
+
category: "Assessments",
|
|
52
|
+
readOnly: false,
|
|
53
|
+
confirmationHint: "Records answer to the assessment question",
|
|
54
|
+
annotations: {
|
|
55
|
+
readOnlyHint: false,
|
|
56
|
+
destructiveHint: false,
|
|
57
|
+
idempotentHint: true
|
|
58
|
+
},
|
|
59
|
+
zodSchema: AnswerQuestionSchema,
|
|
60
|
+
handler: async ({ assessment_question_id, assessment_answer_ids, assessment_answer_values }) => {
|
|
61
|
+
const input = { assessmentQuestionId: assessment_question_id };
|
|
62
|
+
if (assessment_answer_ids) input.assessmentAnswerIds = assessment_answer_ids;
|
|
63
|
+
if (assessment_answer_values) input.assessmentAnswerValues = assessment_answer_values;
|
|
64
|
+
return createToolResult(true, {
|
|
65
|
+
selectedAnswers: await graphql.selectAssessmentQuestionAnswers(input),
|
|
66
|
+
message: "Assessment question answered successfully"
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/tools/_helpers.ts
|
|
73
|
+
/**
|
|
74
|
+
* Resolves a template_id to an assessment group ID by searching through all groups.
|
|
75
|
+
* Returns either the group ID or an error result.
|
|
76
|
+
*/
|
|
77
|
+
async function resolveTemplateToGroupId(graphql, templateId) {
|
|
78
|
+
const matchingGroups = (await graphql.listAssessmentGroups({ first: 100 })).nodes.filter((g) => g.assessmentFormTemplate?.id === templateId);
|
|
79
|
+
if (matchingGroups.length === 0) return { error: createToolResult(false, void 0, `No assessment group found for template_id "${templateId}". Use assessments_list_groups to see available groups.`) };
|
|
80
|
+
if (matchingGroups.length > 1) return { error: createToolResult(false, void 0, `Multiple assessment groups found for template_id "${templateId}" (group IDs: ${matchingGroups.map((g) => g.id).join(", ")}). Please specify assessment_group_id explicitly. Use assessments_list_groups to find available groups.`) };
|
|
81
|
+
return { groupId: matchingGroups[0].id };
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/tools/assessments_create.ts
|
|
85
|
+
const CreateAssessmentSchema = z.object({
|
|
86
|
+
title: z.string().describe("Title of the assessment"),
|
|
87
|
+
assessment_group_id: z.string().optional().describe("ID of the assessment group to create the assessment in (preferred). Use assessments_list_groups to find available groups."),
|
|
88
|
+
template_id: z.string().optional().describe("ID of the assessment template. If assessment_group_id is not provided, the first group using this template will be used."),
|
|
89
|
+
assignee_ids: z.array(z.string()).optional().describe("Array of user IDs to assign the assessment to")
|
|
90
|
+
});
|
|
91
|
+
function createAssessmentsCreateTool(clients) {
|
|
92
|
+
const graphql = clients.graphql;
|
|
93
|
+
return defineTool({
|
|
94
|
+
name: "assessments_create",
|
|
95
|
+
description: "Create a new privacy assessment within an assessment group. Assessment groups are linked to templates. You can provide either an assessment_group_id directly, or a template_id to auto-resolve the first matching group. Use assessments_list_groups to find available groups.",
|
|
96
|
+
category: "Assessments",
|
|
97
|
+
readOnly: false,
|
|
98
|
+
confirmationHint: "Creates a new privacy assessment",
|
|
99
|
+
annotations: {
|
|
100
|
+
readOnlyHint: false,
|
|
101
|
+
destructiveHint: false,
|
|
102
|
+
idempotentHint: false
|
|
103
|
+
},
|
|
104
|
+
zodSchema: CreateAssessmentSchema,
|
|
105
|
+
handler: async ({ title, assessment_group_id, template_id, assignee_ids }) => {
|
|
106
|
+
let assessmentGroupId = assessment_group_id;
|
|
107
|
+
if (!assessmentGroupId && template_id) {
|
|
108
|
+
const resolved = await resolveTemplateToGroupId(graphql, template_id);
|
|
109
|
+
if ("error" in resolved) return resolved.error;
|
|
110
|
+
assessmentGroupId = resolved.groupId;
|
|
111
|
+
}
|
|
112
|
+
if (!assessmentGroupId) return createToolResult(false, void 0, "Either assessment_group_id or template_id must be provided. Use assessments_list_groups to find available groups.");
|
|
113
|
+
return createToolResult(true, {
|
|
114
|
+
assessment: await graphql.createAssessment({
|
|
115
|
+
title,
|
|
116
|
+
assessmentGroupId,
|
|
117
|
+
assigneeIds: assignee_ids
|
|
118
|
+
}),
|
|
119
|
+
message: `Assessment "${title}" created successfully`
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/tools/assessments_create_group.ts
|
|
126
|
+
const CreateGroupSchema = z.object({
|
|
127
|
+
title: z.string().describe("Title of the assessment group"),
|
|
128
|
+
template_id: z.string().describe("ID of the assessment template to link this group to"),
|
|
129
|
+
description: z.string().optional().describe("Description of the assessment group (optional)"),
|
|
130
|
+
reviewer_ids: z.array(z.string()).optional().describe("IDs of users assigned to review new assessments in this group (optional)")
|
|
131
|
+
});
|
|
132
|
+
function createAssessmentsCreateGroupTool(clients) {
|
|
133
|
+
const graphql = clients.graphql;
|
|
134
|
+
return defineTool({
|
|
135
|
+
name: "assessments_create_group",
|
|
136
|
+
description: "Create a new assessment group linked to a template. Assessment groups are containers for assessments.",
|
|
137
|
+
category: "Assessments",
|
|
138
|
+
readOnly: false,
|
|
139
|
+
confirmationHint: "Creates a new assessment group",
|
|
140
|
+
annotations: {
|
|
141
|
+
readOnlyHint: false,
|
|
142
|
+
destructiveHint: false,
|
|
143
|
+
idempotentHint: false
|
|
144
|
+
},
|
|
145
|
+
zodSchema: CreateGroupSchema,
|
|
146
|
+
handler: async ({ title, template_id, description, reviewer_ids }) => {
|
|
147
|
+
return createToolResult(true, {
|
|
148
|
+
assessmentGroup: await graphql.createAssessmentGroup({
|
|
149
|
+
title,
|
|
150
|
+
assessmentFormTemplateId: template_id,
|
|
151
|
+
description,
|
|
152
|
+
reviewerIds: reviewer_ids
|
|
153
|
+
}),
|
|
154
|
+
message: `Assessment group "${title}" created successfully`
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/tools/assessments_create_template.ts
|
|
161
|
+
const CreateTemplateSchema = z.object({
|
|
162
|
+
title: z.string().describe("Title of the assessment form template"),
|
|
163
|
+
description: z.string().optional().describe("Description of the template"),
|
|
164
|
+
status: z.nativeEnum(AssessmentFormTemplateStatus).optional().describe("Template status: DRAFT or PUBLISHED (default: DRAFT)"),
|
|
165
|
+
sections: z.array(z.record(z.string(), z.unknown())).optional().describe("Array of section objects with title and optional questions array")
|
|
166
|
+
});
|
|
167
|
+
function createAssessmentsCreateTemplateTool(clients) {
|
|
168
|
+
const graphql = clients.graphql;
|
|
169
|
+
return defineTool({
|
|
170
|
+
name: "assessments_create_template",
|
|
171
|
+
description: "Create a new assessment form template with sections and questions inline. This is the \"import\" side of the JSON import/export workflow. You can provide the full template structure (sections with questions and answer options) in a single call. Question types: LONG_ANSWER_TEXT, SHORT_ANSWER_TEXT, SINGLE_SELECT, MULTI_SELECT, FILE. SubTypes: NONE, CUSTOM, USER, TEAM, DATA_SUB_CATEGORY, HAS_PERSONAL_DATA, ATTRIBUTE_KEY, SENSITIVE_CATEGORY. Auto-corrections: referenceId is auto-generated as UUID if missing or not UUID format; subType is auto-set to CUSTOM when allowSelectOther is true; requireRiskEvaluation is ignored when no riskFrameworkId is provided.",
|
|
172
|
+
category: "Assessments",
|
|
173
|
+
readOnly: false,
|
|
174
|
+
confirmationHint: "Creates a new assessment form template",
|
|
175
|
+
annotations: {
|
|
176
|
+
readOnlyHint: false,
|
|
177
|
+
destructiveHint: false,
|
|
178
|
+
idempotentHint: false
|
|
179
|
+
},
|
|
180
|
+
zodSchema: CreateTemplateSchema,
|
|
181
|
+
handler: async ({ title, description, status, sections }) => {
|
|
182
|
+
const input = {
|
|
183
|
+
title,
|
|
184
|
+
description,
|
|
185
|
+
status: status ?? "DRAFT",
|
|
186
|
+
sections
|
|
187
|
+
};
|
|
188
|
+
return createToolResult(true, {
|
|
189
|
+
template: await graphql.createAssessmentFormTemplate(input),
|
|
190
|
+
message: `Assessment template "${title}" created successfully`
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/tools/assessments_export_template.ts
|
|
197
|
+
const ExportTemplateSchema = z.object({ template_id: z.string().describe("ID of the assessment form template to export") });
|
|
198
|
+
function createAssessmentsExportTemplateTool(clients) {
|
|
199
|
+
const graphql = clients.graphql;
|
|
200
|
+
return defineTool({
|
|
201
|
+
name: "assessments_export_template",
|
|
202
|
+
description: "Export a full assessment form template as JSON, including all sections, questions, answer options, and configuration. This is the \"export\" side of the JSON import/export workflow. The output can be used as input for assessments_create_template to recreate the template elsewhere.",
|
|
203
|
+
category: "Assessments",
|
|
204
|
+
readOnly: true,
|
|
205
|
+
annotations: {
|
|
206
|
+
readOnlyHint: true,
|
|
207
|
+
destructiveHint: false,
|
|
208
|
+
idempotentHint: true
|
|
209
|
+
},
|
|
210
|
+
zodSchema: ExportTemplateSchema,
|
|
211
|
+
handler: async ({ template_id }) => {
|
|
212
|
+
const template = await graphql.getAssessmentFormTemplate(template_id);
|
|
213
|
+
return createToolResult(true, {
|
|
214
|
+
_exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
215
|
+
_format: "transcend-assessment-template-v1",
|
|
216
|
+
template: {
|
|
217
|
+
title: template.title,
|
|
218
|
+
description: template.description,
|
|
219
|
+
status: template.status,
|
|
220
|
+
sections: template.sections.map((section) => ({
|
|
221
|
+
title: section.title,
|
|
222
|
+
questions: section.questions.map((q) => ({
|
|
223
|
+
title: q.title,
|
|
224
|
+
type: q.type,
|
|
225
|
+
subType: q.subType,
|
|
226
|
+
description: q.description,
|
|
227
|
+
placeholder: q.placeholder,
|
|
228
|
+
isRequired: q.isRequired,
|
|
229
|
+
referenceId: q.referenceId,
|
|
230
|
+
allowSelectOther: q.allowSelectOther,
|
|
231
|
+
requireRiskEvaluation: q.requireRiskEvaluation,
|
|
232
|
+
answerOptions: q.answerOptions.map((opt) => ({ value: opt.value }))
|
|
233
|
+
}))
|
|
234
|
+
}))
|
|
235
|
+
},
|
|
236
|
+
_raw: template
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/tools/assessments_get.ts
|
|
243
|
+
const GetAssessmentSchema = z.object({ assessment_id: z.string().describe("ID of the assessment to retrieve") });
|
|
244
|
+
function createAssessmentsGetTool(clients) {
|
|
245
|
+
const graphql = clients.graphql;
|
|
246
|
+
return defineTool({
|
|
247
|
+
name: "assessments_get",
|
|
248
|
+
description: "Get detailed information about a specific assessment including questions and responses",
|
|
249
|
+
category: "Assessments",
|
|
250
|
+
readOnly: true,
|
|
251
|
+
annotations: {
|
|
252
|
+
readOnlyHint: true,
|
|
253
|
+
destructiveHint: false,
|
|
254
|
+
idempotentHint: true
|
|
255
|
+
},
|
|
256
|
+
zodSchema: GetAssessmentSchema,
|
|
257
|
+
handler: async ({ assessment_id }) => {
|
|
258
|
+
return createToolResult(true, await graphql.getAssessment(assessment_id));
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region src/tools/assessments_list.ts
|
|
264
|
+
const AssessmentStatusEnum = z.nativeEnum(AssessmentFormStatus);
|
|
265
|
+
const ListAssessmentsSchema = z.object({ status: AssessmentStatusEnum.optional().describe("Filter by assessment status") }).merge(PaginationSchema);
|
|
266
|
+
function createAssessmentsListTool(clients) {
|
|
267
|
+
const graphql = clients.graphql;
|
|
268
|
+
return defineTool({
|
|
269
|
+
name: "assessments_list",
|
|
270
|
+
description: "List all privacy assessments in your organization. Supports filtering by status. Note: Cursor pagination is not supported (max 100 results).",
|
|
271
|
+
category: "Assessments",
|
|
272
|
+
readOnly: true,
|
|
273
|
+
annotations: {
|
|
274
|
+
readOnlyHint: true,
|
|
275
|
+
destructiveHint: false,
|
|
276
|
+
idempotentHint: true
|
|
277
|
+
},
|
|
278
|
+
zodSchema: ListAssessmentsSchema,
|
|
279
|
+
handler: async ({ status, limit, cursor }) => {
|
|
280
|
+
const result = await graphql.listAssessments({
|
|
281
|
+
first: limit,
|
|
282
|
+
after: cursor,
|
|
283
|
+
filterBy: status ? { statuses: [status] } : void 0
|
|
284
|
+
});
|
|
285
|
+
return createListResult(result.nodes, {
|
|
286
|
+
totalCount: result.totalCount,
|
|
287
|
+
hasNextPage: result.pageInfo?.hasNextPage
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/tools/assessments_list_groups.ts
|
|
294
|
+
const ListGroupsSchema = PaginationSchema;
|
|
295
|
+
function createAssessmentsListGroupsTool(clients) {
|
|
296
|
+
const graphql = clients.graphql;
|
|
297
|
+
return defineTool({
|
|
298
|
+
name: "assessments_list_groups",
|
|
299
|
+
description: "List all assessment groups. Groups are containers for assessments and are linked to templates. Use this to find the right group ID for creating assessments.",
|
|
300
|
+
category: "Assessments",
|
|
301
|
+
readOnly: true,
|
|
302
|
+
annotations: {
|
|
303
|
+
readOnlyHint: true,
|
|
304
|
+
destructiveHint: false,
|
|
305
|
+
idempotentHint: true
|
|
306
|
+
},
|
|
307
|
+
zodSchema: ListGroupsSchema,
|
|
308
|
+
handler: async ({ limit, cursor }) => {
|
|
309
|
+
const result = await graphql.listAssessmentGroups({
|
|
310
|
+
first: limit,
|
|
311
|
+
after: cursor
|
|
312
|
+
});
|
|
313
|
+
return createListResult(result.nodes, {
|
|
314
|
+
totalCount: result.totalCount,
|
|
315
|
+
hasNextPage: result.pageInfo?.hasNextPage
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
//#endregion
|
|
321
|
+
//#region src/tools/assessments_list_templates.ts
|
|
322
|
+
const ListTemplatesSchema = PaginationSchema;
|
|
323
|
+
function createAssessmentsListTemplatesTool(clients) {
|
|
324
|
+
const graphql = clients.graphql;
|
|
325
|
+
return defineTool({
|
|
326
|
+
name: "assessments_list_templates",
|
|
327
|
+
description: "List all available assessment templates. Note: Cursor pagination is not supported by the Transcend API for templates - use limit to control results (max 100).",
|
|
328
|
+
category: "Assessments",
|
|
329
|
+
readOnly: true,
|
|
330
|
+
annotations: {
|
|
331
|
+
readOnlyHint: true,
|
|
332
|
+
destructiveHint: false,
|
|
333
|
+
idempotentHint: true
|
|
334
|
+
},
|
|
335
|
+
zodSchema: ListTemplatesSchema,
|
|
336
|
+
handler: async ({ limit, cursor }) => {
|
|
337
|
+
const result = await graphql.listAssessmentTemplates({
|
|
338
|
+
first: limit,
|
|
339
|
+
after: cursor
|
|
340
|
+
});
|
|
341
|
+
return createListResult(result.nodes, {
|
|
342
|
+
totalCount: result.totalCount,
|
|
343
|
+
hasNextPage: result.pageInfo?.hasNextPage
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
//#endregion
|
|
349
|
+
//#region src/tools/assessments_prefill.ts
|
|
350
|
+
const PrefillSchema = z.object({
|
|
351
|
+
title: z.string().describe("Title for the new assessment form"),
|
|
352
|
+
template_id: z.string().optional().describe("Template ID to create the form from. Will auto-resolve to the first matching assessment group."),
|
|
353
|
+
assessment_group_id: z.string().optional().describe("Assessment group ID (alternative to template_id)"),
|
|
354
|
+
answers: z.record(z.string(), z.union([z.string(), z.array(z.string())])).describe("Map of answers keyed by question title or referenceId. Values should be strings for text/single-select, or arrays of strings for multi-select."),
|
|
355
|
+
assignee_ids: z.array(z.string()).optional().describe("Internal user IDs to assign the form to (optional)"),
|
|
356
|
+
assignee_emails: z.array(z.string()).optional().describe("External email addresses to assign the form to (optional)"),
|
|
357
|
+
reviewer_ids: z.array(z.string()).optional().describe("User IDs to set as reviewers (optional)"),
|
|
358
|
+
submit_for_review: z.boolean().optional().describe("Whether to automatically submit the form for review after prefilling (default: false)")
|
|
359
|
+
});
|
|
360
|
+
function createAssessmentsPrefillTool(clients) {
|
|
361
|
+
const graphql = clients.graphql;
|
|
362
|
+
return defineTool({
|
|
363
|
+
name: "assessments_prefill",
|
|
364
|
+
description: "Convenience tool: Create a new assessment form, AI-prefill all the answers, and assign it to a reviewer. Combines: create form → get questions → answer each question → assign reviewers → optionally submit for review. Provide answers as a map of {questionTitle: answer} or {referenceId: answer}. For SINGLE_SELECT/MULTI_SELECT, the answer should match the exact text of the answer option(s). For text questions, provide the free-text answer string. For multi-select, provide an array of answer option values.",
|
|
365
|
+
category: "Assessments",
|
|
366
|
+
readOnly: false,
|
|
367
|
+
confirmationHint: "Creates assessment, prefills answers, assigns reviewers",
|
|
368
|
+
annotations: {
|
|
369
|
+
readOnlyHint: false,
|
|
370
|
+
destructiveHint: false,
|
|
371
|
+
idempotentHint: false
|
|
372
|
+
},
|
|
373
|
+
zodSchema: PrefillSchema,
|
|
374
|
+
handler: async ({ answers, title, assessment_group_id, template_id, assignee_ids, assignee_emails, reviewer_ids, submit_for_review }) => {
|
|
375
|
+
let assessmentGroupId = assessment_group_id;
|
|
376
|
+
if (!assessmentGroupId && template_id) {
|
|
377
|
+
const resolved = await resolveTemplateToGroupId(graphql, template_id);
|
|
378
|
+
if ("error" in resolved) return resolved.error;
|
|
379
|
+
assessmentGroupId = resolved.groupId;
|
|
380
|
+
}
|
|
381
|
+
if (!assessmentGroupId) return createToolResult(false, void 0, "Either template_id or assessment_group_id is required.");
|
|
382
|
+
const assessmentId = (await graphql.createAssessment({
|
|
383
|
+
title,
|
|
384
|
+
assessmentGroupId
|
|
385
|
+
})).id;
|
|
386
|
+
const fullForm = await graphql.getAssessment(assessmentId);
|
|
387
|
+
if (!fullForm.sections || fullForm.sections.length === 0) return createToolResult(true, {
|
|
388
|
+
assessment: fullForm,
|
|
389
|
+
message: "Assessment created but has no sections/questions to prefill.",
|
|
390
|
+
answersApplied: 0
|
|
391
|
+
});
|
|
392
|
+
const results = [];
|
|
393
|
+
let answersApplied = 0;
|
|
394
|
+
let answersSkipped = 0;
|
|
395
|
+
for (const section of fullForm.sections) {
|
|
396
|
+
if (!section.questions) continue;
|
|
397
|
+
for (const question of section.questions) {
|
|
398
|
+
const answerKey = Object.keys(answers).find((key) => key === question.referenceId || key.toLowerCase() === (question.title || "").toLowerCase() || key === question.id);
|
|
399
|
+
if (!answerKey) {
|
|
400
|
+
results.push({
|
|
401
|
+
question: question.title || question.id,
|
|
402
|
+
status: "skipped"
|
|
403
|
+
});
|
|
404
|
+
answersSkipped++;
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
const answerValue = answers[answerKey];
|
|
408
|
+
if (answerValue === void 0) {
|
|
409
|
+
results.push({
|
|
410
|
+
question: question.title || question.id,
|
|
411
|
+
status: "skipped"
|
|
412
|
+
});
|
|
413
|
+
answersSkipped++;
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
const qType = (question.type || "").toUpperCase();
|
|
418
|
+
if (qType === "SINGLE_SELECT" || qType === "MULTI_SELECT") {
|
|
419
|
+
const answerValues = Array.isArray(answerValue) ? answerValue : [answerValue];
|
|
420
|
+
const matchedIds = [];
|
|
421
|
+
for (const val of answerValues) {
|
|
422
|
+
const matchedOption = (question.answerOptions || []).find((opt) => opt.value.toLowerCase() === val.toLowerCase());
|
|
423
|
+
if (matchedOption) matchedIds.push(matchedOption.id);
|
|
424
|
+
}
|
|
425
|
+
if (matchedIds.length > 0) {
|
|
426
|
+
await graphql.selectAssessmentQuestionAnswers({
|
|
427
|
+
assessmentQuestionId: question.id,
|
|
428
|
+
assessmentAnswerIds: matchedIds
|
|
429
|
+
});
|
|
430
|
+
answersApplied++;
|
|
431
|
+
results.push({
|
|
432
|
+
question: question.title || question.id,
|
|
433
|
+
status: "answered",
|
|
434
|
+
answer: answerValues.join(", ")
|
|
435
|
+
});
|
|
436
|
+
} else {
|
|
437
|
+
await graphql.selectAssessmentQuestionAnswers({
|
|
438
|
+
assessmentQuestionId: question.id,
|
|
439
|
+
assessmentAnswerValues: answerValues.map((v) => ({
|
|
440
|
+
value: v,
|
|
441
|
+
isUserCreated: true
|
|
442
|
+
}))
|
|
443
|
+
});
|
|
444
|
+
answersApplied++;
|
|
445
|
+
results.push({
|
|
446
|
+
question: question.title || question.id,
|
|
447
|
+
status: "answered (custom value)",
|
|
448
|
+
answer: answerValues.join(", ")
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
const textValue = Array.isArray(answerValue) ? answerValue.join("\n") : answerValue;
|
|
453
|
+
await graphql.selectAssessmentQuestionAnswers({
|
|
454
|
+
assessmentQuestionId: question.id,
|
|
455
|
+
assessmentAnswerValues: [{
|
|
456
|
+
value: textValue,
|
|
457
|
+
isUserCreated: true
|
|
458
|
+
}]
|
|
459
|
+
});
|
|
460
|
+
answersApplied++;
|
|
461
|
+
results.push({
|
|
462
|
+
question: question.title || question.id,
|
|
463
|
+
status: "answered",
|
|
464
|
+
answer: textValue.length > 100 ? textValue.substring(0, 100) + "..." : textValue
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
} catch (err) {
|
|
468
|
+
results.push({
|
|
469
|
+
question: question.title || question.id,
|
|
470
|
+
status: `error: ${err instanceof Error ? err.message : String(err)}`
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
let assignmentResult = null;
|
|
476
|
+
if (assignee_ids || assignee_emails) assignmentResult = await graphql.updateAssessmentFormAssignees({
|
|
477
|
+
id: assessmentId,
|
|
478
|
+
assigneeIds: assignee_ids,
|
|
479
|
+
externalAssigneeEmails: assignee_emails
|
|
480
|
+
});
|
|
481
|
+
if (reviewer_ids) await graphql.updateAssessment({
|
|
482
|
+
id: assessmentId,
|
|
483
|
+
reviewerIds: reviewer_ids
|
|
484
|
+
});
|
|
485
|
+
let submitResult = null;
|
|
486
|
+
if (submit_for_review) {
|
|
487
|
+
const sectionIds = fullForm.sections.map((s) => s.id);
|
|
488
|
+
if (sectionIds.length > 0) submitResult = await graphql.submitAssessmentForReview({
|
|
489
|
+
id: assessmentId,
|
|
490
|
+
assessmentSectionIds: sectionIds
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return createToolResult(true, {
|
|
494
|
+
assessmentId,
|
|
495
|
+
title,
|
|
496
|
+
answersApplied,
|
|
497
|
+
answersSkipped,
|
|
498
|
+
totalQuestions: results.length,
|
|
499
|
+
results,
|
|
500
|
+
assignment: assignmentResult ? {
|
|
501
|
+
status: assignmentResult.status,
|
|
502
|
+
message: "Assignees updated"
|
|
503
|
+
} : null,
|
|
504
|
+
submittedForReview: !!submitResult,
|
|
505
|
+
message: `Assessment "${title}" created and prefilled with ${answersApplied}/${results.length} answers. ` + (assignmentResult ? `Assigned to reviewers. ` : "") + (submitResult ? "Submitted for review." : "Ready for manual submission.")
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
//#endregion
|
|
511
|
+
//#region src/tools/assessments_submit_response.ts
|
|
512
|
+
const SubmitResponseSchema = z.object({
|
|
513
|
+
assessment_id: z.string().describe("ID of the assessment to submit for review"),
|
|
514
|
+
assessment_section_ids: z.array(z.string()).describe("Array of section IDs to submit for review. Required by the API.")
|
|
515
|
+
});
|
|
516
|
+
function createAssessmentsSubmitResponseTool(clients) {
|
|
517
|
+
const graphql = clients.graphql;
|
|
518
|
+
return defineTool({
|
|
519
|
+
name: "assessments_submit_response",
|
|
520
|
+
description: "Submit an assessment form for review. Optionally specify which sections to submit. This transitions the assessment toward the IN_REVIEW status.",
|
|
521
|
+
category: "Assessments",
|
|
522
|
+
readOnly: false,
|
|
523
|
+
confirmationHint: "Submits assessment for review — cannot be undone",
|
|
524
|
+
annotations: {
|
|
525
|
+
readOnlyHint: false,
|
|
526
|
+
destructiveHint: true,
|
|
527
|
+
idempotentHint: false
|
|
528
|
+
},
|
|
529
|
+
zodSchema: SubmitResponseSchema,
|
|
530
|
+
handler: async ({ assessment_id, assessment_section_ids }) => {
|
|
531
|
+
return createToolResult(true, {
|
|
532
|
+
assessment: await graphql.submitAssessmentForReview({
|
|
533
|
+
id: assessment_id,
|
|
534
|
+
assessmentSectionIds: assessment_section_ids
|
|
535
|
+
}),
|
|
536
|
+
message: "Assessment submitted for review successfully"
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
//#endregion
|
|
542
|
+
//#region src/tools/assessments_update.ts
|
|
543
|
+
const UpdateAssessmentSchema = z.object({
|
|
544
|
+
assessment_id: z.string().describe("ID of the assessment to update"),
|
|
545
|
+
title: z.string().optional().describe("New title for the assessment"),
|
|
546
|
+
description: z.string().optional().describe("New description"),
|
|
547
|
+
reviewer_ids: z.array(z.string()).optional().describe("IDs of users assigned to review this assessment"),
|
|
548
|
+
due_date: z.string().optional().describe("New due date (ISO format)"),
|
|
549
|
+
status: AssessmentStatusEnum.optional().describe("New status")
|
|
550
|
+
});
|
|
551
|
+
function createAssessmentsUpdateTool(clients) {
|
|
552
|
+
const graphql = clients.graphql;
|
|
553
|
+
return defineTool({
|
|
554
|
+
name: "assessments_update",
|
|
555
|
+
description: "Update an existing assessment",
|
|
556
|
+
category: "Assessments",
|
|
557
|
+
readOnly: false,
|
|
558
|
+
confirmationHint: "Updates the assessment",
|
|
559
|
+
annotations: {
|
|
560
|
+
readOnlyHint: false,
|
|
561
|
+
destructiveHint: false,
|
|
562
|
+
idempotentHint: true
|
|
563
|
+
},
|
|
564
|
+
zodSchema: UpdateAssessmentSchema,
|
|
565
|
+
handler: async ({ assessment_id, title, description, reviewer_ids, due_date, status }) => {
|
|
566
|
+
return createToolResult(true, {
|
|
567
|
+
assessment: await graphql.updateAssessment({
|
|
568
|
+
id: assessment_id,
|
|
569
|
+
title,
|
|
570
|
+
description,
|
|
571
|
+
reviewerIds: reviewer_ids,
|
|
572
|
+
dueDate: due_date,
|
|
573
|
+
status
|
|
574
|
+
}),
|
|
575
|
+
message: "Assessment updated successfully"
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
//#endregion
|
|
581
|
+
//#region src/tools/assessments_update_assignees.ts
|
|
582
|
+
const UpdateAssigneesSchema = z.object({
|
|
583
|
+
assessment_id: z.string().describe("ID of the assessment form to update assignees for"),
|
|
584
|
+
assignee_ids: z.array(z.string()).optional().describe("Array of internal user IDs to assign to the assessment"),
|
|
585
|
+
external_assignee_emails: z.array(z.string()).optional().describe("Array of external email addresses to assign to the assessment")
|
|
586
|
+
});
|
|
587
|
+
function createAssessmentsUpdateAssigneesTool(clients) {
|
|
588
|
+
const graphql = clients.graphql;
|
|
589
|
+
return defineTool({
|
|
590
|
+
name: "assessments_update_assignees",
|
|
591
|
+
description: "Assign internal users (by ID) or external users (by email) to an assessment form. This also transitions DRAFT assessments to SHARED status.",
|
|
592
|
+
category: "Assessments",
|
|
593
|
+
readOnly: false,
|
|
594
|
+
confirmationHint: "Assigns users to the assessment form",
|
|
595
|
+
annotations: {
|
|
596
|
+
readOnlyHint: false,
|
|
597
|
+
destructiveHint: false,
|
|
598
|
+
idempotentHint: true
|
|
599
|
+
},
|
|
600
|
+
zodSchema: UpdateAssigneesSchema,
|
|
601
|
+
handler: async ({ assessment_id, assignee_ids, external_assignee_emails }) => {
|
|
602
|
+
const result = await graphql.updateAssessmentFormAssignees({
|
|
603
|
+
id: assessment_id,
|
|
604
|
+
assigneeIds: assignee_ids,
|
|
605
|
+
externalAssigneeEmails: external_assignee_emails
|
|
606
|
+
});
|
|
607
|
+
return createToolResult(true, {
|
|
608
|
+
assessment: result,
|
|
609
|
+
message: `Assessment assignees updated successfully. Status: ${result.status}`
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
//#endregion
|
|
615
|
+
//#region src/tools/index.ts
|
|
616
|
+
function getAssessmentTools(clients) {
|
|
617
|
+
return [
|
|
618
|
+
createAssessmentsListTool(clients),
|
|
619
|
+
createAssessmentsGetTool(clients),
|
|
620
|
+
createAssessmentsCreateTool(clients),
|
|
621
|
+
createAssessmentsCreateGroupTool(clients),
|
|
622
|
+
createAssessmentsListGroupsTool(clients),
|
|
623
|
+
createAssessmentsUpdateTool(clients),
|
|
624
|
+
createAssessmentsListTemplatesTool(clients),
|
|
625
|
+
createAssessmentsUpdateAssigneesTool(clients),
|
|
626
|
+
createAssessmentsAnswerQuestionTool(clients),
|
|
627
|
+
createAssessmentsSubmitResponseTool(clients),
|
|
628
|
+
createAssessmentsCreateTemplateTool(clients),
|
|
629
|
+
createAssessmentsAddSectionTool(clients),
|
|
630
|
+
createAssessmentsExportTemplateTool(clients),
|
|
631
|
+
createAssessmentsPrefillTool(clients)
|
|
632
|
+
];
|
|
633
|
+
}
|
|
634
|
+
//#endregion
|
|
635
|
+
//#region src/graphql.ts
|
|
636
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
637
|
+
function generateUUID() {
|
|
638
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
639
|
+
const r = Math.random() * 16 | 0;
|
|
640
|
+
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
function normalizeQuestion(q) {
|
|
644
|
+
let { referenceId, subType, allowSelectOther, requireRiskEvaluation } = q;
|
|
645
|
+
if (!referenceId || !UUID_RE.test(referenceId)) referenceId = generateUUID();
|
|
646
|
+
if (allowSelectOther && (!subType || subType === "NONE")) subType = "CUSTOM";
|
|
647
|
+
if (requireRiskEvaluation && !q.riskFrameworkId) requireRiskEvaluation = false;
|
|
648
|
+
return {
|
|
649
|
+
title: q.title,
|
|
650
|
+
type: q.type,
|
|
651
|
+
subType: subType || "NONE",
|
|
652
|
+
placeholder: q.placeholder || "",
|
|
653
|
+
description: q.description || "",
|
|
654
|
+
isRequired: q.isRequired ?? false,
|
|
655
|
+
referenceId,
|
|
656
|
+
answerOptions: q.answerOptions || [],
|
|
657
|
+
allowSelectOther: allowSelectOther ?? false,
|
|
658
|
+
requireRiskEvaluation: requireRiskEvaluation ?? false,
|
|
659
|
+
...q.riskLogic && { riskLogic: q.riskLogic },
|
|
660
|
+
...q.riskCategoryIds && { riskCategoryIds: q.riskCategoryIds },
|
|
661
|
+
...q.riskFrameworkId && { riskFrameworkId: q.riskFrameworkId },
|
|
662
|
+
...q.displayLogic && { displayLogic: q.displayLogic }
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
var AssessmentsMixin = class extends TranscendGraphQLBase {
|
|
666
|
+
async listAssessments(options) {
|
|
667
|
+
const data = await this.makeRequest(`
|
|
668
|
+
query ListAssessments($first: Int, $filterBy: AssessmentFormFiltersInput) {
|
|
669
|
+
assessmentForms(first: $first, filterBy: $filterBy) {
|
|
670
|
+
nodes {
|
|
671
|
+
id
|
|
672
|
+
title
|
|
673
|
+
status
|
|
674
|
+
createdAt
|
|
675
|
+
}
|
|
676
|
+
totalCount
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
`, {
|
|
680
|
+
first: Math.min(options?.first || 50, 100),
|
|
681
|
+
filterBy: options?.filterBy?.statuses ? { statuses: options.filterBy.statuses } : void 0
|
|
682
|
+
});
|
|
683
|
+
return {
|
|
684
|
+
nodes: data.assessmentForms.nodes,
|
|
685
|
+
pageInfo: {
|
|
686
|
+
hasNextPage: data.assessmentForms.nodes.length < data.assessmentForms.totalCount,
|
|
687
|
+
hasPreviousPage: false
|
|
688
|
+
},
|
|
689
|
+
totalCount: data.assessmentForms.totalCount
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
async getAssessment(id) {
|
|
693
|
+
const node = (await this.makeRequest(`
|
|
694
|
+
query GetAssessment($ids: [ID!]!) {
|
|
695
|
+
assessmentForms(first: 1, filterBy: { ids: $ids }) {
|
|
696
|
+
nodes {
|
|
697
|
+
id
|
|
698
|
+
title
|
|
699
|
+
status
|
|
700
|
+
dueDate
|
|
701
|
+
submittedAt
|
|
702
|
+
createdAt
|
|
703
|
+
updatedAt
|
|
704
|
+
sections {
|
|
705
|
+
id
|
|
706
|
+
title
|
|
707
|
+
index
|
|
708
|
+
status
|
|
709
|
+
questions {
|
|
710
|
+
id
|
|
711
|
+
title
|
|
712
|
+
index
|
|
713
|
+
type
|
|
714
|
+
subType
|
|
715
|
+
description
|
|
716
|
+
isRequired
|
|
717
|
+
placeholder
|
|
718
|
+
answerOptions {
|
|
719
|
+
id
|
|
720
|
+
index
|
|
721
|
+
value
|
|
722
|
+
}
|
|
723
|
+
selectedAnswers {
|
|
724
|
+
id
|
|
725
|
+
index
|
|
726
|
+
value
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
`, { ids: [id] })).assessmentForms.nodes[0];
|
|
734
|
+
if (!node) throw new Error(`Assessment with id ${id} not found`);
|
|
735
|
+
return node;
|
|
736
|
+
}
|
|
737
|
+
async selectAssessmentQuestionAnswers(input) {
|
|
738
|
+
return (await this.makeRequest(`
|
|
739
|
+
mutation SelectAssessmentQuestionAnswers($input: SelectAssessmentQuestionAnswerInput!) {
|
|
740
|
+
selectAssessmentQuestionAnswers(input: $input) {
|
|
741
|
+
selectedAnswers {
|
|
742
|
+
id
|
|
743
|
+
index
|
|
744
|
+
value
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
`, { input })).selectAssessmentQuestionAnswers.selectedAnswers;
|
|
749
|
+
}
|
|
750
|
+
async updateAssessmentFormAssignees(input) {
|
|
751
|
+
return (await this.makeRequest(`
|
|
752
|
+
mutation UpdateAssessmentFormAssignees($input: UpdateAssessmentFormAssigneesInput!) {
|
|
753
|
+
updateAssessmentFormAssignees(input: $input) {
|
|
754
|
+
assessmentForm {
|
|
755
|
+
id
|
|
756
|
+
title
|
|
757
|
+
status
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
`, { input })).updateAssessmentFormAssignees.assessmentForm;
|
|
762
|
+
}
|
|
763
|
+
async listAssessmentGroups(options) {
|
|
764
|
+
const data = await this.makeRequest(`
|
|
765
|
+
query ListAssessmentGroups($first: Int) {
|
|
766
|
+
assessmentGroups(first: $first) {
|
|
767
|
+
nodes {
|
|
768
|
+
id
|
|
769
|
+
title
|
|
770
|
+
assessmentFormTemplate {
|
|
771
|
+
id
|
|
772
|
+
title
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
totalCount
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
`, { first: Math.min(options?.first || 50, 100) });
|
|
779
|
+
return {
|
|
780
|
+
nodes: data.assessmentGroups.nodes,
|
|
781
|
+
pageInfo: {
|
|
782
|
+
hasNextPage: data.assessmentGroups.nodes.length < data.assessmentGroups.totalCount,
|
|
783
|
+
hasPreviousPage: false
|
|
784
|
+
},
|
|
785
|
+
totalCount: data.assessmentGroups.totalCount
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
async createAssessmentGroup(input) {
|
|
789
|
+
return (await this.makeRequest(`
|
|
790
|
+
mutation CreateAssessmentGroup($input: CreateAssessmentGroupInput!) {
|
|
791
|
+
createAssessmentGroup(input: $input) {
|
|
792
|
+
assessmentGroup {
|
|
793
|
+
id
|
|
794
|
+
title
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
`, { input })).createAssessmentGroup.assessmentGroup;
|
|
799
|
+
}
|
|
800
|
+
async createAssessment(input) {
|
|
801
|
+
const mutation = `
|
|
802
|
+
mutation CreateAssessmentForms($input: CreateAssessmentFormsInput!) {
|
|
803
|
+
createAssessmentForms(input: $input) {
|
|
804
|
+
assessmentForms {
|
|
805
|
+
id
|
|
806
|
+
title
|
|
807
|
+
status
|
|
808
|
+
createdAt
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
`;
|
|
813
|
+
const batchInput = { assessmentForms: [{
|
|
814
|
+
title: input.title,
|
|
815
|
+
assessmentGroupId: input.assessmentGroupId,
|
|
816
|
+
...input.assigneeIds && { assigneeIds: input.assigneeIds }
|
|
817
|
+
}] };
|
|
818
|
+
const created = (await this.makeRequest(mutation, { input: batchInput })).createAssessmentForms.assessmentForms[0];
|
|
819
|
+
if (!created) throw new Error("createAssessmentForms returned an empty array");
|
|
820
|
+
return created;
|
|
821
|
+
}
|
|
822
|
+
async updateAssessment(input) {
|
|
823
|
+
return (await this.makeRequest(`
|
|
824
|
+
mutation UpdateAssessmentForm($input: UpdateAssessmentFormInput!) {
|
|
825
|
+
updateAssessmentForm(input: $input) {
|
|
826
|
+
assessmentForm {
|
|
827
|
+
id
|
|
828
|
+
title
|
|
829
|
+
description
|
|
830
|
+
status
|
|
831
|
+
dueDate
|
|
832
|
+
updatedAt
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
`, { input })).updateAssessmentForm.assessmentForm;
|
|
837
|
+
}
|
|
838
|
+
async listAssessmentTemplates(options) {
|
|
839
|
+
const data = await this.makeRequest(`
|
|
840
|
+
query ListAssessmentTemplates($first: Int) {
|
|
841
|
+
assessmentFormTemplates(first: $first) {
|
|
842
|
+
nodes {
|
|
843
|
+
id
|
|
844
|
+
title
|
|
845
|
+
description
|
|
846
|
+
}
|
|
847
|
+
totalCount
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
`, { first: Math.min(options?.first || 50, 100) });
|
|
851
|
+
return {
|
|
852
|
+
nodes: data.assessmentFormTemplates.nodes.map((t) => ({
|
|
853
|
+
id: t.id,
|
|
854
|
+
title: t.title,
|
|
855
|
+
description: t.description || void 0,
|
|
856
|
+
version: "1.0.0",
|
|
857
|
+
isActive: true,
|
|
858
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
859
|
+
})),
|
|
860
|
+
pageInfo: {
|
|
861
|
+
hasNextPage: data.assessmentFormTemplates.nodes.length < data.assessmentFormTemplates.totalCount,
|
|
862
|
+
hasPreviousPage: false
|
|
863
|
+
},
|
|
864
|
+
totalCount: data.assessmentFormTemplates.totalCount
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
async submitAssessmentForReview(input) {
|
|
868
|
+
await this.makeRequest(`
|
|
869
|
+
mutation SubmitAssessmentFormForReview($input: SubmitAssessmentFormForReviewInput!) {
|
|
870
|
+
submitAssessmentFormForReview(input: $input) {
|
|
871
|
+
clientMutationId
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
`, { input });
|
|
875
|
+
return this.getAssessment(input.id);
|
|
876
|
+
}
|
|
877
|
+
async createAssessmentFormTemplate(input) {
|
|
878
|
+
const mutation = `
|
|
879
|
+
mutation CreateAssessmentFormTemplate($input: CreateAssessmentFormTemplateInput!) {
|
|
880
|
+
createAssessmentFormTemplate(input: $input) {
|
|
881
|
+
assessmentFormTemplate {
|
|
882
|
+
id
|
|
883
|
+
title
|
|
884
|
+
status
|
|
885
|
+
sections {
|
|
886
|
+
id
|
|
887
|
+
title
|
|
888
|
+
index
|
|
889
|
+
questions {
|
|
890
|
+
id
|
|
891
|
+
title
|
|
892
|
+
index
|
|
893
|
+
type
|
|
894
|
+
subType
|
|
895
|
+
referenceId
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
`;
|
|
902
|
+
const gqlInput = {
|
|
903
|
+
title: input.title,
|
|
904
|
+
description: input.description || "",
|
|
905
|
+
status: input.status || "DRAFT",
|
|
906
|
+
source: input.source || "MANUAL"
|
|
907
|
+
};
|
|
908
|
+
if (input.sections) gqlInput.sections = input.sections.map((s) => ({
|
|
909
|
+
title: s.title,
|
|
910
|
+
questions: s.questions?.map(normalizeQuestion) || []
|
|
911
|
+
}));
|
|
912
|
+
return (await this.makeRequest(mutation, { input: gqlInput })).createAssessmentFormTemplate.assessmentFormTemplate;
|
|
913
|
+
}
|
|
914
|
+
async createAssessmentSection(input) {
|
|
915
|
+
const mutation = `
|
|
916
|
+
mutation CreateAssessmentSection($input: CreateAssessmentSectionInput!) {
|
|
917
|
+
createAssessmentSection(input: $input) {
|
|
918
|
+
assessmentSection {
|
|
919
|
+
id
|
|
920
|
+
title
|
|
921
|
+
index
|
|
922
|
+
questions {
|
|
923
|
+
id
|
|
924
|
+
title
|
|
925
|
+
index
|
|
926
|
+
type
|
|
927
|
+
subType
|
|
928
|
+
referenceId
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
`;
|
|
934
|
+
const gqlInput = {
|
|
935
|
+
assessmentFormTemplateId: input.assessmentFormTemplateId,
|
|
936
|
+
title: input.title
|
|
937
|
+
};
|
|
938
|
+
if (input.questions) gqlInput.questions = input.questions.map(normalizeQuestion);
|
|
939
|
+
return (await this.makeRequest(mutation, { input: gqlInput })).createAssessmentSection.assessmentSection;
|
|
940
|
+
}
|
|
941
|
+
async createAssessmentQuestions(assessmentSectionId, questions) {
|
|
942
|
+
const mutation = `
|
|
943
|
+
mutation CreateAssessmentQuestions($input: [CreateAssessmentQuestionInput!]!) {
|
|
944
|
+
createAssessmentQuestions(input: $input) {
|
|
945
|
+
assessmentQuestions {
|
|
946
|
+
id
|
|
947
|
+
title
|
|
948
|
+
index
|
|
949
|
+
type
|
|
950
|
+
subType
|
|
951
|
+
referenceId
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
`;
|
|
956
|
+
const input = questions.map((q) => ({
|
|
957
|
+
title: q.title,
|
|
958
|
+
type: q.type,
|
|
959
|
+
subType: q.subType || "NONE",
|
|
960
|
+
placeholder: q.placeholder || "",
|
|
961
|
+
description: q.description || "",
|
|
962
|
+
isRequired: q.isRequired ?? false,
|
|
963
|
+
referenceId: q.referenceId,
|
|
964
|
+
assessmentSectionId,
|
|
965
|
+
answerOptions: q.answerOptions || [],
|
|
966
|
+
allowSelectOther: q.allowSelectOther ?? false,
|
|
967
|
+
requireRiskEvaluation: q.requireRiskEvaluation ?? false
|
|
968
|
+
}));
|
|
969
|
+
return (await this.makeRequest(mutation, { input })).createAssessmentQuestions.assessmentQuestions;
|
|
970
|
+
}
|
|
971
|
+
async getAssessmentFormTemplate(templateId) {
|
|
972
|
+
const node = (await this.makeRequest(`
|
|
973
|
+
query GetAssessmentFormTemplate($ids: [ID!]) {
|
|
974
|
+
assessmentFormTemplates(first: 1, filterBy: { ids: $ids }) {
|
|
975
|
+
nodes {
|
|
976
|
+
id
|
|
977
|
+
title
|
|
978
|
+
description
|
|
979
|
+
status
|
|
980
|
+
source
|
|
981
|
+
createdAt
|
|
982
|
+
updatedAt
|
|
983
|
+
sections {
|
|
984
|
+
id
|
|
985
|
+
title
|
|
986
|
+
index
|
|
987
|
+
questions {
|
|
988
|
+
id
|
|
989
|
+
title
|
|
990
|
+
index
|
|
991
|
+
type
|
|
992
|
+
subType
|
|
993
|
+
description
|
|
994
|
+
placeholder
|
|
995
|
+
isRequired
|
|
996
|
+
referenceId
|
|
997
|
+
allowSelectOther
|
|
998
|
+
requireRiskEvaluation
|
|
999
|
+
answerOptions {
|
|
1000
|
+
id
|
|
1001
|
+
index
|
|
1002
|
+
value
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
`, { ids: [templateId] })).assessmentFormTemplates.nodes[0];
|
|
1010
|
+
if (!node) throw new Error(`Assessment template with id ${templateId} not found`);
|
|
1011
|
+
return node;
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
//#endregion
|
|
1015
|
+
export { AnswerQuestionValueSchema as _, SubmitResponseSchema as a, ListGroupsSchema as c, GetAssessmentSchema as d, ExportTemplateSchema as f, AnswerQuestionSchema as g, CreateAssessmentSchema as h, UpdateAssessmentSchema as i, AssessmentStatusEnum as l, CreateGroupSchema as m, getAssessmentTools as n, PrefillSchema as o, CreateTemplateSchema as p, UpdateAssigneesSchema as r, ListTemplatesSchema as s, AssessmentsMixin as t, ListAssessmentsSchema as u, AddSectionSchema as v };
|
|
1016
|
+
|
|
1017
|
+
//# sourceMappingURL=graphql-BVBi59RV.mjs.map
|