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

♻️ (typescript) refactor ScheduleDetails to tsx #3964

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

MatissJanis
Copy link
Member

Related: #3954

@actual-github-bot actual-github-bot bot changed the title ♻️ (typescript) refactor ScheduleDetails to tsx [WIP] ♻️ (typescript) refactor ScheduleDetails to tsx Dec 11, 2024
Copy link

netlify bot commented Dec 11, 2024

Deploy Preview for actualbudget ready!

Name Link
🔨 Latest commit 42e6d37
🔍 Latest deploy log https://app.netlify.com/sites/actualbudget/deploys/6759dc5adc4ea30008cd98aa
😎 Deploy Preview https://deploy-preview-3964.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.

Copy link
Contributor

github-actions bot commented Dec 11, 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.47 MB → 5.47 MB (+370 B) +0.01%
Changeset
File Δ Size
src/components/schedules/ScheduleDetails.tsx 🆕 +30.81 kB 0 B → 30.81 kB
src/components/schedules/ScheduleDetails.jsx 🔥 -30.45 kB (-100%) 30.45 kB → 0 B
View detailed bundle breakdown

Added

No assets were added

Removed

No assets were removed

Bigger

Asset File Size % Changed
static/js/index.js 3.45 MB → 3.45 MB (+370 B) +0.01%

Smaller

No assets were smaller

Unchanged

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

Copy link
Contributor

github-actions bot commented Dec 11, 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%

@MatissJanis MatissJanis changed the title [WIP] ♻️ (typescript) refactor ScheduleDetails to tsx ♻️ (typescript) refactor ScheduleDetails to tsx Dec 11, 2024
type Data<TResponse> = ReadonlyArray<TResponse>;
type Data<TResponse> = TResponse[];
Copy link
Member Author

Choose a reason for hiding this comment

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

Updating all the downstream interfaces to be readonly would be a real big pain.. so hopefully you folks don't mind this change.

Copy link
Contributor

coderabbitai bot commented Dec 11, 2024

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

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/schedules/ScheduleDetails.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.

Walkthrough

The pull request introduces several modifications across multiple files, primarily focusing on enhancing type safety and improving the structure of TypeScript definitions. In ScheduleDetails.tsx, new types Fields and ScheduleDetailsProps are defined, and various function signatures are updated to utilize these types, improving clarity and error handling. The updateScheduleConditions function is refined to accept a fields parameter of type Fields, and the reducer's state structure is enhanced with explicit types.

The AmountInput.tsx file sees the introduction of the BetweenAmountInputProps type, which specifies the structure of its props, thereby enhancing type safety. The useSelected.tsx file updates the children prop type in SelectedProviderProps from ReactElement to ReactNode, allowing for greater flexibility in the types of children that can be passed.

In the query-helpers.ts file, the Data<TResponse> type is changed to a mutable array type, allowing for more flexible data manipulation. The type definitions in rule.d.ts and schedule.d.ts are updated to include new properties and types, enhancing the clarity of conditions and actions associated with scheduling. Finally, the ServerHandlers interface is updated to specify the type of the conditions parameter, ensuring better type safety.

Suggested labels

sparkles: Merged

Suggested reviewers

  • MikesGlitch
  • joel-jeremy

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 generate docstrings to generate docstrings for this PR. (Experiment)
  • @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: 1

🧹 Outside diff range and nitpick comments (3)
packages/desktop-client/src/components/schedules/ScheduleDetails.tsx (1)

584-584: Address @ts-expect-error comments to enhance type safety

Multiple @ts-expect-error comments are used to suppress TypeScript errors, indicating unresolved type issues. Converting GenericInput and related components to TypeScript and providing proper typings would improve type safety and maintainability.

Also applies to: 638-638, 670-670, 683-683, 705-705, 713-713

packages/desktop-client/src/hooks/useSelected.tsx (1)

11-11: LGTM! Consider consistent typing across providers.

Good improvement changing children to ReactNode in SelectedProviderProps. This allows for more flexible children types, matching React's typical patterns.

Consider updating SelectedProviderWithItemsProps to also use ReactNode for consistency:

type SelectedProviderWithItemsProps<T extends Item> = {
  // ... other props
-  children: ReactElement;
+  children: ReactNode;
};

Also applies to: 261-261

packages/loot-core/src/types/models/rule.d.ts (1)

Line range hint 34-60: Strong type system design with good extensibility.

The type system is well-designed with:

  • Clear separation of concerns in type definitions
  • Good use of TypeScript's conditional types
  • Flexible yet type-safe handling of different operators
  • Forward-compatible structure that allows for future extensions

Consider documenting these type patterns in the project's TypeScript guidelines to ensure consistent implementation across the codebase.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 62d8358 and a39e387.

