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

Use strict typing in useSheetValue and fix bug where query is not being updated when changed #3864

Merged
merged 5 commits into from
Nov 22, 2024

Conversation

joel-jeremy
Copy link
Contributor

TS strict typing for useSheetValue and fix an issue where the sheet value uses the old query object whenever the query changes due to the query not being part of the useLayoutEffect dependencies.

@actual-github-bot actual-github-bot bot changed the title Use strict typing in useSheetValue and fix bug where query is not being updated when changed [WIP] Use strict typing in useSheetValue and fix bug where query is not being updated when changed Nov 20, 2024
Copy link

netlify bot commented Nov 20, 2024

Deploy Preview for actualbudget ready!

Name Link
🔨 Latest commit cb9f778
🔍 Latest deploy log https://app.netlify.com/sites/actualbudget/deploys/673fc110fd7b830008295634
😎 Deploy Preview https://deploy-preview-3864.demo.actualbudget.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@joel-jeremy joel-jeremy changed the title [WIP] Use strict typing in useSheetValue and fix bug where query is not being updated when changed Use strict typing in useSheetValue and fix bug where query is not being updated when changed Nov 20, 2024
Copy link
Contributor

github-actions bot commented Nov 20, 2024

Bundle Stats — desktop-client

Hey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle.

As this PR is updated, I'll keep you updated on how the bundle size is impacted.

Total

Files count Total bundle size % Changed
10 5.46 MB → 5.46 MB (-5 B) -0.00%
Changeset
File Δ Size
src/components/budget/envelope/BalanceMenu.tsx 📈 +5 B (+0.44%) 1.11 kB → 1.11 kB
src/components/budget/envelope/budgetsummary/ToBudgetMenu.tsx 📈 +5 B (+0.36%) 1.36 kB → 1.37 kB
src/components/budget/envelope/BalanceMovementMenu.tsx 📈 +5 B (+0.31%) 1.57 kB → 1.58 kB
src/components/accounts/Reconcile.tsx 📈 +5 B (+0.09%) 5.19 kB → 5.2 kB
src/components/autocomplete/CategoryAutocomplete.tsx 📈 +2 B (+0.02%) 10.18 kB → 10.18 kB
src/components/spreadsheet/useSheetValue.ts 📉 -27 B (-2.32%) 1.14 kB → 1.11 kB
View detailed bundle breakdown

Added

No assets were added

Removed

No assets were removed

Bigger

Asset File Size % Changed
static/js/wide.js 241.19 kB → 241.19 kB (+5 B) +0.00%

Smaller

Asset File Size % Changed
static/js/index.js 3.44 MB → 3.44 MB (-10 B) -0.00%

Unchanged

Asset File Size % Changed
static/js/workbox-window.prod.es5.js 5.69 kB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 13.5 kB 0%
static/js/BackgroundImage.js 122.29 kB 0%
static/js/resize-observer.js 18.37 kB 0%
static/js/AppliedFilters.js 21.32 kB 0%
static/js/useAccountPreviewTransactions.js 1.68 kB 0%
static/js/narrow.js 82.72 kB 0%
static/js/ReportRouter.js 1.52 MB 0%

Copy link
Contributor

github-actions bot commented Nov 20, 2024

Bundle Stats — loot-core

Hey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle.

As this PR is updated, I'll keep you updated on how the bundle size is impacted.

Total

Files count Total bundle size % Changed
1 1.32 MB 0%

Changeset

No files were changed

View detailed bundle breakdown

Added

No assets were added

Removed

No assets were removed

Bigger

No assets were bigger

Smaller

No assets were smaller

Unchanged

Asset File Size % Changed
kcab.worker.js 1.32 MB 0%

Copy link
Contributor

coderabbitai bot commented Nov 20, 2024

Walkthrough

The pull request introduces several modifications across multiple components in the desktop-client package. Key changes include the implementation of nullish coalescing operators (??) in various components to ensure that critical variables, such as cleared, balance, catBalance, and forNextMonth, default to 0 when their values are null or undefined. This adjustment enhances error handling and ensures that calculations relying on these variables are robust against undefined values. Additionally, the CategoryAutocomplete component has seen updates to its rendering logic, including the introduction of default render functions for better modularity. The useSheetValue function has also been updated with a new type definition, improving type safety and clarity in handling sheet values. Overall, the changes focus on enhancing the reliability and maintainability of the components without altering their existing functionalities.

