Skip to content

Features added to export-workbook plugin#762

Merged
carlbrugger merged 9 commits intoFlatFilers:mainfrom
aprimetechnology:workbook-export
Mar 13, 2025
Merged

Features added to export-workbook plugin#762
carlbrugger merged 9 commits intoFlatFilers:mainfrom
aprimetechnology:workbook-export

Conversation

@amitlissack
Copy link
Contributor

Please explain how to summarize this PR for the Changelog:

New options were added to the export-workbook plugin options:

  • columnNameTransformer is a callback function enabling users to transform column names before exporting workbook. The callback takes a column name and slug name and returns a string.
  • sheetOptions is map of slug name to SheetOptions object with these props:
    • origin the starting point of the sheet (can either be a row number or full column, row coordinate)
    • skipColumnHeaders optionally not include column headers. I know its not relevant for our use case, but could be worth while for someone.

Tell code reviewer how and what to test:

This was tested in the plugin sandbox.

A second sheet was added:

export const companies: Flatfile.SheetConfig = {
  name: 'Companies',
  slug: 'companies',
  fields: [
    {
      key: 'name',
      type: 'string',
      label: 'Name',
      constraints: [
        { type: 'required' },
        { type: 'unique', config: { caseSensitive: false } },
      ],
    },
    {
      key: 'location',
      type: 'string',
      label: 'Location',
    },
  ],
}

export-workbook was installed like so:

exportWorkbookPlugin({
        debug: true,
        sheetOptions: {
          companies: {
            origin: {row: 10, column: 2},
          },
        },
        columnNameTransformer: (name, slug) => slug === 'contacts' ? name.toUpperCase() : name,
      })
    )

Here are the results of an export:

The companies export starts the data at row 10 and column 2, as specified by origin
Screenshot 2025-02-27 at 8 16 07 AM

The contacts export transforms the column names to upper case.
Screenshot 2025-02-27 at 8 16 01 AM

@amitlissack amitlissack marked this pull request as ready for review February 27, 2025 13:40
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2025

Walkthrough

This pull request introduces a major version update for the @flatfile/plugin-export-workbook, adding new options for adjusting the origin and column headers. It restructures import statements by moving the PluginOptions type definition to a new file and refactors the exportRecords function to include an additional progress callback parameter (tick). A new utility function, createXLSXSheetOptions, is added, accompanied by a test suite to validate its behavior. No changes have been made to the public API.

Changes

File(s) Changes summary
.changeset/fluffy-pillows-call.md New file documenting a major version update for the plugin with options to adjust origin and column headers.
plugins/export-workbook/src/index.ts Modified import statements: PluginOptions is now imported from ./options instead of ./plugin; exportRecords remains imported from ./plugin.
plugins/export-workbook/src/options.ts Formatting changes to interfaces and types: SheetAddress, ExportSheetOptions, ColumnNameTransformerCallback, and PluginOptions; semicolons removed and ColumnNameTransformerCallback reformatted for readability.
plugins/export-workbook/src/plugin.ts Removed PluginOptions interface; updated exportRecords function signature to include a new tick callback parameter; introduced PACKAGE_NAME for consistent logging; enhanced handling of column name transformation and empty cell processing.
plugins/export-workbook/src/utils.ts
plugins/export-workbook/src/utils.spec.ts
Added a new function createXLSXSheetOptions to convert ExportSheetOptions into JSON2SheetOpts, along with a test suite validating its output under various scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant Client as FlatfileEvent Caller
    participant Plugin as exportRecords Function
    participant Utils as createXLSXSheetOptions
    participant Logger as Logging System

    Client->>Plugin: Call exportRecords(event, options, tick)
    Plugin->>Utils: Convert ExportSheetOptions to JSON2SheetOpts
    Utils-->>Plugin: Return JSON2SheetOpts configuration
    Plugin->>Logger: Log operation using PACKAGE_NAME
    Plugin->>Client: Report progress via tick callback
Loading

Possibly related PRs

Suggested reviewers

  • bangarang

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between ba2d2c3 and 09d27f9.

📒 Files selected for processing (1)
  • plugins/export-workbook/src/utils.spec.ts (1 hunks)
🔇 Additional comments (1)
plugins/export-workbook/src/utils.spec.ts (1)

1-23: Well-structured test suite with comprehensive test cases.

This test suite provides good coverage for the createXLSXSheetOptions utility function, testing various input scenarios including null, undefined, empty objects, and objects with different property combinations. The test cases properly verify the transformation of ExportSheetOptions to JSON2SheetOpts format, ensuring the function behaves correctly for all expected use cases.


🪧 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: 0

🧹 Nitpick comments (2)
plugins/export-workbook/src/utils.ts (1)

62-87: Well-implemented utility function with proper JSDoc

The implementation correctly transforms ExportSheetOptions to JSON2SheetOpts format with clean handling of different input types for the origin property and proper mapping of skipColumnHeaders to skipHeader.

