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

Feature/implement ocr button #2731

Merged
merged 22 commits into from
Oct 1, 2024
Merged

Feature/implement ocr button #2731

merged 22 commits into from
Oct 1, 2024

Conversation

Blokh
Copy link
Collaborator

@Blokh Blokh commented Sep 25, 2024

  1. Generated 2 intergrations for OCR for document and schema.
  2. added OCR button logic
  3. implemented parsing result onto the document schema prorperties

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced Optical Character Recognition (OCR) functionality, allowing users to perform OCR on documents.
    • Added user feedback messages for OCR success and error states.
    • New ImageOCR component for triggering OCR actions.
    • Enhanced document handling logic to integrate OCR results.
    • Added support for document processing within the Case.Documents component.
    • Updated the DocumentsToolbar to include OCR functionality.
    • Enhanced interface properties to manage OCR actions and loading states.
    • New custom hooks for managing OCR processes and fetching results.
  • Bug Fixes

    • Streamlined file retrieval process, improving performance and reliability.
  • Documentation

    • Updated localization files to support new features and user notifications.
  • Refactor

    • Simplified hooks and component logic related to document processing and OCR integration.

@Blokh Blokh self-assigned this Sep 25, 2024
Copy link

changeset-bot bot commented Sep 25, 2024

⚠️ No Changeset found

Latest commit: 41c6d15

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor

coderabbitai bot commented Sep 25, 2024

Warning

Rate limit exceeded

@Blokh has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 17 minutes and 11 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Files that changed from the base of the PR and between 9e89e6a and 41c6d15.

Walkthrough

The pull request introduces significant updates to the backoffice-v2 application, focusing on enhancing Optical Character Recognition (OCR) capabilities. Key changes include the addition of new components, hooks, and utility functions to handle OCR processes, as well as updates to localization files for user feedback. The lucide-react package is also upgraded, potentially improving UI elements. Overall, these changes aim to streamline document processing and enhance user interaction with OCR functionalities.

Changes

File Path Change Summary
apps/backoffice-v2/package.json Updated lucide-react package version from ^0.239.0 to ^0.445.0.
apps/backoffice-v2/public/locales/en/toast.json Added new localization entries for OCR success and error messages.
apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx Introduced ImageOCR component with props for handling OCR actions.
apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx Integrated OCR results into document processing logic.
apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/MultiDocuments.tsx Added onOcrPressed and isLoadingOCR props to Case.Documents component.
apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/interfaces.ts Updated IMultiDocumentsProps interface to include onOcrPressed and isLoadingOCR props.
apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx Added onOcrPressed, isOCREnabled, and isLoadingOCR props to DocumentsToolbar component.
apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.tsx Refactored document handling logic and updated props for OCR actions.
services/workflows-service/src/workflow/workflow.service.ts Introduced findDocumentById and runOCROnDocument methods for document retrieval and OCR processing.
services/workflows-service/src/workflow/workflow.controller.internal.ts Added new endpoint for running OCR on documents in the workflow.
services/workflows-service/src/common/utils/unified-api-client/unified-api-client.ts Expanded UnifiedApiClient with new methods for OCR processing.
services/workflows-service/src/customer/types.ts Introduced new types for enhanced feature representation.
services/workflows-service/src/workflow/cron/ongoing-monitoring.cron.ts Enhanced type checking for feature configurations.

Possibly related PRs

  • Pdf export feature #2331: This PR also updates the package.json file for @ballerine/backoffice-v2, which aligns with the version update in the main PR.
  • Merchant monitoring pages fixes #2711: This PR includes updates to the Button component, which may relate to the UI changes in the main PR that also involves UI components.
  • Documents block sort #2730: The changes in the useDocumentBlocks hook in this PR involve configuration updates that could relate to the document handling features enhanced in the main PR.
  • version bump #2738: This PR involves a version bump for @ballerine/backoffice-v2, which aligns with the version update in the main PR.

Suggested labels

enhancement, Review effort [1-5]: 4

Suggested reviewers

  • Omri-Levy
  • alonp99

Poem

In the land of code where rabbits hop,
New features bloom, and the changes won't stop.
With OCR magic, documents now sing,
A click of a button, oh what joy it brings!
So hop along, dear friends, let's cheer,
For the updates are here, and the future is clear! 🐇✨


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
Contributor

@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.

Actionable comments posted: 22

🧹 Outside diff range and nitpick comments (16)
apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/interfaces.ts (2)

4-4: LGTM! Consider adding a JSDoc comment for clarity.

The addition of the onOcrPressed property is well-implemented and aligns with the PR objectives. It provides a clear mechanism for handling OCR button presses.

Consider adding a JSDoc comment to provide more context about the onOcrPressed function. This can help other developers understand its purpose and usage. Here's a suggested implementation:

+  /**
+   * Callback function triggered when the OCR button is pressed.
+   * This function should handle the initiation of the OCR process.
+   */
   onOcrPressed: () => void;

Verify OCR functionality implementation and consider adding error handling states.

While the onOcrPressed callback is correctly implemented and the loading state is managed, it's important to ensure that error handling is also addressed to handle potential OCR failures gracefully.

  • Action Items:
    1. Confirm that the Case.Documents component handles errors during the OCR process.
    2. Consider updating the IMultiDocumentsProps interface to include an error state (e.g., error: string | null) to manage OCR-related errors.
🔗 Analysis chain

Line range hint 1-11: Verify component implementation and consider additional states.

While the interface change looks good, it's important to ensure that the corresponding component correctly implements this new OCR functionality.

Please verify the following:

  1. The component using this interface correctly implements the OCR button and handles the onOcrPressed callback.
  2. Consider if additional states (e.g., OCR processing state) need to be added to the interface to handle loading or error states during the OCR process.

Run the following script to find the component implementation:

Review the component implementation to ensure it correctly uses the new onOcrPressed property and consider if additional states are needed in the interface.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find the component implementation using IMultiDocumentsProps

# Test: Search for the component using IMultiDocumentsProps
rg --type typescript -A 10 "IMultiDocumentsProps" apps/backoffice-v2/src/lib/blocks/components/MultiDocuments

Length of output: 144


Script:

#!/bin/bash
# Description: Find the component implementation using IMultiDocumentsProps

# Test: Search for the component using IMultiDocumentsProps with the correct file type
rg --type ts -A 10 "IMultiDocumentsProps" apps/backoffice-v2/src/lib/blocks/components/MultiDocuments

Length of output: 2708

apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/MultiDocuments.tsx (1)

10-14: LGTM! The OCR functionality has been successfully integrated.

The addition of the onOcrPressed prop to the Case.Documents component aligns well with the PR objectives of implementing OCR functionality. The use of optional chaining (?.) is a good practice to handle cases where the prop might not be provided.

Consider the following suggestions to improve code quality and maintainability:

  1. Add prop type definitions for onOcrPressed in the IMultiDocumentsProps interface:
interface IMultiDocumentsProps {
  value: {
    data: Array<{ imageUrl: string }>;
    isLoading: boolean;
    onOcrPressed?: () => void; // Add this line
  };
}
  1. Add a brief comment explaining the purpose of the onOcrPressed prop:
<Case.Documents
  documents={documents}
  isLoading={value?.isLoading}
  // Callback function to handle OCR button press
  onOcrPressed={value?.onOcrPressed}
/>

These changes will enhance type safety and improve code readability for future maintainers.

apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/utils/check-can-ocr/check-can-ocr.ts (2)

6-18: LGTM: Well-structured function signature with clear typing.

The function signature is well-defined with appropriate typing for each parameter. The use of an object parameter with destructuring enhances readability and flexibility.

Consider adding a JSDoc comment to describe the function's purpose and parameters. This would further improve code documentation and IDE support. For example:

/**
 * Checks if OCR can be performed based on the current workflow state and other conditions.
 * @param {Object} params - The parameters for checking OCR availability.
 * @param {ReturnType<typeof useCaseState>} params.caseState - The current state of the case.
 * @param {boolean} params.noAction - Indicates if no action is possible.
 * @param {TWorkflowById} params.workflow - The current workflow.
 * @param {DefaultContextSchema['documents'][number]['decision']} params.decision - The current decision.
 * @param {boolean} params.isLoadingApprove - Indicates if an approval is currently loading.
 * @returns {boolean} Whether OCR can be performed.
 */

19-29: LGTM: Logic is sound and well-implemented.

The function's logic is well-structured and covers the necessary conditions for determining if OCR can proceed. Good use of the helper function checkCanMakeDecision for better code organization.

To improve readability, consider extracting the conditions in the return statement into named variables. This would make the logic more self-documenting. For example:

const isOcrAllowed = !isLoadingApprove && canMakeDecision;
const isWorkflowEligible = isStateManualReview || hasApproveEvent;

return isOcrAllowed && isWorkflowEligible;

This refactoring makes the conditions more explicit and easier to understand at a glance.

apps/backoffice-v2/src/pages/Entity/components/Case/interfaces.ts (1)

51-51: LGTM! Consider adding error handling.

The addition of the onOcrPressed method to the IDocumentsProps interface aligns well with the PR objective of implementing an OCR button. The method signature is clear and follows TypeScript best practices.

Consider updating the method signature to include error handling:

onOcrPressed: (documentId: string) => Promise<void>;

This change would allow for asynchronous OCR processing and provide a way to handle potential errors in the OCR process.

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (2)

17-18: LGTM: New props for OCR functionality.

The new props onOcrPressed and shouldOCR are well-named and typed appropriately for their intended use.

Consider adding JSDoc comments to these props to provide more context about their usage. For example:

/**
 * Callback function triggered when OCR action is initiated.
 */
onOcrPressed?: () => void;

/**
 * Flag to determine if OCR functionality should be enabled.
 */
shouldOCR: boolean;

39-43: LGTM: Conditional rendering of ImageOCR component.

The conditional rendering of the ImageOCR component is implemented correctly, using the shouldOCR prop and checking for the existence of image. The component is properly configured with the required props.

Consider extracting the inline styles to a separate CSS class or a styled component for better maintainability. For example:

<div className="ocr-wrapper">
  <ImageOCR isOcrDisabled={!shouldOCR} onOcrPressed={onOcrPressed} />
</div>

Then define the ocr-wrapper class in your CSS file:

.ocr-wrapper {
  margin-bottom: 2.5rem;
  display: flex;
  height: 100%;
  flex-direction: column;
  align-items: center;
  gap: 12.5rem;
}

This separation of concerns can make the code more maintainable and easier to read.

apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx (1)

Line range hint 1-89: Summary of changes and areas for attention

The changes in this file align with the PR objectives and the AI summary. The renaming of the hook to useDocumentsLogic and the simplification of OCR logic are positive changes. However, there are a few areas that require attention:

  1. Verify the usage and necessity of the newly added useCustomerQuery.
  2. Ensure that all references to this hook have been updated across the codebase due to the name change.
  3. Consider making the shouldOCR property more dynamic to accommodate different use cases.
  4. Confirm that all previous OCR-related logic has been properly removed or relocated.

Please address these points to ensure the changes are fully integrated and optimized.

apps/backoffice-v2/public/locales/en/toast.json (1)

84-87: LGTM! Consider enhancing the error message.

The new entries for document OCR are well-structured and align with the PR objectives. They provide clear feedback for both successful and failed OCR operations.

Consider enhancing the error message to be more specific and include a placeholder for additional error details. This could help users understand what went wrong and assist in debugging. For example:

  "document_ocr": {
    "success": "OCR performed successfully.",
-   "error": "Failed to perform OCR on the document."
+   "error": "Failed to perform OCR on the document. Error: {{errorMessage}}"
  },

This change would make the error message consistent with other error messages in the file that include {{errorMessage}} placeholders.

apps/backoffice-v2/src/domains/workflows/fetchers.ts (1)