Suggested labels

sparkles: Merged

Suggested reviewers

  • youngcw
  • carkom

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint (1.23.1)

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/desktop-client/src/components/accounts/Reconcile.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-eslint-plugin".

(The package "eslint-plugin-eslint-plugin" was not found when loaded as a Node module from the directory "/packages/eslint-plugin-actual".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-eslint-plugin@latest --save-dev

The plugin "eslint-plugin-eslint-plugin" was referenced from the config file in "packages/eslint-plugin-actual/.eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 63ea2fc and cb9f778.

⛔ Files ignored due to path filters (5)
  • packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-5-chromium-linux.png is excluded by !**/*.png
  • upcoming-release-notes/3864.md is excluded by !**/*.md
📒 Files selected for processing (6)
  • packages/desktop-client/src/components/accounts/Reconcile.tsx (1 hunks)
  • packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx (2 hunks)
  • packages/desktop-client/src/components/budget/envelope/BalanceMenu.tsx (1 hunks)
  • packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx (1 hunks)
  • packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetMenu.tsx (1 hunks)
  • packages/desktop-client/src/components/spreadsheet/useSheetValue.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/desktop-client/src/components/accounts/Reconcile.tsx
  • packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx
  • packages/desktop-client/src/components/budget/envelope/BalanceMenu.tsx
  • packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx
  • packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetMenu.tsx
  • packages/desktop-client/src/components/spreadsheet/useSheetValue.ts

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

🧹 Outside diff range and nitpick comments (4)
packages/desktop-client/src/components/spreadsheet/useSheetValue.ts (1)

Line range hint 29-44: Consider extracting initial state for improved readability.

While the implementation is correct, the initial state object could be extracted to a separate constant for better readability.

Consider this refactor:

-  const [result, setResult] = useState<SheetValueResult<SheetName, FieldName>>({
-    name: fullSheetName,
-    value: bindingObj.value === undefined ? null : bindingObj.value,
-    query: bindingObj.query,
-  });
+  const initialState: SheetValueResult<SheetName, FieldName> = {
+    name: fullSheetName,
+    value: bindingObj.value === undefined ? null : bindingObj.value,
+    query: bindingObj.query,
+  };
+  const [result, setResult] = useState<SheetValueResult<SheetName, FieldName>>(initialState);
packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetMenu.tsx (1)

28-28: LGTM! Consider adding explicit return type for useEnvelopeSheetValue

The nullish coalescing operator ensures forNextMonth is always a number, preventing potential issues with undefined values. This is a good defensive programming practice.

Consider adding an explicit return type for useEnvelopeSheetValue to make the nullability more apparent at the call site:

// In EnvelopeBudgetComponents.ts
export function useEnvelopeSheetValue(query: Query): number | null {
  // ... implementation
}
packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx (1)

23-24: LGTM! Consider adding explicit type annotation for improved type safety.

The nullish coalescing operator ensures catBalance always has a valid numeric value, preventing potential issues with undefined values in the TransferMenu component.

Consider adding an explicit type annotation for additional type safety:

-  const catBalance =
-    useEnvelopeSheetValue(envelopeBudget.catBalance(categoryId)) ?? 0;
+  const catBalance: number =
+    useEnvelopeSheetValue(envelopeBudget.catBalance(categoryId)) ?? 0;
packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx (1)

390-393: Great improvements in type safety and null handling!

The changes effectively address two aspects:

  1. Added proper type parameters to useSheetValue enhances type safety
  2. The nullish coalescing operator ensures a safe default of 0, preventing potential issues with undefined values in calculations

Consider extracting the sheet value resolution into a custom hook for better reusability:

function useCategoryBalance(categoryId: string, budgetType: string) {
  const balanceBinding = budgetType === 'rollover'
    ? envelopeBudget.catBalance(categoryId)
    : trackingBudget.catBalance(categoryId);
    
  return useSheetValue<'envelope-budget' | 'tracking-budget', typeof balanceBinding>(
    balanceBinding,
  ) ?? 0;
}

This would simplify the component and make the balance calculation logic reusable across other components.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f523d25 and a6accae.

⛔ Files ignored due to path filters (1)
  • upcoming-release-notes/3864.md is excluded by !**/*.md
📒 Files selected for processing (6)
  • packages/desktop-client/src/components/accounts/Reconcile.tsx (1 hunks)
  • packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx (1 hunks)
  • packages/desktop-client/src/components/budget/envelope/BalanceMenu.tsx (1 hunks)
  • packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx (1 hunks)
  • packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetMenu.tsx (1 hunks)
  • packages/desktop-client/src/components/spreadsheet/useSheetValue.ts (3 hunks)
🔇 Additional comments (9)
packages/desktop-client/src/components/budget/envelope/BalanceMenu.tsx (3)

Line range hint 8-18: LGTM! Well-structured TypeScript type definitions.

The component's props are properly typed with clear interfaces and good use of TypeScript features like Omit for prop manipulation.


Line range hint 35-83: LGTM! Well-implemented menu logic.

The menu implementation shows good practices:

  • Proper conditional rendering based on balance state
  • Good error handling for unknown menu options
  • Clean callback handling with optional chaining
  • Well-structured translations

32-33: Verify useEnvelopeSheetValue hook implementation.

While the nullish coalescing operator addition is good for handling undefined values, we should verify that useEnvelopeSheetValue properly handles query updates as mentioned in the PR objectives.

Let's check the hook implementation:

✅ Verification successful

Let me search for the implementation of useEnvelopeSheetValue since it wasn't found in the previous results.


Let me search for the implementation of useSheetValue since we found that useEnvelopeSheetValue is just a wrapper around it.


Let me check the spreadsheet implementation to understand how cell updates are handled.


Based on the code analysis, I can now provide a final response about the useEnvelopeSheetValue hook and its handling of query updates.

The hook implementation properly handles query updates

The useEnvelopeSheetValue hook is a type-safe wrapper around useSheetValue, which is backed by a robust spreadsheet implementation that:

  1. Uses a proper observer pattern through observeCell to track cell dependencies
  2. Maintains an LRU cache for performance optimization
  3. Listens to 'cells-changed' events and notifies all observers when updates occur
  4. Properly cleans up observers when components unmount

The nullish coalescing operator addition is a good defensive programming practice, but it wasn't related to any query update issues. The underlying spreadsheet system correctly propagates updates to all observers.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for useEnvelopeSheetValue implementation to verify dependency handling
ast-grep --pattern 'function useEnvelopeSheetValue($_) {
  $$$
}'

# Also check for any useEffect/useLayoutEffect usage within the same file
rg -A 5 'use(Layout)?Effect.*\(' --type ts

Length of output: 60294


Script:

#!/bin/bash
# Search for useEnvelopeSheetValue implementation
rg -A 10 'useEnvelopeSheetValue' --type ts

# Also search for any related sheet value hooks
ast-grep --pattern 'function useSheetValue($_) {
  $$$
}'

Length of output: 23484


Script:

#!/bin/bash
# Search for useSheetValue implementation
rg -A 15 'export function useSheetValue' --type ts

# Also look for the spreadsheet context implementation
rg -A 10 'SpreadsheetContext' --type ts

Length of output: 3402


Script:

#!/bin/bash
# Look for the Spreadsheet class implementation
rg -A 20 'class Spreadsheet' --type ts

# Also check for any cell update related methods
rg -A 10 'updateCell|observeCell|listen' packages/loot-core/src/client/SpreadsheetProvider.tsx

Length of output: 5204

packages/desktop-client/src/components/spreadsheet/useSheetValue.ts (3)

15-22: Well-structured type definition!

The SheetValueResult type is well-designed with proper generic constraints and nullable handling. It effectively captures the structure of sheet values while maintaining type safety.


55-69: Bug fix confirmed: Query updates now properly tracked.

The addition of bindingObj.query to the effect dependencies ensures that the component correctly responds to query changes, fixing the reported bug.


50-54: Consider cleanup for query on unmount.

While the query creation is handled, there's no explicit cleanup when the component unmounts or when the query changes.

Let's check if there's a cleanup method in the spreadsheet API:

If a cleanup method exists, consider adding:

 useLayoutEffect(() => {
   if (bindingObj.query) {
     spreadsheet.createQuery(sheetName, bindingObj.name, bindingObj.query);
   }
+  return () => {
+    if (bindingObj.query) {
+      spreadsheet.removeQuery(sheetName, bindingObj.name);
+    }
+  };
packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx (1)

23-24: Verify query update behavior in useEnvelopeSheetValue hook.

Since the PR mentions fixing a bug where "query is not being updated when changed", we should verify that useEnvelopeSheetValue(envelopeBudget.catBalance(categoryId)) properly updates when the query changes.

Let's check the implementation of useEnvelopeSheetValue:

✅ Verification successful

Let me try a different search strategy to find the implementation:


Let me search for the implementation of the hook's dependencies to understand how it handles query updates:


Based on the search results, I found the release note "3864.md" that directly addresses the query update issue: "Use strict typing in useSheetValue and fix bug where query is not being updated when the query object changed". Additionally, I can see that useEnvelopeSheetValue is a thin wrapper around useSheetValue, which has been fixed to properly handle query updates.

No issues with query updates in useEnvelopeSheetValue

The PR has already fixed the query update behavior in useSheetValue, which is used by useEnvelopeSheetValue. The fix ensures that sheet values are properly updated when the query object changes. Since useEnvelopeSheetValue is just a type-safe wrapper around the fixed useSheetValue, it will correctly handle query updates.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for useEnvelopeSheetValue implementation and its dependencies
echo "Searching for useEnvelopeSheetValue implementation..."
rg -t typescript -t javascript "export.*function useEnvelopeSheetValue" -A 10

echo "Checking for related test files..."
fd -e test.tsx -e test.ts -e spec.tsx -e spec.ts envelope

Length of output: 370


Script:

#!/bin/bash
# Search for useEnvelopeSheetValue with ripgrep without file type restriction
echo "Searching for useEnvelopeSheetValue..."
rg "useEnvelopeSheetValue" -A 10

# Search for files containing "envelope" in their name
echo -e "\nSearching for envelope-related files..."
fd envelope

Length of output: 31003


Script:

#!/bin/bash
# Search for useSheetValue implementation since useEnvelopeSheetValue uses it
echo "Searching for useSheetValue implementation..."
rg "useSheetValue" -A 10

# Search for sheet value update related code
echo -e "\nSearching for sheet value update mechanisms..."
ast-grep --pattern 'function $_(sheet: $_) {
  $$$
  query $$$
  $$$
}'

Length of output: 36448

packages/desktop-client/src/components/accounts/Reconcile.tsx (2)

39-41: LGTM: Safe handling of cleared balance

The nullish coalescing operator ensures that cleared is always a number, making the targetDiff calculation and subsequent conditional rendering more robust.


32-38: Verify query dependency handling in useSheetValue hook

The type safety improvements and default value handling look good. However, given the PR's objective to fix a bug where "query is not being updated when changed", we should verify that the useSheetValue hook properly handles query updates.

Let's verify the hook's implementation:

✅ Verification successful

Query updates are properly handled in useSheetValue hook

Looking at the implementation, the hook correctly handles query updates through the useLayoutEffect dependency array which includes bindingObj.query. When the query changes, the effect will re-run, destroying the old query binding and creating a new one with the updated query. This ensures that changes to the query object will properly trigger updates.

The implementation shows:

  1. Query is included in the effect dependencies: [sheetName, bindingObj.name, bindingObj.query]
  2. Old query binding is cleaned up through the effect cleanup function
  3. New query is created with spreadsheet.createQuery when the effect re-runs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for useSheetValue implementation to verify query dependency handling
ast-grep --pattern 'function useSheetValue<$_>($_) {
  $$$
}'

Length of output: 63


Script:

#!/bin/bash
# Let's try a different pattern to find useSheetValue implementation
ast-grep --pattern 'useSheetValue = $_'

# Also search with ripgrep for any occurrence of useSheetValue
rg "useSheetValue" -A 10

Length of output: 39193


Script:

#!/bin/bash
# Let's look for the useSheetValue implementation in the spreadsheet directory
rg -l "useSheetValue" packages/desktop-client/src/components/spreadsheet/

# And then get the content of the useSheetValue implementation
cat packages/desktop-client/src/components/spreadsheet/useSheetValue.ts

Length of output: 2251

@joel-jeremy
Copy link
Contributor Author

/update-vrt

1 similar comment
@joel-jeremy
Copy link
Contributor Author

/update-vrt

@matt-fidd
Copy link
Contributor

@joel-jeremy looks like VRT is failing on this one again

@joel-jeremy joel-jeremy force-pushed the useSheetValue-fix-and-ts branch from eaaff53 to cb9f778 Compare November 21, 2024 23:23
Copy link
Contributor

@matt-fidd matt-fidd left a comment

Choose a reason for hiding this comment

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

LGTM

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

Successfully merging this pull request may close these issues.

2 participants