Consider adding additional type guards for the origin property to handle unexpected object structures:

if (sheetOptions?.origin) {
  if (typeof sheetOptions.origin === 'number') {
    options.origin = sheetOptions.origin
-  } else {
+  } else if ('column' in sheetOptions.origin && 'row' in sheetOptions.origin) {
    options.origin = {
      c: sheetOptions.origin.column,
      r: sheetOptions.origin.row,
    }
+  }
}
plugins/export-workbook/src/plugin.ts (1)

102-102: Type assertion to Comments
Though this approach works, consider avoiding type assertions for clarity. A typed definition can prevent accidental type mismatches.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eeafb79 and ac432d0.

📒 Files selected for processing (6)
  • .changeset/fluffy-pillows-call.md (1 hunks)
  • plugins/export-workbook/src/index.ts (1 hunks)
  • plugins/export-workbook/src/options.ts (1 hunks)
  • plugins/export-workbook/src/plugin.ts (11 hunks)
  • plugins/export-workbook/src/utils.spec.ts (1 hunks)
  • plugins/export-workbook/src/utils.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .changeset/fluffy-pillows-call.md
🔇 Additional comments (24)
plugins/export-workbook/src/utils.spec.ts (1)

1-23: Well-structured test suite for the new utility function

This test suite efficiently tests the createXLSXSheetOptions function using parameterized testing with it.each. The test cases cover important scenarios including null/undefined inputs and various combinations of options. The approach ensures that the function transforms ExportSheetOptions correctly into JSON2SheetOpts format.

plugins/export-workbook/src/index.ts (1)

5-6: Good restructuring of imports

Moving the PluginOptions interface to a dedicated options file improves code organization, especially as the interface now includes additional properties for new features.

plugins/export-workbook/src/options.ts (3)

3-23: Well-defined interfaces for sheet configuration

The SheetAddress and ExportSheetOptions interfaces are clearly defined with comprehensive JSDoc comments. They provide a clean structure for specifying sheet origin coordinates and column header options.


25-25: Good function type definition for column name transformation

The ColumnNameTransformerCallback type provides a clear contract for implementing column name transformations, with appropriate parameters for the column name and sheet slug.


27-50: Comprehensive plugin options interface with complete documentation

The PluginOptions interface includes all necessary properties with thorough JSDoc comments. The new properties sheetOptions and columnNameTransformer align well with the PR objectives, providing flexible customization for exports.

plugins/export-workbook/src/plugin.ts (19)

11-15: Imports for utility functions look good.
No issues detected.


16-16: Importing Comments
This import aligns with the usage for adding comments to .xlsx cells.


17-17: Importing PluginOptions
Shifting the interface to a dedicated file is a neat approach for organization.


21-21: Use of LOG_NAME
Defining a constant for log naming improves consistency.


28-28: Updated JSDoc to reference tick
This accurately reflects the function’s parameters.


52-52: Logging sheets found
Helpful debug log for capturing the sheets in the workbook.


60-60: Logging skipped sheets
Clear communication in debug logs.


65-69: Potential column name collisions in columnNameTransformer
This is a useful feature; however, consider verifying that two or more columns do not accidentally transform to the same name. This could lead to overwriting.

Would you like a script to scan for potential collisions, or is this guaranteed never to occur in your implementation?


86-86: Reducing record columns
This appears correct for eliminating excluded fields and constructing the final row object.


95-95: Initialize comments array
Representing cell comments as an empty array is consistent.


112-113: Applying column name transformer to cell values
Renaming each column before populating the worksheet is properly handled here.


152-154: Creating XLSX sheet with custom options
Integrating createXLSXSheetOptions improves maintainability by centralizing sheet configuration logic.


185-185: Logging empty data scenario
Clear error message if no data is present.


198-198: Logging file generation
Clear statement confirming the file is saved.


201-201: Logging failure to write the file
Adequate error handling case.


225-225: Refined log message parameters
Ensures consistent usage of LOG_NAME.


230-230: Logging file upload failure
Another important failure mode captured.


235-235: Logging completion
Provides helpful feedback that the process has finished.


266-266: Error logging
Capturing full error details can be valuable for debugging, but ensure no sensitive data is included in the logged message.

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

🧹 Nitpick comments (2)
plugins/export-workbook/src/utils.ts (1)

62-90: Well-implemented utility function with clear responsibility.

This utility function cleanly converts between the plugin's option format and the XLSX library's format, with proper handling of different origin types.

One minor suggestion for improved robustness:

  if (sheetOptions?.origin) {
    if (typeof sheetOptions.origin === 'number') {
      options.origin = sheetOptions.origin
-    } else if (
-      'column' in sheetOptions.origin &&
-      'row' in sheetOptions.origin
-    ) {
+    } else if (
+      typeof sheetOptions.origin === 'object' && 
+      'column' in sheetOptions.origin &&
+      'row' in sheetOptions.origin
+    ) {
      options.origin = {
        c: sheetOptions.origin.column,
        r: sheetOptions.origin.row,
      }
    }
  }