302-318: Function implementation looks good, with some suggestions for improvement.

The new fetchWorkflowDocumentOCRResult function is well-implemented and consistent with the existing code style. However, I have a couple of suggestions to enhance its clarity and type safety:

  1. Consider renaming the function to better reflect its action. The current name suggests it's fetching a result, but it's actually triggering an OCR run. A more accurate name could be triggerWorkflowDocumentOCR or runWorkflowDocumentOCR.

  2. Instead of using z.any() for schema validation, consider defining a more specific schema for the expected response. This will provide better type safety and documentation of the expected response structure.

Here's a suggested refactor incorporating these changes:

export const triggerWorkflowDocumentOCR = async ({
  workflowDefinitionId,
  documentId,
}: {
  workflowDefinitionId: string;
  documentId: string;
}) => {
  const [workflow, error] = await apiClient({
    method: Method.PATCH,
    url: `${getOriginUrl(
      env.VITE_API_URL,
    )}/api/v1/internal/workflows/${workflowDefinitionId}/documents/${documentId}/run-ocr`,
    schema: z.object({
      // Define the expected response structure here
      // For example:
      success: z.boolean(),
      message: z.string(),
      result: z.any(), // Replace with a more specific schema if possible
    }),
  });

  return handleZodError(error, workflow);
};

This refactor improves the function name clarity and adds a basic schema for better type safety. Adjust the schema definition based on the actual expected response structure from the API.

services/workflows-service/src/workflow/workflow.controller.internal.ts (1)

341-357: LGTM with suggestions for improvement

The implementation of the runDocumentOcr method looks good overall. It follows the established patterns in the controller and uses appropriate decorators for API documentation and access control. However, there are a few areas where it could be improved:

  1. Error handling: Consider adding explicit error handling to catch and properly handle potential exceptions from the service call.

  2. Input validation: It might be beneficial to add input validation for the params object to ensure all required fields are present and valid before processing.

  3. Return type specification: The method could benefit from a more specific return type annotation to clearly indicate what kind of data is being returned from the OCR operation.

Here's a suggested refactoring that addresses these points:

@common.Patch(':id/documents/:documentId/run-ocr')
@swagger.ApiOkResponse({ type: YourOCRResultType }) // Replace with actual type
@swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
@swagger.ApiForbiddenResponse({ type: errors.ForbiddenException })
@swagger.ApiBadRequestResponse({ type: errors.BadRequestException })
@UseGuards(WorkflowAssigneeGuard)
async runDocumentOcr(
  @common.Param() params: DocumentUpdateParamsInput,
  @CurrentProject() currentProjectId: TProjectId,
): Promise<YourOCRResultType> { // Replace with actual return type
  if (!params.id || !params.documentId) {
    throw new errors.BadRequestException('Missing required parameters');
  }

  try {
    const ocrResult = await this.service.runOCROnDocument({
      workflowRuntimeId: params.id,
      documentId: params.documentId,
      projectId: currentProjectId,
    });

    return ocrResult;
  } catch (error) {
    if (isRecordNotFoundError(error)) {
      throw new errors.NotFoundException(`No resource was found for ${JSON.stringify(params)}`);
    }
    // Log the error here
    throw new errors.InternalServerErrorException('An error occurred while processing the OCR request');
  }
}

This refactored version includes input validation, error handling, and assumes a specific return type (YourOCRResultType) which should be replaced with the actual type returned by your OCR operation.

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.tsx (1)

48-48: Align variable naming for consistency

The variable shouldOCR uses uppercase letters for "OCR", while onOcrPressed uses "Ocr" in camel case. For consistency with other variables like isLoading and onOcrPressed, consider renaming shouldOCR to shouldOcr.

Apply the following changes:

At line 48:

-    shouldOCR,
+    shouldOcr,

At line 92:

-    shouldOCR={shouldOCR}
+    shouldOcr={shouldOcr}

Also applies to: 92-92

services/workflows-service/src/storage/storage.service.ts (1)

143-149: Add error handling in 'fileToBase64' method

The method fileToBase64 lacks error handling for scenarios where the file might not exist or cannot be read. This could lead to unhandled exceptions.

Apply this diff to add try-catch error handling:

      fileToBase64(filepath: string): string {
-       const fileBuffer = readFileSync(filepath);
-
-       const base64String = fileBuffer.toString('base64');
-
-       return base64String;
+       try {
+         const fileBuffer = readFileSync(filepath);
+         return fileBuffer.toString('base64');
+       } catch (error) {
+         this.logger.error('Error reading file:', error);
+         throw new Error('Failed to convert file to Base64.');
+       }
      }
apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (1)

84-86: Naming Convention: Use camelCase for Variable Names

The variables mutateOCRDocument and isLoadingOCRDocument use uppercase letters in the middle of the identifier. For consistency with camelCase naming conventions in JavaScript/TypeScript, consider renaming them to mutateOcrDocument and isLoadingOcrDocument.