⛔ Files ignored due to path filters (1)
  • upcoming-release-notes/3964.md is excluded by !**/*.md
📒 Files selected for processing (7)
  • packages/desktop-client/src/components/schedules/ScheduleDetails.tsx (29 hunks)
  • packages/desktop-client/src/components/util/AmountInput.tsx (1 hunks)
  • packages/desktop-client/src/hooks/useSelected.tsx (2 hunks)
  • packages/loot-core/src/client/query-helpers.ts (1 hunks)
  • packages/loot-core/src/types/models/rule.d.ts (3 hunks)
  • packages/loot-core/src/types/models/schedule.d.ts (4 hunks)
  • packages/loot-core/src/types/server-handlers.d.ts (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/desktop-client/src/components/schedules/ScheduleDetails.tsx

[error] 211-213: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🔇 Additional comments (7)
packages/loot-core/src/types/models/schedule.d.ts (1)

38-39: Explicitly typing _conditions and _actions enhances clarity

Defining _conditions and _actions with specific types in ScheduleEntity improves code clarity and ensures better type checking.

packages/desktop-client/src/components/util/AmountInput.tsx (1)

158-166: Define BetweenAmountInputProps to improve type safety

Adding explicit type definitions for BetweenAmountInputProps and updating the component signature enhances type safety and readability of the code.

packages/loot-core/src/types/server-handlers.d.ts (1)

124-124: LGTM! Good type safety improvement.

Explicitly typing the conditions parameter as unknown instead of implicit any is a good practice. This enforces proper type checking before using the value, making the code more type-safe.

packages/loot-core/src/client/query-helpers.ts (1)

48-48: LGTM! Type definition now matches implementation.

The change from ReadonlyArray<TResponse> to TResponse[] aligns the type definition with how the data is actually used in the implementation, where the array is mutated internally by the class methods.

packages/loot-core/src/types/models/rule.d.ts (3)

1-1: LGTM! Clean import statement.

The import is properly structured using the type keyword for better type-only imports.


58-60: Well-structured conditional type for between operations.

The type definition properly enforces the correct structure for 'isbetween' operations, requiring both num1 and num2 values.

✅ Verification successful

Type definition for 'isbetween' operator is correctly implemented and used consistently

The verification shows that the 'isbetween' operator is well-integrated throughout the codebase:

  • The type definition matches actual usage in code:
    • transaction-rules.ts correctly uses value.num1 and value.num2 for range boundaries
    • rules.test.ts contains tests verifying the correct structure { num1: number, num2: number }
    • ScheduleDetails.tsx and EditRuleModal.jsx handle the between value structure appropriately
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing between operations to verify they match the new type structure
ast-grep --pattern 'op: "isbetween"'

# Look for any direct value assignments in between operations
rg -A 5 'isbetween.*value.*='

Length of output: 70


Script:

#!/bin/bash
# Search for 'isbetween' usage in the codebase with broader patterns
rg -i "isbetween" -A 5

# Search for rule conditions with AST pattern matching
ast-grep --pattern '{
  op: $_,
  value: $_
}'

# Look for test files that might contain between operation examples
fd -e test.ts -e test.js -X rg -l "between"

Length of output: 20627


38-38: Verify handling of the new date type union.

The date field now accepts both string and RecurConfig. While this provides more flexibility, we should ensure all consumers properly handle both cases.

✅ Verification successful

Let me analyze the search results to verify the impact of the date type change from string to string | RecurConfig.

The key findings from the search results:

  1. The date field is used in multiple places across the codebase
  2. Most usages expect a string type
  3. We need to check if there's proper type handling for the new union type

Let's search for usages of the Rule type and RecurConfig to understand the implementation:


Let me search for the actual usage of the rule.date field to verify how it's handled:


Let me try a different search pattern to find the RecurConfig definition and rule.date usage:


Based on the search results, I can now provide a final response about the date type change:

The date type change is properly handled across the codebase.

The change from string to string | RecurConfig is part of a well-structured system where:

  1. The RecurConfig type is properly defined in packages/loot-core/src/types/models/schedule.d.ts with all necessary properties for recurring schedules
  2. The implementation in ScheduleDetails.tsx correctly handles both string and RecurConfig types
  3. The RecurringSchedulePicker component provides proper UI and type-safe handling for the RecurConfig option

The change is consistent with the scheduling system's architecture and doesn't introduce any type safety issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for places where the date field is accessed to verify proper type handling
ast-grep --pattern 'field: "date"' 

# Search for direct access to date values to ensure proper type checking
rg -A 3 'date.*:.*string'

Length of output: 34071


Script:

#!/bin/bash
# Search for Rule type usage
rg -A 3 "Rule[^a-zA-Z]"

# Search for RecurConfig usage and definition
rg -A 3 "RecurConfig"

# Search for rule date field access
ast-grep --pattern 'rule.date'

Length of output: 67846


Script:

#!/bin/bash
# Search for rule.date usage and RecurConfig type definition
rg -A 5 "rule\.date"

# Search for RecurConfig type definition and usage
ast-grep --pattern "type RecurConfig"

Length of output: 62


Script:

#!/bin/bash
# Search for RecurConfig definition and usage with broader patterns
rg -A 5 "RecurConfig"

# Search for date field access in rules with broader context
rg -B 2 -A 5 "date.*:.*RecurConfig"

# Look for files that might handle rule dates
ast-grep --pattern 'date = rule.$$$'

Length of output: 12278

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

🧹 Outside diff range and nitpick comments (4)
packages/desktop-client/src/components/schedules/ScheduleDetails.tsx (4)

Line range hint 425-439: Consider extracting field mapping logic to a separate function.

The field mapping logic for conditions is currently embedded within the effect hook with a comment indicating it's a "gross hack". This should be extracted into a separate, well-documented utility function.

Consider applying this refactor:

+ const mapConditionFields = (condition: typeof conditions[0]) => {
+   switch (condition.field) {
+     case 'description':
+       return { ...condition, field: 'payee' };
+     case 'acct':
+       return { ...condition, field: 'account' };
+     default:
+       return condition;
+   }
+ };

- const conditions = updated.conditions.map(cond => {
-   if (cond.field === 'description') {
-     return { ...cond, field: 'payee' };
-   } else if (cond.field === 'acct') {
-     return { ...cond, field: 'account' };
-   }
-   return cond;
- });
+ const conditions = updated.conditions.map(mapConditionFields);

Line range hint 594-723: Remove @ts-expect-error comments and fix underlying type issues.

There are multiple @ts-expect-error comments in the code that should be addressed by properly typing the components.

These components need proper TypeScript definitions:

  1. GenericInput (Line 594)
  2. OpSelect (Line 648)
  3. BetweenAmountInput (Line 680)
  4. AmountInput (Line 693)
  5. RecurringSchedulePicker (Line 715)
  6. DateSelect (Line 723)

Consider creating proper type definitions for these components instead of suppressing the type errors.


475-481: Add loading state during schedule name validation.

The schedule name validation could benefit from a loading state to prevent multiple save attempts while checking for duplicate names.

Consider applying this enhancement:

+ const [isValidating, setIsValidating] = useState(false);

  async function onSave(close: () => void, schedule: Partial<ScheduleEntity>) {
    dispatch({ type: 'form-error', error: null });
+   setIsValidating(true);
    if (state.fields.name) {
      const { data: sameName } = await runQuery(
        q('schedules').filter({ name: state.fields.name }).select('id'),
      );
      if (sameName.length > 0 && sameName[0].id !== schedule.id) {
        dispatch({
          type: 'form-error',
          error: t('There is already a schedule with this name'),
        });
+       setIsValidating(false);
        return;
      }
    }
+   setIsValidating(false);

Then update the Save button to show loading state:

  <Button
    variant="primary"
+   isLoading={isValidating}
    onPress={() => {
      onSave(close, schedule);
    }}
  >
    {adding ? t('Add') : t('Save')}
  </Button>

543-547: Consider adding optimistic updates for transaction linking.

The transaction linking operation could benefit from optimistic updates to improve the user experience.

Consider updating the state optimistically before the API call:

  async function onLinkTransactions(ids: string[], scheduleId?: string) {
+   // Optimistically update the UI
+   const updatedTransactions = state.transactions.map(t => 
+     ids.includes(t.id) ? { ...t, schedule: scheduleId } : t
+   );
+   dispatch({ type: 'set-transactions', transactions: updatedTransactions });

    await send('transactions-batch-update', {
      updated: ids.map(id => ({
        id,
        schedule: scheduleId,
      })),
    });
    selectedInst.dispatch({ type: 'select-none' });
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a39e387 and 42e6d37.

📒 Files selected for processing (1)
  • packages/desktop-client/src/components/schedules/ScheduleDetails.tsx (26 hunks)
🔇 Additional comments (2)
packages/desktop-client/src/components/schedules/ScheduleDetails.tsx (2)

43-51: LGTM: Well-structured type definition for Fields.

The Fields type definition is comprehensive and properly typed. The union types for amount and date fields accurately represent their possible values.


211-213: Wrap switch case body in braces to prevent variable hoisting.

@@ -121,7 +121,7 @@ export interface ServerHandlers {
'payees-get-rules': (arg: { id: string }) => Promise<RuleEntity[]>;

'make-filters-from-conditions': (arg: {
conditions;
conditions: unknown;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could be a RuleConditionEntity and the return type is the type of the parameter of Query.filter function

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