Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: replace question preview with student element and move artificial instance computation to backend #4357

Merged
merged 1 commit into from
Nov 5, 2024

Conversation

sjschlapbach
Copy link
Member

@sjschlapbach sjschlapbach commented Nov 5, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new GraphQL query GetArtificialInstance for retrieving detailed artificial instance data.
    • Enhanced the QuestionArea component to support a new data structure for student responses.
  • Improvements

    • Updated type definitions for student responses across various components to improve consistency and type safety.
    • Implemented loading states and error handling in the QuestionDetails component for better user experience.
  • Bug Fixes

    • Resolved inconsistencies in student response handling within multiple components.
  • Chores

    • Removed the useFakedInstance hook as it was no longer needed.

Copy link

coderabbitai bot commented Nov 5, 2024

📝 Walkthrough

Walkthrough

This pull request introduces significant changes primarily focused on updating type definitions related to student responses across various components and hooks. The type StudentResponseType has been replaced with StackStudentResponseType, affecting multiple files including components and hooks that handle student responses. Additionally, a new GraphQL query, GetArtificialInstance, has been added to enhance data retrieval capabilities. The overall structure and logic of the components remain largely intact, with adjustments made to accommodate the new type definitions.

Changes

File Path Change Summary
apps/frontend-manage/src/components/courses/groupActivity/GroupActivityGradingStack.tsx Updated import for StudentElement to use StackStudentResponseType instead of StudentResponseType.
apps/frontend-manage/src/components/questions/manipulation/StudentElementPreview.tsx Changed studentResponse state type from StudentResponseType to StackStudentResponseType.
apps/frontend-manage/src/lib/hooks/useFakedInstance.ts Removed the useFakedInstance hook.
apps/frontend-manage/src/pages/questions/[id].tsx Replaced GraphQL query from GetSingleQuestionDocument to GetArtificialInstanceDocument, updated state initialization and component structure.
apps/frontend-pwa/src/components/groupActivity/GroupActivityStack.tsx Updated studentResponse and decisions processing to use StackStudentResponseType.
apps/frontend-pwa/src/components/hooks/useStackEvaluationAggregation.ts Renamed imported type from StudentResponseType to StackStudentResponseType.
apps/frontend-pwa/src/components/liveSession/QuestionArea.tsx Changed studentResponse type from SingleStudentResponseType to InstanceStackStudentResponseType.
apps/frontend-pwa/src/components/practiceQuiz/ElementStack.tsx Updated studentResponse and related logic to use StackStudentResponseType.
packages/graphql/src/graphql/ops/QGetArtificialInstance.graphql Added new GraphQL query GetArtificialInstance to fetch artificial instances based on elementId.
packages/graphql/src/ops.schema.json Updated GraphQL schema with new types, fields, and modifications to existing types.
packages/graphql/src/public/client.json Added entry for GetArtificialInstance in the GraphQL public client configuration.
packages/graphql/src/public/schema.graphql Introduced new query method artificialInstance(elementId: Int!): ElementInstance in the GraphQL schema.
packages/graphql/src/public/server.json Added multiple new queries and fragments to the GraphQL schema to enhance API capabilities.
packages/graphql/src/schema/query.ts Added artificialInstance method to the Query object in the GraphQL schema.
packages/graphql/src/services/questions.ts Introduced getArtificialElementInstance function and updated QuestionOptionsArgs interface.
packages/shared-components/src/StudentElement.tsx Renamed SingleStudentResponseType to InstanceStackStudentResponseType and StudentResponseType to StackStudentResponseType.
packages/shared-components/src/hooks/useSingleStudentResponse.ts Updated types in useSingleStudentResponse hook to reflect new naming conventions.
packages/shared-components/src/hooks/useStudentResponse.ts Changed types in UseStudentResponseProps interface and updated logic in useEffect to use StackStudentResponseType.

Possibly related PRs

Suggested reviewers

  • rschlaefli

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

sonarqubecloud bot commented Nov 5, 2024

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (20)
packages/shared-components/src/hooks/useSingleStudentResponse.ts (1)

Line range hint 20-52: Consider refactoring for improved maintainability.

While the implementation is functionally correct, we could improve its maintainability and readability:

  1. Extract the response initialization logic for each element type into separate functions
  2. Use a type guard or switch statement instead of type checking with __typename
  3. Consider using a map for element type handlers

Here's a suggested refactor:

type ResponseInitializer = (
  instance: ElementInstance,
  defaultRead: boolean
) => InstanceStackStudentResponseType;