This additional check would ensure the origin is actually an object before checking for properties.

plugins/export-workbook/src/plugin.ts (1)

137-146: Optimization opportunity for empty cell generation.

The current implementation creates empty cells for all fields when there are no results. Consider optimizing this by creating the empty object only once.

  results = [
    [
-      Object.fromEntries(
-        sheet.config.fields.map((field) => [
-          columnNameTransformer(field.key),
-          emptyCell,
-        ])
-      ),
+      sheet.config.fields.reduce((acc, field) => {
+        acc[columnNameTransformer(field.key)] = emptyCell;
+        return acc;
+      }, {})
    ],
  ]
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac432d0 and 2813247.

📒 Files selected for processing (2)
  • plugins/export-workbook/src/plugin.ts (10 hunks)
  • plugins/export-workbook/src/utils.ts (2 hunks)
🔇 Additional comments (6)
plugins/export-workbook/src/utils.ts (1)

1-2: Clean import organization.

The imports are well organized, bringing in both the internal type definitions and the XLSX library types needed for the new functionality.

plugins/export-workbook/src/plugin.ts (5)

11-16: Clean import restructuring.

The imports have been well-organized, with the PluginOptions correctly moved to a separate file and utility functions properly imported.


20-20: Good practice using a constant for logging.

Using a constant for the log name ensures consistency throughout the codebase and makes maintenance easier.


64-68: Well-implemented column name transformer feature.

The implementation of the column name transformer is clean and follows functional programming principles. The optional chaining and default implementation are handled elegantly.


110-112: Correctly applied column name transformer to cell formatting.

The column name transformer is properly applied to the cell keys.


150-153:

Details

❓ Verification inconclusive

Clean integration of the new sheet options feature.

The integration of the createXLSXSheetOptions utility function is well done, properly handling the optional sheet options based on the sheet slug.

Consider adding a check for when sheet.config.slug is undefined:

  const worksheet = XLSX.utils.json_to_sheet(
    rows,
-   createXLSXSheetOptions(options.sheetOptions?.[sheet.config.slug])
+   createXLSXSheetOptions(sheet.config.slug ? options.sheetOptions?.[sheet.config.slug] : undefined)
  )

🏁 Script executed:

#!/bin/bash
# Check if there are any sheets without a slug in the codebase
rg -i "sheet\s+.*without.*slug|missing.*slug" --type ts
rg "config\s*:\s*\{\s*slug\s*:\s*undefined\s*" --type ts

Length of output: 116


Optional Slug Check for Sheet Options

The integration of the createXLSXSheetOptions utility is solid. However, please verify that there is no risk of sheet.config.slug being undefined. If there is any chance it might be, consider modifying the call to safeguard against it:

  const worksheet = XLSX.utils.json_to_sheet(
    rows,
-   createXLSXSheetOptions(options.sheetOptions?.[sheet.config.slug])
+   createXLSXSheetOptions(sheet.config.slug ? options.sheetOptions?.[sheet.config.slug] : undefined)
  )

Please manually verify that no sheets can have an undefined slug or confirm that the defensive check is unnecessary.

Copy link
Contributor

@carlbrugger carlbrugger left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! 🙌🏼

Just a few nits. Also, the please add the new options to the README.md along explanations as to what the options do. Without playing around, it is unclear that the origin pads the sheet with empty cells/rows. It might be helpful to add a usage example.

@amitlissack amitlissack requested a review from carlbrugger March 13, 2025 13:10
Copy link
Contributor

@carlbrugger carlbrugger left a comment

Choose a reason for hiding this comment

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

Almost there! Let add the import type and it will be good to go.

@amitlissack amitlissack requested a review from carlbrugger March 13, 2025 13:16
Co-authored-by: Carl Brugger <cebrugg@gmail.com>
@amitlissack
Copy link
Contributor Author

amitlissack commented Mar 13, 2025

Almost there! Let add the import type and it will be good to go.

Apologies. I asked for a re-review before making that change. Should be good.

Copy link
Contributor

@carlbrugger carlbrugger left a comment

Choose a reason for hiding this comment

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

Last nit

Co-authored-by: Carl Brugger <cebrugg@gmail.com>
@amitlissack amitlissack requested a review from carlbrugger March 13, 2025 18:09
Copy link
Contributor

@carlbrugger carlbrugger left a comment

Choose a reason for hiding this comment

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

🚀 nice work!

@amitlissack
Copy link
Contributor Author

🚀 nice work!

@carlbrugger thanks for the thoughtful review!

@amitlissack
Copy link
Contributor Author

@carlbrugger I do not have the option to merge this PR. How can it be merged?

@carlbrugger carlbrugger merged commit d6bef61 into FlatFilers:main Mar 13, 2025
37 checks passed
@carlbrugger
Copy link
Contributor

I gotcha

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.

2 participants