Apply this diff to adjust the variable names:

 const {
-  mutate: mutateOCRDocument,
-  isLoading: isLoadingOCRDocument,
+  mutate: mutateOcrDocument,
+  isLoading: isLoadingOcrDocument,
services/workflows-service/src/workflow/workflow.service.ts (1)

2615-2616: Evaluate transaction timeout setting

The transaction timeout is set to 180,000 milliseconds (3 minutes). If the OCR process takes longer, this could cause the transaction to fail.

Consider handling long-running OCR operations outside of a database transaction or adjusting the timeout if necessary.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 5142b8e and 783bf7e.

🔇 Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • apps/backoffice-v2/package.json (1 hunks)
  • apps/backoffice-v2/public/locales/en/toast.json (1 hunks)
  • apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx (1 hunks)
  • apps/backoffice-v2/src/domains/entities/hooks/mutations/useDocumentOcr/useDocumentOcr.ts (1 hunks)
  • apps/backoffice-v2/src/domains/workflows/fetchers.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/CallToActionLegacy/hooks/useCallToActionLegacyLogic/useCallToActionLegacyLogic.tsx (0 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/MultiDocuments.tsx (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/interfaces.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (6 hunks)
  • apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/utils/check-can-ocr/check-can-ocr.ts (1 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (3 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.tsx (4 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx (2 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/interfaces.ts (1 hunks)
  • services/workflows-service/prisma/data-migrations (1 hunks)
  • services/workflows-service/src/common/utils/unified-api-client/unified-api-client.ts (3 hunks)
  • services/workflows-service/src/storage/storage.controller.internal.ts (2 hunks)
  • services/workflows-service/src/storage/storage.service.ts (2 hunks)
  • services/workflows-service/src/workflow/workflow.controller.internal.ts (1 hunks)
  • services/workflows-service/src/workflow/workflow.service.ts (5 hunks)
💤 Files not reviewed due to no reviewable changes (1)
  • apps/backoffice-v2/src/lib/blocks/components/CallToActionLegacy/hooks/useCallToActionLegacyLogic/useCallToActionLegacyLogic.tsx
✅ Files skipped from review due to trivial changes (1)
  • services/workflows-service/prisma/data-migrations
🔇 Additional comments not posted (22)
apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx (4)

1-3: LGTM: Imports are appropriate and well-organized.

The imports are relevant to the component's functionality and follow a logical order. No unused imports are observed.


1-30: Overall, the ImageOCR component is well-implemented and aligns with PR objectives.

The new ImageOCR component successfully implements the OCR button functionality as described in the PR objectives. The code is well-structured, follows React best practices, and uses appropriate styling.

A few minor optimizations were suggested to improve code quality:

  1. Removing unnecessary fragment and template literals.
  2. Addressing the unused documentId prop.

These changes will enhance the code without altering the component's functionality. Great job on implementing this feature!


11-30: 🛠️ Refactor suggestion

Component implementation can be optimized.

The ImageOCR component is well-implemented, but there are a few minor optimizations that can be made:

  1. The empty fragment (<>...</>) is unnecessary as there's only one child element.
  2. The type="button" attribute uses template literals unnecessarily.
  3. The documentId prop is destructured but not used in the component.

Consider applying the following changes:

-export const ImageOCR: FunctionComponent<IImageOCR> = ({
+export const ImageOCR: FunctionComponent<Omit<IImageOCR, 'documentId'>> = ({
   isOcrDisabled,
   onOcrPressed,
-  documentId,
   className,
   ...props
-}) => (
-  <>
-    <button
-      type={`button`}
+}) => (
+  <button
+    type="button"
       className={ctw(
         `btn btn-circle btn-ghost btn-sm bg-base-300/70 text-[0.688rem] focus:outline-primary`,
       )}
       onClick={() => onOcrPressed?.()}
       disabled={isOcrDisabled}
     >
       <ScanTextIcon />
-    </button>
-  </>
+  </button>
 );

These changes will:

  1. Remove the unnecessary fragment.
  2. Simplify the button type attribute.
  3. Remove the unused documentId prop from the component's props type.

To ensure documentId is not used elsewhere, run:

#!/bin/bash
# Description: Check usage of documentId in ImageOCR component and related files

# Test: Search for documentId usage in the component and any files that import it
rg --type typescript 'documentId' apps/backoffice-v2/src/common/components/molecules/ImageOCR/
rg --type typescript 'from.*ImageOCR' apps/backoffice-v2/src/ | xargs rg --type typescript 'documentId'

5-9: Interface definition looks good, but documentId is unused.

The IImageOCR interface is well-defined and includes all necessary properties for the component. However, the documentId property is not used in the current implementation of the ImageOCR component.

If documentId is intended for future use, consider adding a TODO comment. If it's not needed, you may want to remove it. Here's a script to check its usage:

✅ Verification successful

Interface definition looks good, but documentId is unused in the ImageOCR component.

The IImageOCR interface includes all necessary properties for the component. However, the documentId property is not utilized in the current implementation of the ImageOCR component.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage of documentId in ImageOCR component

# Test: Search for documentId usage in the component
rg --type typescript 'documentId' apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx

Length of output: 303


Script:

#!/bin/bash
# Description: Use ast-grep to find usage of documentId in ImageOCR.tsx

ast-grep --lang typescript --pattern $'Identifier documentId' apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx

Length of output: 579


Script:

#!/bin/bash
# Description: Check usage of documentId in ImageOCR.tsx using the correct TypeScript type identifier

# Test: Search for documentId usage in the component
rg --type ts 'documentId' apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx

Length of output: 134

apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/utils/check-can-ocr/check-can-ocr.ts (2)

1-4: LGTM: Imports are well-organized and relevant.

The imports are logically organized and all seem to be utilized within the function. Good job on keeping the imports clean and relevant.


1-29: Overall: Well-implemented utility function for OCR availability check.

This new utility function checkCanOcr is well-aligned with the PR objectives of implementing OCR-related functionality. The code is well-structured, properly typed, and logically sound. The minor suggestions for improvement (adding JSDoc and refactoring for readability) will further enhance the code quality and maintainability.

Great job on implementing this crucial piece of the OCR feature!

apps/backoffice-v2/src/domains/entities/hooks/mutations/useDocumentOcr/useDocumentOcr.ts (3)

1-6: LGTM: Imports are appropriate and well-organized.

The imports cover all necessary dependencies for the hook's functionality, including React Query for state management, toast notifications, internationalization, and internal utilities. The import structure follows a consistent pattern, which is good for maintainability.


20-23: LGTM: Proper success handling

The success handling is well-implemented:

  • It invalidates the relevant queries to ensure fresh data.
  • It displays a localized success message using the toast notification system.

This approach ensures that the UI is updated with the latest data and provides good user feedback.


1-30: Overall assessment: Good implementation with minor improvements needed

The useDocumentOcr hook is well-structured and makes good use of React Query for managing the OCR mutation. Here's a summary of the main points:

  1. The hook name has a typo that needs to be fixed (useDocumentOrc -> useDocumentOcr).
  2. There's an inconsistency in parameter naming (workflowId vs workflowDefinitionId) that should be addressed.
  3. Success handling is well-implemented with proper query invalidation and user feedback.
  4. Error handling could be refined by removing unnecessary query invalidation and potentially including more context in the error message.

Addressing these points will improve the overall quality and consistency of the implementation. Great job on implementing this OCR functionality!

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (3)

8-8: LGTM: New import for ImageOCR component.

The import for the ImageOCR component is correctly placed and follows the existing import structure. This maintains code organization and readability.


26-26: LGTM: Destructured onOcrPressed prop.

The onOcrPressed prop is correctly destructured from the component props, maintaining consistency with its earlier definition.


Line range hint 1-85: Overall assessment: Changes look good and align with PR objectives.

The modifications to the DocumentsToolbar component successfully integrate OCR functionality as intended. The new props, imports, and conditional rendering are implemented correctly and follow React best practices. The changes are consistent with the PR objectives of implementing an OCR button and related functionality.

To ensure that the ImageOCR component is implemented correctly and that there are no unintended side effects, please run the following verification script:

This script will help verify the correct implementation and usage of the ImageOCR component across the codebase.

✅ Verification successful

Verification Successful: ImageOCR component is correctly implemented and integrated.

The ImageOCR component exists at ./apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx and is implemented with the correct props. Its integration within Case.Documents.Toolbar.tsx aligns with the PR objectives, ensuring the OCR functionality is properly incorporated without introducing issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of ImageOCR component and its usage

# Test 1: Check if ImageOCR component exists
echo "Checking for ImageOCR component..."
ast-grep --lang typescript --pattern $'export const ImageOCR: FunctionComponent<{$$$}> = ({$$$}) => {$$$}'

# Test 2: Verify ImageOCR props
echo "Verifying ImageOCR props..."
ast-grep --lang typescript --pattern $'export const ImageOCR: FunctionComponent<{
  isOcrDisabled: boolean;
  onOcrPressed: () => void;
  $$$
}>'

# Test 3: Check for any other usages of ImageOCR in the codebase
echo "Checking for other usages of ImageOCR..."
rg --type typescript "import.*ImageOCR" -A 10

Length of output: 572


Script:

#!/bin/bash
# Description: Re-verify the implementation of ImageOCR component and its usage without specifying file type

# Test 1: Check if ImageOCR component exists
echo "Checking for ImageOCR component..."
ast-grep --lang typescript --pattern $'export const ImageOCR: FunctionComponent<{$$$}> = ({$$$}) => {$$$}'

# Test 2: Verify ImageOCR props
echo "Verifying ImageOCR props..."
ast-grep --lang typescript --pattern $'export const ImageOCR: FunctionComponent<{
  isOcrDisabled: boolean;
  onOcrPressed: () => void;
  $$$
}>'

# Test 3: Check for any other usages of ImageOCR in the codebase without specifying file type
echo "Checking for other usages of ImageOCR..."
rg "import.*ImageOCR" -A 10

Length of output: 1812


Script:

#!/bin/bash
# Description: Verify the existence and implementation of the ImageOCR component

# Test 1: Check if the ImageOCR component file exists
echo "Checking if ImageOCR component file exists..."
fd "ImageOCR.tsx" ./apps/backoffice-v2/src/common/components/molecules/ImageOCR/ --hidden

# Test 2: If the file exists, display its contents
if [ -f "./apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx" ]; then
  echo "Displaying contents of ImageOCR.tsx..."
  cat ./apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx
else
  echo "ImageOCR.tsx does not exist."
fi

Length of output: 1235

apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx (3)

73-73: 🛠️ Refactor suggestion

Consider making shouldOCR more dynamic and verify removal of previous OCR logic.

The addition of shouldOCR: true simplifies the OCR logic as mentioned in the AI summary. However, setting it to a static true value might not be flexible for all use cases.

Consider making shouldOCR more dynamic, perhaps based on document type or user permissions:

shouldOCR: determineIfShouldOCR(selectedImage, userPermissions),

Also, please verify that the previous OCR-related logic has been properly removed or relocated. Run the following script to check for any remaining OCR-related code:

#!/bin/bash
# Description: Check for remaining OCR-related code

# Test: Search for OCR-related terms
rg --type typescript -i 'ocr|optical character recognition' apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx

14-14: Approve name change and verify usage across the codebase.

The renaming of useDocuments to useDocumentsLogic is more descriptive and aligns with the file name. This is a good change for clarity.

However, ensure that all references to this hook have been updated across the codebase. Run the following script to check for any remaining references to useDocuments:

✅ Verification successful

Name change verified and approved.

All references to useDocuments have been successfully updated to useDocumentsLogic across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for remaining references to useDocuments

# Test: Search for useDocuments usage
rg --type typescript 'useDocuments'

Length of output: 189


Script:

#!/bin/bash
# Description: Check for remaining references to useDocuments in TypeScript files

# Search for 'useDocuments' in .ts and .tsx files
rg 'useDocuments' --glob '*.ts' --glob '*.tsx'

Length of output: 978


12-12: Verify the usage of useCustomerQuery.

The addition of useCustomerQuery suggests that customer data is now being used in this hook. Please ensure that this query is necessary and properly utilized within the component.

To confirm the usage of useCustomerQuery, run the following script:

✅ Verification successful

useCustomerQuery is properly utilized within the component.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of useCustomerQuery in the component

# Test: Search for useCustomerQuery usage
rg --type typescript -A 10 'useCustomerQuery' apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx

Length of output: 173


Script:

#!/bin/bash
# Description: Verify the usage of useCustomerQuery in the component with the correct file type

# Test: Search for useCustomerQuery usage in .tsx files
rg --type tsx -A 10 'useCustomerQuery' apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx

Length of output: 159


Script:

#!/bin/bash
# Description: Verify the usage of useCustomerQuery in .tsx files using glob pattern

# Test: Search for useCustomerQuery usage in .tsx files
rg --glob '*.tsx' -A 10 'useCustomerQuery' apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx

Length of output: 830

apps/backoffice-v2/package.json (1)

100-100: Significant version update for lucide-react package.

The lucide-react package has been updated from version ^0.239.0 to ^0.445.0, which is a substantial version jump. While this update may introduce new features or improvements that could benefit the OCR button implementation, it's important to consider the following:

  1. Verify the changelog for any breaking changes that might affect the existing codebase.
  2. Check for new features or improvements in the latest version that could be leveraged for the OCR functionality.
  3. Ensure thorough testing of the application, particularly areas that use Lucide icons, to confirm compatibility with this new version.

To assist in verifying the impact of this change, you can run the following script:

services/workflows-service/src/storage/storage.controller.internal.ts (1)

11-11: Import manageFileByProvider added appropriately

The addition of the import statement for manageFileByProvider ensures that the file storage management is correctly utilized within the uploadFile method.

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.tsx (3)

10-10: Import statement updated correctly

The import of useDocumentsLogic reflects the updated document management logic and replaces the previous hook appropriately.


48-50: Destructured values from 'useDocumentsLogic' are correctly updated

Including shouldOCR and fileToDownloadBase64 from useDocumentsLogic aligns with the new OCR functionality and appears to be implemented correctly.


92-93: Passing OCR props to 'DocumentsToolbar'

Passing shouldOCR and onOcrPressed to DocumentsToolbar enables OCR actions within the toolbar. Ensure that the DocumentsToolbar component is updated to accept these new props to avoid any undefined prop issues.

services/workflows-service/src/storage/storage.service.ts (2)

129-137: Validate 'persistedFile.uri' before downloading

In the method __downloadFileFromRemote, ensure that persistedFile.uri is validated to prevent downloading from malicious or invalid URLs.

[security]

Consider adding additional validation or sanitization steps for the URI.


24-28: Dependency Injection: Verify the addition of new dependencies

The constructor now includes HttpService and AppLoggerService. Ensure that these services are properly provided in the module to avoid runtime errors.

Run the following script to check if HttpService and AppLoggerService are imported and provided:

#!/bin/bash
# Description: Verify that HttpService and AppLoggerService are properly injected.

# Test: Search for 'HttpModule' import. Expect: 'HttpModule' is imported in the module.
rg "import\s+\{.*HttpModule.*\}\s+from.*" services/workflows-service/src/**/*.module.ts

# Test: Search for 'AppLoggerService' provider. Expect: 'AppLoggerService' is provided in the module.
rg "providers\s*:\s*\[.*AppLoggerService.*\]" services/workflows-service/src/**/*.module.ts

Comment on lines 8 to 11
export const useDocumentOrc = ({ workflowId }: { workflowId: string }) => {
const filterId = useFilterId();
const workflowById = workflowsQueryKeys.byId({ workflowId, filterId });
const queryClient = useQueryClient();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in hook name: useDocumentOrc should be useDocumentOcr

There's a typo in the hook name. OCR stands for Optical Character Recognition, so the correct spelling should be "Ocr" instead of "Orc".

Please apply the following change:

-export const useDocumentOrc = ({ workflowId }: { workflowId: string }) => {
+export const useDocumentOcr = ({ workflowId }: { workflowId: string }) => {

This will ensure consistency with the file name and prevent potential confusion.

📝 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.

Suggested change
export const useDocumentOrc = ({ workflowId }: { workflowId: string }) => {
const filterId = useFilterId();
const workflowById = workflowsQueryKeys.byId({ workflowId, filterId });
const queryClient = useQueryClient();
export const useDocumentOcr = ({ workflowId }: { workflowId: string }) => {
const filterId = useFilterId();
const workflowById = workflowsQueryKeys.byId({ workflowId, filterId });
const queryClient = useQueryClient();

Comment on lines 13 to 19
return useMutation({
mutationFn: ({ documentId }: { documentId: string }) => {
return fetchWorkflowDocumentOCRResult({
workflowDefinitionId: workflowId,
documentId,
});
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure consistency in parameter naming

The mutation function uses workflowDefinitionId, but the hook receives workflowId as a parameter. This inconsistency could lead to confusion.

Consider one of the following options:

  1. Rename the parameter to match the usage:
-export const useDocumentOcr = ({ workflowId }: { workflowId: string }) => {
+export const useDocumentOcr = ({ workflowDefinitionId }: { workflowDefinitionId: string }) => {
  // ... (update all occurrences of workflowId to workflowDefinitionId)
  1. Or, if workflowId is the correct term, update the fetch function call:
  return fetchWorkflowDocumentOCRResult({
-   workflowDefinitionId: workflowId,
+   workflowId,
    documentId,
  });

Choose the option that best aligns with your project's terminology and the actual purpose of this ID.

Committable suggestion was skipped due to low confidence.

Comment on lines 24 to 28
onError: (_error, _variables) => {
console.error(_error);
void queryClient.invalidateQueries(workflowsQueryKeys._def);
toast.error(t('toast:document_ocr.error'));
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refine error handling approach

While the current error handling provides user feedback and logs the error, there are a couple of points to consider:

  1. Invalidating queries on error might not be necessary and could potentially cause issues by triggering unnecessary refetches.
  2. The error details are not utilized in the user-facing error message.

Consider the following improvements:

-    onError: (_error, _variables) => {
-      console.error(_error);
-      void queryClient.invalidateQueries(workflowsQueryKeys._def);
-      toast.error(t('toast:document_ocr.error'));
+    onError: (error, variables) => {
+      console.error('OCR error:', error, 'for document:', variables.documentId);
+      toast.error(t('toast:document_ocr.error', { documentId: variables.documentId }));
     },

This change:

  1. Removes the query invalidation on error, as it's likely unnecessary.
  2. Improves error logging by including context (document ID).
  3. Potentially enriches the error message with the document ID (update your i18n file accordingly).

Also, consider adding more specific error handling if the fetchWorkflowDocumentOCRResult function provides structured error responses.

Committable suggestion was skipped due to low confidence.

Comment on lines +117 to +138
async runDocumentOcr({
images,
supportedCountries,
overrideSchemas,
}: {
images: TOcrImages;
supportedCountries: string[];
overrideSchemas: {
overrideSchemas: Array<{
countryCode: string;
documentType: string;
documentCategory: string;
schema: TSchema;
}>;
};
}) {
return await this.axiosInstance.post('/v1/document/smart-ocr', {
images,
supportedCountries,
overrideSchemas,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling in runDocumentOcr method for consistency

The runDocumentOcr method lacks error handling. To maintain consistency with the existing postBatchBusinessReport method and improve reliability, consider adding a try/catch block to handle potential errors and log them appropriately.

Apply this diff:

  async runDocumentOcr({
    images,
    supportedCountries,
    overrideSchemas,
  }: {
    images: TOcrImages;
    supportedCountries: string[];
    overrideSchemas: {
      overrideSchemas: Array<{
        countryCode: string;
        documentType: string;
        documentCategory: string;
        schema: TSchema;
      }>;
    };
  }) {
+    try {
      return await this.axiosInstance.post('/v1/document/smart-ocr', {
        images,
        supportedCountries,
        overrideSchemas,
      });
+    } catch (error) {
+      this.logger.error('Error in runDocumentOcr', error);
+      throw error;
+    }
  }
📝 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.

Suggested change
async runDocumentOcr({
images,
supportedCountries,
overrideSchemas,
}: {
images: TOcrImages;
supportedCountries: string[];
overrideSchemas: {
overrideSchemas: Array<{
countryCode: string;
documentType: string;
documentCategory: string;
schema: TSchema;
}>;
};
}) {
return await this.axiosInstance.post('/v1/document/smart-ocr', {
images,
supportedCountries,
overrideSchemas,
});
}
async runDocumentOcr({
images,
supportedCountries,
overrideSchemas,
}: {
images: TOcrImages;
supportedCountries: string[];
overrideSchemas: {
overrideSchemas: Array<{
countryCode: string;
documentType: string;
documentCategory: string;
schema: TSchema;
}>;
};
}) {
try {
return await this.axiosInstance.post('/v1/document/smart-ocr', {
images,
supportedCountries,
overrideSchemas,
});
} catch (error) {
this.logger.error('Error in runDocumentOcr', error);
throw error;
}
}

🛠️ Refactor suggestion

Simplify overrideSchemas parameter structure in runDocumentOcr

The overrideSchemas parameter includes an extra overrideSchemas property, which may be redundant. Consider simplifying the structure by passing the array directly if the API allows it. This can improve code readability and reduce unnecessary nesting.

Apply this diff:

In the method signature:

  async runDocumentOcr({
    images,
    supportedCountries,
    overrideSchemas,
  }: {
    images: TOcrImages;
    supportedCountries: string[];
-   overrideSchemas: {
-     overrideSchemas: Array<{
+   overrideSchemas: Array<{
        countryCode: string;
        documentType: string;
        documentCategory: string;
        schema: TSchema;
-     }>;
-   };
+   }>;
  }) {

And in the Axios request:

    return await this.axiosInstance.post('/v1/document/smart-ocr', {
      images,
      supportedCountries,
-     overrideSchemas,
+     overrideSchemas,
    });
📝 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.

Suggested change
async runDocumentOcr({
images,
supportedCountries,
overrideSchemas,
}: {
images: TOcrImages;
supportedCountries: string[];
overrideSchemas: {
overrideSchemas: Array<{
countryCode: string;
documentType: string;
documentCategory: string;
schema: TSchema;
}>;
};
}) {
return await this.axiosInstance.post('/v1/document/smart-ocr', {
images,
supportedCountries,
overrideSchemas,
});
}
async runDocumentOcr({
images,
supportedCountries,
overrideSchemas,
}: {
images: TOcrImages;
supportedCountries: string[];
overrideSchemas: Array<{
countryCode: string;
documentType: string;
documentCategory: string;
schema: TSchema;
}>;
}) {
return await this.axiosInstance.post('/v1/document/smart-ocr', {
images,
supportedCountries,
overrideSchemas,
});
}

Comment on lines 30 to 48
interface TOcrImage {
runOcr({
images,
schema,
}: {
images: Array<
| {
remote: {
imageUri: string;
mimeType: string;
};
}
| {
base64: string;
}
>;
schema: TSchema;
}): Promise<axios.AxiosResponse<any>>;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reuse 'TOcrImages' type in interface definition for consistency

To maintain consistency and reduce redundancy, consider using the previously defined TOcrImages type for the images parameter in the runOcr method within the TOcrImage interface, instead of redefining the type inline.

Apply the following diff:

 interface TOcrImage {
   runOcr({
     images,
     schema,
   }: {
-    images: Array<
-      | {
-          remote: {
-            imageUri: string;
-            mimeType: string;
-          };
-        }
-      | {
-          base64: string;
-        }
-    >;
+    images: TOcrImages;
     schema: TSchema;
   }): Promise<axios.AxiosResponse<any>>;
 }
📝 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.

Suggested change
interface TOcrImage {
runOcr({
images,
schema,
}: {
images: Array<
| {
remote: {
imageUri: string;
mimeType: string;
};
}
| {
base64: string;
}
>;
schema: TSchema;
}): Promise<axios.AxiosResponse<any>>;
}
interface TOcrImage {
runOcr({
images,
schema,
}: {
images: TOcrImages;
schema: TSchema;
}): Promise<axios.AxiosResponse<any>>;
}

Comment on lines 83 to 90
const {
mutate: mutateOCRDocument,
isLoading: isLoadingOCRDocument,
data: ocrResult,
} = useDocumentOrc({
workflowId: workflow?.id,
});

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inconsistent Hook Usage: Rename useDocumentOrc to useDocumentOcr

The hook is referred to as useDocumentOrc, but it should be useDocumentOcr to accurately represent the OCR functionality. This inconsistency may cause runtime errors or confusion.

Apply this diff to correct the hook usage:

 const {
-  mutate: mutateOCRDocument,
-  isLoading: isLoadingOCRDocument,
-  data: ocrResult,
-} = useDocumentOrc({
+  mutate: mutateOcrDocument,
+  isLoading: isLoadingOcrDocument,
+  data: ocrResult,
+} = useDocumentOcr({
   workflowId: workflow?.id,
 });

Committable suggestion was skipped due to low confidence.

Comment on lines 2529 to 2533
const document = runtimeData?.context?.documents?.find(
(document: DefaultContextSchema['documents'][number]) => document.id === documentId,
);

const documentSchema = addPropertiesSchemaToDocument(document, workflowDef.documentsSchema);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add null check for document existence

In the findDocumentById method, there's no check to handle the case where the document is not found. This could lead to a TypeError when document is undefined in subsequent operations.

Apply this diff to handle the case when the document is not found:

   const document = runtimeData?.context?.documents?.find(
     (document: DefaultContextSchema['documents'][number]) => document.id === documentId,
   );
+  if (!document) {
+    throw new NotFoundException(`Document with ID ${documentId} not found in workflow ${workflowId}`);
+  }
📝 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.

Suggested change
const document = runtimeData?.context?.documents?.find(
(document: DefaultContextSchema['documents'][number]) => document.id === documentId,
);
const documentSchema = addPropertiesSchemaToDocument(document, workflowDef.documentsSchema);
const document = runtimeData?.context?.documents?.find(
(document: DefaultContextSchema['documents'][number]) => document.id === documentId,
);
if (!document) {
throw new NotFoundException(`Document with ID ${documentId} not found in workflow ${workflowId}`);
}
const documentSchema = addPropertiesSchemaToDocument(document, workflowDef.documentsSchema);

Comment on lines +2600 to +2601
const base64String = this.storageService.fileToBase64(filePath!);

Copy link
Contributor

@coderabbitai coderabbitai bot Sep 25, 2024

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle potential undefined filePath

In cases where signedUrl is not available, the code assumes filePath is defined. If filePath is undefined, calling fileToBase64 will result in a runtime error.

Add a check to ensure that filePath is defined before using it:

+  if (!filePath) {
+    throw new InternalServerErrorException('File path is undefined');
+  }
   const base64String = this.storageService.fileToBase64(filePath!);
📝 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.

Suggested change
const base64String = this.storageService.fileToBase64(filePath!);
if (!filePath) {
throw new InternalServerErrorException('File path is undefined');
}
const base64String = this.storageService.fileToBase64(filePath!);

Copy link
Collaborator

Choose a reason for hiding this comment

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

Makes sense, regarding adding error handling in a specefic place - since you don't know here how fileToBase behaves with wrong input (here you are using ! and assume it will be okay in runtime) - it makes sense to add this error handling

Copy link
Contributor

Choose a reason for hiding this comment

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

@alonp99, glad to hear that adding the error handling makes sense!

((^.^)/)

Comment on lines 2586 to 2590
id: page.ballerineFileId!,
format: 'signed-url',
projectIds: [projectId],
});

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure ballerineFileId is defined

When accessing page.ballerineFileId!, the non-null assertion operator is used. If ballerineFileId is undefined or null, this will cause a runtime error.

Consider adding a check to ensure ballerineFileId is defined before using it, or handle the case where it might be missing:

   const { signedUrl, mimeType, filePath } = await this.storageService.fetchFileContent({
-    id: page.ballerineFileId!,
+    id: page.ballerineFileId,
     format: 'signed-url',
     projectIds: [projectId],
   });
+  if (!page.ballerineFileId) {
+    throw new BadRequestException('Page is missing ballerineFileId');
+  }

Committable suggestion was skipped due to low confidence.

Comment on lines 2608 to 2613
await new UnifiedApiClient().runOcr({
images,
schema: documentWithSchema.propertiesSchema as unknown as TSchema,
})
)?.data;
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for OCR service call

The call to runOcr may fail or throw an exception, but there is no error handling in place. This could result in unhandled exceptions.

Consider wrapping the OCR service call in a try-catch block to handle potential errors gracefully:

+  try {
     return (
       await new UnifiedApiClient().runOcr({
         images,
         schema: documentWithSchema.propertiesSchema as unknown as TSchema,
       })
     )?.data;
+  } catch (error) {
+    this.logger.error('OCR service failed', { error });
+    throw new InternalServerErrorException('Failed to process OCR');
+  }

Committable suggestion was skipped due to low confidence.

documentId: string;
}) => {
const [workflow, error] = await apiClient({
method: Method.PATCH,
Copy link
Collaborator

Choose a reason for hiding this comment

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

PATCH?

mutate: mutateOCRDocument,
isLoading: isLoadingOCRDocument,
data: ocrResult,
} = useDocumentOrc({
Copy link
Collaborator

Choose a reason for hiding this comment

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

Typo

import { CommonWorkflowEvent, CommonWorkflowStates, DefaultContextSchema } from '@ballerine/common';
import { checkCanMakeDecision } from '@/lib/blocks/hooks/useDocumentBlocks/utils/check-can-make-decision/check-can-make-decision';

export const checkCanOcr = ({
Copy link
Collaborator

@alonp99 alonp99 Sep 25, 2024

Choose a reason for hiding this comment

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

find better naming

Copy link
Contributor

Choose a reason for hiding this comment

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

@alonp99, I agree that the function name checkCanOcr can be more descriptive. Perhaps renaming it to canPerformOcr, isOcrAllowed, or shouldEnableOcr would enhance readability and better convey its purpose.


✏️ Learnings added
Learnt from: alonp99
PR: ballerine-io/ballerine#2731
File: apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/utils/check-can-ocr/check-can-ocr.ts:6-6
Timestamp: 2024-09-25T21:48:10.975Z
Learning: When naming functions, use clear and descriptive names that accurately reflect their purpose to improve code readability.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

workflow: TWorkflowById;
decision: DefaultContextSchema['documents'][number]['decision'];
isLoadingApprove: boolean;
}) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

can you explain why this function is needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

removed

(document: DefaultContextSchema['documents'][number]) => document.id === documentId,
);

const documentSchema = addPropertiesSchemaToDocument(document, workflowDef.documentsSchema);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not documentSchema, you can call it documentWithSchema or just document - its very confusing in the rest of the code

throw new BadRequestException('Cannot run document OCR on document without pages');
}

const documentWithSchema = addPropertiesSchemaToDocument(
Copy link
Collaborator

Choose a reason for hiding this comment

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

its seems like youre adding the properties twice, its also done infindDocumentById

Copy link
Contributor

@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.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 783bf7e and 9df1bfc.

📒 Files selected for processing (3)
  • apps/backoffice-v2/src/domains/entities/hooks/mutations/useDocumentOcr/useDocumentOcr.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (6 hunks)
  • services/workflows-service/prisma/data-migrations (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/backoffice-v2/src/domains/entities/hooks/mutations/useDocumentOcr/useDocumentOcr.ts
  • services/workflows-service/prisma/data-migrations
🔇 Additional comments (4)
apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (4)

4-4: LGTM: Import statement updated correctly

The addition of isObject to the import statement from '@ballerine/common' is appropriate and consistent with its usage in the file.


32-32: LGTM: New import for OCR functionality added

The import of useDocumentOcr is correctly added and aligns with the new OCR functionality being implemented in the hook.


Line range hint 1-570: Summary of OCR Implementation Review

The implementation of OCR functionality in the useDocumentBlocks hook is generally well-done. Here's a summary of the key points:

  1. The necessary imports and hook usage for OCR have been correctly added.
  2. The integration of OCR results into the document processing logic is implemented.
  3. An OCR button functionality has been added to the UI.

However, there are a few minor issues to address:

  1. Consistency in naming conventions (e.g., mutateOCRDocument vs mutateOcrDocument).
  2. Potential object mutation in the documentEntries logic.
  3. An unused variable (isLoadingOCRDocument) that should be removed if not needed.

Please address these issues to improve the overall quality and consistency of the implementation.


470-470: ⚠️ Potential issue

Fix typo in function name

The function name mutateOCRDocument should be mutateOcrDocument for consistency with camelCase naming conventions.

Apply this diff to fix the typo:

-  onOcrPressed: () => mutateOCRDocument({ documentId: id }),
+  onOcrPressed: () => mutateOcrDocument({ documentId: id }),

Likely invalid or redundant comment.

…o/ballerine into feature/implement_ocr_button
Copy link
Contributor

@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.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (9)
apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/interfaces.ts (1)

4-5: LGTM! Consider minor adjustment for consistency.

The new properties onOcrPressed and isLoadingOCR are well-defined and align with the PR objectives. They follow TypeScript best practices and have clear, descriptive names.

For consistency with the existing isLoading property, consider moving isLoadingOCR right after it. This groups related properties together, improving readability:

export interface IMultiDocumentsProps {
  value: {
    isLoading: boolean;
    isLoadingOCR: boolean;
    onOcrPressed: () => void;
    data: Array<{
      imageUrl: string;
      title: string;
      fileType: string;
    }>;
  };
}
apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/MultiDocuments.tsx (1)

10-15: LGTM! Consider adding type assertions for improved type safety.

The changes align well with the PR objectives by adding OCR-related props to the Case.Documents component. This implementation allows for OCR functionality and loading state management.

For improved type safety, consider adding type assertions to the new props:

 <Case.Documents
   documents={documents}
   isLoading={value?.isLoading}
-  onOcrPressed={value?.onOcrPressed}
-  isLoadingOCR={value?.isLoadingOCR}
+  onOcrPressed={value?.onOcrPressed as (() => void) | undefined}
+  isLoadingOCR={value?.isLoadingOCR as boolean | undefined}
 />

This change ensures that the types of onOcrPressed and isLoadingOCR are explicitly defined, which can help catch potential type-related issues earlier in the development process.

apps/backoffice-v2/src/lib/blocks/components/EditableDetails/interfaces.ts (1)

28-28: LGTM! Consider adding a JSDoc comment for clarity.

The addition of the isSaveDisabled property is well-implemented. It's optional, which maintains backward compatibility, and its boolean type is appropriate for representing a disabled state.

Consider adding a JSDoc comment to provide more context about when and why this property might be used. For example:

/**
 * Indicates whether the save functionality should be disabled.
 * This can be used to prevent saving when certain conditions are not met.
 */
isSaveDisabled?: boolean;
apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx (1)

12-33: LGTM: Well-implemented component with a minor suggestion.

The ImageOCR component is well-implemented, following React best practices. The conditional rendering, styling, and prop usage are all handled effectively.

However, there's a minor optimization opportunity in the onClick handler:

Consider memoizing the onClick handler to avoid creating a new function on each render:

-    onClick={() => !isLoadingOCR && onOcrPressed?.()}
+    onClick={React.useCallback(() => !isLoadingOCR && onOcrPressed?.(), [isLoadingOCR, onOcrPressed])}

This change would require adding React to the import statement:

-import { ComponentProps, FunctionComponent } from 'react';
+import React, { ComponentProps, FunctionComponent } from 'react';
apps/backoffice-v2/src/lib/blocks/components/Details/Details.tsx (1)

16-16: LGTM! Consider adding type annotation for isSaveDisabled.

The addition of the isSaveDisabled prop and its usage in the EditableDetails component is well-implemented. It extends the component's functionality in a clear and consistent manner.

For improved type safety and code clarity, consider adding a type annotation for the isSaveDisabled prop. You can update the component's props type or add an inline annotation:

isSaveDisabled?: boolean,

This will ensure that only boolean values are passed for this prop and improve the component's API documentation.

Also applies to: 42-42

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (3)

17-19: LGTM: New props for OCR functionality.

The new props onOcrPressed, shouldOCR, and isLoadingOCR are well-defined and properly typed. They align with the OCR functionality being added to the component.

Consider grouping related props together for better readability. You could move shouldOCR next to onOcrPressed like this:

onOcrPressed?: () => void;
shouldOCR: boolean;
isLoadingOCR: boolean;

27-30: Align prop order with type definition.

The destructuring of the new props is correct, but the order doesn't match the type definition.

Consider reordering the destructured props to match the order in the type definition for consistency and improved readability:

onOcrPressed,
shouldOCR,
isLoadingOCR,

41-49: LGTM: New OCR functionality implementation.

The implementation of the OCR functionality is well-structured and correctly uses the new ImageOCR component with appropriate props. The conditional rendering ensures the OCR button is only shown when necessary.

Consider using the ctw utility for className concatenation to maintain consistency with the rest of the file:

<div className={ctw('gap-y-50 mb-10 flex h-full flex-col items-center')}>
apps/backoffice-v2/src/lib/blocks/create-blocks-typed/types.ts (1)

118-118: LGTM! Consider adding a comment for clarity.

The addition of the isSaveDisabled optional boolean property to the TDetailsCell type is a good enhancement. It provides more granular control over the save functionality in the UI, which can be useful in various scenarios such as data validation or permission checks.

Consider adding a brief comment to explain the purpose of this property, for example:

/** When true, disables the save functionality for this details cell */
isSaveDisabled?: boolean;

This will help other developers understand the intended use of this property at a glance.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 9df1bfc and 4c4f013.

📒 Files selected for processing (13)
  • apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx (1 hunks)
  • apps/backoffice-v2/src/domains/customer/fetchers.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/Details/Details.tsx (2 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/EditableDetails/EditableDetails.tsx (2 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/EditableDetails/interfaces.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/MultiDocuments.tsx (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/interfaces.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/create-blocks-typed/types.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (7 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (3 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.tsx (4 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx (2 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/interfaces.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.tsx
  • apps/backoffice-v2/src/pages/Entity/components/Case/interfaces.ts
🔇 Additional comments (17)
apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx (3)

1-3: LGTM: Imports are well-organized and necessary.

The imports are logically organized and include all the necessary dependencies for the component's functionality.


1-33: Overall, excellent implementation with minor suggestions for improvement.

The ImageOCR component is well-designed and implemented. It provides a reusable OCR button with appropriate props for controlling its state and behavior. The code is clean, follows React best practices, and uses TypeScript effectively for type safety.

Consider the minor suggestions provided in the previous comments to further optimize the component. Great job on this implementation!


5-10: LGTM: Well-defined interface, but review documentId usage.

The IImageOCR interface is well-structured and includes all necessary props for the component. However, the documentId prop is defined but not used in the component implementation.

Please verify if the documentId prop is necessary or if it's used in a parent component:

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (2)

8-8: LGTM: New import for OCR functionality.

The import of the ImageOCR component is correctly placed and aligns with the new OCR functionality being added to the DocumentsToolbar.


Line range hint 1-92: Overall: Well-implemented OCR functionality.

The changes in this file successfully implement the OCR button functionality as described in the PR objectives. The code is well-structured, and the new OCR-related components and props are integrated seamlessly into the existing DocumentsToolbar component.

A few minor suggestions have been made to improve consistency and readability:

  1. Grouping related props in the type definition.
  2. Aligning the order of destructured props with the type definition.
  3. Using the ctw utility for className concatenation in the new OCR section.

These small adjustments will enhance the overall quality and maintainability of the code.

apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx (5)

11-11: LGTM: Import changes align with new functionality.

The addition of useCustomerQuery and removal of copyToClipboard are consistent with the described changes in the PR objectives and AI summary.


13-13: LGTM: Function name change improves clarity.

Renaming useDocuments to useDocumentsLogic better reflects the hook's purpose and aligns with the changes described in the AI summary.


15-15: LGTM: Customer data query added.

The addition of useCustomerQuery hook usage is consistent with the new import and likely supports the OCR-related features mentioned in the PR objectives.


Line range hint 1-85: Overall, the changes align well with the PR objectives.

The refactoring of useDocumentsLogic hook successfully implements the OCR-related changes described in the PR objectives. The code is cleaner, with unnecessary OCR logic removed and new customer-related functionality added.

However, please ensure to address the TODO comment regarding the default value of shouldOCR before finalizing this PR.


71-71: ⚠️ Potential issue

Address TODO comment and review default value for shouldOCR.

The addition of shouldOCR aligns with the PR objectives. However, please address the following:

  1. Remove the default true value as indicated by the TODO comment.
  2. Ensure that the isDocumentOcrEnabled feature flag is properly set for customers.
  3. Consider adding a comment explaining the purpose of this flag for future maintainers.

To verify the usage of isDocumentOcrEnabled, run the following script:

✅ Verification successful

To accurately locate usages of isDocumentOcrEnabled, please run the following script:


TODO Comment Addressed: Remove default true for shouldOCR.

The isDocumentOcrEnabled feature flag is properly defined with a default value of false and is consistently used within the codebase. You can safely remove the default true value as indicated by the TODO comment.

  • Action Items:
    1. Remove || true from the shouldOCR assignment.
    2. Verify that isDocumentOcrEnabled is correctly configured for all customers.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other occurrences of isDocumentOcrEnabled in the codebase

# Test: Search for isDocumentOcrEnabled usage
rg --type typescript 'isDocumentOcrEnabled'

Length of output: 78


Script:

# !/bin/bash
# Description: Check for other occurrences of isDocumentOcrEnabled in TypeScript files

rg 'isDocumentOcrEnabled' --glob '*.ts' --glob '*.tsx'

Length of output: 372

apps/backoffice-v2/src/lib/blocks/components/EditableDetails/EditableDetails.tsx (2)

106-106: LGTM: New prop enhances component flexibility

The addition of the isSaveDisabled prop is a good enhancement. It allows for external control of the "Save" button's disabled state, improving the component's flexibility and reusability.


431-435: LGTM: Improved "Save" button accessibility and visual feedback

The changes to the "Save" button rendering logic are well-implemented:

  1. The new classes provide clear visual feedback when the button is disabled.
  2. The aria-disabled attribute improves accessibility by properly indicating the button's state to assistive technologies.
  3. The conditional rendering ensures the button only appears when relevant.

These changes enhance both the user experience and accessibility of the component.

apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (5)

4-4: LGTM: Import statement updated correctly

The addition of isObject to the import statement is appropriate for the new OCR functionality.


32-32: LGTM: New OCR hook imported correctly

The import of useDocumentOcr is correctly added and is essential for the new OCR functionality.


83-90: ⚠️ Potential issue

Fix typo and consider removing unused variable

  1. The variable name mutateOCRDocument should be mutateOcrDocument for consistency with camelCase naming conventions.
  2. The isLoadingOCRDocument variable is not used in the visible code. Consider removing it if it's not used elsewhere in the component.

Apply this diff to fix the typo and remove the unused variable:

 const {
-  mutate: mutateOCRDocument,
-  isLoading: isLoadingOCRDocument,
+  mutate: mutateOcrDocument,
   data: ocrResult,
 } = useDocumentOcr({
   workflowId: workflow?.id,
 });

Likely invalid or redundant comment.


370-381: ⚠️ Potential issue

Avoid mutating formattedValue directly

The current implementation directly mutates formattedValue, which could lead to unintended side effects if these objects are used elsewhere. Consider using an immutable approach to update the value.

Apply this diff to use an immutable approach:

 const documentEntries = Object.entries(
   {
     ...additionalProperties,
     ...propertiesSchema?.properties,
   } ?? {},
 ).map(([title, formattedValue]) => {
   if (isObject(formattedValue)) {
-    formattedValue.value ||= ocrResult?.parsedData?.[title];
+    return [title, {
+      ...formattedValue,
+      value: formattedValue.value || ocrResult?.parsedData?.[title],
+    }];
   }

-  return [title, formattedValue];
+  return [title, formattedValue];
 });

This change ensures that we're not modifying the original formattedValue object, but instead creating a new object with the updated value.

Likely invalid or redundant comment.


456-456: LGTM: Save disabled during OCR processing

The isSaveDisabled property is correctly set to isLoadingOCRDocument, which prevents saving while OCR is in progress. This is a good practice to avoid inconsistent states.

Consider if there are other conditions that should disable saving. You may want to combine this with existing conditions if they exist. To verify, you can run the following command to check for other usages of isSaveDisabled:

@@ -27,6 +27,7 @@ const CustomerSchema = z.object({
createBusinessReportBatch: z
.object({ enabled: z.boolean().default(false), options: createBusinessReportOptions })
.optional(),
isDocumentOcrEnabled: z.boolean().default(false).optional(),
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Inconsistent Default Value for isDocumentOcrEnabled

The property isDocumentOcrEnabled is defined with a default value of false in fetchers.ts. However, in useDocumentsLogic.tsx, it is used with a fallback to true:

shouldOCR: customer?.features?.isDocumentOcrEnabled || true, // TODO remove default true after review

This inconsistency can lead to shouldOCR being true even when it should default to false, potentially causing unintended behavior.

Recommendations:

  • Remove the fallback to true in useDocumentsLogic.tsx to align with the schema default.
  • Address the TODO comment to ensure consistency across the codebase.
🔗 Analysis chain

LGTM: New OCR feature flag added correctly

The new isDocumentOcrEnabled property has been added appropriately to the features object within the CustomerSchema. It's correctly defined as an optional boolean with a default value of false, which aligns with best practices for feature flags.

A few points to consider:

  1. The naming is clear and follows the existing naming conventions in the schema.
  2. The default value of false ensures backwards compatibility with existing data.
  3. The property is optional, which is appropriate for a feature flag.

To ensure this change doesn't introduce any unexpected behavior, let's verify its usage:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any existing usage of isDocumentOcrEnabled
# Expected: No results if this is a new feature

rg --type typescript 'isDocumentOcrEnabled'

Length of output: 78


Script:

#!/bin/bash
# Description: Check for any existing usage of isDocumentOcrEnabled in TypeScript files
# Expected: No results if this is a new feature

rg 'isDocumentOcrEnabled' -g '*.ts' -g '*.tsx'

Length of output: 364


Script:

#!/bin/bash
# Description: Extract surrounding lines for the usage of isDocumentOcrEnabled in useDocumentsLogic.tsx
# Expected: Contextual code to assess the implementation and TODO comment

rg 'isDocumentOcrEnabled' -A 5 -B 5 apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx

Length of output: 394

Comment on lines 472 to 473
onOcrPressed: () => mutateOCRDocument({ documentId: id }),
isLoadingOCR: isLoadingOCRDocument,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in OCR mutation function name

The OCR functionality is correctly implemented, but there's a typo in the function name.

Apply this diff to fix the typo:

-  onOcrPressed: () => mutateOCRDocument({ documentId: id }),
+  onOcrPressed: () => mutateOcrDocument({ documentId: id }),
   isLoadingOCR: isLoadingOCRDocument,

The rest of the changes look good. The isLoadingOCR property is correctly set to isLoadingOCRDocument.

📝 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.

Suggested change
onOcrPressed: () => mutateOCRDocument({ documentId: id }),
isLoadingOCR: isLoadingOCRDocument,
onOcrPressed: () => mutateOcrDocument({ documentId: id }),
isLoadingOCR: isLoadingOCRDocument,

Copy link
Contributor

@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.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (5)
apps/backoffice-v2/src/pages/Entity/components/Case/interfaces.ts (2)

53-53: LGTM: OCR loading state added

The addition of isLoadingOCR property aligns with the PR objective and complements the onOcrPressed method. It's correctly defined as an optional boolean.

Consider using a more specific name like isOcrProcessing to clearly indicate that it represents the processing state of OCR, not just loading.


51-54: Summary of changes to IDocumentsProps

The changes to the IDocumentsProps interface align well with the PR objectives of implementing OCR functionality:

  1. The onOcrPressed method provides a callback for the OCR button.
  2. The isLoadingOCR property allows for indicating the OCR processing state.

However, the purpose of isDocumentEditable in relation to OCR is not clear from the PR objectives.

To ensure comprehensive documentation:

Consider updating the PR description to include the rationale for adding the isDocumentEditable property and how it relates to the OCR functionality. This will help maintain clear documentation of the interface's evolution and its relationship to the OCR feature.

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (3)

17-19: LGTM: New props for OCR functionality.

The new props onOcrPressed, isOCREnabled, and isLoadingOCR are well-typed and align with the PR objectives. Their naming follows React conventions.

Consider adding JSDoc comments to these new props to improve code documentation. For example:

/**
 * Callback function triggered when OCR is initiated.
 */
onOcrPressed?: () => void;

/**
 * Flag indicating whether OCR functionality is enabled.
 */
isOCREnabled: boolean;

/**
 * Flag indicating whether OCR processing is in progress.
 */
isLoadingOCR: boolean;

27-30: Consider grouping related props together.

The new OCR-related props have been correctly added to the component's parameter list. However, for better readability and maintainability, consider grouping related props together.

Suggest reordering the props as follows:

}) => ({
  image,
  isLoading,
  hideOpenExternalButton,
  onRotateDocument,
  onOpenDocumentInNewTab,
  onOcrPressed,
  isOCREnabled,
  isLoadingOCR,
  shouldDownload,
  fileToDownloadBase64,
}) => {

This groups the OCR-related props together, making the code more organized.


41-47: LGTM: ImageOCR component integration.

The ImageOCR component is correctly integrated and conditionally rendered based on the presence of an image. The OCR-related props are properly passed to the component.

For improved clarity, consider renaming the isOcrDisabled prop in the ImageOCR component to isOcrEnabled and passing the value directly:

<ImageOCR
  isOcrEnabled={isOCREnabled}
  onOcrPressed={onOcrPressed}
  isLoadingOCR={isLoadingOCR}
/>

This change would make the prop naming consistent across components and eliminate the need for a negation operation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 4c4f013 and a5a8a1a.

📒 Files selected for processing (10)
  • apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/MultiDocuments.tsx (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/interfaces.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (7 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (3 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.tsx (4 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx (2 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/interfaces.ts (1 hunks)
  • services/workflows-service/prisma/data-migrations (1 hunks)
  • services/workflows-service/src/workflow/workflow.service.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • apps/backoffice-v2/src/common/components/molecules/ImageOCR/ImageOCR.tsx
  • apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/MultiDocuments.tsx
  • apps/backoffice-v2/src/lib/blocks/components/MultiDocuments/interfaces.ts
  • apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.tsx
  • apps/backoffice-v2/src/pages/Entity/components/Case/hooks/useDocuments/useDocumentsLogic.tsx
  • services/workflows-service/prisma/data-migrations
  • services/workflows-service/src/workflow/workflow.service.ts
🔇 Additional comments (4)
apps/backoffice-v2/src/pages/Entity/components/Case/interfaces.ts (2)

51-51: LGTM: OCR button callback added

The addition of onOcrPressed method aligns with the PR objective of implementing an OCR button. The method signature is correct for a callback, and it follows React's naming convention for event handlers.


54-54: Please clarify the purpose of isDocumentEditable

The addition of isDocumentEditable property is not directly mentioned in the PR objectives. Could you please clarify:

  1. How does this property relate to the OCR functionality being implemented?
  2. In what scenarios would a document be editable or non-editable in the context of OCR?
  3. How is this property intended to be used in the UI or logic related to OCR?

This information will help ensure that the property aligns with the overall objectives of the PR and is implemented correctly.

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (2)

8-8: LGTM: New import for OCR functionality.

The import for the ImageOCR component is correctly placed and follows the project's import conventions. This addition aligns with the PR objective of implementing OCR functionality.


Line range hint 1-89: Overall assessment: Implementation looks good with minor suggestions for improvement.

The changes to the DocumentsToolbar component successfully integrate OCR functionality as per the PR objectives. The code is well-structured, follows React best practices, and maintains consistency with the existing codebase. The suggestions provided are minor and aimed at improving code clarity and organization.

Great job on implementing this feature! Once the suggested minor improvements are addressed, this code will be ready for merging.

Copy link
Contributor

@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.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 96cae03 and ca3d26e.

📒 Files selected for processing (2)
  • services/workflows-service/src/workflow/workflow.service.ts (4 hunks)
  • services/workflows-service/src/workflow/workflow.service.unit.test.ts (1 hunks)
🔇 Additional comments (1)
services/workflows-service/src/workflow/workflow.service.unit.test.ts (1)

Line range hint 1-238: Ensure comprehensive updates throughout the test file

While the change to the WorkflowService constructor is isolated, it's important to ensure that this modification is reflected consistently throughout the test file. Consider the following points:

  1. Review all instances where WorkflowService is instantiated in this file and update them accordingly.

  2. Check if there are any test cases that might need to be modified or added to cover scenarios related to the new parameter.

  3. Verify that the mock data and setup in the beforeEach block are still sufficient for all test cases, given the new parameter.

  4. If there are any descriptions or documentation within the test file about the WorkflowService structure, make sure they are updated to include information about the new parameter.

To help with this review, you can run the following command to find all occurrences of WorkflowService instantiation in the file:

This will help identify any other places where the WorkflowService constructor is called and ensure they are all updated consistently.

✅ Verification successful

Correct the shell script to search for WorkflowService instantiations

The previous command failed because typescript is not a recognized file type in ripgrep. Please use the corrected script below to search for all instances of new WorkflowService( in the specified test file:


Verification Successful: WorkflowService instantiations are consistent

All instances of WorkflowService instantiation in the test file have been reviewed and are consistent with the expected changes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for WorkflowService instantiations
rg --type typescript -A 5 'new WorkflowService\(' services/workflows-service/src/workflow/workflow.service.unit.test.ts

Length of output: 156


Script:

#!/bin/bash
# Search for WorkflowService instantiations in the specified test file
rg 'new WorkflowService\(' services/workflows-service/src/workflow/workflow.service.unit.test.ts -A 5

Length of output: 271

@@ -207,6 +207,7 @@ describe('WorkflowService', () => {
ruleEngineService,
{} as any,
{} as any,
{} as any,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider improving the test setup for the new WorkflowService parameter

The addition of a new parameter to the WorkflowService constructor indicates a change in its implementation. However, there are a few concerns:

  1. There's no documentation or comments explaining what this new parameter represents. Consider adding a comment to clarify its purpose.

  2. Using {} as any is generally not a good testing practice. It bypasses TypeScript's type checking and doesn't properly mock the expected interface, which could lead to missed issues during testing.

  3. Instead of {} as any, consider creating a proper mock object that represents the expected interface. This will make the test more robust and easier to maintain.

  4. If there are other test cases for WorkflowService in this file or others, make sure to update them to include this new parameter as well.

Here's a suggestion to improve the code:

// Define an interface for the new parameter (replace NewDependency with the actual type)
interface NewDependency {
  // Add the expected properties and methods
}

// Create a mock object
const mockNewDependency: NewDependency = {
  // Implement the necessary properties and methods
};

// Use the mock object in the constructor
service = new WorkflowService(
  // ... other parameters ...
  mockNewDependency,
);

This approach will provide better type safety and make the test more representative of the actual usage.

Comment on lines +2553 to +2561
const document = await this.findDocumentById({
workflowId: workflowRuntimeId,
projectId,
documentId,
transaction,
});

if (!('pages' in document)) {
throw new BadRequestException('Cannot run document OCR on document without pages');
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add null check after retrieving the document

In the runOCROnDocument method, there's no check to handle the case where findDocumentById returns undefined if the document is not found. Accessing properties on an undefined value will result in a runtime error.

Apply this diff to handle the case when the document is not found:

         const document = await this.findDocumentById({
           workflowId: workflowRuntimeId,
           projectId,
           documentId,
           transaction,
         });

+        if (!document) {
+          throw new NotFoundException(`Document with ID ${documentId} not found in workflow ${workflowRuntimeId}`);
+        }

         if (!('pages' in document)) {
           throw new BadRequestException('Cannot run document OCR on document without pages');
         }
📝 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.

Suggested change
const document = await this.findDocumentById({
workflowId: workflowRuntimeId,
projectId,
documentId,
transaction,
});
if (!('pages' in document)) {
throw new BadRequestException('Cannot run document OCR on document without pages');
const document = await this.findDocumentById({
workflowId: workflowRuntimeId,
projectId,
documentId,
transaction,
});
if (!document) {
throw new NotFoundException(`Document with ID ${documentId} not found in workflow ${workflowRuntimeId}`);
}
if (!('pages' in document)) {
throw new BadRequestException('Cannot run document OCR on document without pages');

Comment on lines 2564 to 2585
const documentPagesContent = document.pages.map(async page => {
const { signedUrl, mimeType, filePath } = await this.storageService.fetchFileContent({
id: page.ballerineFileId!,
format: 'signed-url',
projectIds: [projectId],
});

if (signedUrl) {
return {
remote: {
imageUri: signedUrl,
mimeType,
},
};
}

const base64String = this.storageService.fileToBase64(filePath!);

return { base64: `data:${mimeType};base64,${base64String}` };
});

const images = (await Promise.all(documentPagesContent)) satisfies TOcrImages;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor asynchronous processing of document pages

Consider refactoring the asynchronous mapping over document.pages to improve readability and error handling. Using a for...of loop can make the code clearer and facilitate better error control.

Apply this diff to refactor the code:

-        const documentPagesContent = document.pages.map(async page => {
-          const { signedUrl, mimeType, filePath } = await this.storageService.fetchFileContent({
-            id: page.ballerineFileId!,
-            format: 'signed-url',
-            projectIds: [projectId],
-          });
-
-          if (signedUrl) {
-            return {
-              remote: {
-                imageUri: signedUrl,
-                mimeType,
-              },
-            };
-          }
-
-          const base64String = this.storageService.fileToBase64(filePath!);
-
-          return { base64: `data:${mimeType};base64,${base64String}` };
-        });
-
-        const images = (await Promise.all(documentPagesContent)) satisfies TOcrImages;
+        const images: TOcrImages = [];
+        for (const page of document.pages) {
+          const { signedUrl, mimeType, filePath } = await this.storageService.fetchFileContent({
+            id: page.ballerineFileId!,
+            format: 'signed-url',
+            projectIds: [projectId],
+          });
+
+          if (signedUrl) {
+            images.push({
+              remote: {
+                imageUri: signedUrl,
+                mimeType,
+              },
+            });
+          } else {
+            const base64String = this.storageService.fileToBase64(filePath!);
+            images.push({
+              base64: `data:${mimeType};base64,${base64String}`,
+            });
+          }
+        }
📝 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.

Suggested change
const documentPagesContent = document.pages.map(async page => {
const { signedUrl, mimeType, filePath } = await this.storageService.fetchFileContent({
id: page.ballerineFileId!,
format: 'signed-url',
projectIds: [projectId],
});
if (signedUrl) {
return {
remote: {
imageUri: signedUrl,
mimeType,
},
};
}
const base64String = this.storageService.fileToBase64(filePath!);
return { base64: `data:${mimeType};base64,${base64String}` };
});
const images = (await Promise.all(documentPagesContent)) satisfies TOcrImages;
const images: TOcrImages = [];
for (const page of document.pages) {
const { signedUrl, mimeType, filePath } = await this.storageService.fetchFileContent({
id: page.ballerineFileId!,
format: 'signed-url',
projectIds: [projectId],
});
if (signedUrl) {
images.push({
remote: {
imageUri: signedUrl,
mimeType,
},
});
} else {
const base64String = this.storageService.fileToBase64(filePath!);
images.push({
base64: `data:${mimeType};base64,${base64String}`,
});
}
}

# Conflicts:
#	pnpm-lock.yaml
#	services/workflows-service/prisma/data-migrations
#	services/workflows-service/src/workflow/workflow.service.ts
Copy link
Contributor

@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.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8096d8f and 2ed1587.

📒 Files selected for processing (2)
  • services/workflows-service/src/storage/storage.service.ts (2 hunks)
  • services/workflows-service/src/workflow/workflow.service.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/workflows-service/src/workflow/workflow.service.ts

Comment on lines +121 to +149
private __getAbsoluteFilePAth(filePath: string) {
if (!path.isAbsolute(filePath)) return filePath;

const rootDir = path.parse(os.homedir()).root;

return path.join(rootDir, filePath);
}

private async __downloadFileFromRemote(persistedFile: File) {
const localeFilePath = `${os.tmpdir()}/${persistedFile.id}`;
const downloadedFilePath = await new HttpFileService({
client: this.httpService,
logger: this.logger,
}).download(persistedFile.uri, localeFilePath);

return downloadedFilePath;
}

_isUri(persistedFile: File) {
return z.string().url().safeParse(persistedFile.uri).success;
}

fileToBase64(filepath: string): string {
const fileBuffer = readFileSync(filepath);

const base64String = fileBuffer.toString('base64');

return base64String;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure consistent method naming conventions

The methods in the StorageService class use inconsistent naming conventions for private methods:

  • Double underscores: __getAbsoluteFilePath, __downloadFileFromRemote
  • Single underscore: _isUri
  • No underscore: fileToBase64

Consider standardizing the naming convention for private methods. A common practice is to use a single underscore prefix for private or protected methods in TypeScript. This will enhance code consistency and maintainability.

return { filePath: filePath, mimeType };
}

private __getAbsoluteFilePAth(filePath: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the typo in the method name '__getAbsoluteFilePAth'

The method name __getAbsoluteFilePAth contains a typographical error with an uppercase 'A' in "PAth". It should be corrected to __getAbsoluteFilePath to maintain proper naming conventions and improve readability.

Apply this diff to correct the method name:

-private __getAbsoluteFilePAth(filePath: string) {
+private __getAbsoluteFilePath(filePath: string) {
📝 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.

Suggested change
private __getAbsoluteFilePAth(filePath: string) {
private __getAbsoluteFilePath(filePath: string) {

} ?? {},
).map(([title, formattedValue]) => {
if (isObject(formattedValue)) {
formattedValue.value ||= ocrResult?.parsedData?.[title];
Copy link
Contributor

Choose a reason for hiding this comment

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

In React its more important not to make mutations. Just pass the value to the right instead of formattedValue.

@@ -31,6 +38,13 @@ export const DocumentsToolbar: FunctionComponent<{

return (
<div className={`absolute z-50 flex space-x-2 bottom-right-6`}>
{image && (
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason the condition is not the same as the button below? The isLoading and image id.

Comment on lines 30 to 38
interface TOcrImage {
runOcr({
images,
schema,
}: {
images: TOcrImages;
schema: TSchema;
}): Promise<axios.AxiosResponse<any>>;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the goal of creating and using this interface over implementing runOcr directly?

Copy link
Contributor

@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.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (5)
apps/backoffice-v2/src/domains/workflows/fetchers.ts (2)

302-318: Improve schema validation for better type safety

The implementation of fetchWorkflowDocumentOCRResult looks good overall and integrates well with the existing codebase. However, there's an opportunity to enhance type safety:

  1. Consider defining a more specific Zod schema for the expected OCR result instead of using z.any(). This will provide better runtime validation and TypeScript type inference.

Here's a suggestion to improve the schema validation:

import { z } from 'zod';

// Define this schema based on the expected OCR result structure
const OCRResultSchema = z.object({
  // Add expected fields here, for example:
  text: z.string(),
  confidence: z.number(),
  // ... other fields
});

export const fetchWorkflowDocumentOCRResult = async ({
  workflowRuntimeId,
  documentId,
}: {
  workflowRuntimeId: string;
  documentId: string;
}) => {
  const [workflow, error] = await apiClient({
    method: Method.GET,
    url: `${getOriginUrl(
      env.VITE_API_URL,
    )}/api/v1/internal/workflows/${workflowRuntimeId}/documents/${documentId}/run-ocr`,
    schema: OCRResultSchema, // Use the defined schema here
  });

  return handleZodError(error, workflow);
};

This change will provide better type safety and runtime validation for the OCR result.


302-302: Add JSDoc comments for the new function

To maintain consistency with other functions in the file and improve code documentation, consider adding JSDoc comments for the fetchWorkflowDocumentOCRResult function. This will provide better context and usage information for other developers.

Here's a suggested JSDoc comment:

/**
 * Fetches the OCR result for a specific document in a workflow.
 * 
 * @param {Object} params - The parameters for the function.
 * @param {string} params.workflowRuntimeId - The ID of the workflow runtime.
 * @param {string} params.documentId - The ID of the document to run OCR on.
 * @returns {Promise<any>} The OCR result. Consider replacing 'any' with a more specific type once the OCRResultSchema is defined.
 */
export const fetchWorkflowDocumentOCRResult = async ({
  // ... rest of the function

Adding this documentation will help other developers understand the purpose and usage of this new function.

services/workflows-service/src/workflow/workflow.controller.internal.ts (1)

341-357: LGTM with suggestions for improvement

The implementation of the runDocumentOcr method looks good overall. It correctly defines the endpoint, uses Swagger for documentation, and leverages the WorkflowAssigneeGuard for authorization. However, there are a couple of areas where it could be improved:

  1. Consider adding explicit error handling for not found and forbidden scenarios. This would make the error responses consistent with other methods in the controller and improve the API's reliability.

  2. The method currently returns the OCR result directly. Consider adding some additional processing or validation of the OCR result before returning it to ensure data consistency and handle potential errors from the OCR service.

Here's a suggested refactor to address these points:

@common.Get(':id/documents/:documentId/run-ocr')
@swagger.ApiOkResponse({ type: WorkflowDefinitionModel })
@swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
@swagger.ApiForbiddenResponse({ type: errors.ForbiddenException })
@UseGuards(WorkflowAssigneeGuard)
async runDocumentOcr(
  @common.Param() params: DocumentUpdateParamsInput,
  @CurrentProject() currentProjectId: TProjectId,
) {
  try {
    const ocrResult = await this.service.runOCROnDocument({
      workflowRuntimeId: params?.id,
      documentId: params?.documentId,
      projectId: currentProjectId,
    });

    // Add any necessary validation or processing of ocrResult here

    return ocrResult;
  } catch (error) {
    if (error instanceof errors.NotFoundException) {
      throw new errors.NotFoundException(`No resource was found for ${JSON.stringify(params)}`);
    }
    if (error instanceof errors.ForbiddenException) {
      throw new errors.ForbiddenException(`Access denied for ${JSON.stringify(params)}`);
    }
    throw error;
  }
}

This refactored version includes error handling for not found and forbidden scenarios, and provides a place to add any necessary validation or processing of the OCR result before returning it.

services/workflows-service/src/common/utils/unified-api-client/unified-api-client.ts (2)

90-95: Simplify runOcr method by removing unnecessary await

The use of return await in an async function is redundant when no additional processing is needed after the await. Removing the await can improve performance slightly and make the code cleaner.

Apply this diff to simplify the method:

 async runOcr({ images, schema }: { images: TOcrImages; schema: TSchema }) {
-    return await this.axiosInstance.post('/v1/smart-ocr', {
+    return this.axiosInstance.post('/v1/smart-ocr', {
       images,
       schema,
     });
 }

97-118: Simplify runDocumentOcr method by removing unnecessary await

Similarly to runOcr, the runDocumentOcr method uses return await unnecessarily. Removing the await makes the code cleaner without changing functionality.

Apply this diff to simplify the method:

 async runDocumentOcr({
   images,
   supportedCountries,
   overrideSchemas,
 }: {
   images: TOcrImages;
   supportedCountries: string[];
   overrideSchemas: {
     overrideSchemas: Array<{
       countryCode: string;
       documentType: string;
       documentCategory: string;
       schema: TSchema;
     }>;
   };
 }) {
-    return await this.axiosInstance.post('/v1/document/smart-ocr', {
+    return this.axiosInstance.post('/v1/document/smart-ocr', {
       images,
       supportedCountries,
       overrideSchemas,
     });
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2ed1587 and 53f7d3d.

📒 Files selected for processing (10)
  • apps/backoffice-v2/src/domains/workflows/fetchers.ts (1 hunks)
  • apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (7 hunks)
  • apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (3 hunks)
  • services/workflows-service/prisma/data-migrations (1 hunks)
  • services/workflows-service/src/common/utils/unified-api-client/unified-api-client.ts (3 hunks)
  • services/workflows-service/src/customer/types.ts (1 hunks)
  • services/workflows-service/src/workflow/cron/ongoing-monitoring.cron.intg.test.ts (8 hunks)
  • services/workflows-service/src/workflow/cron/ongoing-monitoring.cron.ts (0 hunks)
  • services/workflows-service/src/workflow/workflow.controller.internal.ts (1 hunks)
  • services/workflows-service/src/workflow/workflow.service.ts (4 hunks)
💤 Files with no reviewable changes (1)
  • services/workflows-service/src/workflow/cron/ongoing-monitoring.cron.ts
✅ Files skipped from review due to trivial changes (1)
  • services/workflows-service/prisma/data-migrations
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/workflows-service/src/workflow/workflow.service.ts
🔇 Additional comments (19)
services/workflows-service/src/customer/types.ts (1)

16-22: Approved: Enhanced flexibility in TCustomerFeatures type

The changes to the TCustomerFeatures type improve its flexibility by allowing either a detailed object structure or a simple boolean value. This aligns well with the PR objectives and can potentially simplify the representation of OCR-related features.

However, please consider the following recommendations:

  1. Verify that all usages of TCustomerFeatures in the codebase are updated to handle both the object and boolean cases.
  2. Update the documentation to reflect this new type structure and provide guidelines on when to use the boolean option versus the detailed object.
  3. Consider reviewing the CUSTOMER_FEATURES constant to ensure it's compatible with this new type definition.

To verify the impact of this change, please run the following script:

This script will help identify areas of the codebase that might need updates due to the type change.

apps/backoffice-v2/src/domains/workflows/fetchers.ts (1)

301-318: Summary of changes and suggestions

The addition of the fetchWorkflowDocumentOCRResult function is well-implemented and consistent with the existing codebase. It properly integrates with the current architecture and follows established patterns.

To further improve the code:

  1. Enhance type safety by defining a specific Zod schema for the OCR result.
  2. Add JSDoc comments to provide better documentation for the new function.

These suggestions will contribute to maintaining a robust and well-documented codebase.

services/workflows-service/src/workflow/cron/ongoing-monitoring.cron.intg.test.ts (8)

9-9: LGTM: Import statement updated correctly.

The import statement has been updated to use FEATURE_LIST_WITH_OPTIONS instead of FEATURE_LIST, which aligns with the changes in the feature representation mentioned in the summary.


140-141: LGTM: Feature structure updated with improved configuration.

The feature structure for customer1 has been updated to use FEATURE_LIST_WITH_OPTIONS.ONGOING_MERCHANT_REPORT_T1. This new structure provides a more detailed configuration, including name, enabled status, and specific options like definitionVariation, intervalInDays, active, checkTypes, and proxyViaCountry. This change enhances the clarity and specificity of the feature definitions used in the tests.


160-161: LGTM: Feature structure consistently updated for customer2.

The feature structure for customer2 has been updated to use FEATURE_LIST_WITH_OPTIONS.ONGOING_MERCHANT_REPORT_T2. This change is consistent with the updates made for customer1, maintaining a uniform structure across different customers while allowing for different feature types (T2 in this case).


180-181: LGTM: Feature structure updated with disabled state for customer3.

The feature structure for customer3 has been updated to use FEATURE_LIST_WITH_OPTIONS.ONGOING_MERCHANT_REPORT_T2 with the enabled flag set to false. This variation in the test data is valuable for testing different scenarios, particularly how the system handles disabled features.


200-201: LGTM: Feature structure updated with enabled but inactive state for customer4.

The feature structure for customer4 has been updated to use FEATURE_LIST_WITH_OPTIONS.ONGOING_MERCHANT_REPORT_T2 with the enabled flag set to true, but the active option set to false. This configuration adds another valuable variation to the test data, allowing for testing of scenarios where a feature is enabled at the customer level but not actively running.


224-225: LGTM: Feature structure updated for businesses with disabled state for business1.

The feature structure for business1 has been updated to use FEATURE_LIST_WITH_OPTIONS.ONGOING_MERCHANT_REPORT_T1 with the enabled flag set to false. This change maintains consistency with the customer feature updates and provides a valuable test case for how the system handles disabled features at the business level.


247-248: LGTM: Feature structure updated for businesses with enabled state for business3.

The feature structure for business3 has been updated to use FEATURE_LIST_WITH_OPTIONS.ONGOING_MERCHANT_REPORT_T1 with the enabled flag set to true. This change provides a good contrast to business1 and ensures that the test data covers both enabled and disabled scenarios at the business level.


Line range hint 1-286: Overall LGTM: Comprehensive update to feature structure enhances test scenarios.

The changes in this file consistently update the feature structure for both customers and businesses, replacing FEATURE_LIST with FEATURE_LIST_WITH_OPTIONS. This new structure provides more detailed configuration options, including name, enabled status, and various feature-specific options.

The updates significantly improve the test data by introducing a range of scenarios:

  1. Enabled and active features
  2. Enabled but inactive features
  3. Disabled features
  4. Different feature types (T1 and T2)

These variations will allow for more comprehensive testing of the OngoingMonitoringCron service, ensuring it can handle different feature configurations correctly.

The changes align well with the AI-generated summary and maintain consistency throughout the file. This update enhances the overall quality and coverage of the integration tests.

apps/backoffice-v2/src/pages/Entity/components/Case/Case.Documents.Toolbar.tsx (1)

41-45: Rendering conditions differ from other toolbar buttons

As previously noted, the ImageOCR component is rendered without checking !isLoading and image?.id, unlike other buttons in the toolbar. For consistency and to prevent potential issues, consider adding similar conditions to the ImageOCR rendering logic.

services/workflows-service/src/common/utils/unified-api-client/unified-api-client.ts (2)

5-5: Importing TSchema is appropriate

The import statement correctly brings in the TSchema type from @sinclair/typebox, which is used for defining schemas in the OCR methods.


18-28: Well-defined TOcrImages type

The TOcrImages type accurately represents the possible formats for OCR images, allowing for both remote images with URIs and base64-encoded images. This provides flexibility in how images are supplied to the OCR methods.

apps/backoffice-v2/src/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks.tsx (6)

4-4: Import Statement Verified

The import statement correctly includes the necessary modules from @ballerine/common.


32-32: OCR Hook Imported Successfully

The useDocumentOcr hook is correctly imported for integrating OCR functionality.


83-90: Initialization of OCR Mutation Hook

The OCR mutation hook is correctly initialized with the required workflowId, allowing OCR functionality to be utilized within the component.


370-388: Properly Merging OCR Results Without Mutating State

The code correctly merges OCR parsed data into the document entries by creating new objects, thereby avoiding direct mutation of the formattedValue. This adheres to React's best practices regarding state immutability.


467-467: Disabling Save During OCR Processing

The isSaveDisabled property is appropriately set to isLoadingOCRDocument, ensuring that the save action is disabled while OCR processing is in progress, which prevents any conflicting state updates.


482-484: Integrating OCR Trigger in Documents Cell

The onOcrPressed handler correctly triggers the OCR mutation for the specified document ID, and the loading state is properly managed using isLoadingOCRDocument. This integration enables users to initiate OCR processing seamlessly.

Comment on lines +17 to +19
onOcrPressed?: () => void;
isOCREnabled: boolean;
isLoadingOCR: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider making onOcrPressed a required prop

The onOcrPressed prop is currently optional (?:), but it's being passed directly to the ImageOCR component without a default value or null check. If onOcrPressed is essential for the ImageOCR functionality, consider making it a required prop to prevent potential undefined errors.

Comment on lines +41 to +45
<ImageOCR
isOcrDisabled={!isOCREnabled}
onOcrPressed={onOcrPressed}
isLoadingOCR={isLoadingOCR}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Rename isOcrDisabled to isOCREnabled for clarity

The prop isOcrDisabled receives the negation of isOCREnabled. Renaming isOcrDisabled to isOCREnabled in the ImageOCR component can improve readability by avoiding double negatives and aligning naming conventions.

Apply this diff to update the prop name in the ImageOCR component:

-const ImageOCR = ({ isOcrDisabled, onOcrPressed, isLoadingOCR }) => { ... }
+const ImageOCR = ({ isOCREnabled, onOcrPressed, isLoadingOCR }) => { ... }

...

-<button disabled={isOcrDisabled} ... >
+<button disabled={!isOCREnabled} ... >

Then update the usage in Case.Documents.Toolbar.tsx:

-<ImageOCR
-  isOcrDisabled={!isOCREnabled}
+<ImageOCR
+  isOCREnabled={isOCREnabled}
   onOcrPressed={onOcrPressed}
   isLoadingOCR={isLoadingOCR}
/>

Committable suggestion was skipped due to low confidence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants