@transcend-io/mcp-server-assessment 2.0.1 → 2.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.
@@ -1,4 +1,4 @@
1
- import { OffsetPaginationSchema, TranscendGraphQLBase, assertOffsetInRange, createListResult, createToolResult, defineTool, derivePageInfo, describeNoMatches, z } from "@transcend-io/mcp-server-base";
1
+ import { ErrorCode, OffsetPaginationSchema, ToolError, TranscendGraphQLBase, assertOffsetInRange, createListResult, createToolResult, defineTool, derivePageInfo, describeNoMatches, z } from "@transcend-io/mcp-server-base";
2
2
  import { AssessmentFormStatus, AssessmentFormTemplateStatus, ScopeName } from "@transcend-io/privacy-types";
3
3
  //#region src/tools/assessments_add_section.ts
4
4
  const AddSectionSchema = z.object({
@@ -270,15 +270,16 @@ function createAssessmentsExportTemplateTool(clients) {
270
270
  //#endregion
271
271
  //#region src/tools/assessments_get.ts
272
272
  const GetAssessmentSchema = z.object({
273
- assessmentId: z.string().describe("ID of the assessment to retrieve"),
274
- assessmentName: z.string().optional().describe("Optional human-readable name (e.g. title) for the tool call in chat; not sent to the API.")
273
+ assessmentId: z.string().describe("ID of the assessment form to read. Call assessments_list to look one up by title or status."),
274
+ sectionIds: z.array(z.string()).optional().describe("Expand these sections, returning their questions, answer options and submitted answers in full. Omit on the first call: you get the section list back and pick from it. A whole form can run to hundreds of questions, far more than fits in one response."),
275
+ questionText: z.string().optional().describe("Return only the questions whose text matches this, with their answers, instead of whole sections. Use it to answer whether a form covers a topic — \"retention\", \"third party\" — without guessing which section holds it. Combine with sectionIds to search inside those sections.")
275
276
  });
276
277
  function createAssessmentsGetTool(clients) {
277
278
  const graphql = clients.graphql;
278
279
  const { dashboardUrl } = clients;
279
280
  return defineTool({
280
281
  name: "assessments_get",
281
- description: "Get detailed information about a specific assessment including questions and responses. The response includes a `url` field with the canonical admin-dashboard link surface that to the user verbatim and do not construct assessment URLs from raw IDs.",
282
+ description: "Read one filled-in assessment and the answers submitted to it. Given only assessmentId it returns the section list with a question count each, NOT the question text. To read the questions, either pass questionText to get just the ones on a topic wherever they sit, or sectionIds to expand whole sections; every sectionId must exist or the call fails, and reading the form in full means passing every one of them. Reviewer feedback is counted here but read with assessments_list_comments. Surface the returned `url` verbatim; never build assessment URLs from IDs.",
282
283
  category: "Assessments",
283
284
  readOnly: true,
284
285
  annotations: {
@@ -287,15 +288,31 @@ function createAssessmentsGetTool(clients) {
287
288
  idempotentHint: true
288
289
  },
289
290
  zodSchema: GetAssessmentSchema,
290
- handler: async ({ assessmentId }) => {
291
- const result = await graphql.getAssessment(assessmentId);
291
+ handler: async ({ assessmentId, sectionIds, questionText }) => {
292
+ const search = questionText !== void 0 && questionText.length > 0;
293
+ const expand = !search && sectionIds !== void 0 && sectionIds.length > 0;
294
+ const [read, byLevel] = await Promise.all([search ? graphql.searchAssessmentQuestions(assessmentId, questionText, { sectionIds }) : expand ? graphql.getAssessment(assessmentId, { sectionIds }) : graphql.getAssessmentSkeleton(assessmentId), graphql.countAssessmentComments(assessmentId)]);
295
+ const found = "matches" in read ? read : void 0;
296
+ const result = found ? found.form : read;
292
297
  const links = buildAssessmentLinks({
293
298
  dashboardUrl,
294
299
  assessmentFormId: result.id
295
300
  });
301
+ const totalCount = byLevel.FORM + byLevel.SECTION + byLevel.QUESTION;
296
302
  return createToolResult(true, {
297
303
  ...result,
298
- ...links
304
+ ...links,
305
+ ...found && {
306
+ questionMatches: found.matches,
307
+ ...found.matches.length > 0 ? { matchNote: `${found.matches.length} of ${found.searchedCount} question(s) match "${questionText}". Answers are included; the sections list shows what else the form asks.` } : { noMatches: `The search succeeded: no question out of ${found.searchedCount} matches "${questionText}". Try a broader term before concluding the form omits the topic, since this matches question text rather than answers.` }
308
+ },
309
+ commentSummary: {
310
+ totalCount,
311
+ byLevel,
312
+ includesResolved: true,
313
+ ...totalCount > 0 ? { readWith: "Call assessments_list_comments with this assessmentId to read the feedback, filter it by author, or include the resolved ones." } : {}
314
+ },
315
+ ...expand || search ? {} : { expandHint: "Pass sectionIds to read the questions in a section, or questionText to find the questions on a topic across the whole form." }
299
316
  });
300
317
  }
301
318
  });
@@ -433,6 +450,138 @@ function describeOutcome({ returned, totalCount, offset, limit, appliedFilters }
433
450
  return offset === 0 ? `Showing all ${returned} match${returned === 1 ? "" : "es"}. No further pages.` : `Showing the last ${returned} of ${totalCount} matches. No further pages.`;
434
451
  }
435
452
  //#endregion
453
+ //#region src/tools/assessments_list_comments.ts
454
+ /** Rows to pull per round trip when reading a comment query to the end. */
455
+ const COMMENT_FETCH_CHUNK = 100;
456
+ const ListAssessmentCommentsSchema = z.object({
457
+ assessmentId: z.string().describe("ID of the assessment form whose feedback you want. Call assessments_list to look one up by title or status."),
458
+ authorIds: z.array(z.string()).optional().describe("Only comments written by these people. Call admin_list_users to turn a name or email into an id, or assessments_list with includeDetails to see who is reviewing a form. Omit for every author."),
459
+ resolution: z.enum([
460
+ "OPEN",
461
+ "RESOLVED",
462
+ "ALL"
463
+ ]).optional().default("OPEN").describe("OPEN returns only unresolved feedback, which is the feedback still asking for something. RESOLVED returns only what has been dealt with, ALL returns both. Default OPEN."),
464
+ levels: z.array(z.enum([
465
+ "FORM",
466
+ "SECTION",
467
+ "QUESTION"
468
+ ])).optional().describe("Only feedback left at these levels: FORM for the assessment as a whole, SECTION for one of its sections, QUESTION for a single question. Use QUESTION for \"what did reviewers say about the answers\". Omit for every level.")
469
+ }).merge(OffsetPaginationSchema);
470
+ /**
471
+ * Read an offset-paginated comment query to the end. The three levels are
472
+ * merged and ordered as one list, so a page can only be cut once every source
473
+ * has been read — a page boundary in one source says nothing about the others.
474
+ */
475
+ async function readAllComments(fetchPage) {
476
+ const first = await fetchPage(0, COMMENT_FETCH_CHUNK);
477
+ const all = [...first.nodes];
478
+ while (all.length < first.totalCount && first.nodes.length > 0) {
479
+ const next = await fetchPage(all.length, COMMENT_FETCH_CHUNK);
480
+ if (next.nodes.length === 0) break;
481
+ all.push(...next.nodes);
482
+ }
483
+ return all;
484
+ }
485
+ /**
486
+ * Total order over the merged list. Creation time alone is not one: comments
487
+ * written in the same second, which bulk review passes produce, would be free
488
+ * to swap places between calls and make an offset name a different comment each
489
+ * time. Ties fall back to id.
490
+ */
491
+ function byCreationThenId(a, b) {
492
+ return a.createdAt === b.createdAt ? a.id.localeCompare(b.id) : a.createdAt.localeCompare(b.createdAt);
493
+ }
494
+ /**
495
+ * Say what a comment sits on, leaving out whatever the form did not name.
496
+ * An untitled section is reported by its absence rather than as an empty
497
+ * string, which would read as a section titled with nothing.
498
+ */
499
+ function describeTarget(comment, fields) {
500
+ return {
501
+ ...comment,
502
+ ...Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== void 0))
503
+ };
504
+ }
505
+ function createAssessmentsListCommentsTool(clients) {
506
+ const graphql = clients.graphql;
507
+ const { dashboardUrl } = clients;
508
+ return defineTool({
509
+ name: "assessments_list_comments",
510
+ description: "Read the reviewer feedback on one assessment — the comments left on it during review. Returns feedback from all three levels at once, whether it was left on the form as a whole, on a section, or on a single question, each row naming what it sits on. Narrow with levels to one of those, authorIds to who wrote it, and resolution to whether it is still open. Use this rather than assessments_get, which reads the questions and answers and only counts the feedback.",
511
+ category: "Assessments",
512
+ readOnly: true,
513
+ annotations: {
514
+ readOnlyHint: true,
515
+ destructiveHint: false,
516
+ idempotentHint: true
517
+ },
518
+ zodSchema: ListAssessmentCommentsSchema,
519
+ handler: async ({ assessmentId, authorIds, resolution, levels, limit, offset }) => {
520
+ const wanted = (level) => levels === void 0 || levels.length === 0 || levels.includes(level);
521
+ const questions = await graphql.listAssessmentQuestionComments(assessmentId);
522
+ const [formComments, sectionComments] = await Promise.all([wanted("FORM") ? readAllComments((o, first) => graphql.listAssessmentFormComments(assessmentId, {
523
+ first,
524
+ offset: o,
525
+ authorIds
526
+ })) : [], wanted("SECTION") ? readAllComments((o, first) => graphql.listAssessmentSectionComments(questions.sectionIds, {
527
+ first,
528
+ offset: o,
529
+ authorIds
530
+ })) : []]);
531
+ const matchesAuthor = (comment) => {
532
+ if (authorIds === void 0 || authorIds.length === 0) return true;
533
+ const id = comment.author?.id;
534
+ return id !== void 0 && authorIds.includes(id);
535
+ };
536
+ const matchesResolution = (comment) => resolution === "ALL" || (resolution === "RESOLVED" ? comment.resolvedAt !== void 0 : !comment.resolvedAt);
537
+ const matched = [
538
+ ...formComments,
539
+ ...sectionComments,
540
+ ...questions.nodes
541
+ ].filter((comment) => wanted(comment.level) && matchesAuthor(comment) && matchesResolution(comment)).sort(byCreationThenId);
542
+ const totalByLevel = {
543
+ FORM: 0,
544
+ SECTION: 0,
545
+ QUESTION: 0
546
+ };
547
+ for (const comment of matched) totalByLevel[comment.level] += 1;
548
+ if (offset > 0 && offset >= matched.length && matched.length > 0) throw new ToolError(ErrorCode.VALIDATION_ERROR, `offset ${offset} is past the end of the result set: ${matched.length} comment(s) match resolution ${resolution}${authorIds && authorIds.length > 0 ? ` and the authorIds filter` : ""}. Retry with an offset below ${matched.length}.`, false, {
549
+ offset,
550
+ totalCount: matched.length,
551
+ resolution,
552
+ ...authorIds && { authorIds }
553
+ });
554
+ const page = matched.slice(offset, offset + limit).map((comment) => {
555
+ if (comment.level === "FORM") return comment;
556
+ if (comment.level === "SECTION") return describeTarget(comment, { sectionTitle: questions.sectionTitles[comment.targetId] });
557
+ const sectionId = questions.questionSections[comment.targetId];
558
+ return describeTarget(comment, {
559
+ questionTitle: questions.questionTitles[comment.targetId],
560
+ sectionId,
561
+ sectionTitle: sectionId === void 0 ? void 0 : questions.sectionTitles[sectionId]
562
+ });
563
+ });
564
+ return createToolResult(true, {
565
+ assessmentId,
566
+ ...buildAssessmentLinks({
567
+ dashboardUrl,
568
+ assessmentFormId: assessmentId
569
+ }),
570
+ comments: page,
571
+ returned: page.length,
572
+ totalCount: matched.length,
573
+ totalByLevel,
574
+ pageInfo: derivePageInfo({
575
+ offset,
576
+ nodeCount: page.length,
577
+ totalCount: matched.length
578
+ }),
579
+ ...matched.length === 0 ? { noMatches: resolution === "OPEN" ? "This form has no open feedback matching the filters. Pass resolution ALL to include feedback already resolved." : "This form has no feedback matching the filters." } : {}
580
+ });
581
+ }
582
+ });
583
+ }
584
+ //#endregion
436
585
  //#region src/tools/assessments_list_groups.ts
437
586
  const ListGroupsSchema = OffsetPaginationSchema.extend({
438
587
  text: z.string().optional().describe("Free-text match on the group title and description"),
@@ -538,22 +687,100 @@ function createAssessmentsListTemplatesTool(clients) {
538
687
  });
539
688
  }
540
689
  //#endregion
690
+ //#region src/errors.ts
691
+ /**
692
+ * Machine-readable failures the assessment tools return, each paired with
693
+ * whether a retry can help.
694
+ *
695
+ * The two travel together because `createToolResult` types `code` as a bare
696
+ * string and takes `retryable` beside it, so nothing stops two sites emitting
697
+ * one code with opposite retry advice. Naming the pair once removes the choice
698
+ * from the call site.
699
+ *
700
+ * These name the remedy rather than the class of problem. `ErrorCode` is the
701
+ * transport taxonomy for thrown `ToolError`s and answers "was this auth, or a
702
+ * timeout"; a caller that reached one of these already knows the request was
703
+ * accepted and needs to be told what to change.
704
+ */
705
+ /** No group or template given, so there is nowhere to create the form. */
706
+ const PREFILL_GROUP_REQUIRED = {
707
+ code: "ASSESSMENT_PREFILL_GROUP_REQUIRED",
708
+ retryable: false
709
+ };
710
+ /** No assignee of any kind given, so the form could not accept answers. */
711
+ const PREFILL_ASSIGNEE_REQUIRED = {
712
+ code: "ASSESSMENT_PREFILL_ASSIGNEE_REQUIRED",
713
+ retryable: false
714
+ };
715
+ /**
716
+ * Submission was asked for with only external assignees.
717
+ *
718
+ * Kept apart from {@link PREFILL_ASSIGNEE_REQUIRED} because the remedy differs:
719
+ * this caller supplied assignees and still has to add an internal one.
720
+ */
721
+ const PREFILL_INTERNAL_ASSIGNEE_REQUIRED = {
722
+ code: "ASSESSMENT_PREFILL_INTERNAL_ASSIGNEE_REQUIRED",
723
+ retryable: false
724
+ };
725
+ /** The form was built but some answers did not land, so it can be finished. */
726
+ const PREFILL_INCOMPLETE = {
727
+ code: "ASSESSMENT_PREFILL_INCOMPLETE",
728
+ retryable: true
729
+ };
730
+ //#endregion
541
731
  //#region src/tools/assessments_prefill.ts
732
+ /**
733
+ * Re-raise a failure from after the form was created, naming the form.
734
+ *
735
+ * This tool creates before it does anything else, so every later step fails
736
+ * with a form already on the dashboard. A bare error names none of it, leaving
737
+ * the caller no handle on what it made and no recovery but to create a second
738
+ * one, which is how half-built duplicates end up in a group.
739
+ *
740
+ * The message also reports how many answers had landed by then. "Created but
741
+ * submitting failed" alone does not say whether the form holds every answer or
742
+ * none, and that is the difference between finishing it and starting over.
743
+ *
744
+ * @param assessmentId - The form that already exists
745
+ * @param title - Its title, so the message reads without a second lookup
746
+ * @param step - What was being attempted, phrased to follow "but "
747
+ * @param error - The underlying failure
748
+ * @param progress - Answers written before the failure, out of the form's total
749
+ * @param hint - What to do differently, when the step has a known cause
750
+ * @throws ToolError naming the form, its progress and the step that failed
751
+ */
752
+ /** Progress for a failure that landed before any answer was attempted. */
753
+ const NOT_STARTED = {
754
+ answersApplied: 0,
755
+ totalQuestions: 0
756
+ };
757
+ function failWithFormId(assessmentId, title, step, error, progress, hint) {
758
+ const { answersApplied, totalQuestions } = progress;
759
+ const held = totalQuestions ? `holds ${answersApplied}/${totalQuestions} answers` : "holds no answers yet";
760
+ throw new ToolError(ErrorCode.API_ERROR, `Assessment "${title}" was created but ${step} failed: ${error instanceof Error ? error.message : String(error)}. The form exists and ${held}. Read it with assessments_get and finish it there rather than creating another.${hint ? ` ${hint}` : ""}`, false, {
761
+ assessmentId,
762
+ step,
763
+ answersApplied,
764
+ totalQuestions
765
+ });
766
+ }
542
767
  const PrefillSchema = z.object({
543
768
  title: z.string().describe("Title for the new assessment form"),
544
769
  templateId: z.string().optional().describe("Fallback for when no group is known. Lands the form in whichever group happens to be first among those built from this template, so never use it when the user named a group."),
545
770
  assessmentGroupId: z.string().optional().describe("Group to create the form in (preferred). Resolve by name with `assessments_list_groups`."),
546
- answers: z.record(z.string(), z.union([z.string(), z.array(z.string())])).describe("Map of answers keyed by question title or referenceId, both of which come from assessments_export_template on the template you are creating from. A string for text and single-select, an array for multi-select. Select answers must match the option text exactly."),
547
- assigneeIds: z.array(z.string()).optional().describe("Internal user IDs to assign the form to (optional)"),
548
- assigneeEmails: z.array(z.string()).optional().describe("External email addresses to assign the form to (optional)"),
771
+ answers: z.record(z.string(), z.union([z.string(), z.array(z.string())])).describe("Map of answers keyed by question title or referenceId, both of which come from assessments_export_template on the template you are creating from. Prefer referenceId; it survives rewording. A string for text and single-select, an array for multi-select. A select value matching an option text selects it, and anything else is kept as a custom answer, so do not drop a value the options do not cover."),
772
+ assigneeIds: z.array(z.string()).optional().describe("Internal user IDs to assign before prefilling. Provide this or assigneeEmails so the form can leave DRAFT."),
773
+ assigneeEmails: z.array(z.string()).optional().describe("External email addresses to assign before prefilling. Provide this or assigneeIds so the form can leave DRAFT. They can answer but cannot submit, so submitForReview also needs assigneeIds."),
549
774
  reviewerIds: z.array(z.string()).optional().describe("User IDs to set as reviewers (optional)"),
775
+ includeDetails: z.boolean().optional().default(false).describe("When true, include one result row per question. Default false returns compact counts."),
550
776
  submitForReview: z.boolean().optional().describe("Whether to automatically submit the form for review after prefilling (default: false)")
551
777
  });
552
778
  function createAssessmentsPrefillTool(clients) {
553
779
  const graphql = clients.graphql;
780
+ const { dashboardUrl } = clients;
554
781
  return defineTool({
555
782
  name: "assessments_prefill",
556
- description: "Create an assessment form, fill in the answers you supply, and assign it for review in one call. Combines: create form → read its questions → answer each → assign reviewers optionally submit. The answers are yours to provide; nothing is generated for you.",
783
+ description: "Create an assessment form, fill in the answers you supply, and assign it for review in one call. Combines: create form → assign it → read its questions → answer each → optionally submit. Requires assigneeIds or assigneeEmails: a form accepts no answers until it is assigned. The answers are yours to provide; nothing is generated for you. Surface the returned `url` verbatim.",
557
784
  category: "Assessments",
558
785
  readOnly: false,
559
786
  annotations: {
@@ -562,31 +789,49 @@ function createAssessmentsPrefillTool(clients) {
562
789
  idempotentHint: false
563
790
  },
564
791
  zodSchema: PrefillSchema,
565
- handler: async ({ answers, title, assessmentGroupId, templateId, assigneeIds, assigneeEmails, reviewerIds, submitForReview }) => {
792
+ handler: async ({ answers, title, assessmentGroupId, templateId, assigneeIds, assigneeEmails, reviewerIds, includeDetails, submitForReview }) => {
566
793
  let resolvedAssessmentGroupId = assessmentGroupId;
567
794
  if (!resolvedAssessmentGroupId && templateId) {
568
795
  const resolved = await resolveTemplateToGroupId(graphql, templateId);
569
796
  if ("error" in resolved) return resolved.error;
570
797
  resolvedAssessmentGroupId = resolved.groupId;
571
798
  }
572
- if (!resolvedAssessmentGroupId) return createToolResult(false, void 0, "Either templateId or assessmentGroupId is required.");
799
+ if (!resolvedAssessmentGroupId) return createToolResult(false, void 0, "Either templateId or assessmentGroupId is required. Resolve a group by name with assessments_list_groups.", PREFILL_GROUP_REQUIRED);
800
+ if (!assigneeIds?.length && !assigneeEmails?.length) return createToolResult(false, void 0, "Provide assigneeIds or assigneeEmails before prefilling. An assessment must be assigned so it can move from DRAFT to SHARED before answers move it to IN_PROGRESS.", PREFILL_ASSIGNEE_REQUIRED);
801
+ if (submitForReview && !assigneeIds?.length) return createToolResult(false, void 0, "submitForReview needs assigneeIds. Submitting acts as the calling user, so that user must be among the internal assignees. External assignees can answer a form but cannot submit it, so assigneeEmails alone would create the form, fill it in, and then fail to submit.", PREFILL_INTERNAL_ASSIGNEE_REQUIRED);
573
802
  const assessmentId = (await graphql.createAssessment({
574
803
  title,
575
- assessmentGroupId: resolvedAssessmentGroupId
804
+ assessmentGroupId: resolvedAssessmentGroupId,
805
+ assigneeIds
576
806
  })).id;
577
- const fullForm = await graphql.getAssessment(assessmentId);
807
+ const assignmentResult = await graphql.updateAssessmentFormAssignees({
808
+ id: assessmentId,
809
+ assigneeIds,
810
+ externalAssigneeEmails: assigneeEmails
811
+ }).catch((error) => failWithFormId(assessmentId, title, "assigning it", error, NOT_STARTED));
812
+ if (reviewerIds) await graphql.updateAssessment({
813
+ id: assessmentId,
814
+ reviewerIds
815
+ }).catch((error) => failWithFormId(assessmentId, title, "setting its reviewers", error, NOT_STARTED));
816
+ const fullForm = await graphql.getAssessment(assessmentId).catch((error) => failWithFormId(assessmentId, title, "reading its questions", error, NOT_STARTED));
578
817
  if (!fullForm.sections || fullForm.sections.length === 0) return createToolResult(true, {
579
818
  assessment: fullForm,
819
+ ...buildAssessmentLinks({
820
+ dashboardUrl,
821
+ assessmentFormId: assessmentId
822
+ }),
580
823
  message: "Assessment created but has no sections/questions to prefill.",
581
824
  answersApplied: 0
582
825
  });
583
826
  const results = [];
584
827
  let answersApplied = 0;
585
828
  let answersSkipped = 0;
829
+ const matchedAnswerKeys = /* @__PURE__ */ new Set();
586
830
  for (const section of fullForm.sections) {
587
831
  if (!section.questions) continue;
588
832
  for (const question of section.questions) {
589
833
  const answerKey = Object.keys(answers).find((key) => key === question.referenceId || key.toLowerCase() === (question.title || "").toLowerCase() || key === question.id);
834
+ if (answerKey) matchedAnswerKeys.add(answerKey);
590
835
  if (!answerKey) {
591
836
  results.push({
592
837
  question: question.title || question.id,
@@ -609,36 +854,26 @@ function createAssessmentsPrefillTool(clients) {
609
854
  if (qType === "SINGLE_SELECT" || qType === "MULTI_SELECT") {
610
855
  const answerValues = Array.isArray(answerValue) ? answerValue : [answerValue];
611
856
  const matchedIds = [];
857
+ const customValues = [];
612
858
  for (const val of answerValues) {
613
859
  const matchedOption = (question.answerOptions || []).find((opt) => opt.value.toLowerCase() === val.toLowerCase());
614
860
  if (matchedOption) matchedIds.push(matchedOption.id);
861
+ else customValues.push(val);
615
862
  }
616
- if (matchedIds.length > 0) {
617
- await graphql.selectAssessmentQuestionAnswers({
618
- assessmentQuestionId: question.id,
619
- assessmentAnswerIds: matchedIds
620
- });
621
- answersApplied++;
622
- results.push({
623
- question: question.title || question.id,
624
- status: "answered",
625
- answer: answerValues.join(", ")
626
- });
627
- } else {
628
- await graphql.selectAssessmentQuestionAnswers({
629
- assessmentQuestionId: question.id,
630
- assessmentAnswerValues: answerValues.map((v) => ({
631
- value: v,
632
- isUserCreated: true
633
- }))
634
- });
635
- answersApplied++;
636
- results.push({
637
- question: question.title || question.id,
638
- status: "answered (custom value)",
639
- answer: answerValues.join(", ")
640
- });
641
- }
863
+ await graphql.selectAssessmentQuestionAnswers({
864
+ assessmentQuestionId: question.id,
865
+ ...matchedIds.length > 0 && { assessmentAnswerIds: matchedIds },
866
+ ...customValues.length > 0 && { assessmentAnswerValues: customValues.map((v) => ({
867
+ value: v,
868
+ isUserCreated: true
869
+ })) }
870
+ });
871
+ answersApplied++;
872
+ results.push({
873
+ question: question.title || question.id,
874
+ status: customValues.length > 0 ? "answered (custom value)" : "answered",
875
+ answer: answerValues.join(", ")
876
+ });
642
877
  } else {
643
878
  const textValue = Array.isArray(answerValue) ? answerValue.join("\n") : answerValue;
644
879
  await graphql.selectAssessmentQuestionAnswers({
@@ -663,15 +898,29 @@ function createAssessmentsPrefillTool(clients) {
663
898
  }
664
899
  }
665
900
  }
666
- let assignmentResult = null;
667
- if (assigneeIds || assigneeEmails) assignmentResult = await graphql.updateAssessmentFormAssignees({
668
- id: assessmentId,
669
- assigneeIds,
670
- externalAssigneeEmails: assigneeEmails
671
- });
672
- if (reviewerIds) await graphql.updateAssessment({
673
- id: assessmentId,
674
- reviewerIds
901
+ const unansweredQuestions = (await graphql.getAssessment(assessmentId).catch((error) => failWithFormId(assessmentId, title, "checking the answers landed", error, {
902
+ answersApplied,
903
+ totalQuestions: results.length
904
+ }))).sections?.flatMap((section) => section.questions ?? []).filter((question) => !question.selectedAnswers?.length).map((question) => question.title || question.id);
905
+ const failedResults = results.filter((result) => result.status.startsWith("error:"));
906
+ const unmatchedAnswerKeys = Object.keys(answers).filter((key) => !matchedAnswerKeys.has(key));
907
+ if (failedResults.length > 0 || unmatchedAnswerKeys.length > 0) return createToolResult(false, void 0, `Assessment "${title}" was created and assigned, but ${[failedResults.length > 0 ? `${failedResults.length} answer${failedResults.length === 1 ? " was" : "s were"} rejected` : "", unmatchedAnswerKeys.length > 0 ? `${unmatchedAnswerKeys.length} answer key${unmatchedAnswerKeys.length === 1 ? "" : "s"} matched no question on the form` : ""].filter(Boolean).join(" and ")}. Keys must match a question title or referenceId from assessments_export_template. The form exists, so finish it with assessments_answer_question and then assessments_submit_response; calling assessments_prefill again would create a second form.`, {
908
+ ...PREFILL_INCOMPLETE,
909
+ details: {
910
+ assessmentId,
911
+ ...buildAssessmentLinks({
912
+ dashboardUrl,
913
+ assessmentFormId: assessmentId
914
+ }),
915
+ answersApplied,
916
+ totalQuestions: results.length,
917
+ unmatchedAnswerKeys,
918
+ unansweredQuestions: unansweredQuestions ?? [],
919
+ errors: failedResults.map(({ question, status }) => ({
920
+ question,
921
+ status
922
+ }))
923
+ }
675
924
  });
676
925
  let submitResult = null;
677
926
  if (submitForReview) {
@@ -679,21 +928,29 @@ function createAssessmentsPrefillTool(clients) {
679
928
  if (sectionIds.length > 0) submitResult = await graphql.submitAssessmentForReview({
680
929
  id: assessmentId,
681
930
  assessmentSectionIds: sectionIds
682
- });
931
+ }).catch((error) => failWithFormId(assessmentId, title, "submitting it for review", error, {
932
+ answersApplied,
933
+ totalQuestions: results.length
934
+ }, "Submitting acts as the calling user, so that user must be among assigneeIds."));
683
935
  }
684
936
  return createToolResult(true, {
685
937
  assessmentId,
938
+ ...buildAssessmentLinks({
939
+ dashboardUrl,
940
+ assessmentFormId: assessmentId
941
+ }),
686
942
  title,
687
943
  answersApplied,
688
944
  answersSkipped,
689
945
  totalQuestions: results.length,
690
- results,
691
- assignment: assignmentResult ? {
946
+ ...unansweredQuestions?.length && { unansweredQuestions },
947
+ ...includeDetails && { results },
948
+ assignment: {
692
949
  status: assignmentResult.status,
693
- message: "Assignees updated"
694
- } : null,
950
+ message: "Assignees updated before prefilling"
951
+ },
695
952
  submittedForReview: !!submitResult,
696
- message: `Assessment "${title}" created and prefilled with ${answersApplied}/${results.length} answers. ` + (assignmentResult ? `Assigned to reviewers. ` : "") + (submitResult ? "Submitted for review." : "Ready for manual submission.")
953
+ message: `Assessment "${title}" created and prefilled with ${answersApplied}/${results.length} answers. Assigned before prefilling. ` + (unansweredQuestions?.length ? `${unansweredQuestions.length} questions were left unanswered because no answer was supplied for them. ` : "") + (submitResult ? "Submitted for review." : "Ready for manual submission.")
697
954
  });
698
955
  }
699
956
  });
@@ -828,6 +1085,7 @@ function getAssessmentTools(clients) {
828
1085
  createAssessmentsCreateTool(clients),
829
1086
  createAssessmentsCreateGroupTool(clients),
830
1087
  createAssessmentsListGroupsTool(clients),
1088
+ createAssessmentsListCommentsTool(clients),
831
1089
  createAssessmentsUpdateTool(clients),
832
1090
  createAssessmentsListTemplatesTool(clients),
833
1091
  createAssessmentsUpdateAssigneesTool(clients),
@@ -1390,83 +1648,120 @@ const documents = {
1390
1648
  }
1391
1649
  }]
1392
1650
  },
1393
- "\n query AssessmentsGet($ids: [ID!]!) {\n assessmentForms(first: 1, filterBy: { ids: $ids }) {\n nodes {\n id\n title\n status\n dueDate\n submittedAt\n createdAt\n updatedAt\n assessmentGroup {\n id\n }\n sections {\n id\n title\n index\n status\n questions {\n id\n title\n index\n type\n subType\n description\n isRequired\n placeholder\n answerOptions {\n id\n index\n value\n }\n selectedAnswers {\n id\n index\n value\n }\n }\n }\n }\n }\n }\n": {
1651
+ "\n query AssessmentQuestionsSearch(\n $first: Int\n $offset: Int\n $filterBy: AssessmentQuestionFiltersInput\n ) {\n assessmentQuestions(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n id\n title\n index\n type\n subType\n description\n isRequired\n placeholder\n answerOptions {\n id\n index\n value\n }\n selectedAnswers {\n id\n index\n value\n }\n }\n totalCount\n }\n }\n": {
1394
1652
  "kind": "Document",
1395
1653
  "definitions": [{
1396
1654
  "kind": "OperationDefinition",
1397
1655
  "operation": "query",
1398
1656
  "name": {
1399
1657
  "kind": "Name",
1400
- "value": "AssessmentsGet"
1658
+ "value": "AssessmentQuestionsSearch"
1401
1659
  },
1402
- "variableDefinitions": [{
1403
- "kind": "VariableDefinition",
1404
- "variable": {
1405
- "kind": "Variable",
1406
- "name": {
1407
- "kind": "Name",
1408
- "value": "ids"
1660
+ "variableDefinitions": [
1661
+ {
1662
+ "kind": "VariableDefinition",
1663
+ "variable": {
1664
+ "kind": "Variable",
1665
+ "name": {
1666
+ "kind": "Name",
1667
+ "value": "first"
1668
+ }
1669
+ },
1670
+ "type": {
1671
+ "kind": "NamedType",
1672
+ "name": {
1673
+ "kind": "Name",
1674
+ "value": "Int"
1675
+ }
1409
1676
  }
1410
1677
  },
1411
- "type": {
1412
- "kind": "NonNullType",
1678
+ {
1679
+ "kind": "VariableDefinition",
1680
+ "variable": {
1681
+ "kind": "Variable",
1682
+ "name": {
1683
+ "kind": "Name",
1684
+ "value": "offset"
1685
+ }
1686
+ },
1413
1687
  "type": {
1414
- "kind": "ListType",
1415
- "type": {
1416
- "kind": "NonNullType",
1417
- "type": {
1418
- "kind": "NamedType",
1419
- "name": {
1420
- "kind": "Name",
1421
- "value": "ID"
1422
- }
1423
- }
1688
+ "kind": "NamedType",
1689
+ "name": {
1690
+ "kind": "Name",
1691
+ "value": "Int"
1692
+ }
1693
+ }
1694
+ },
1695
+ {
1696
+ "kind": "VariableDefinition",
1697
+ "variable": {
1698
+ "kind": "Variable",
1699
+ "name": {
1700
+ "kind": "Name",
1701
+ "value": "filterBy"
1702
+ }
1703
+ },
1704
+ "type": {
1705
+ "kind": "NamedType",
1706
+ "name": {
1707
+ "kind": "Name",
1708
+ "value": "AssessmentQuestionFiltersInput"
1424
1709
  }
1425
1710
  }
1426
1711
  }
1427
- }],
1712
+ ],
1428
1713
  "selectionSet": {
1429
1714
  "kind": "SelectionSet",
1430
1715
  "selections": [{
1431
1716
  "kind": "Field",
1432
1717
  "name": {
1433
1718
  "kind": "Name",
1434
- "value": "assessmentForms"
1719
+ "value": "assessmentQuestions"
1435
1720
  },
1436
- "arguments": [{
1437
- "kind": "Argument",
1438
- "name": {
1439
- "kind": "Name",
1440
- "value": "first"
1721
+ "arguments": [
1722
+ {
1723
+ "kind": "Argument",
1724
+ "name": {
1725
+ "kind": "Name",
1726
+ "value": "first"
1727
+ },
1728
+ "value": {
1729
+ "kind": "Variable",
1730
+ "name": {
1731
+ "kind": "Name",
1732
+ "value": "first"
1733
+ }
1734
+ }
1441
1735
  },
1442
- "value": {
1443
- "kind": "IntValue",
1444
- "value": "1"
1445
- }
1446
- }, {
1447
- "kind": "Argument",
1448
- "name": {
1449
- "kind": "Name",
1450
- "value": "filterBy"
1736
+ {
1737
+ "kind": "Argument",
1738
+ "name": {
1739
+ "kind": "Name",
1740
+ "value": "offset"
1741
+ },
1742
+ "value": {
1743
+ "kind": "Variable",
1744
+ "name": {
1745
+ "kind": "Name",
1746
+ "value": "offset"
1747
+ }
1748
+ }
1451
1749
  },
1452
- "value": {
1453
- "kind": "ObjectValue",
1454
- "fields": [{
1455
- "kind": "ObjectField",
1750
+ {
1751
+ "kind": "Argument",
1752
+ "name": {
1753
+ "kind": "Name",
1754
+ "value": "filterBy"
1755
+ },
1756
+ "value": {
1757
+ "kind": "Variable",
1456
1758
  "name": {
1457
1759
  "kind": "Name",
1458
- "value": "ids"
1459
- },
1460
- "value": {
1461
- "kind": "Variable",
1462
- "name": {
1463
- "kind": "Name",
1464
- "value": "ids"
1465
- }
1760
+ "value": "filterBy"
1466
1761
  }
1467
- }]
1762
+ }
1468
1763
  }
1469
- }],
1764
+ ],
1470
1765
  "selectionSet": {
1471
1766
  "kind": "SelectionSet",
1472
1767
  "selections": [{
@@ -1496,59 +1791,49 @@ const documents = {
1496
1791
  "kind": "Field",
1497
1792
  "name": {
1498
1793
  "kind": "Name",
1499
- "value": "status"
1794
+ "value": "index"
1500
1795
  }
1501
1796
  },
1502
1797
  {
1503
1798
  "kind": "Field",
1504
1799
  "name": {
1505
1800
  "kind": "Name",
1506
- "value": "dueDate"
1801
+ "value": "type"
1507
1802
  }
1508
1803
  },
1509
1804
  {
1510
1805
  "kind": "Field",
1511
1806
  "name": {
1512
1807
  "kind": "Name",
1513
- "value": "submittedAt"
1808
+ "value": "subType"
1514
1809
  }
1515
1810
  },
1516
1811
  {
1517
1812
  "kind": "Field",
1518
1813
  "name": {
1519
1814
  "kind": "Name",
1520
- "value": "createdAt"
1815
+ "value": "description"
1521
1816
  }
1522
1817
  },
1523
1818
  {
1524
1819
  "kind": "Field",
1525
1820
  "name": {
1526
1821
  "kind": "Name",
1527
- "value": "updatedAt"
1822
+ "value": "isRequired"
1528
1823
  }
1529
1824
  },
1530
1825
  {
1531
1826
  "kind": "Field",
1532
1827
  "name": {
1533
1828
  "kind": "Name",
1534
- "value": "assessmentGroup"
1535
- },
1536
- "selectionSet": {
1537
- "kind": "SelectionSet",
1538
- "selections": [{
1539
- "kind": "Field",
1540
- "name": {
1541
- "kind": "Name",
1542
- "value": "id"
1543
- }
1544
- }]
1829
+ "value": "placeholder"
1545
1830
  }
1546
1831
  },
1547
1832
  {
1548
1833
  "kind": "Field",
1549
1834
  "name": {
1550
1835
  "kind": "Name",
1551
- "value": "sections"
1836
+ "value": "answerOptions"
1552
1837
  },
1553
1838
  "selectionSet": {
1554
1839
  "kind": "SelectionSet",
@@ -1564,7 +1849,33 @@ const documents = {
1564
1849
  "kind": "Field",
1565
1850
  "name": {
1566
1851
  "kind": "Name",
1567
- "value": "title"
1852
+ "value": "index"
1853
+ }
1854
+ },
1855
+ {
1856
+ "kind": "Field",
1857
+ "name": {
1858
+ "kind": "Name",
1859
+ "value": "value"
1860
+ }
1861
+ }
1862
+ ]
1863
+ }
1864
+ },
1865
+ {
1866
+ "kind": "Field",
1867
+ "name": {
1868
+ "kind": "Name",
1869
+ "value": "selectedAnswers"
1870
+ },
1871
+ "selectionSet": {
1872
+ "kind": "SelectionSet",
1873
+ "selections": [
1874
+ {
1875
+ "kind": "Field",
1876
+ "name": {
1877
+ "kind": "Name",
1878
+ "value": "id"
1568
1879
  }
1569
1880
  },
1570
1881
  {
@@ -1578,147 +1889,2014 @@ const documents = {
1578
1889
  "kind": "Field",
1579
1890
  "name": {
1580
1891
  "kind": "Name",
1581
- "value": "status"
1892
+ "value": "value"
1893
+ }
1894
+ }
1895
+ ]
1896
+ }
1897
+ }
1898
+ ]
1899
+ }
1900
+ }, {
1901
+ "kind": "Field",
1902
+ "name": {
1903
+ "kind": "Name",
1904
+ "value": "totalCount"
1905
+ }
1906
+ }]
1907
+ }
1908
+ }]
1909
+ }
1910
+ }]
1911
+ },
1912
+ "\n query AssessmentsGet($ids: [ID!]!) {\n assessmentForms(first: 1, filterBy: { ids: $ids }) {\n nodes {\n id\n title\n description\n status\n dueDate\n submittedAt\n createdAt\n updatedAt\n assessmentGroup {\n id\n }\n assignees {\n id\n name\n email\n }\n reviewers {\n id\n name\n email\n }\n externalAssignees {\n id\n email\n }\n sections {\n id\n title\n index\n status\n questions {\n id\n title\n index\n type\n subType\n description\n isRequired\n placeholder\n referenceId\n answerOptions {\n id\n index\n value\n }\n selectedAnswers {\n id\n index\n value\n }\n }\n }\n }\n }\n }\n": {
1913
+ "kind": "Document",
1914
+ "definitions": [{
1915
+ "kind": "OperationDefinition",
1916
+ "operation": "query",
1917
+ "name": {
1918
+ "kind": "Name",
1919
+ "value": "AssessmentsGet"
1920
+ },
1921
+ "variableDefinitions": [{
1922
+ "kind": "VariableDefinition",
1923
+ "variable": {
1924
+ "kind": "Variable",
1925
+ "name": {
1926
+ "kind": "Name",
1927
+ "value": "ids"
1928
+ }
1929
+ },
1930
+ "type": {
1931
+ "kind": "NonNullType",
1932
+ "type": {
1933
+ "kind": "ListType",
1934
+ "type": {
1935
+ "kind": "NonNullType",
1936
+ "type": {
1937
+ "kind": "NamedType",
1938
+ "name": {
1939
+ "kind": "Name",
1940
+ "value": "ID"
1941
+ }
1942
+ }
1943
+ }
1944
+ }
1945
+ }
1946
+ }],
1947
+ "selectionSet": {
1948
+ "kind": "SelectionSet",
1949
+ "selections": [{
1950
+ "kind": "Field",
1951
+ "name": {
1952
+ "kind": "Name",
1953
+ "value": "assessmentForms"
1954
+ },
1955
+ "arguments": [{
1956
+ "kind": "Argument",
1957
+ "name": {
1958
+ "kind": "Name",
1959
+ "value": "first"
1960
+ },
1961
+ "value": {
1962
+ "kind": "IntValue",
1963
+ "value": "1"
1964
+ }
1965
+ }, {
1966
+ "kind": "Argument",
1967
+ "name": {
1968
+ "kind": "Name",
1969
+ "value": "filterBy"
1970
+ },
1971
+ "value": {
1972
+ "kind": "ObjectValue",
1973
+ "fields": [{
1974
+ "kind": "ObjectField",
1975
+ "name": {
1976
+ "kind": "Name",
1977
+ "value": "ids"
1978
+ },
1979
+ "value": {
1980
+ "kind": "Variable",
1981
+ "name": {
1982
+ "kind": "Name",
1983
+ "value": "ids"
1984
+ }
1985
+ }
1986
+ }]
1987
+ }
1988
+ }],
1989
+ "selectionSet": {
1990
+ "kind": "SelectionSet",
1991
+ "selections": [{
1992
+ "kind": "Field",
1993
+ "name": {
1994
+ "kind": "Name",
1995
+ "value": "nodes"
1996
+ },
1997
+ "selectionSet": {
1998
+ "kind": "SelectionSet",
1999
+ "selections": [
2000
+ {
2001
+ "kind": "Field",
2002
+ "name": {
2003
+ "kind": "Name",
2004
+ "value": "id"
2005
+ }
2006
+ },
2007
+ {
2008
+ "kind": "Field",
2009
+ "name": {
2010
+ "kind": "Name",
2011
+ "value": "title"
2012
+ }
2013
+ },
2014
+ {
2015
+ "kind": "Field",
2016
+ "name": {
2017
+ "kind": "Name",
2018
+ "value": "description"
2019
+ }
2020
+ },
2021
+ {
2022
+ "kind": "Field",
2023
+ "name": {
2024
+ "kind": "Name",
2025
+ "value": "status"
2026
+ }
2027
+ },
2028
+ {
2029
+ "kind": "Field",
2030
+ "name": {
2031
+ "kind": "Name",
2032
+ "value": "dueDate"
2033
+ }
2034
+ },
2035
+ {
2036
+ "kind": "Field",
2037
+ "name": {
2038
+ "kind": "Name",
2039
+ "value": "submittedAt"
2040
+ }
2041
+ },
2042
+ {
2043
+ "kind": "Field",
2044
+ "name": {
2045
+ "kind": "Name",
2046
+ "value": "createdAt"
2047
+ }
2048
+ },
2049
+ {
2050
+ "kind": "Field",
2051
+ "name": {
2052
+ "kind": "Name",
2053
+ "value": "updatedAt"
2054
+ }
2055
+ },
2056
+ {
2057
+ "kind": "Field",
2058
+ "name": {
2059
+ "kind": "Name",
2060
+ "value": "assessmentGroup"
2061
+ },
2062
+ "selectionSet": {
2063
+ "kind": "SelectionSet",
2064
+ "selections": [{
2065
+ "kind": "Field",
2066
+ "name": {
2067
+ "kind": "Name",
2068
+ "value": "id"
2069
+ }
2070
+ }]
2071
+ }
2072
+ },
2073
+ {
2074
+ "kind": "Field",
2075
+ "name": {
2076
+ "kind": "Name",
2077
+ "value": "assignees"
2078
+ },
2079
+ "selectionSet": {
2080
+ "kind": "SelectionSet",
2081
+ "selections": [
2082
+ {
2083
+ "kind": "Field",
2084
+ "name": {
2085
+ "kind": "Name",
2086
+ "value": "id"
2087
+ }
2088
+ },
2089
+ {
2090
+ "kind": "Field",
2091
+ "name": {
2092
+ "kind": "Name",
2093
+ "value": "name"
2094
+ }
2095
+ },
2096
+ {
2097
+ "kind": "Field",
2098
+ "name": {
2099
+ "kind": "Name",
2100
+ "value": "email"
2101
+ }
2102
+ }
2103
+ ]
2104
+ }
2105
+ },
2106
+ {
2107
+ "kind": "Field",
2108
+ "name": {
2109
+ "kind": "Name",
2110
+ "value": "reviewers"
2111
+ },
2112
+ "selectionSet": {
2113
+ "kind": "SelectionSet",
2114
+ "selections": [
2115
+ {
2116
+ "kind": "Field",
2117
+ "name": {
2118
+ "kind": "Name",
2119
+ "value": "id"
1582
2120
  }
1583
2121
  },
1584
- {
1585
- "kind": "Field",
1586
- "name": {
1587
- "kind": "Name",
1588
- "value": "questions"
1589
- },
1590
- "selectionSet": {
1591
- "kind": "SelectionSet",
1592
- "selections": [
1593
- {
1594
- "kind": "Field",
1595
- "name": {
1596
- "kind": "Name",
1597
- "value": "id"
1598
- }
1599
- },
1600
- {
1601
- "kind": "Field",
1602
- "name": {
1603
- "kind": "Name",
1604
- "value": "title"
1605
- }
1606
- },
1607
- {
1608
- "kind": "Field",
1609
- "name": {
1610
- "kind": "Name",
1611
- "value": "index"
1612
- }
1613
- },
1614
- {
1615
- "kind": "Field",
1616
- "name": {
1617
- "kind": "Name",
1618
- "value": "type"
1619
- }
1620
- },
1621
- {
1622
- "kind": "Field",
1623
- "name": {
1624
- "kind": "Name",
1625
- "value": "subType"
1626
- }
1627
- },
1628
- {
1629
- "kind": "Field",
1630
- "name": {
1631
- "kind": "Name",
1632
- "value": "description"
1633
- }
1634
- },
1635
- {
1636
- "kind": "Field",
1637
- "name": {
1638
- "kind": "Name",
1639
- "value": "isRequired"
1640
- }
1641
- },
1642
- {
1643
- "kind": "Field",
1644
- "name": {
1645
- "kind": "Name",
1646
- "value": "placeholder"
1647
- }
2122
+ {
2123
+ "kind": "Field",
2124
+ "name": {
2125
+ "kind": "Name",
2126
+ "value": "name"
2127
+ }
2128
+ },
2129
+ {
2130
+ "kind": "Field",
2131
+ "name": {
2132
+ "kind": "Name",
2133
+ "value": "email"
2134
+ }
2135
+ }
2136
+ ]
2137
+ }
2138
+ },
2139
+ {
2140
+ "kind": "Field",
2141
+ "name": {
2142
+ "kind": "Name",
2143
+ "value": "externalAssignees"
2144
+ },
2145
+ "selectionSet": {
2146
+ "kind": "SelectionSet",
2147
+ "selections": [{
2148
+ "kind": "Field",
2149
+ "name": {
2150
+ "kind": "Name",
2151
+ "value": "id"
2152
+ }
2153
+ }, {
2154
+ "kind": "Field",
2155
+ "name": {
2156
+ "kind": "Name",
2157
+ "value": "email"
2158
+ }
2159
+ }]
2160
+ }
2161
+ },
2162
+ {
2163
+ "kind": "Field",
2164
+ "name": {
2165
+ "kind": "Name",
2166
+ "value": "sections"
2167
+ },
2168
+ "selectionSet": {
2169
+ "kind": "SelectionSet",
2170
+ "selections": [
2171
+ {
2172
+ "kind": "Field",
2173
+ "name": {
2174
+ "kind": "Name",
2175
+ "value": "id"
2176
+ }
2177
+ },
2178
+ {
2179
+ "kind": "Field",
2180
+ "name": {
2181
+ "kind": "Name",
2182
+ "value": "title"
2183
+ }
2184
+ },
2185
+ {
2186
+ "kind": "Field",
2187
+ "name": {
2188
+ "kind": "Name",
2189
+ "value": "index"
2190
+ }
2191
+ },
2192
+ {
2193
+ "kind": "Field",
2194
+ "name": {
2195
+ "kind": "Name",
2196
+ "value": "status"
2197
+ }
2198
+ },
2199
+ {
2200
+ "kind": "Field",
2201
+ "name": {
2202
+ "kind": "Name",
2203
+ "value": "questions"
2204
+ },
2205
+ "selectionSet": {
2206
+ "kind": "SelectionSet",
2207
+ "selections": [
2208
+ {
2209
+ "kind": "Field",
2210
+ "name": {
2211
+ "kind": "Name",
2212
+ "value": "id"
2213
+ }
2214
+ },
2215
+ {
2216
+ "kind": "Field",
2217
+ "name": {
2218
+ "kind": "Name",
2219
+ "value": "title"
2220
+ }
2221
+ },
2222
+ {
2223
+ "kind": "Field",
2224
+ "name": {
2225
+ "kind": "Name",
2226
+ "value": "index"
2227
+ }
2228
+ },
2229
+ {
2230
+ "kind": "Field",
2231
+ "name": {
2232
+ "kind": "Name",
2233
+ "value": "type"
2234
+ }
2235
+ },
2236
+ {
2237
+ "kind": "Field",
2238
+ "name": {
2239
+ "kind": "Name",
2240
+ "value": "subType"
2241
+ }
2242
+ },
2243
+ {
2244
+ "kind": "Field",
2245
+ "name": {
2246
+ "kind": "Name",
2247
+ "value": "description"
2248
+ }
2249
+ },
2250
+ {
2251
+ "kind": "Field",
2252
+ "name": {
2253
+ "kind": "Name",
2254
+ "value": "isRequired"
2255
+ }
2256
+ },
2257
+ {
2258
+ "kind": "Field",
2259
+ "name": {
2260
+ "kind": "Name",
2261
+ "value": "placeholder"
2262
+ }
2263
+ },
2264
+ {
2265
+ "kind": "Field",
2266
+ "name": {
2267
+ "kind": "Name",
2268
+ "value": "referenceId"
2269
+ }
2270
+ },
2271
+ {
2272
+ "kind": "Field",
2273
+ "name": {
2274
+ "kind": "Name",
2275
+ "value": "answerOptions"
2276
+ },
2277
+ "selectionSet": {
2278
+ "kind": "SelectionSet",
2279
+ "selections": [
2280
+ {
2281
+ "kind": "Field",
2282
+ "name": {
2283
+ "kind": "Name",
2284
+ "value": "id"
2285
+ }
2286
+ },
2287
+ {
2288
+ "kind": "Field",
2289
+ "name": {
2290
+ "kind": "Name",
2291
+ "value": "index"
2292
+ }
2293
+ },
2294
+ {
2295
+ "kind": "Field",
2296
+ "name": {
2297
+ "kind": "Name",
2298
+ "value": "value"
2299
+ }
2300
+ }
2301
+ ]
2302
+ }
2303
+ },
2304
+ {
2305
+ "kind": "Field",
2306
+ "name": {
2307
+ "kind": "Name",
2308
+ "value": "selectedAnswers"
2309
+ },
2310
+ "selectionSet": {
2311
+ "kind": "SelectionSet",
2312
+ "selections": [
2313
+ {
2314
+ "kind": "Field",
2315
+ "name": {
2316
+ "kind": "Name",
2317
+ "value": "id"
2318
+ }
2319
+ },
2320
+ {
2321
+ "kind": "Field",
2322
+ "name": {
2323
+ "kind": "Name",
2324
+ "value": "index"
2325
+ }
2326
+ },
2327
+ {
2328
+ "kind": "Field",
2329
+ "name": {
2330
+ "kind": "Name",
2331
+ "value": "value"
2332
+ }
2333
+ }
2334
+ ]
2335
+ }
2336
+ }
2337
+ ]
2338
+ }
2339
+ }
2340
+ ]
2341
+ }
2342
+ }
2343
+ ]
2344
+ }
2345
+ }]
2346
+ }
2347
+ }]
2348
+ }
2349
+ }]
2350
+ },
2351
+ "\n query AssessmentsGetSkeleton($ids: [ID!]!) {\n assessmentForms(first: 1, filterBy: { ids: $ids }) {\n nodes {\n id\n title\n description\n status\n dueDate\n submittedAt\n createdAt\n updatedAt\n assessmentGroup {\n id\n }\n assignees {\n id\n name\n email\n }\n reviewers {\n id\n name\n email\n }\n externalAssignees {\n id\n email\n }\n sections {\n id\n title\n index\n status\n questions {\n id\n }\n }\n }\n }\n }\n": {
2352
+ "kind": "Document",
2353
+ "definitions": [{
2354
+ "kind": "OperationDefinition",
2355
+ "operation": "query",
2356
+ "name": {
2357
+ "kind": "Name",
2358
+ "value": "AssessmentsGetSkeleton"
2359
+ },
2360
+ "variableDefinitions": [{
2361
+ "kind": "VariableDefinition",
2362
+ "variable": {
2363
+ "kind": "Variable",
2364
+ "name": {
2365
+ "kind": "Name",
2366
+ "value": "ids"
2367
+ }
2368
+ },
2369
+ "type": {
2370
+ "kind": "NonNullType",
2371
+ "type": {
2372
+ "kind": "ListType",
2373
+ "type": {
2374
+ "kind": "NonNullType",
2375
+ "type": {
2376
+ "kind": "NamedType",
2377
+ "name": {
2378
+ "kind": "Name",
2379
+ "value": "ID"
2380
+ }
2381
+ }
2382
+ }
2383
+ }
2384
+ }
2385
+ }],
2386
+ "selectionSet": {
2387
+ "kind": "SelectionSet",
2388
+ "selections": [{
2389
+ "kind": "Field",
2390
+ "name": {
2391
+ "kind": "Name",
2392
+ "value": "assessmentForms"
2393
+ },
2394
+ "arguments": [{
2395
+ "kind": "Argument",
2396
+ "name": {
2397
+ "kind": "Name",
2398
+ "value": "first"
2399
+ },
2400
+ "value": {
2401
+ "kind": "IntValue",
2402
+ "value": "1"
2403
+ }
2404
+ }, {
2405
+ "kind": "Argument",
2406
+ "name": {
2407
+ "kind": "Name",
2408
+ "value": "filterBy"
2409
+ },
2410
+ "value": {
2411
+ "kind": "ObjectValue",
2412
+ "fields": [{
2413
+ "kind": "ObjectField",
2414
+ "name": {
2415
+ "kind": "Name",
2416
+ "value": "ids"
2417
+ },
2418
+ "value": {
2419
+ "kind": "Variable",
2420
+ "name": {
2421
+ "kind": "Name",
2422
+ "value": "ids"
2423
+ }
2424
+ }
2425
+ }]
2426
+ }
2427
+ }],
2428
+ "selectionSet": {
2429
+ "kind": "SelectionSet",
2430
+ "selections": [{
2431
+ "kind": "Field",
2432
+ "name": {
2433
+ "kind": "Name",
2434
+ "value": "nodes"
2435
+ },
2436
+ "selectionSet": {
2437
+ "kind": "SelectionSet",
2438
+ "selections": [
2439
+ {
2440
+ "kind": "Field",
2441
+ "name": {
2442
+ "kind": "Name",
2443
+ "value": "id"
2444
+ }
2445
+ },
2446
+ {
2447
+ "kind": "Field",
2448
+ "name": {
2449
+ "kind": "Name",
2450
+ "value": "title"
2451
+ }
2452
+ },
2453
+ {
2454
+ "kind": "Field",
2455
+ "name": {
2456
+ "kind": "Name",
2457
+ "value": "description"
2458
+ }
2459
+ },
2460
+ {
2461
+ "kind": "Field",
2462
+ "name": {
2463
+ "kind": "Name",
2464
+ "value": "status"
2465
+ }
2466
+ },
2467
+ {
2468
+ "kind": "Field",
2469
+ "name": {
2470
+ "kind": "Name",
2471
+ "value": "dueDate"
2472
+ }
2473
+ },
2474
+ {
2475
+ "kind": "Field",
2476
+ "name": {
2477
+ "kind": "Name",
2478
+ "value": "submittedAt"
2479
+ }
2480
+ },
2481
+ {
2482
+ "kind": "Field",
2483
+ "name": {
2484
+ "kind": "Name",
2485
+ "value": "createdAt"
2486
+ }
2487
+ },
2488
+ {
2489
+ "kind": "Field",
2490
+ "name": {
2491
+ "kind": "Name",
2492
+ "value": "updatedAt"
2493
+ }
2494
+ },
2495
+ {
2496
+ "kind": "Field",
2497
+ "name": {
2498
+ "kind": "Name",
2499
+ "value": "assessmentGroup"
2500
+ },
2501
+ "selectionSet": {
2502
+ "kind": "SelectionSet",
2503
+ "selections": [{
2504
+ "kind": "Field",
2505
+ "name": {
2506
+ "kind": "Name",
2507
+ "value": "id"
2508
+ }
2509
+ }]
2510
+ }
2511
+ },
2512
+ {
2513
+ "kind": "Field",
2514
+ "name": {
2515
+ "kind": "Name",
2516
+ "value": "assignees"
2517
+ },
2518
+ "selectionSet": {
2519
+ "kind": "SelectionSet",
2520
+ "selections": [
2521
+ {
2522
+ "kind": "Field",
2523
+ "name": {
2524
+ "kind": "Name",
2525
+ "value": "id"
2526
+ }
2527
+ },
2528
+ {
2529
+ "kind": "Field",
2530
+ "name": {
2531
+ "kind": "Name",
2532
+ "value": "name"
2533
+ }
2534
+ },
2535
+ {
2536
+ "kind": "Field",
2537
+ "name": {
2538
+ "kind": "Name",
2539
+ "value": "email"
2540
+ }
2541
+ }
2542
+ ]
2543
+ }
2544
+ },
2545
+ {
2546
+ "kind": "Field",
2547
+ "name": {
2548
+ "kind": "Name",
2549
+ "value": "reviewers"
2550
+ },
2551
+ "selectionSet": {
2552
+ "kind": "SelectionSet",
2553
+ "selections": [
2554
+ {
2555
+ "kind": "Field",
2556
+ "name": {
2557
+ "kind": "Name",
2558
+ "value": "id"
2559
+ }
2560
+ },
2561
+ {
2562
+ "kind": "Field",
2563
+ "name": {
2564
+ "kind": "Name",
2565
+ "value": "name"
2566
+ }
2567
+ },
2568
+ {
2569
+ "kind": "Field",
2570
+ "name": {
2571
+ "kind": "Name",
2572
+ "value": "email"
2573
+ }
2574
+ }
2575
+ ]
2576
+ }
2577
+ },
2578
+ {
2579
+ "kind": "Field",
2580
+ "name": {
2581
+ "kind": "Name",
2582
+ "value": "externalAssignees"
2583
+ },
2584
+ "selectionSet": {
2585
+ "kind": "SelectionSet",
2586
+ "selections": [{
2587
+ "kind": "Field",
2588
+ "name": {
2589
+ "kind": "Name",
2590
+ "value": "id"
2591
+ }
2592
+ }, {
2593
+ "kind": "Field",
2594
+ "name": {
2595
+ "kind": "Name",
2596
+ "value": "email"
2597
+ }
2598
+ }]
2599
+ }
2600
+ },
2601
+ {
2602
+ "kind": "Field",
2603
+ "name": {
2604
+ "kind": "Name",
2605
+ "value": "sections"
2606
+ },
2607
+ "selectionSet": {
2608
+ "kind": "SelectionSet",
2609
+ "selections": [
2610
+ {
2611
+ "kind": "Field",
2612
+ "name": {
2613
+ "kind": "Name",
2614
+ "value": "id"
2615
+ }
2616
+ },
2617
+ {
2618
+ "kind": "Field",
2619
+ "name": {
2620
+ "kind": "Name",
2621
+ "value": "title"
2622
+ }
2623
+ },
2624
+ {
2625
+ "kind": "Field",
2626
+ "name": {
2627
+ "kind": "Name",
2628
+ "value": "index"
2629
+ }
2630
+ },
2631
+ {
2632
+ "kind": "Field",
2633
+ "name": {
2634
+ "kind": "Name",
2635
+ "value": "status"
2636
+ }
2637
+ },
2638
+ {
2639
+ "kind": "Field",
2640
+ "name": {
2641
+ "kind": "Name",
2642
+ "value": "questions"
2643
+ },
2644
+ "selectionSet": {
2645
+ "kind": "SelectionSet",
2646
+ "selections": [{
2647
+ "kind": "Field",
2648
+ "name": {
2649
+ "kind": "Name",
2650
+ "value": "id"
2651
+ }
2652
+ }]
2653
+ }
2654
+ }
2655
+ ]
2656
+ }
2657
+ }
2658
+ ]
2659
+ }
2660
+ }]
2661
+ }
2662
+ }]
2663
+ }
2664
+ }]
2665
+ },
2666
+ "\n query AssessmentsListFormComments($first: Int, $offset: Int, $formIds: [ID!], $authorIds: [ID!]) {\n assessmentFormComments(\n first: $first\n offset: $offset\n filterBy: { assessmentFormIds: $formIds, authorIds: $authorIds }\n ) {\n nodes {\n id\n content\n parentCommentId\n resolvedAt\n createdAt\n updatedAt\n externalAuthorEmail\n author {\n id\n email\n name\n }\n files {\n id\n }\n }\n totalCount\n }\n }\n": {
2667
+ "kind": "Document",
2668
+ "definitions": [{
2669
+ "kind": "OperationDefinition",
2670
+ "operation": "query",
2671
+ "name": {
2672
+ "kind": "Name",
2673
+ "value": "AssessmentsListFormComments"
2674
+ },
2675
+ "variableDefinitions": [
2676
+ {
2677
+ "kind": "VariableDefinition",
2678
+ "variable": {
2679
+ "kind": "Variable",
2680
+ "name": {
2681
+ "kind": "Name",
2682
+ "value": "first"
2683
+ }
2684
+ },
2685
+ "type": {
2686
+ "kind": "NamedType",
2687
+ "name": {
2688
+ "kind": "Name",
2689
+ "value": "Int"
2690
+ }
2691
+ }
2692
+ },
2693
+ {
2694
+ "kind": "VariableDefinition",
2695
+ "variable": {
2696
+ "kind": "Variable",
2697
+ "name": {
2698
+ "kind": "Name",
2699
+ "value": "offset"
2700
+ }
2701
+ },
2702
+ "type": {
2703
+ "kind": "NamedType",
2704
+ "name": {
2705
+ "kind": "Name",
2706
+ "value": "Int"
2707
+ }
2708
+ }
2709
+ },
2710
+ {
2711
+ "kind": "VariableDefinition",
2712
+ "variable": {
2713
+ "kind": "Variable",
2714
+ "name": {
2715
+ "kind": "Name",
2716
+ "value": "formIds"
2717
+ }
2718
+ },
2719
+ "type": {
2720
+ "kind": "ListType",
2721
+ "type": {
2722
+ "kind": "NonNullType",
2723
+ "type": {
2724
+ "kind": "NamedType",
2725
+ "name": {
2726
+ "kind": "Name",
2727
+ "value": "ID"
2728
+ }
2729
+ }
2730
+ }
2731
+ }
2732
+ },
2733
+ {
2734
+ "kind": "VariableDefinition",
2735
+ "variable": {
2736
+ "kind": "Variable",
2737
+ "name": {
2738
+ "kind": "Name",
2739
+ "value": "authorIds"
2740
+ }
2741
+ },
2742
+ "type": {
2743
+ "kind": "ListType",
2744
+ "type": {
2745
+ "kind": "NonNullType",
2746
+ "type": {
2747
+ "kind": "NamedType",
2748
+ "name": {
2749
+ "kind": "Name",
2750
+ "value": "ID"
2751
+ }
2752
+ }
2753
+ }
2754
+ }
2755
+ }
2756
+ ],
2757
+ "selectionSet": {
2758
+ "kind": "SelectionSet",
2759
+ "selections": [{
2760
+ "kind": "Field",
2761
+ "name": {
2762
+ "kind": "Name",
2763
+ "value": "assessmentFormComments"
2764
+ },
2765
+ "arguments": [
2766
+ {
2767
+ "kind": "Argument",
2768
+ "name": {
2769
+ "kind": "Name",
2770
+ "value": "first"
2771
+ },
2772
+ "value": {
2773
+ "kind": "Variable",
2774
+ "name": {
2775
+ "kind": "Name",
2776
+ "value": "first"
2777
+ }
2778
+ }
2779
+ },
2780
+ {
2781
+ "kind": "Argument",
2782
+ "name": {
2783
+ "kind": "Name",
2784
+ "value": "offset"
2785
+ },
2786
+ "value": {
2787
+ "kind": "Variable",
2788
+ "name": {
2789
+ "kind": "Name",
2790
+ "value": "offset"
2791
+ }
2792
+ }
2793
+ },
2794
+ {
2795
+ "kind": "Argument",
2796
+ "name": {
2797
+ "kind": "Name",
2798
+ "value": "filterBy"
2799
+ },
2800
+ "value": {
2801
+ "kind": "ObjectValue",
2802
+ "fields": [{
2803
+ "kind": "ObjectField",
2804
+ "name": {
2805
+ "kind": "Name",
2806
+ "value": "assessmentFormIds"
2807
+ },
2808
+ "value": {
2809
+ "kind": "Variable",
2810
+ "name": {
2811
+ "kind": "Name",
2812
+ "value": "formIds"
2813
+ }
2814
+ }
2815
+ }, {
2816
+ "kind": "ObjectField",
2817
+ "name": {
2818
+ "kind": "Name",
2819
+ "value": "authorIds"
2820
+ },
2821
+ "value": {
2822
+ "kind": "Variable",
2823
+ "name": {
2824
+ "kind": "Name",
2825
+ "value": "authorIds"
2826
+ }
2827
+ }
2828
+ }]
2829
+ }
2830
+ }
2831
+ ],
2832
+ "selectionSet": {
2833
+ "kind": "SelectionSet",
2834
+ "selections": [{
2835
+ "kind": "Field",
2836
+ "name": {
2837
+ "kind": "Name",
2838
+ "value": "nodes"
2839
+ },
2840
+ "selectionSet": {
2841
+ "kind": "SelectionSet",
2842
+ "selections": [
2843
+ {
2844
+ "kind": "Field",
2845
+ "name": {
2846
+ "kind": "Name",
2847
+ "value": "id"
2848
+ }
2849
+ },
2850
+ {
2851
+ "kind": "Field",
2852
+ "name": {
2853
+ "kind": "Name",
2854
+ "value": "content"
2855
+ }
2856
+ },
2857
+ {
2858
+ "kind": "Field",
2859
+ "name": {
2860
+ "kind": "Name",
2861
+ "value": "parentCommentId"
2862
+ }
2863
+ },
2864
+ {
2865
+ "kind": "Field",
2866
+ "name": {
2867
+ "kind": "Name",
2868
+ "value": "resolvedAt"
2869
+ }
2870
+ },
2871
+ {
2872
+ "kind": "Field",
2873
+ "name": {
2874
+ "kind": "Name",
2875
+ "value": "createdAt"
2876
+ }
2877
+ },
2878
+ {
2879
+ "kind": "Field",
2880
+ "name": {
2881
+ "kind": "Name",
2882
+ "value": "updatedAt"
2883
+ }
2884
+ },
2885
+ {
2886
+ "kind": "Field",
2887
+ "name": {
2888
+ "kind": "Name",
2889
+ "value": "externalAuthorEmail"
2890
+ }
2891
+ },
2892
+ {
2893
+ "kind": "Field",
2894
+ "name": {
2895
+ "kind": "Name",
2896
+ "value": "author"
2897
+ },
2898
+ "selectionSet": {
2899
+ "kind": "SelectionSet",
2900
+ "selections": [
2901
+ {
2902
+ "kind": "Field",
2903
+ "name": {
2904
+ "kind": "Name",
2905
+ "value": "id"
2906
+ }
2907
+ },
2908
+ {
2909
+ "kind": "Field",
2910
+ "name": {
2911
+ "kind": "Name",
2912
+ "value": "email"
2913
+ }
2914
+ },
2915
+ {
2916
+ "kind": "Field",
2917
+ "name": {
2918
+ "kind": "Name",
2919
+ "value": "name"
2920
+ }
2921
+ }
2922
+ ]
2923
+ }
2924
+ },
2925
+ {
2926
+ "kind": "Field",
2927
+ "name": {
2928
+ "kind": "Name",
2929
+ "value": "files"
2930
+ },
2931
+ "selectionSet": {
2932
+ "kind": "SelectionSet",
2933
+ "selections": [{
2934
+ "kind": "Field",
2935
+ "name": {
2936
+ "kind": "Name",
2937
+ "value": "id"
2938
+ }
2939
+ }]
2940
+ }
2941
+ }
2942
+ ]
2943
+ }
2944
+ }, {
2945
+ "kind": "Field",
2946
+ "name": {
2947
+ "kind": "Name",
2948
+ "value": "totalCount"
2949
+ }
2950
+ }]
2951
+ }
2952
+ }]
2953
+ }
2954
+ }]
2955
+ },
2956
+ "\n query AssessmentsListSectionComments(\n $first: Int\n $offset: Int\n $sectionIds: [ID!]\n $authorIds: [ID!]\n ) {\n assessmentSectionComments(\n first: $first\n offset: $offset\n filterBy: { assessmentSectionIds: $sectionIds, authorIds: $authorIds }\n ) {\n nodes {\n id\n content\n assessmentSectionId\n parentCommentId\n resolvedAt\n createdAt\n updatedAt\n externalAuthorEmail\n author {\n id\n email\n name\n }\n files {\n id\n }\n }\n totalCount\n }\n }\n": {
2957
+ "kind": "Document",
2958
+ "definitions": [{
2959
+ "kind": "OperationDefinition",
2960
+ "operation": "query",
2961
+ "name": {
2962
+ "kind": "Name",
2963
+ "value": "AssessmentsListSectionComments"
2964
+ },
2965
+ "variableDefinitions": [
2966
+ {
2967
+ "kind": "VariableDefinition",
2968
+ "variable": {
2969
+ "kind": "Variable",
2970
+ "name": {
2971
+ "kind": "Name",
2972
+ "value": "first"
2973
+ }
2974
+ },
2975
+ "type": {
2976
+ "kind": "NamedType",
2977
+ "name": {
2978
+ "kind": "Name",
2979
+ "value": "Int"
2980
+ }
2981
+ }
2982
+ },
2983
+ {
2984
+ "kind": "VariableDefinition",
2985
+ "variable": {
2986
+ "kind": "Variable",
2987
+ "name": {
2988
+ "kind": "Name",
2989
+ "value": "offset"
2990
+ }
2991
+ },
2992
+ "type": {
2993
+ "kind": "NamedType",
2994
+ "name": {
2995
+ "kind": "Name",
2996
+ "value": "Int"
2997
+ }
2998
+ }
2999
+ },
3000
+ {
3001
+ "kind": "VariableDefinition",
3002
+ "variable": {
3003
+ "kind": "Variable",
3004
+ "name": {
3005
+ "kind": "Name",
3006
+ "value": "sectionIds"
3007
+ }
3008
+ },
3009
+ "type": {
3010
+ "kind": "ListType",
3011
+ "type": {
3012
+ "kind": "NonNullType",
3013
+ "type": {
3014
+ "kind": "NamedType",
3015
+ "name": {
3016
+ "kind": "Name",
3017
+ "value": "ID"
3018
+ }
3019
+ }
3020
+ }
3021
+ }
3022
+ },
3023
+ {
3024
+ "kind": "VariableDefinition",
3025
+ "variable": {
3026
+ "kind": "Variable",
3027
+ "name": {
3028
+ "kind": "Name",
3029
+ "value": "authorIds"
3030
+ }
3031
+ },
3032
+ "type": {
3033
+ "kind": "ListType",
3034
+ "type": {
3035
+ "kind": "NonNullType",
3036
+ "type": {
3037
+ "kind": "NamedType",
3038
+ "name": {
3039
+ "kind": "Name",
3040
+ "value": "ID"
3041
+ }
3042
+ }
3043
+ }
3044
+ }
3045
+ }
3046
+ ],
3047
+ "selectionSet": {
3048
+ "kind": "SelectionSet",
3049
+ "selections": [{
3050
+ "kind": "Field",
3051
+ "name": {
3052
+ "kind": "Name",
3053
+ "value": "assessmentSectionComments"
3054
+ },
3055
+ "arguments": [
3056
+ {
3057
+ "kind": "Argument",
3058
+ "name": {
3059
+ "kind": "Name",
3060
+ "value": "first"
3061
+ },
3062
+ "value": {
3063
+ "kind": "Variable",
3064
+ "name": {
3065
+ "kind": "Name",
3066
+ "value": "first"
3067
+ }
3068
+ }
3069
+ },
3070
+ {
3071
+ "kind": "Argument",
3072
+ "name": {
3073
+ "kind": "Name",
3074
+ "value": "offset"
3075
+ },
3076
+ "value": {
3077
+ "kind": "Variable",
3078
+ "name": {
3079
+ "kind": "Name",
3080
+ "value": "offset"
3081
+ }
3082
+ }
3083
+ },
3084
+ {
3085
+ "kind": "Argument",
3086
+ "name": {
3087
+ "kind": "Name",
3088
+ "value": "filterBy"
3089
+ },
3090
+ "value": {
3091
+ "kind": "ObjectValue",
3092
+ "fields": [{
3093
+ "kind": "ObjectField",
3094
+ "name": {
3095
+ "kind": "Name",
3096
+ "value": "assessmentSectionIds"
3097
+ },
3098
+ "value": {
3099
+ "kind": "Variable",
3100
+ "name": {
3101
+ "kind": "Name",
3102
+ "value": "sectionIds"
3103
+ }
3104
+ }
3105
+ }, {
3106
+ "kind": "ObjectField",
3107
+ "name": {
3108
+ "kind": "Name",
3109
+ "value": "authorIds"
3110
+ },
3111
+ "value": {
3112
+ "kind": "Variable",
3113
+ "name": {
3114
+ "kind": "Name",
3115
+ "value": "authorIds"
3116
+ }
3117
+ }
3118
+ }]
3119
+ }
3120
+ }
3121
+ ],
3122
+ "selectionSet": {
3123
+ "kind": "SelectionSet",
3124
+ "selections": [{
3125
+ "kind": "Field",
3126
+ "name": {
3127
+ "kind": "Name",
3128
+ "value": "nodes"
3129
+ },
3130
+ "selectionSet": {
3131
+ "kind": "SelectionSet",
3132
+ "selections": [
3133
+ {
3134
+ "kind": "Field",
3135
+ "name": {
3136
+ "kind": "Name",
3137
+ "value": "id"
3138
+ }
3139
+ },
3140
+ {
3141
+ "kind": "Field",
3142
+ "name": {
3143
+ "kind": "Name",
3144
+ "value": "content"
3145
+ }
3146
+ },
3147
+ {
3148
+ "kind": "Field",
3149
+ "name": {
3150
+ "kind": "Name",
3151
+ "value": "assessmentSectionId"
3152
+ }
3153
+ },
3154
+ {
3155
+ "kind": "Field",
3156
+ "name": {
3157
+ "kind": "Name",
3158
+ "value": "parentCommentId"
3159
+ }
3160
+ },
3161
+ {
3162
+ "kind": "Field",
3163
+ "name": {
3164
+ "kind": "Name",
3165
+ "value": "resolvedAt"
3166
+ }
3167
+ },
3168
+ {
3169
+ "kind": "Field",
3170
+ "name": {
3171
+ "kind": "Name",
3172
+ "value": "createdAt"
3173
+ }
3174
+ },
3175
+ {
3176
+ "kind": "Field",
3177
+ "name": {
3178
+ "kind": "Name",
3179
+ "value": "updatedAt"
3180
+ }
3181
+ },
3182
+ {
3183
+ "kind": "Field",
3184
+ "name": {
3185
+ "kind": "Name",
3186
+ "value": "externalAuthorEmail"
3187
+ }
3188
+ },
3189
+ {
3190
+ "kind": "Field",
3191
+ "name": {
3192
+ "kind": "Name",
3193
+ "value": "author"
3194
+ },
3195
+ "selectionSet": {
3196
+ "kind": "SelectionSet",
3197
+ "selections": [
3198
+ {
3199
+ "kind": "Field",
3200
+ "name": {
3201
+ "kind": "Name",
3202
+ "value": "id"
3203
+ }
3204
+ },
3205
+ {
3206
+ "kind": "Field",
3207
+ "name": {
3208
+ "kind": "Name",
3209
+ "value": "email"
3210
+ }
3211
+ },
3212
+ {
3213
+ "kind": "Field",
3214
+ "name": {
3215
+ "kind": "Name",
3216
+ "value": "name"
3217
+ }
3218
+ }
3219
+ ]
3220
+ }
3221
+ },
3222
+ {
3223
+ "kind": "Field",
3224
+ "name": {
3225
+ "kind": "Name",
3226
+ "value": "files"
3227
+ },
3228
+ "selectionSet": {
3229
+ "kind": "SelectionSet",
3230
+ "selections": [{
3231
+ "kind": "Field",
3232
+ "name": {
3233
+ "kind": "Name",
3234
+ "value": "id"
3235
+ }
3236
+ }]
3237
+ }
3238
+ }
3239
+ ]
3240
+ }
3241
+ }, {
3242
+ "kind": "Field",
3243
+ "name": {
3244
+ "kind": "Name",
3245
+ "value": "totalCount"
3246
+ }
3247
+ }]
3248
+ }
3249
+ }]
3250
+ }
3251
+ }]
3252
+ },
3253
+ "\n query AssessmentsCommentTargets($ids: [ID!]!) {\n assessmentForms(first: 1, filterBy: { ids: $ids }) {\n nodes {\n id\n sections {\n id\n questions {\n id\n }\n }\n }\n }\n }\n": {
3254
+ "kind": "Document",
3255
+ "definitions": [{
3256
+ "kind": "OperationDefinition",
3257
+ "operation": "query",
3258
+ "name": {
3259
+ "kind": "Name",
3260
+ "value": "AssessmentsCommentTargets"
3261
+ },
3262
+ "variableDefinitions": [{
3263
+ "kind": "VariableDefinition",
3264
+ "variable": {
3265
+ "kind": "Variable",
3266
+ "name": {
3267
+ "kind": "Name",
3268
+ "value": "ids"
3269
+ }
3270
+ },
3271
+ "type": {
3272
+ "kind": "NonNullType",
3273
+ "type": {
3274
+ "kind": "ListType",
3275
+ "type": {
3276
+ "kind": "NonNullType",
3277
+ "type": {
3278
+ "kind": "NamedType",
3279
+ "name": {
3280
+ "kind": "Name",
3281
+ "value": "ID"
3282
+ }
3283
+ }
3284
+ }
3285
+ }
3286
+ }
3287
+ }],
3288
+ "selectionSet": {
3289
+ "kind": "SelectionSet",
3290
+ "selections": [{
3291
+ "kind": "Field",
3292
+ "name": {
3293
+ "kind": "Name",
3294
+ "value": "assessmentForms"
3295
+ },
3296
+ "arguments": [{
3297
+ "kind": "Argument",
3298
+ "name": {
3299
+ "kind": "Name",
3300
+ "value": "first"
3301
+ },
3302
+ "value": {
3303
+ "kind": "IntValue",
3304
+ "value": "1"
3305
+ }
3306
+ }, {
3307
+ "kind": "Argument",
3308
+ "name": {
3309
+ "kind": "Name",
3310
+ "value": "filterBy"
3311
+ },
3312
+ "value": {
3313
+ "kind": "ObjectValue",
3314
+ "fields": [{
3315
+ "kind": "ObjectField",
3316
+ "name": {
3317
+ "kind": "Name",
3318
+ "value": "ids"
3319
+ },
3320
+ "value": {
3321
+ "kind": "Variable",
3322
+ "name": {
3323
+ "kind": "Name",
3324
+ "value": "ids"
3325
+ }
3326
+ }
3327
+ }]
3328
+ }
3329
+ }],
3330
+ "selectionSet": {
3331
+ "kind": "SelectionSet",
3332
+ "selections": [{
3333
+ "kind": "Field",
3334
+ "name": {
3335
+ "kind": "Name",
3336
+ "value": "nodes"
3337
+ },
3338
+ "selectionSet": {
3339
+ "kind": "SelectionSet",
3340
+ "selections": [{
3341
+ "kind": "Field",
3342
+ "name": {
3343
+ "kind": "Name",
3344
+ "value": "id"
3345
+ }
3346
+ }, {
3347
+ "kind": "Field",
3348
+ "name": {
3349
+ "kind": "Name",
3350
+ "value": "sections"
3351
+ },
3352
+ "selectionSet": {
3353
+ "kind": "SelectionSet",
3354
+ "selections": [{
3355
+ "kind": "Field",
3356
+ "name": {
3357
+ "kind": "Name",
3358
+ "value": "id"
3359
+ }
3360
+ }, {
3361
+ "kind": "Field",
3362
+ "name": {
3363
+ "kind": "Name",
3364
+ "value": "questions"
3365
+ },
3366
+ "selectionSet": {
3367
+ "kind": "SelectionSet",
3368
+ "selections": [{
3369
+ "kind": "Field",
3370
+ "name": {
3371
+ "kind": "Name",
3372
+ "value": "id"
3373
+ }
3374
+ }]
3375
+ }
3376
+ }]
3377
+ }
3378
+ }]
3379
+ }
3380
+ }]
3381
+ }
3382
+ }]
3383
+ }
3384
+ }]
3385
+ },
3386
+ "\n query AssessmentsCountFormComments($formIds: [ID!]) {\n assessmentFormComments(first: 1, filterBy: { assessmentFormIds: $formIds }) {\n totalCount\n }\n }\n": {
3387
+ "kind": "Document",
3388
+ "definitions": [{
3389
+ "kind": "OperationDefinition",
3390
+ "operation": "query",
3391
+ "name": {
3392
+ "kind": "Name",
3393
+ "value": "AssessmentsCountFormComments"
3394
+ },
3395
+ "variableDefinitions": [{
3396
+ "kind": "VariableDefinition",
3397
+ "variable": {
3398
+ "kind": "Variable",
3399
+ "name": {
3400
+ "kind": "Name",
3401
+ "value": "formIds"
3402
+ }
3403
+ },
3404
+ "type": {
3405
+ "kind": "ListType",
3406
+ "type": {
3407
+ "kind": "NonNullType",
3408
+ "type": {
3409
+ "kind": "NamedType",
3410
+ "name": {
3411
+ "kind": "Name",
3412
+ "value": "ID"
3413
+ }
3414
+ }
3415
+ }
3416
+ }
3417
+ }],
3418
+ "selectionSet": {
3419
+ "kind": "SelectionSet",
3420
+ "selections": [{
3421
+ "kind": "Field",
3422
+ "name": {
3423
+ "kind": "Name",
3424
+ "value": "assessmentFormComments"
3425
+ },
3426
+ "arguments": [{
3427
+ "kind": "Argument",
3428
+ "name": {
3429
+ "kind": "Name",
3430
+ "value": "first"
3431
+ },
3432
+ "value": {
3433
+ "kind": "IntValue",
3434
+ "value": "1"
3435
+ }
3436
+ }, {
3437
+ "kind": "Argument",
3438
+ "name": {
3439
+ "kind": "Name",
3440
+ "value": "filterBy"
3441
+ },
3442
+ "value": {
3443
+ "kind": "ObjectValue",
3444
+ "fields": [{
3445
+ "kind": "ObjectField",
3446
+ "name": {
3447
+ "kind": "Name",
3448
+ "value": "assessmentFormIds"
3449
+ },
3450
+ "value": {
3451
+ "kind": "Variable",
3452
+ "name": {
3453
+ "kind": "Name",
3454
+ "value": "formIds"
3455
+ }
3456
+ }
3457
+ }]
3458
+ }
3459
+ }],
3460
+ "selectionSet": {
3461
+ "kind": "SelectionSet",
3462
+ "selections": [{
3463
+ "kind": "Field",
3464
+ "name": {
3465
+ "kind": "Name",
3466
+ "value": "totalCount"
3467
+ }
3468
+ }]
3469
+ }
3470
+ }]
3471
+ }
3472
+ }]
3473
+ },
3474
+ "\n query AssessmentsCountSectionComments($sectionIds: [ID!]) {\n assessmentSectionComments(first: 1, filterBy: { assessmentSectionIds: $sectionIds }) {\n totalCount\n }\n }\n": {
3475
+ "kind": "Document",
3476
+ "definitions": [{
3477
+ "kind": "OperationDefinition",
3478
+ "operation": "query",
3479
+ "name": {
3480
+ "kind": "Name",
3481
+ "value": "AssessmentsCountSectionComments"
3482
+ },
3483
+ "variableDefinitions": [{
3484
+ "kind": "VariableDefinition",
3485
+ "variable": {
3486
+ "kind": "Variable",
3487
+ "name": {
3488
+ "kind": "Name",
3489
+ "value": "sectionIds"
3490
+ }
3491
+ },
3492
+ "type": {
3493
+ "kind": "ListType",
3494
+ "type": {
3495
+ "kind": "NonNullType",
3496
+ "type": {
3497
+ "kind": "NamedType",
3498
+ "name": {
3499
+ "kind": "Name",
3500
+ "value": "ID"
3501
+ }
3502
+ }
3503
+ }
3504
+ }
3505
+ }],
3506
+ "selectionSet": {
3507
+ "kind": "SelectionSet",
3508
+ "selections": [{
3509
+ "kind": "Field",
3510
+ "name": {
3511
+ "kind": "Name",
3512
+ "value": "assessmentSectionComments"
3513
+ },
3514
+ "arguments": [{
3515
+ "kind": "Argument",
3516
+ "name": {
3517
+ "kind": "Name",
3518
+ "value": "first"
3519
+ },
3520
+ "value": {
3521
+ "kind": "IntValue",
3522
+ "value": "1"
3523
+ }
3524
+ }, {
3525
+ "kind": "Argument",
3526
+ "name": {
3527
+ "kind": "Name",
3528
+ "value": "filterBy"
3529
+ },
3530
+ "value": {
3531
+ "kind": "ObjectValue",
3532
+ "fields": [{
3533
+ "kind": "ObjectField",
3534
+ "name": {
3535
+ "kind": "Name",
3536
+ "value": "assessmentSectionIds"
3537
+ },
3538
+ "value": {
3539
+ "kind": "Variable",
3540
+ "name": {
3541
+ "kind": "Name",
3542
+ "value": "sectionIds"
3543
+ }
3544
+ }
3545
+ }]
3546
+ }
3547
+ }],
3548
+ "selectionSet": {
3549
+ "kind": "SelectionSet",
3550
+ "selections": [{
3551
+ "kind": "Field",
3552
+ "name": {
3553
+ "kind": "Name",
3554
+ "value": "totalCount"
3555
+ }
3556
+ }]
3557
+ }
3558
+ }]
3559
+ }
3560
+ }]
3561
+ },
3562
+ "\n query AssessmentsCountQuestionComments($questionIds: [ID!]) {\n assessmentQuestionComments(first: 1, filterBy: { assessmentQuestionIds: $questionIds }) {\n totalCount\n }\n }\n": {
3563
+ "kind": "Document",
3564
+ "definitions": [{
3565
+ "kind": "OperationDefinition",
3566
+ "operation": "query",
3567
+ "name": {
3568
+ "kind": "Name",
3569
+ "value": "AssessmentsCountQuestionComments"
3570
+ },
3571
+ "variableDefinitions": [{
3572
+ "kind": "VariableDefinition",
3573
+ "variable": {
3574
+ "kind": "Variable",
3575
+ "name": {
3576
+ "kind": "Name",
3577
+ "value": "questionIds"
3578
+ }
3579
+ },
3580
+ "type": {
3581
+ "kind": "ListType",
3582
+ "type": {
3583
+ "kind": "NonNullType",
3584
+ "type": {
3585
+ "kind": "NamedType",
3586
+ "name": {
3587
+ "kind": "Name",
3588
+ "value": "ID"
3589
+ }
3590
+ }
3591
+ }
3592
+ }
3593
+ }],
3594
+ "selectionSet": {
3595
+ "kind": "SelectionSet",
3596
+ "selections": [{
3597
+ "kind": "Field",
3598
+ "name": {
3599
+ "kind": "Name",
3600
+ "value": "assessmentQuestionComments"
3601
+ },
3602
+ "arguments": [{
3603
+ "kind": "Argument",
3604
+ "name": {
3605
+ "kind": "Name",
3606
+ "value": "first"
3607
+ },
3608
+ "value": {
3609
+ "kind": "IntValue",
3610
+ "value": "1"
3611
+ }
3612
+ }, {
3613
+ "kind": "Argument",
3614
+ "name": {
3615
+ "kind": "Name",
3616
+ "value": "filterBy"
3617
+ },
3618
+ "value": {
3619
+ "kind": "ObjectValue",
3620
+ "fields": [{
3621
+ "kind": "ObjectField",
3622
+ "name": {
3623
+ "kind": "Name",
3624
+ "value": "assessmentQuestionIds"
3625
+ },
3626
+ "value": {
3627
+ "kind": "Variable",
3628
+ "name": {
3629
+ "kind": "Name",
3630
+ "value": "questionIds"
3631
+ }
3632
+ }
3633
+ }]
3634
+ }
3635
+ }],
3636
+ "selectionSet": {
3637
+ "kind": "SelectionSet",
3638
+ "selections": [{
3639
+ "kind": "Field",
3640
+ "name": {
3641
+ "kind": "Name",
3642
+ "value": "totalCount"
3643
+ }
3644
+ }]
3645
+ }
3646
+ }]
3647
+ }
3648
+ }]
3649
+ },
3650
+ "\n query AssessmentsListQuestionComments($ids: [ID!]!) {\n assessmentForms(first: 1, filterBy: { ids: $ids }) {\n nodes {\n sections {\n id\n title\n questions {\n id\n title\n comments {\n id\n content\n parentCommentId\n resolvedAt\n createdAt\n updatedAt\n externalAuthorEmail\n author {\n id\n email\n name\n }\n files {\n id\n }\n }\n }\n }\n }\n }\n }\n": {
3651
+ "kind": "Document",
3652
+ "definitions": [{
3653
+ "kind": "OperationDefinition",
3654
+ "operation": "query",
3655
+ "name": {
3656
+ "kind": "Name",
3657
+ "value": "AssessmentsListQuestionComments"
3658
+ },
3659
+ "variableDefinitions": [{
3660
+ "kind": "VariableDefinition",
3661
+ "variable": {
3662
+ "kind": "Variable",
3663
+ "name": {
3664
+ "kind": "Name",
3665
+ "value": "ids"
3666
+ }
3667
+ },
3668
+ "type": {
3669
+ "kind": "NonNullType",
3670
+ "type": {
3671
+ "kind": "ListType",
3672
+ "type": {
3673
+ "kind": "NonNullType",
3674
+ "type": {
3675
+ "kind": "NamedType",
3676
+ "name": {
3677
+ "kind": "Name",
3678
+ "value": "ID"
3679
+ }
3680
+ }
3681
+ }
3682
+ }
3683
+ }
3684
+ }],
3685
+ "selectionSet": {
3686
+ "kind": "SelectionSet",
3687
+ "selections": [{
3688
+ "kind": "Field",
3689
+ "name": {
3690
+ "kind": "Name",
3691
+ "value": "assessmentForms"
3692
+ },
3693
+ "arguments": [{
3694
+ "kind": "Argument",
3695
+ "name": {
3696
+ "kind": "Name",
3697
+ "value": "first"
3698
+ },
3699
+ "value": {
3700
+ "kind": "IntValue",
3701
+ "value": "1"
3702
+ }
3703
+ }, {
3704
+ "kind": "Argument",
3705
+ "name": {
3706
+ "kind": "Name",
3707
+ "value": "filterBy"
3708
+ },
3709
+ "value": {
3710
+ "kind": "ObjectValue",
3711
+ "fields": [{
3712
+ "kind": "ObjectField",
3713
+ "name": {
3714
+ "kind": "Name",
3715
+ "value": "ids"
3716
+ },
3717
+ "value": {
3718
+ "kind": "Variable",
3719
+ "name": {
3720
+ "kind": "Name",
3721
+ "value": "ids"
3722
+ }
3723
+ }
3724
+ }]
3725
+ }
3726
+ }],
3727
+ "selectionSet": {
3728
+ "kind": "SelectionSet",
3729
+ "selections": [{
3730
+ "kind": "Field",
3731
+ "name": {
3732
+ "kind": "Name",
3733
+ "value": "nodes"
3734
+ },
3735
+ "selectionSet": {
3736
+ "kind": "SelectionSet",
3737
+ "selections": [{
3738
+ "kind": "Field",
3739
+ "name": {
3740
+ "kind": "Name",
3741
+ "value": "sections"
3742
+ },
3743
+ "selectionSet": {
3744
+ "kind": "SelectionSet",
3745
+ "selections": [
3746
+ {
3747
+ "kind": "Field",
3748
+ "name": {
3749
+ "kind": "Name",
3750
+ "value": "id"
3751
+ }
3752
+ },
3753
+ {
3754
+ "kind": "Field",
3755
+ "name": {
3756
+ "kind": "Name",
3757
+ "value": "title"
3758
+ }
3759
+ },
3760
+ {
3761
+ "kind": "Field",
3762
+ "name": {
3763
+ "kind": "Name",
3764
+ "value": "questions"
3765
+ },
3766
+ "selectionSet": {
3767
+ "kind": "SelectionSet",
3768
+ "selections": [
3769
+ {
3770
+ "kind": "Field",
3771
+ "name": {
3772
+ "kind": "Name",
3773
+ "value": "id"
3774
+ }
3775
+ },
3776
+ {
3777
+ "kind": "Field",
3778
+ "name": {
3779
+ "kind": "Name",
3780
+ "value": "title"
3781
+ }
3782
+ },
3783
+ {
3784
+ "kind": "Field",
3785
+ "name": {
3786
+ "kind": "Name",
3787
+ "value": "comments"
1648
3788
  },
1649
- {
1650
- "kind": "Field",
1651
- "name": {
1652
- "kind": "Name",
1653
- "value": "answerOptions"
1654
- },
1655
- "selectionSet": {
1656
- "kind": "SelectionSet",
1657
- "selections": [
1658
- {
1659
- "kind": "Field",
1660
- "name": {
1661
- "kind": "Name",
1662
- "value": "id"
1663
- }
1664
- },
1665
- {
1666
- "kind": "Field",
1667
- "name": {
1668
- "kind": "Name",
1669
- "value": "index"
1670
- }
1671
- },
1672
- {
1673
- "kind": "Field",
1674
- "name": {
1675
- "kind": "Name",
1676
- "value": "value"
1677
- }
3789
+ "selectionSet": {
3790
+ "kind": "SelectionSet",
3791
+ "selections": [
3792
+ {
3793
+ "kind": "Field",
3794
+ "name": {
3795
+ "kind": "Name",
3796
+ "value": "id"
1678
3797
  }
1679
- ]
1680
- }
1681
- },
1682
- {
1683
- "kind": "Field",
1684
- "name": {
1685
- "kind": "Name",
1686
- "value": "selectedAnswers"
1687
- },
1688
- "selectionSet": {
1689
- "kind": "SelectionSet",
1690
- "selections": [
1691
- {
1692
- "kind": "Field",
1693
- "name": {
1694
- "kind": "Name",
1695
- "value": "id"
1696
- }
3798
+ },
3799
+ {
3800
+ "kind": "Field",
3801
+ "name": {
3802
+ "kind": "Name",
3803
+ "value": "content"
3804
+ }
3805
+ },
3806
+ {
3807
+ "kind": "Field",
3808
+ "name": {
3809
+ "kind": "Name",
3810
+ "value": "parentCommentId"
3811
+ }
3812
+ },
3813
+ {
3814
+ "kind": "Field",
3815
+ "name": {
3816
+ "kind": "Name",
3817
+ "value": "resolvedAt"
3818
+ }
3819
+ },
3820
+ {
3821
+ "kind": "Field",
3822
+ "name": {
3823
+ "kind": "Name",
3824
+ "value": "createdAt"
3825
+ }
3826
+ },
3827
+ {
3828
+ "kind": "Field",
3829
+ "name": {
3830
+ "kind": "Name",
3831
+ "value": "updatedAt"
3832
+ }
3833
+ },
3834
+ {
3835
+ "kind": "Field",
3836
+ "name": {
3837
+ "kind": "Name",
3838
+ "value": "externalAuthorEmail"
3839
+ }
3840
+ },
3841
+ {
3842
+ "kind": "Field",
3843
+ "name": {
3844
+ "kind": "Name",
3845
+ "value": "author"
1697
3846
  },
1698
- {
1699
- "kind": "Field",
1700
- "name": {
1701
- "kind": "Name",
1702
- "value": "index"
1703
- }
3847
+ "selectionSet": {
3848
+ "kind": "SelectionSet",
3849
+ "selections": [
3850
+ {
3851
+ "kind": "Field",
3852
+ "name": {
3853
+ "kind": "Name",
3854
+ "value": "id"
3855
+ }
3856
+ },
3857
+ {
3858
+ "kind": "Field",
3859
+ "name": {
3860
+ "kind": "Name",
3861
+ "value": "email"
3862
+ }
3863
+ },
3864
+ {
3865
+ "kind": "Field",
3866
+ "name": {
3867
+ "kind": "Name",
3868
+ "value": "name"
3869
+ }
3870
+ }
3871
+ ]
3872
+ }
3873
+ },
3874
+ {
3875
+ "kind": "Field",
3876
+ "name": {
3877
+ "kind": "Name",
3878
+ "value": "files"
1704
3879
  },
1705
- {
1706
- "kind": "Field",
1707
- "name": {
1708
- "kind": "Name",
1709
- "value": "value"
1710
- }
3880
+ "selectionSet": {
3881
+ "kind": "SelectionSet",
3882
+ "selections": [{
3883
+ "kind": "Field",
3884
+ "name": {
3885
+ "kind": "Name",
3886
+ "value": "id"
3887
+ }
3888
+ }]
1711
3889
  }
1712
- ]
1713
- }
3890
+ }
3891
+ ]
1714
3892
  }
1715
- ]
1716
- }
3893
+ }
3894
+ ]
1717
3895
  }
1718
- ]
1719
- }
3896
+ }
3897
+ ]
1720
3898
  }
1721
- ]
3899
+ }]
1722
3900
  }
1723
3901
  }]
1724
3902
  }
@@ -3401,9 +5579,59 @@ const documents = {
3401
5579
  function graphql(source) {
3402
5580
  return documents[source] ?? {};
3403
5581
  }
3404
- //#endregion
3405
- //#region src/graphql.ts
3406
- const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5582
+ //#endregion
5583
+ //#region src/graphql.ts
5584
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5585
+ /** Rows to pull per round trip when draining question search results. */
5586
+ const QUESTION_FETCH_CHUNK = 100;
5587
+ /**
5588
+ * Flatten one API comment into the shared {@link AssessmentComment} shape.
5589
+ * External reviewers arrive as a bare `externalAuthorEmail` rather than an
5590
+ * `author` record, so both spellings collapse into one author field.
5591
+ */
5592
+ function toComment(comment, level, targetId) {
5593
+ return {
5594
+ id: comment.id,
5595
+ level,
5596
+ targetId,
5597
+ content: comment.content,
5598
+ author: comment.author ? {
5599
+ id: comment.author.id,
5600
+ email: comment.author.email,
5601
+ name: comment.author.name
5602
+ } : comment.externalAuthorEmail ? { email: comment.externalAuthorEmail } : void 0,
5603
+ parentCommentId: comment.parentCommentId ?? void 0,
5604
+ resolvedAt: comment.resolvedAt ?? void 0,
5605
+ fileCount: comment.files?.length || void 0,
5606
+ createdAt: comment.createdAt,
5607
+ updatedAt: comment.updatedAt ?? void 0
5608
+ };
5609
+ }
5610
+ function toComments(comments, level, targetId) {
5611
+ return comments?.map((c) => toComment(c, level, targetId));
5612
+ }
5613
+ /** Not-found for a form ID, pointing the caller at the tool that lists valid IDs. */
5614
+ function assessmentNotFound(id) {
5615
+ return new ToolError(ErrorCode.NOT_FOUND, `No assessment form with id "${id}". Call assessments_list to find valid assessment IDs, or assessments_list_templates if you meant a template rather than a filled-in form.`, false, { assessmentId: id });
5616
+ }
5617
+ /**
5618
+ * Not-found for a section ID. Raised when any requested ID is missing, not only
5619
+ * when all of them are: returning the sections that did match would be a
5620
+ * partial answer wearing the shape of a complete one, and a caller who asked
5621
+ * for four sections and reads three has no way to tell. Lists the sections the
5622
+ * form does have, since the caller reached here from a skeleton read and most
5623
+ * likely mistyped or reused an ID from a different form.
5624
+ */
5625
+ function sectionNotFound(assessmentId, missing, available) {
5626
+ return new ToolError(ErrorCode.NOT_FOUND, `Assessment "${assessmentId}" has no section with ID ${missing.map((s) => `"${s}"`).join(", ")}. No sections were returned, including any that did match. Call assessments_get without sectionIds to list the sections this form has.`, false, {
5627
+ assessmentId,
5628
+ missingSectionIds: missing,
5629
+ availableSections: available.map((s) => ({
5630
+ id: s.id,
5631
+ title: s.title ?? void 0
5632
+ }))
5633
+ });
5634
+ }
3407
5635
  function generateUUID() {
3408
5636
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
3409
5637
  const r = Math.random() * 16 | 0;
@@ -3433,6 +5661,59 @@ function normalizeQuestion(q) {
3433
5661
  };
3434
5662
  }
3435
5663
  /**
5664
+ * Who a form is assigned to and who reviews it.
5665
+ *
5666
+ * A caller that has just assigned a form has no other way to confirm it took:
5667
+ * the write tools echo back a status and nothing else, so without these on the
5668
+ * form itself the only read-back is the list index, queried for a single form
5669
+ * whose id the caller is already holding.
5670
+ *
5671
+ * @param node - An assessment form as the API returns it
5672
+ * @returns The participant lists, each undefined when the API omitted it
5673
+ */
5674
+ function mapParticipants(node) {
5675
+ return {
5676
+ assignees: node.assignees?.map(({ id, name, email }) => ({
5677
+ id,
5678
+ name,
5679
+ email
5680
+ })),
5681
+ reviewers: node.reviewers?.map(({ id, name, email }) => ({
5682
+ id,
5683
+ name,
5684
+ email
5685
+ })),
5686
+ externalAssignees: node.externalAssignees?.map(({ id, email }) => ({
5687
+ id,
5688
+ email
5689
+ }))
5690
+ };
5691
+ }
5692
+ /** Narrow an API answer option to the fields a reader needs. */
5693
+ function toAnswerOption(option) {
5694
+ return {
5695
+ id: option.id,
5696
+ index: option.index,
5697
+ value: option.value
5698
+ };
5699
+ }
5700
+ /**
5701
+ * The choices on offer, dropped when they say nothing the answers do not.
5702
+ *
5703
+ * Free-text questions have no choice set: the API models the typed answer as an
5704
+ * option, so the paragraph comes back once under `answerOptions` and again,
5705
+ * byte for byte, under `selectedAnswers`. Select questions are the case worth
5706
+ * keeping, where the options a respondent passed over are real information.
5707
+ * Comparing the two by id tells them apart without hardcoding which question
5708
+ * types behave which way, and drops nothing a caller could not already read off
5709
+ * `selectedAnswers`.
5710
+ */
5711
+ function choicesNotAlreadyAnswered(options, selected) {
5712
+ if (!options) return void 0;
5713
+ const answered = new Set((selected ?? []).map((answer) => answer.id));
5714
+ return options.every((option) => answered.has(option.id)) ? void 0 : options.map(toAnswerOption);
5715
+ }
5716
+ /**
3436
5717
  * Assessment index. `AssessmentFormsPayload` exposes `totalCount` but no
3437
5718
  * `pageInfo`, so paging is offset-based and `hasNextPage` has to be derived
3438
5719
  * from `offset + nodes.length < totalCount`.
@@ -3483,12 +5764,61 @@ const ListAssessmentsDoc = graphql(`
3483
5764
  }
3484
5765
  }
3485
5766
  `);
5767
+ /**
5768
+ * Questions matched by text, queried at the root rather than through a form.
5769
+ *
5770
+ * `assessmentQuestions` is the only field that filters on question text; the
5771
+ * `questions` list hanging off a section takes no arguments at all, so the
5772
+ * alternative is reading every question and matching them here. Scoping is by
5773
+ * section id, there being no form filter, which is why the caller's sections
5774
+ * have to be resolved first.
5775
+ */
5776
+ const SearchQuestionsDoc = graphql(`
5777
+ query AssessmentQuestionsSearch(
5778
+ $first: Int
5779
+ $offset: Int
5780
+ $filterBy: AssessmentQuestionFiltersInput
5781
+ ) {
5782
+ assessmentQuestions(first: $first, offset: $offset, filterBy: $filterBy) {
5783
+ nodes {
5784
+ id
5785
+ title
5786
+ index
5787
+ type
5788
+ subType
5789
+ description
5790
+ isRequired
5791
+ placeholder
5792
+ answerOptions {
5793
+ id
5794
+ index
5795
+ value
5796
+ }
5797
+ selectedAnswers {
5798
+ id
5799
+ index
5800
+ value
5801
+ }
5802
+ }
5803
+ totalCount
5804
+ }
5805
+ }
5806
+ `);
5807
+ /**
5808
+ * Full form contents. Question comments ride along on the nested `comments`
5809
+ * field rather than the root `assessmentQuestionComments` query because
5810
+ * `AssessmentQuestionComment` carries no question ID, so a batched root query
5811
+ * cannot say which question each comment belongs to. The nested field takes no
5812
+ * pagination arguments, hence the `@include` guard: callers who did not ask for
5813
+ * comments must not pay for an unbounded list of them.
5814
+ */
3486
5815
  const GetAssessmentDoc = graphql(`
3487
5816
  query AssessmentsGet($ids: [ID!]!) {
3488
5817
  assessmentForms(first: 1, filterBy: { ids: $ids }) {
3489
5818
  nodes {
3490
5819
  id
3491
5820
  title
5821
+ description
3492
5822
  status
3493
5823
  dueDate
3494
5824
  submittedAt
@@ -3497,6 +5827,20 @@ const GetAssessmentDoc = graphql(`
3497
5827
  assessmentGroup {
3498
5828
  id
3499
5829
  }
5830
+ assignees {
5831
+ id
5832
+ name
5833
+ email
5834
+ }
5835
+ reviewers {
5836
+ id
5837
+ name
5838
+ email
5839
+ }
5840
+ externalAssignees {
5841
+ id
5842
+ email
5843
+ }
3500
5844
  sections {
3501
5845
  id
3502
5846
  title
@@ -3511,6 +5855,7 @@ const GetAssessmentDoc = graphql(`
3511
5855
  description
3512
5856
  isRequired
3513
5857
  placeholder
5858
+ referenceId
3514
5859
  answerOptions {
3515
5860
  id
3516
5861
  index
@@ -3527,6 +5872,209 @@ const GetAssessmentDoc = graphql(`
3527
5872
  }
3528
5873
  }
3529
5874
  `);
5875
+ /**
5876
+ * Section index for a form: everything except question bodies. `questions { id }`
5877
+ * is only there to count them — a real form runs to hundreds of questions and
5878
+ * tens of thousands of characters, which is why this is the default read.
5879
+ */
5880
+ const GetAssessmentSkeletonDoc = graphql(`
5881
+ query AssessmentsGetSkeleton($ids: [ID!]!) {
5882
+ assessmentForms(first: 1, filterBy: { ids: $ids }) {
5883
+ nodes {
5884
+ id
5885
+ title
5886
+ description
5887
+ status
5888
+ dueDate
5889
+ submittedAt
5890
+ createdAt
5891
+ updatedAt
5892
+ assessmentGroup {
5893
+ id
5894
+ }
5895
+ assignees {
5896
+ id
5897
+ name
5898
+ email
5899
+ }
5900
+ reviewers {
5901
+ id
5902
+ name
5903
+ email
5904
+ }
5905
+ externalAssignees {
5906
+ id
5907
+ email
5908
+ }
5909
+ sections {
5910
+ id
5911
+ title
5912
+ index
5913
+ status
5914
+ questions {
5915
+ id
5916
+ }
5917
+ }
5918
+ }
5919
+ }
5920
+ }
5921
+ `);
5922
+ /**
5923
+ * The three comment levels are separate root queries because only
5924
+ * `AssessmentQuestionRaw` exposes a nested `comments` field, and that nested
5925
+ * field takes no pagination arguments. Going through the root queries is the
5926
+ * only way to bound how many comments a call returns, and it is also what lets
5927
+ * question comments be read from their ids rather than by expanding a section.
5928
+ *
5929
+ * None of them can filter on resolution: `resolvedAt` is a returned field, not
5930
+ * a filter input. Callers asking for open comments only are served by filtering
5931
+ * what comes back.
5932
+ */
5933
+ const ListFormCommentsDoc = graphql(`
5934
+ query AssessmentsListFormComments($first: Int, $offset: Int, $formIds: [ID!], $authorIds: [ID!]) {
5935
+ assessmentFormComments(
5936
+ first: $first
5937
+ offset: $offset
5938
+ filterBy: { assessmentFormIds: $formIds, authorIds: $authorIds }
5939
+ ) {
5940
+ nodes {
5941
+ id
5942
+ content
5943
+ parentCommentId
5944
+ resolvedAt
5945
+ createdAt
5946
+ updatedAt
5947
+ externalAuthorEmail
5948
+ author {
5949
+ id
5950
+ email
5951
+ name
5952
+ }
5953
+ files {
5954
+ id
5955
+ }
5956
+ }
5957
+ totalCount
5958
+ }
5959
+ }
5960
+ `);
5961
+ const ListSectionCommentsDoc = graphql(`
5962
+ query AssessmentsListSectionComments(
5963
+ $first: Int
5964
+ $offset: Int
5965
+ $sectionIds: [ID!]
5966
+ $authorIds: [ID!]
5967
+ ) {
5968
+ assessmentSectionComments(
5969
+ first: $first
5970
+ offset: $offset
5971
+ filterBy: { assessmentSectionIds: $sectionIds, authorIds: $authorIds }
5972
+ ) {
5973
+ nodes {
5974
+ id
5975
+ content
5976
+ assessmentSectionId
5977
+ parentCommentId
5978
+ resolvedAt
5979
+ createdAt
5980
+ updatedAt
5981
+ externalAuthorEmail
5982
+ author {
5983
+ id
5984
+ email
5985
+ name
5986
+ }
5987
+ files {
5988
+ id
5989
+ }
5990
+ }
5991
+ totalCount
5992
+ }
5993
+ }
5994
+ `);
5995
+ /**
5996
+ * Question comments come through the form rather than the `assessmentQuestionComments`
5997
+ * root query, because that root query returns no back-reference to the question
5998
+ * a comment sits on — batching ids into it would answer "what feedback exists"
5999
+ * while losing "on which question". This asks for question id, title and
6000
+ * comments only, so it carries none of the answer text that makes a full form
6001
+ * read expensive.
6002
+ */
6003
+ /**
6004
+ * Ids of everything on a form that can carry a comment. Small enough to fetch
6005
+ * alongside a form read, and it is what lets comment totals be counted without
6006
+ * pulling a single comment body.
6007
+ */
6008
+ const CommentTargetsDoc = graphql(`
6009
+ query AssessmentsCommentTargets($ids: [ID!]!) {
6010
+ assessmentForms(first: 1, filterBy: { ids: $ids }) {
6011
+ nodes {
6012
+ id
6013
+ sections {
6014
+ id
6015
+ questions {
6016
+ id
6017
+ }
6018
+ }
6019
+ }
6020
+ }
6021
+ }
6022
+ `);
6023
+ /** Comment totals per level, read from `totalCount` without fetching bodies. */
6024
+ const CountFormCommentsDoc = graphql(`
6025
+ query AssessmentsCountFormComments($formIds: [ID!]) {
6026
+ assessmentFormComments(first: 1, filterBy: { assessmentFormIds: $formIds }) {
6027
+ totalCount
6028
+ }
6029
+ }
6030
+ `);
6031
+ const CountSectionCommentsDoc = graphql(`
6032
+ query AssessmentsCountSectionComments($sectionIds: [ID!]) {
6033
+ assessmentSectionComments(first: 1, filterBy: { assessmentSectionIds: $sectionIds }) {
6034
+ totalCount
6035
+ }
6036
+ }
6037
+ `);
6038
+ const CountQuestionCommentsDoc = graphql(`
6039
+ query AssessmentsCountQuestionComments($questionIds: [ID!]) {
6040
+ assessmentQuestionComments(first: 1, filterBy: { assessmentQuestionIds: $questionIds }) {
6041
+ totalCount
6042
+ }
6043
+ }
6044
+ `);
6045
+ const ListQuestionCommentsDoc = graphql(`
6046
+ query AssessmentsListQuestionComments($ids: [ID!]!) {
6047
+ assessmentForms(first: 1, filterBy: { ids: $ids }) {
6048
+ nodes {
6049
+ sections {
6050
+ id
6051
+ title
6052
+ questions {
6053
+ id
6054
+ title
6055
+ comments {
6056
+ id
6057
+ content
6058
+ parentCommentId
6059
+ resolvedAt
6060
+ createdAt
6061
+ updatedAt
6062
+ externalAuthorEmail
6063
+ author {
6064
+ id
6065
+ email
6066
+ name
6067
+ }
6068
+ files {
6069
+ id
6070
+ }
6071
+ }
6072
+ }
6073
+ }
6074
+ }
6075
+ }
6076
+ }
6077
+ `);
3530
6078
  const SelectAssessmentQuestionAnswersDoc = graphql(`
3531
6079
  mutation AssessmentsSelectAnswers($input: SelectAssessmentQuestionAnswerInput!) {
3532
6080
  selectAssessmentQuestionAnswers(input: $input) {
@@ -3788,46 +6336,244 @@ var AssessmentsMixin = class extends TranscendGraphQLBase {
3788
6336
  totalCount
3789
6337
  };
3790
6338
  }
3791
- async getAssessment(id) {
3792
- const node = (await this.makeRequest(GetAssessmentDoc, { ids: [id] })).assessmentForms.nodes[0];
3793
- if (!node) throw new Error(`Assessment with id ${id} not found`);
6339
+ /**
6340
+ * Section index for a form: metadata plus one row per section with a question
6341
+ * count, and no question bodies. This is the cheap read that lets a caller
6342
+ * decide which sections are worth expanding.
6343
+ */
6344
+ async getAssessmentSkeleton(id) {
6345
+ const node = (await this.makeRequest(GetAssessmentSkeletonDoc, { ids: [id] })).assessmentForms.nodes[0];
6346
+ if (!node) throw assessmentNotFound(id);
3794
6347
  return {
3795
6348
  id: node.id,
3796
6349
  title: node.title,
6350
+ description: node.description ?? void 0,
3797
6351
  status: node.status,
3798
6352
  dueDate: node.dueDate ?? void 0,
3799
6353
  submittedAt: node.submittedAt ?? void 0,
3800
6354
  createdAt: node.createdAt,
3801
6355
  updatedAt: node.updatedAt ?? void 0,
3802
6356
  assessmentGroupId: node.assessmentGroup?.id,
6357
+ ...mapParticipants(node),
3803
6358
  sections: node.sections?.map((section) => ({
3804
6359
  id: section.id,
3805
6360
  title: section.title ?? void 0,
3806
6361
  index: section.index ?? void 0,
3807
6362
  status: section.status ?? void 0,
6363
+ questionCount: section.questions?.length ?? 0
6364
+ }))
6365
+ };
6366
+ }
6367
+ /**
6368
+ * The questions on a form whose text matches `text`, with the form's section
6369
+ * index alongside them.
6370
+ *
6371
+ * Both halves come from one skeleton read: it yields the section ids the
6372
+ * search has to be scoped to, and the question ids that say which section
6373
+ * each match belongs to, since a question carries no reference back to its
6374
+ * section. Matches are drained rather than paged — they cannot outnumber the
6375
+ * questions on the form, and a caller searching for one topic should not have
6376
+ * to page to learn whether the form covers it.
6377
+ */
6378
+ async searchAssessmentQuestions(id, text, options = {}) {
6379
+ const node = (await this.makeRequest(GetAssessmentSkeletonDoc, { ids: [id] })).assessmentForms.nodes[0];
6380
+ if (!node) throw assessmentNotFound(id);
6381
+ const available = node.sections ?? [];
6382
+ const wanted = options.sectionIds?.length ? new Set(options.sectionIds) : void 0;
6383
+ if (wanted) {
6384
+ const present = new Set(available.map((section) => section.id));
6385
+ const missing = [...wanted].filter((sectionId) => !present.has(sectionId));
6386
+ if (missing.length > 0) throw sectionNotFound(id, missing, available);
6387
+ }
6388
+ const sections = available.filter((section) => !wanted || wanted.has(section.id));
6389
+ const sectionOfQuestion = /* @__PURE__ */ new Map();
6390
+ for (const section of sections) for (const question of section.questions ?? []) sectionOfQuestion.set(question.id, {
6391
+ id: section.id,
6392
+ title: section.title ?? void 0
6393
+ });
6394
+ const form = {
6395
+ id: node.id,
6396
+ title: node.title,
6397
+ description: node.description ?? void 0,
6398
+ status: node.status,
6399
+ dueDate: node.dueDate ?? void 0,
6400
+ submittedAt: node.submittedAt ?? void 0,
6401
+ createdAt: node.createdAt,
6402
+ updatedAt: node.updatedAt ?? void 0,
6403
+ assessmentGroupId: node.assessmentGroup?.id,
6404
+ sections: available.map((section) => ({
6405
+ id: section.id,
6406
+ title: section.title ?? void 0,
6407
+ index: section.index ?? void 0,
6408
+ status: section.status ?? void 0,
6409
+ questionCount: section.questions?.length ?? 0
6410
+ }))
6411
+ };
6412
+ const searchedCount = sectionOfQuestion.size;
6413
+ if (sections.length === 0) return {
6414
+ form,
6415
+ matches: [],
6416
+ searchedCount
6417
+ };
6418
+ const matches = [];
6419
+ let read = 0;
6420
+ for (;;) {
6421
+ const page = await this.makeRequest(SearchQuestionsDoc, {
6422
+ first: QUESTION_FETCH_CHUNK,
6423
+ offset: read,
6424
+ filterBy: {
6425
+ text,
6426
+ assessmentSectionIds: sections.map((section) => section.id)
6427
+ }
6428
+ });
6429
+ read += page.assessmentQuestions.nodes.length;
6430
+ for (const question of page.assessmentQuestions.nodes) {
6431
+ const section = sectionOfQuestion.get(question.id);
6432
+ if (!section) continue;
6433
+ matches.push({
6434
+ id: question.id,
6435
+ title: question.title ?? void 0,
6436
+ index: question.index ?? void 0,
6437
+ type: question.type,
6438
+ subType: question.subType ?? void 0,
6439
+ description: question.description ?? void 0,
6440
+ isRequired: question.isRequired ?? void 0,
6441
+ placeholder: question.placeholder ?? void 0,
6442
+ answerOptions: choicesNotAlreadyAnswered(question.answerOptions, question.selectedAnswers),
6443
+ selectedAnswers: question.selectedAnswers?.map(toAnswerOption),
6444
+ sectionId: section.id,
6445
+ sectionTitle: section.title
6446
+ });
6447
+ }
6448
+ if (page.assessmentQuestions.nodes.length === 0 || read >= page.assessmentQuestions.totalCount) break;
6449
+ }
6450
+ const order = new Map(form.sections?.map((section, i) => [section.id, i]));
6451
+ matches.sort((a, b) => (order.get(a.sectionId) ?? 0) - (order.get(b.sectionId) ?? 0) || (a.index ?? 0) - (b.index ?? 0));
6452
+ return {
6453
+ form,
6454
+ matches,
6455
+ searchedCount
6456
+ };
6457
+ }
6458
+ /**
6459
+ * Full form contents, optionally narrowed to specific sections. `sectionIds`
6460
+ * filters after the fetch because neither `sections` nor `questions` accepts
6461
+ * pagination arguments in the API — the narrowing exists to bound what the
6462
+ * caller has to read, not what the server has to send.
6463
+ */
6464
+ async getAssessment(id, options = {}) {
6465
+ const node = (await this.makeRequest(GetAssessmentDoc, { ids: [id] })).assessmentForms.nodes[0];
6466
+ if (!node) throw assessmentNotFound(id);
6467
+ const available = node.sections ?? [];
6468
+ const wanted = options.sectionIds?.length ? new Set(options.sectionIds) : void 0;
6469
+ if (wanted) {
6470
+ const present = new Set(available.map((section) => section.id));
6471
+ const missing = [...wanted].filter((sectionId) => !present.has(sectionId));
6472
+ if (missing.length > 0) throw sectionNotFound(id, missing, available);
6473
+ }
6474
+ const sections = available.filter((s) => !wanted || wanted.has(s.id));
6475
+ return {
6476
+ id: node.id,
6477
+ title: node.title,
6478
+ description: node.description ?? void 0,
6479
+ status: node.status,
6480
+ dueDate: node.dueDate ?? void 0,
6481
+ submittedAt: node.submittedAt ?? void 0,
6482
+ createdAt: node.createdAt,
6483
+ updatedAt: node.updatedAt ?? void 0,
6484
+ assessmentGroupId: node.assessmentGroup?.id,
6485
+ ...mapParticipants(node),
6486
+ sections: sections.map((section) => ({
6487
+ id: section.id,
6488
+ title: section.title ?? void 0,
6489
+ index: section.index ?? void 0,
6490
+ status: section.status ?? void 0,
6491
+ questionCount: section.questions?.length ?? 0,
3808
6492
  questions: section.questions?.map((q) => ({
3809
6493
  id: q.id,
3810
6494
  title: q.title ?? void 0,
6495
+ referenceId: q.referenceId ?? void 0,
3811
6496
  index: q.index ?? void 0,
3812
6497
  type: q.type,
3813
6498
  subType: q.subType ?? void 0,
3814
6499
  description: q.description ?? void 0,
3815
6500
  isRequired: q.isRequired ?? void 0,
3816
6501
  placeholder: q.placeholder ?? void 0,
3817
- answerOptions: q.answerOptions?.map((a) => ({
3818
- id: a.id,
3819
- index: a.index,
3820
- value: a.value
3821
- })),
3822
- selectedAnswers: q.selectedAnswers?.map((a) => ({
3823
- id: a.id,
3824
- index: a.index,
3825
- value: a.value
3826
- }))
6502
+ answerOptions: choicesNotAlreadyAnswered(q.answerOptions, q.selectedAnswers),
6503
+ selectedAnswers: q.selectedAnswers?.map(toAnswerOption)
3827
6504
  }))
3828
6505
  }))
3829
6506
  };
3830
6507
  }
6508
+ /** Comments left on the form as a whole, newest page first. */
6509
+ async listAssessmentFormComments(formId, options = {}) {
6510
+ const data = await this.makeRequest(ListFormCommentsDoc, {
6511
+ formIds: [formId],
6512
+ authorIds: options.authorIds,
6513
+ first: Math.min(options.first ?? 50, 100),
6514
+ offset: options.offset ?? 0
6515
+ });
6516
+ return {
6517
+ nodes: data.assessmentFormComments.nodes.map((c) => toComment(c, "FORM", formId)),
6518
+ totalCount: data.assessmentFormComments.totalCount
6519
+ };
6520
+ }
6521
+ /** Comments left on specific sections of a form. */
6522
+ async listAssessmentSectionComments(sectionIds, options = {}) {
6523
+ if (sectionIds.length === 0) return {
6524
+ nodes: [],
6525
+ totalCount: 0
6526
+ };
6527
+ const data = await this.makeRequest(ListSectionCommentsDoc, {
6528
+ sectionIds,
6529
+ authorIds: options.authorIds,
6530
+ first: Math.min(options.first ?? 50, 100),
6531
+ offset: options.offset ?? 0
6532
+ });
6533
+ return {
6534
+ nodes: data.assessmentSectionComments.nodes.map((c) => toComment(c, "SECTION", c.assessmentSectionId)),
6535
+ totalCount: data.assessmentSectionComments.totalCount
6536
+ };
6537
+ }
6538
+ /**
6539
+ * Every comment left on a question of this form, each carrying the question
6540
+ * it sits on. Unpaginated at the API — the nested `comments` field takes no
6541
+ * paging arguments — so callers page the merged result themselves.
6542
+ */
6543
+ async listAssessmentQuestionComments(formId) {
6544
+ const node = (await this.makeRequest(ListQuestionCommentsDoc, { ids: [formId] })).assessmentForms.nodes[0];
6545
+ if (!node) throw assessmentNotFound(formId);
6546
+ const sections = node.sections ?? [];
6547
+ const questions = sections.flatMap((section) => section.questions ?? []);
6548
+ return {
6549
+ nodes: questions.flatMap((question) => toComments(question.comments, "QUESTION", question.id) ?? []),
6550
+ questionTitles: Object.fromEntries(questions.map((q) => [q.id, q.title])),
6551
+ questionSections: Object.fromEntries(sections.flatMap((section) => (section.questions ?? []).map((question) => [question.id, section.id]))),
6552
+ sectionTitles: Object.fromEntries(sections.flatMap((section) => section.title ? [[section.id, section.title]] : [])),
6553
+ sectionIds: sections.map((section) => section.id)
6554
+ };
6555
+ }
6556
+ /**
6557
+ * How many comments sit at each level of a form, without fetching any of
6558
+ * them. Lets a form read say that feedback exists, and how much, for the
6559
+ * price of counts rather than bodies.
6560
+ */
6561
+ async countAssessmentComments(formId) {
6562
+ const node = (await this.makeRequest(CommentTargetsDoc, { ids: [formId] })).assessmentForms.nodes[0];
6563
+ if (!node) throw assessmentNotFound(formId);
6564
+ const sectionIds = (node.sections ?? []).map((section) => section.id);
6565
+ const questionIds = (node.sections ?? []).flatMap((section) => (section.questions ?? []).map((question) => question.id));
6566
+ const [form, section, question] = await Promise.all([
6567
+ this.makeRequest(CountFormCommentsDoc, { formIds: [formId] }),
6568
+ sectionIds.length > 0 ? this.makeRequest(CountSectionCommentsDoc, { sectionIds }) : void 0,
6569
+ questionIds.length > 0 ? this.makeRequest(CountQuestionCommentsDoc, { questionIds }) : void 0
6570
+ ]);
6571
+ return {
6572
+ FORM: form.assessmentFormComments.totalCount,
6573
+ SECTION: section?.assessmentSectionComments.totalCount ?? 0,
6574
+ QUESTION: question?.assessmentQuestionComments.totalCount ?? 0
6575
+ };
6576
+ }
3831
6577
  async selectAssessmentQuestionAnswers(input) {
3832
6578
  return (await this.makeRequest(SelectAssessmentQuestionAnswersDoc, { input })).selectAssessmentQuestionAnswers.selectedAnswers;
3833
6579
  }
@@ -4008,6 +6754,6 @@ var AssessmentsMixin = class extends TranscendGraphQLBase {
4008
6754
  }
4009
6755
  };
4010
6756
  //#endregion
4011
- export { buildAssessmentGroupUrl as _, UpdateAssessmentSchema as a, AnswerQuestionValueSchema as b, ListTemplatesSchema as c, ListAssessmentsSchema as d, GetAssessmentSchema as f, CreateAssessmentSchema as g, CreateGroupSchema as h, UpdateAssigneesSchema as i, ListGroupsSchema as l, CreateTemplateSchema as m, ASSESSMENT_OAUTH_SCOPES as n, SubmitResponseSchema as o, ExportTemplateSchema as p, getAssessmentTools as r, PrefillSchema as s, AssessmentsMixin as t, AssessmentStatusEnum as u, buildAssessmentLinks as v, AddSectionSchema as x, AnswerQuestionSchema as y };
6757
+ export { AddSectionSchema as S, CreateAssessmentSchema as _, UpdateAssessmentSchema as a, AnswerQuestionSchema as b, ListTemplatesSchema as c, AssessmentStatusEnum as d, ListAssessmentsSchema as f, CreateGroupSchema as g, CreateTemplateSchema as h, UpdateAssigneesSchema as i, ListGroupsSchema as l, ExportTemplateSchema as m, ASSESSMENT_OAUTH_SCOPES as n, SubmitResponseSchema as o, GetAssessmentSchema as p, getAssessmentTools as r, PrefillSchema as s, AssessmentsMixin as t, ListAssessmentCommentsSchema as u, buildAssessmentGroupUrl as v, AnswerQuestionValueSchema as x, buildAssessmentLinks as y };
4012
6758
 
4013
- //# sourceMappingURL=graphql-D1ksNLBL.mjs.map
6759
+ //# sourceMappingURL=graphql-Bhzjb2f4.mjs.map