const initializeChoicesResponse: ResponseInitializer = (instance) => ({
  type: instance.elementData.type as ElementChoicesType,
  response: instance.elementData.options.choices.reduce(
    (acc, _, ix) => ({ ...acc, [ix]: undefined }),
    {} as Record<number, boolean | undefined>
  ),
  valid: false,
});

const initializeContentResponse: ResponseInitializer = (instance, defaultRead) => ({
  type: instance.elementData.type,
  response: defaultRead ? true : undefined,
  valid: true,
});

const initializeDefaultResponse: ResponseInitializer = (instance) => ({
  type: instance.elementData.type,
  response: undefined,
  valid: false,
});

function useSingleStudentResponse({
  instance,
  setStudentResponse,
  defaultRead = false,
}: {
  instance?: ElementInstance | null
  setStudentResponse: React.Dispatch<React.SetStateAction<InstanceStackStudentResponseType>>
  defaultRead?: boolean
}) {
  useEffect(() => {
    if (!instance) return;

    const handlers: Record<string, ResponseInitializer> = {
      ChoicesElementData: initializeChoicesResponse,
      [ElementType.Content]: initializeContentResponse,
    };

    const handler = handlers[
      instance.elementData.__typename ?? instance.elementData.type
    ] ?? initializeDefaultResponse;

    setStudentResponse(handler(instance, defaultRead));
  }, [instance]);
}
packages/shared-components/src/hooks/useStudentResponse.ts (1)

Line range hint 26-65: Consider enhancing element type handling with a type guard.

The current implementation uses type checking with __typename and type. Consider using a type guard to improve type safety and readability.

Here's a suggested improvement:

+ type ElementDataType = ElementStack['elements'][0]['elementData']
+ 
+ function isChoicesElement(data: ElementDataType): data is Extract<ElementDataType, { __typename: 'ChoicesElementData' }> {
+   return data.__typename === 'ChoicesElementData'
+ }
+ 
+ function isContentElement(data: ElementDataType): data is Extract<ElementDataType, { type: ElementType.Content }> {
+   return data.type === ElementType.Content
+ }

  useEffect(() => {
    const newStudentResponse =
      stack.elements?.reduce((acc, element) => {
-       if (element.elementData.__typename === 'ChoicesElementData') {
+       if (isChoicesElement(element.elementData)) {
          // ... rest of the choices handling
-       } else if (element.elementData.type === ElementType.Content) {
+       } else if (isContentElement(element.elementData)) {
          // ... rest of the content handling
        }
apps/frontend-pwa/src/components/hooks/useStackEvaluationAggregation.ts (1)

Line range hint 1-93: Consider adding error handling for localStorage parsing.

While the overall implementation looks good, the JSON parsing of localStorage data could fail if the stored data is malformed.

Consider wrapping the parse in a try-catch:

-        const stackStorage: StackStudentResponseType = rawStackStorage
-          ? JSON.parse(rawStackStorage)
-          : null
+        let stackStorage: StackStudentResponseType = null
+        try {
+          stackStorage = rawStackStorage ? JSON.parse(rawStackStorage) : null
+        } catch (e) {
+          console.error('Failed to parse stack storage:', e)
+          // Continue with null storage, which is handled by existing logic
+        }
apps/frontend-manage/src/components/questions/manipulation/StudentElementPreview.tsx (1)

Line range hint 34-123: Consider refactoring for improved maintainability

The element data transformation logic contains complex nested conditionals and type assertions. Consider these improvements:

  1. Extract the element data transformation into a separate utility function
  2. Replace type assertions with proper type guards
  3. Simplify nested conditional checks using helper functions

Example refactor for the element data transformation:

interface ElementDataTransformProps {
  values: ElementFormTypes;
  elementDataTypename: ElementData['__typename'];
}

function transformToElementInstance({ 
  values, 
  elementDataTypename 
}: ElementDataTransformProps): ElementInstance {
  const options = 'options' in values ? transformOptions(values.options) : undefined;
  
  return {
    id: 0,
    type: ElementInstanceType.LiveQuiz,
    elementType: values.type,
    elementData: {
      id: '0',
      elementId: 0,
      __typename: elementDataTypename,
      content: values.content,
      explanation: 'explanation' in values ? values.explanation : undefined,
      name: values.name,
      pointsMultiplier: parseInt(values.pointsMultiplier ?? '1'),
      type: values.type,
      options,
    },
  };
}
apps/frontend-pwa/src/components/liveSession/QuestionArea.tsx (2)

115-116: Consider enhancing error handling for invalid inputs.

While the type update is correct, the function could benefit from more robust error handling:

  1. Consider logging invalid inputs for debugging
  2. Add error feedback for invalid responses
  input: InstanceStackStudentResponseType
}): void => {
  if (!input.valid) {
+   console.warn('Invalid input received:', input);
+   // Consider adding user feedback here
    return;
  }

Line range hint 177-177: Address TODO comment regarding failed response handling.

The current implementation might leave the system in an inconsistent state if some responses are saved while others fail. Consider implementing a transaction-like approach or rollback mechanism.

Would you like me to propose a solution for handling failed response saves more robustly?

packages/shared-components/src/StudentElement.tsx (3)

Line range hint 20-55: LGTM! Consider adding JSDoc comments.

The type definitions are well-structured and comprehensive, covering all element types with their respective response formats. The naming convention clearly indicates the purpose and hierarchy of types.

Consider adding JSDoc comments to document the purpose and usage of these types, especially since they're exported:

+/**
+ * Represents a student's response for a single instance within a stack,
+ * including the response data, validation state, and evaluation results.
+ */
export type InstanceStackStudentResponseType = {
  // ... existing type definition
}

+/**
+ * Maps element IDs to their corresponding student responses within a stack.
+ */
export type StackStudentResponseType = Record<
  number,
  InstanceStackStudentResponseType
>

65-67: LGTM! Consider adding JSDoc comments.

The stack-related props are well-typed and maintain type safety with the new type system.

Consider adding JSDoc comments to document the props:

+/**
+ * Props for handling student responses within a stack context.
+ */
interface StudentElementStackProps extends StudentElementBaseProps {
+  /** Current state of student responses across the stack */
  studentResponse: StackStudentResponseType
+  /** Setter for updating student responses */
  setStudentResponse: Dispatch<SetStateAction<StackStudentResponseType>>
+  /** Optional storage for persisted responses */
  stackStorage?: StackStudentResponseType
  // ... rest of the interface
}

76-79: Consider renaming singleStudentResponse for clarity.

The prop name singleStudentResponse might be misleading as it uses an instance from a stack. Consider a more explicit name to reflect its purpose.

-  singleStudentResponse: InstanceStackStudentResponseType
-  setSingleStudentResponse: Dispatch<
-    SetStateAction<InstanceStackStudentResponseType>
-  >
+  instanceResponse: InstanceStackStudentResponseType
+  setInstanceResponse: Dispatch<
+    SetStateAction<InstanceStackStudentResponseType>
+  >
apps/frontend-pwa/src/components/groupActivity/GroupActivityStack.tsx (3)

Line range hint 72-251: Add error handling for numerical responses

The numerical response parsing could fail with invalid input, but there's no error handling.

Consider adding validation:

 } else if (value.type === ElementType.Numerical) {
+  const numValue = parseFloat(value.response!)
+  if (isNaN(numValue)) {
+    console.error('Invalid numerical response')
+    return acc
+  }
   return {
     instanceId: parseInt(instanceId),
     type: ElementType.Numerical,
-    numericalResponse: parseFloat(value.response!),
+    numericalResponse: numValue,
   }
 }

Line range hint 224-230: Fix typo in contentResponse property name

There's a typo in the property name 'contentReponse' (missing 's').

Apply this fix:

 return {
   instanceId: parseInt(instanceId),
   type: ElementType.Content,
-  contentReponse: value.response,
+  contentResponse: value.response,
 }

Line range hint 72-251: Consider refactoring response processing logic

The response processing logic is complex with nested conditionals. Consider extracting type-specific processing into separate functions for better maintainability.

Example refactor:

const processChoiceResponse = (instanceId: number, value: StackStudentResponseType[string], type: ElementType) => {
  const responseList = Object.entries(value.response!)
    .filter(([, value]) => value)
    .map(([key]) => parseInt(key))
  
  return {
    instanceId: parseInt(instanceId),
    type,
    choicesResponse: responseList,
  }
}

// Similar functions for other types
const processNumericalResponse = (instanceId: number, value: StackStudentResponseType[string]) => {
  const numValue = parseFloat(value.response!)
  if (isNaN(numValue)) {
    console.error('Invalid numerical response')
    return null
  }
  return {
    instanceId: parseInt(instanceId),
    type: ElementType.Numerical,
    numericalResponse: numValue,
  }
}

// Then in the submit handler:
const responses = Object.entries(studentResponse)
  .map(([instanceId, value]) => {
    switch (value.type) {
      case ElementType.Sc:
      case ElementType.Mc:
      case ElementType.Kprim:
        return processChoiceResponse(instanceId, value, value.type)
      case ElementType.Numerical:
        return processNumericalResponse(instanceId, value)
      // ... other cases
    }
  })
  .filter(Boolean) // Remove null responses
apps/frontend-manage/src/components/courses/groupActivity/GroupActivityGradingStack.tsx (2)

Line range hint 64-121: Consider enhancing type safety in findResponse function.

The findResponse function handles multiple element types with complex type-specific logic. Consider these improvements:

  1. Add explicit return type annotation
  2. Use discriminated unions for element types
  3. Extract type-specific response handling into separate functions

Example refactor:

type ResponseResult = {
  [key: number]: {
    type: ElementType;
    response: any; // Replace with specific types
    valid: boolean;
  };
};

const findResponse = useCallback(
  (elementId: number, type: ElementType): ResponseResult | undefined => {
    // ... existing code
  },
  [submission?.decisions]
);

Line range hint 367-386: Consider enhancing error handling in form submission.

The error toast could provide more specific information about what went wrong during submission.

Example enhancement:

if (result.data?.gradeGroupActivitySubmission?.id) {
  setSubmitting(false);
  resetForm();
  setSuccessToast(true);
  setEdited(false);
} else {
  setSubmitting(false);
  setErrorToast(true);
  // Add error details
  console.error('Failed to grade submission:', result.errors);
  // Consider showing specific error message
  // setErrorMessage(result.errors?.[0]?.message ?? 'Unknown error occurred');
}
apps/frontend-pwa/src/components/practiceQuiz/ElementStack.tsx (1)

Line range hint 131-456: Consider extracting complex reduce operations into utility functions.

The reduce operations are type-safe but complex. Consider extracting them into separate utility functions for better maintainability and testability. For example:

const processEvaluations = (evaluations: Evaluation[], stack: Stack): StackStudentResponseType => {
  return evaluations.reduce<StackStudentResponseType>((acc, evaluation) => {
    // existing evaluation processing logic
  }, {})
}

const processContentResponses = (currentResponses: StackStudentResponseType): StackStudentResponseType => {
  return Object.entries(currentResponses).reduce<StackStudentResponseType>((acc, [instanceId, value]) => {
    // existing content processing logic
  }, {})
}

const processSubmissionResponses = (
  studentResponse: StackStudentResponseType,
  evaluations: Evaluation[]
): StackStudentResponseType => {
  return Object.entries(studentResponse).reduce<StackStudentResponseType>((acc, [key, value]) => {
    // existing submission processing logic
  }, {})
}
packages/graphql/src/schema/query.ts (1)

494-503: Consider adding input validation and error handling.

The implementation looks good and aligns with the PR objective of moving artificial instance computation to backend. However, consider enhancing the resolver with:

  1. Input validation to ensure elementId exists
  2. Proper error handling for cases where:
    • Element doesn't exist
    • User doesn't have access to the element
    • Service method fails

Example enhancement:

 artificialInstance: asUser.field({
   nullable: true,
   type: ElementInstance,
   args: {
     elementId: t.arg.int({ required: true }),
   },
-  resolve(_, args, ctx) {
-    return QuestionService.getArtificialElementInstance(args, ctx)
+  async resolve(_, args, ctx) {
+    try {
+      // Verify element exists and user has access
+      const element = await ctx.prisma.element.findUnique({
+        where: { id: args.elementId },
+      })
+      if (!element) {
+        throw new Error('Element not found')
+      }
+      return QuestionService.getArtificialElementInstance(args, ctx)
+    } catch (error) {
+      console.error('Error in artificialInstance resolver:', error)
+      throw error
+    }
+  }
 }),
packages/graphql/src/services/questions.ts (1)

162-182: Consider using constants for default values.

The function contains several hardcoded values that would be better defined as named constants, especially if they're used elsewhere in the codebase.

Consider extracting these into named constants:

+const DEFAULT_ARTIFICIAL_INSTANCE = {
+  id: 0,
+  order: 0,
+  type: DB.ElementInstanceType.LIVE_QUIZ,
+  migrationId: '',
+  originalId: '',
+  ownerId: '',
+  elementBlockId: 0,
+  elementStackId: null,
+} as const;

return {
-  id: 0,
-  elementId: element.id,
-  migrationId: '',
-  originalId: '',
+  ...DEFAULT_ARTIFICIAL_INSTANCE,
+  elementId: element.id,
  elementType: element.type,
-  order: 0,
-  type: DB.ElementInstanceType.LIVE_QUIZ,
  elementData,
  options: {
    pointsMultiplier: element.pointsMultiplier,
  },
  results: initialResults,
  anonymousResults: initialResults,
-  ownerId: '',
-  elementBlockId: 0,
-  elementStackId: null,
  createdAt: new Date(),
  updatedAt: new Date(),
}
packages/graphql/src/public/schema.graphql (1)

1403-1403: Add description for the new query field.

The new query field looks good and aligns with the PR objectives of moving artificial instance computation to the backend. Consider adding a description field to document its purpose and usage.

Apply this diff to add documentation:

+  """
+  Retrieves an artificial element instance for preview purposes based on the provided element ID.
+  """
  artificialInstance(elementId: Int!): ElementInstance
packages/graphql/src/ops.schema.json (2)

20320-20348: Add descriptions for better API documentation.

The new artificialInstance query field is well-structured, but lacks descriptions that would help API consumers understand its purpose and usage.

Consider adding descriptions:

 {
   "name": "artificialInstance",
-  "description": null,
+  "description": "Retrieves an artificial instance for preview purposes based on the given element ID",
   "args": [
     {
       "name": "elementId",
-      "description": null,
+      "description": "The unique identifier of the element for which to generate an artificial instance",
       "type": {
         "kind": "NON_NULL",

20324-20339: Consider adding input validation for elementId.

While the elementId is properly typed as a non-null Int, consider adding validation constraints to ensure it's a positive number.

You might want to:

  1. Add a custom scalar type for positive integers
  2. Document the valid range for elementId
  3. Implement validation in the resolver

This would help prevent invalid requests and improve API robustness.

🛑 Comments failed to post (1)
packages/graphql/src/services/questions.ts (1)

142-182: 🛠️ Refactor suggestion

Add TypeScript return type and documentation.

The new function lacks a return type definition and documentation explaining its purpose and usage.

Add TypeScript type and JSDoc:

+/**
+ * Creates an artificial element instance for preview purposes.
+ * @param elementId - The ID of the element to create an instance from
+ * @param ctx - Context containing user information
+ * @returns ElementInstance or null if element not found
+ */
-export async function getArtificialElementInstance(
+export async function getArtificialElementInstance(
  {
    elementId,
  }: {
    elementId: number
  },
-  ctx: ContextWithUser
+  ctx: ContextWithUser
+): Promise<DB.ElementInstance | null>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

/**
 * Creates an artificial element instance for preview purposes.
 * @param elementId - The ID of the element to create an instance from
 * @param ctx - Context containing user information
 * @returns ElementInstance or null if element not found
 */
export async function getArtificialElementInstance(
  {
    elementId,
  }: {
    elementId: number
  },
  ctx: ContextWithUser
): Promise<DB.ElementInstance | null> {
  const element = await ctx.prisma.element.findUnique({
    where: {
      id: elementId,
      ownerId: ctx.user.sub,
    },
  })

  if (!element) return null

  const elementData = processElementData(element)
  const initialResults = getInitialElementResults(element)

  return {
    id: 0,
    elementId: element.id,
    migrationId: '',
    originalId: '',
    elementType: element.type,
    order: 0,
    type: DB.ElementInstanceType.LIVE_QUIZ,
    elementData,
    options: {
      pointsMultiplier: element.pointsMultiplier,
    },
    results: initialResults,
    anonymousResults: initialResults,
    ownerId: '',
    elementBlockId: 0,
    elementStackId: null,
    createdAt: new Date(),
    updatedAt: new Date(),
  }
}

Copy link

cypress bot commented Nov 5, 2024

klicker-uzh    Run #3550

Run Properties:  status check passed Passed #3550  •  git commit 6a03964d2d ℹ️: Merge 77db2a9a43029fa722802f229895be685a20b5d3 into 8dd73f1dcefd14bd344fcfd8cc09...
Project klicker-uzh
Branch Review replace-question-preview
Run status status check passed Passed #3550
Run duration 11m 08s
Commit git commit 6a03964d2d ℹ️: Merge 77db2a9a43029fa722802f229895be685a20b5d3 into 8dd73f1dcefd14bd344fcfd8cc09...
Committer Julius Schlapbach
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 140
View all changes introduced in this branch ↗︎

@sjschlapbach sjschlapbach merged commit 9a82194 into v3-new-live-quiz Nov 5, 2024
15 checks passed
@sjschlapbach sjschlapbach deleted the replace-question-preview branch November 5, 2024 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant