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

feat(web): add extension settings panel to plugin playground #1383

Open
wants to merge 22 commits into
base: main
Choose a base branch
from

Conversation

mulengawilfred
Copy link
Contributor

@mulengawilfred mulengawilfred commented Jan 28, 2025

Overview

Adds a widget panel to plugin playground. Converts the widget schema groups found in web/src/beta/features/PluginPlayground/Plugins/presets/custom/myPlugin.ts into UI input fields to display in widget panel. This shows that the plugin developer can adjust the widget schema to display different UI components. Stores the input field data locally.

What I've done

What I haven't done

How I tested

Which point I want you to review particularly

Would need to confirm what other UI components we wish to display. Currently only text, number and boolean fields were added. The fields also store the values in local state. Will need to confirm if these values can be used after editing.

Memo

Summary by CodeRabbit

  • New Features

    • Introduced an "Extension Settings" panel within the Plugin Playground, allowing interactive management of plugin configuration.
    • Added a new extension property plugin under an "Extension" category, expanding available customization options.
    • Enhanced file type detection and YAML processing, leading to improved configuration feedback and error handling.
    • Added a new component, PropertyItem, for rendering various input fields based on schema properties.
  • Refactor

    • Streamlined type management and underlying utility logic for more robust and dynamic extension configuration.

Copy link

coderabbitai bot commented Jan 28, 2025

Walkthrough

This pull request streamlines type management and YAML parsing within the Plugin Playground module. It centralizes type imports, removes redundant local definitions and utility functions, and updates function signatures—most notably in the hook. New helper functions and components are added to improve schema field processing and extension settings management. The changes also reconfigure the import paths for utilities and extend the plugin presets with a new extension category.

Changes

File(s) Summary of Changes
web/.../Code/hook.ts Updated function signature with a new parameter and return type (HookReturnType); removed local type definitions and getYmlJson; added the generateProperty helper function.
web/.../Code/index.tsx Changed the import path for getLanguageByFileExtension from ./utils to ../utils.
web/.../Code/utils.ts Removed the old getLanguageByFileExtension; introduced new exported functions: getLanguageByFileExtension, getYmlJson, and customSchemaFieldsToObject.
web/.../hooks.tsx Added a new state variable (fieldValues) and its updater; introduced the ExtensionSettingsPanel component; updated destructuring from useCode to include fieldValues.
web/.../index.tsx Integrated the new ExtensionSettingsPanel into the PluginPlayground layout.
web/.../types.ts Added new type definitions and interfaces: ReearthYML, Widgets, CustomInfoboxBlock, CustomStoryBlock, FieldValue, CustomField, and Group.
web/.../ExtensionSettings/PropertyItem.tsx Introduced a new React component PropertyItem to render various input fields based on schema field properties.
web/.../ExtensionSettings/index.tsx Created a new React component ExtensionSettings that manages plugin settings by processing a YAML file and rendering property items for each field.
web/.../Plugins/presets/extension/extensionProperty.ts Defined a new plugin file for the extension property, setting up both YAML metadata and a UI component.
web/.../Plugins/presets/index.ts Added a new preset category for extensions to the presetPlugins array.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant ES as ExtensionSettings
    participant Utils as YAML Utility
    participant PI as PropertyItem

    U->>ES: Selects plugin/extension
    ES->>Utils: Call getYmlJson(file)
    Utils-->>ES: Return YAML parsing result
    alt Parsing Error
        ES->>U: Display error message
    else Valid YAML
        ES->>ES: Verify extensions & schema fields
        ES->>PI: Render PropertyItem for each field
        PI->>ES: onUpdate event → update fieldValues
    end
Loading

Possibly related PRs

Suggested reviewers

  • mkumbobeaty
  • ZTongci
  • mulengawilfred

Poem

I hopped through lines of code at night,
Tweaking types in the pale moonlight.
YAML fields danced in a rhythmic sway,
New hooks born to light the way.
In extension lands, settings now gleam bright —
A bunny’s joy in every feature’s flight!
🐰✨ Enjoy the roll of every byte!


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80dfe1e and 76ebf1d.

📒 Files selected for processing (1)
  • web/src/beta/features/PluginPlayground/Plugins/presets/index.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/src/beta/features/PluginPlayground/Plugins/presets/index.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: ci-server / ci-server-test
  • GitHub Check: ci-web / ci
  • GitHub Check: ci-server / ci-server-lint
  • GitHub Check: Redirect rules - reearth-web
  • GitHub Check: Header rules - reearth-web
  • GitHub Check: Pages changed - reearth-web

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. (Beta)
  • @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.

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

netlify bot commented Jan 28, 2025

Deploy Preview for reearth-web ready!

Name Link
🔨 Latest commit 76ebf1d
🔍 Latest deploy log https://app.netlify.com/sites/reearth-web/deploys/67a5dc5599d4eb000727de29
😎 Deploy Preview https://deploy-preview-1383--reearth-web.netlify.app
📱 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

@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: 5

🧹 Nitpick comments (3)
web/src/beta/features/PluginPlayground/utils.ts (1)

6-17: Add case-insensitive extension matching.

The function should handle uppercase file extensions (e.g., .JS, .YML).

 export const getLanguageByFileExtension = (fileTitle: string) => {
-  const ext = fileTitle.split(".").pop();
+  const ext = fileTitle.split(".").pop()?.toLowerCase();
   switch (ext) {
     case "js":
       return "javascript";
web/src/beta/features/PluginPlayground/Plugins/presets/custom/myPlugin.ts (1)

20-36: Consider improving schema field definitions.

The schema structure could be enhanced for better maintainability:

  1. Use descriptive IDs instead of numeric values (e.g., "text_field" instead of "1")
  2. Remove redundancy between name and title properties as they serve similar purposes
     schema:
       groups:
       - id: default
         title: Data
         fields:
-          - id: 1
+          - id: text_field
             type: string
             title: Text
-            name: Title
-          - id: 2
+          - id: number_field
             type: number
             title: Number
-            name: Number
-          - id: 3
+          - id: boolean_field
             type: bool
             title: Boolean
-            name: Boolean
web/src/beta/features/PluginPlayground/WidgetsList/index.tsx (1)

22-24: Use optional chaining for better code readability.

The current nested check can be simplified using optional chaining.

-  const ymlFile =
-    selectedPlugin.files &&
-    selectedPlugin.files.find((f) => f.title.endsWith("reearth.yml"));
+  const ymlFile = selectedPlugin.files?.find((f) => f.title.endsWith("reearth.yml"));
🧰 Tools
🪛 Biome (1.9.4)

[error] 23-24: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75dbc0f and 147ab9b.

📒 Files selected for processing (10)
  • web/src/beta/features/PluginPlayground/Code/hook.ts (1 hunks)
  • web/src/beta/features/PluginPlayground/Code/index.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/Code/utils.ts (0 hunks)
  • web/src/beta/features/PluginPlayground/Plugins/presets/custom/myPlugin.ts (1 hunks)
  • web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/WidgetsList/index.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/hooks.tsx (2 hunks)
  • web/src/beta/features/PluginPlayground/index.tsx (2 hunks)
  • web/src/beta/features/PluginPlayground/types.ts (1 hunks)
  • web/src/beta/features/PluginPlayground/utils.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • web/src/beta/features/PluginPlayground/Code/utils.ts
✅ Files skipped from review due to trivial changes (1)
  • web/src/beta/features/PluginPlayground/Code/index.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
web/src/beta/features/PluginPlayground/WidgetsList/index.tsx

[error] 23-24: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 56-56: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Redirect rules - reearth-web
  • GitHub Check: Header rules - reearth-web
  • GitHub Check: Pages changed - reearth-web
  • GitHub Check: ci-server / ci-server-lint
  • GitHub Check: ci-web / ci
  • GitHub Check: ci-server / ci-server-test
🔇 Additional comments (5)
web/src/beta/features/PluginPlayground/utils.ts (1)

19-34: Consider adding validation for the parsed YAML structure.

While the function handles parsing errors well, it doesn't validate if the parsed data matches the expected ReearthYML structure.

Consider adding runtime type checking:

 try {
   const data = yaml.load(file.sourceCode) as ReearthYML;
+  if (!data?.id || !data?.name || !data?.version) {
+    return { 
+      success: false, 
+      message: "Invalid YAML structure: missing required fields" 
+    } as const;
+  }
   return { success: true, data } as const;
✅ Verification successful

Runtime validation for ReearthYML structure is indeed necessary

The suggestion is valid as the current type assertion (as ReearthYML) only provides compile-time checking. The proposed validation ensures the required fields (id, name, version) are present at runtime, preventing potential issues with malformed YAML files that pass parsing but lack mandatory fields.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Find ReearthYML type definition
ast-grep --pattern 'type ReearthYML = {$$$}'

# Find interface definition if type not found
ast-grep --pattern 'interface ReearthYML {$$$}'

# Find usages of getYmlJson
rg "getYmlJson" -A 2

# Look for any existing validation patterns
rg "ReearthYML" -A 5

Length of output: 6101

web/src/beta/features/PluginPlayground/types.ts (1)

7-28: Consider making schema required for widget extensions.

The schema property is optional, but widgets typically require configuration schema to be functional.

 export type ReearthYML = {
   id: string;
   name: string;
   version: string;
   extensions?: {
     id: string;
     type: string;
     name: string;
     description: string;
     widgetLayout?: {
       extended: boolean;
       defaultLocation: {
         zone: WidgetLocation["zone"];
         section: WidgetLocation["section"];
         area: WidgetLocation["area"];
       };
     };
-    schema?: {
+    schema: {
       groups: Group;
     };
   }[];
 };
web/src/beta/features/PluginPlayground/index.tsx (1)

35-37: LGTM! Panel implementation follows existing patterns.

The WidgetsPanel integration is clean and consistent with the existing layout structure.

web/src/beta/features/PluginPlayground/Code/hook.ts (1)

8-9: LGTM! Good refactoring of types and utilities.

The changes improve code organization by:

  1. Centralizing type definitions
  2. Moving YAML parsing logic to a dedicated utility file
web/src/beta/features/PluginPlayground/hooks.tsx (1)

192-194: LGTM! Clean integration of the widgets panel.

The WidgetsPanel component is well-integrated and follows the established pattern of panel components in the codebase.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
web/src/beta/features/PluginPlayground/types.ts (1)

7-28: Consider improving type safety for extension type.

The type property in extensions could be more strictly typed to prevent invalid values.

   extensions?: {
     id: string;
-    type: string;
+    type: "widget" | "block" | string;
     name: string;
     description: string;

Also, consider adding JSDoc comments to explain the purpose of widgetLayout.extended.

web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx (1)

44-69: Improve type safety in render logic.

Consider using type narrowing instead of type assertions for better type safety.

-          value={value as number}
+          value={typeof value === 'number' ? value : 0}

-          value={value as boolean}
+          value={typeof value === 'boolean' ? value : false}

-          value={value as string}
+          value={typeof value === 'string' ? value : ''}
web/src/beta/features/PluginPlayground/WidgetsList/index.tsx (3)

22-32: Improve code readability and error handling.

  1. Use optional chaining for better readability
  2. Consider using a proper error state component instead of empty div
-  const ymlFile =
-    selectedPlugin.files &&
-    selectedPlugin.files.find((f) => f.title.endsWith("reearth.yml"));
+  const ymlFile = selectedPlugin.files?.find((f) => 
+    f.title.endsWith("reearth.yml")
+  );

   if (!ymlFile) {
     setNotification({
       type: "error",
       text: "No YAML configuration file found"
     });
-    return <div />;
+    return <EmptyState message="No YAML configuration file found" />;
   }
🧰 Tools
🪛 Biome (1.9.4)

[error] 23-24: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


66-72: Improve error message specificity.

The error message "No schema found in widget extension" is used for different error conditions. Consider using more specific messages:

   if (!widgetSchema || widgetSchema.length == 0) {
     setNotification({
       type: "error",
-      text: "No schema found in widget extension"
+      text: "Widget schema is empty or undefined"
     });
-    return <div />;
+    return <EmptyState message="No widget schema available" />;
   }

74-81: Add support for multiple schema groups.

The current implementation only renders fields from the first group. Consider supporting multiple groups and add error handling for empty fields.

-  const { fields } = widgetSchema[0];
+  return (
+    <Wrapper>
+      {widgetSchema.map(group => (
+        <div key={group.id}>
+          <h3>{group.title}</h3>
+          {group.fields?.map((field) => (
+            <PropertyItem key={field.id} field={field} />
+          )) ?? <EmptyState message="No fields in this group" />}
+        </div>
+      ))}
+    </Wrapper>
+  );
-  return (
-    <Wrapper>
-      {fields.map((field) => (
-        <PropertyItem key={field.id} field={field} />
-      ))}
-    </Wrapper>
-  );
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 147ab9b and 48e26aa.

📒 Files selected for processing (3)
  • web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/WidgetsList/index.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/types.ts (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx

[error] 32-32: isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead.

See the MDN documentation for more details.
Unsafe fix: Use Number.isNaN instead.

(lint/suspicious/noGlobalIsNan)

web/src/beta/features/PluginPlayground/WidgetsList/index.tsx

[error] 23-24: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Redirect rules - reearth-web
  • GitHub Check: Header rules - reearth-web
  • GitHub Check: Pages changed - reearth-web
  • GitHub Check: ci-server / ci-server-lint
  • GitHub Check: ci-server / ci-server-test
  • GitHub Check: ci-web / ci
🔇 Additional comments (3)
web/src/beta/features/PluginPlayground/types.ts (2)

30-30: LGTM!

Clean and effective type extraction from Visualizer component props.


43-47: LGTM! Type-safe implementation achieved.

The defaultValue property uses a proper union type as previously suggested, which enhances type safety.

web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx (1)

15-24: LGTM! Clean state management implementation.

Good use of a single state variable with type-safe initialization.

@mulengawilfred mulengawilfred changed the title feat(web): add widget panel to plugin playground [WIP] feat(web): add widget panel to plugin playground Jan 29, 2025
@mulengawilfred mulengawilfred changed the title [WIP] feat(web): add widget panel to plugin playground feat(web): add widget panel to plugin playground Feb 5, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (8)
web/src/beta/features/PluginPlayground/utils.ts (2)

6-17: Consider using a Map for language mapping.

The switch statement could be replaced with a Map for better maintainability and performance.

-export const getLanguageByFileExtension = (fileTitle: string) => {
-  const ext = fileTitle.split(".").pop();
-  switch (ext) {
-    case "js":
-      return "javascript";
-    case "yml":
-    case "yaml":
-      return "yaml";
-    default:
-      return "plaintext";
-  }
-};
+const languageMap = new Map([
+  ["js", "javascript"],
+  ["yml", "yaml"],
+  ["yaml", "yaml"]
+]);
+
+export const getLanguageByFileExtension = (fileTitle: string) => {
+  const ext = fileTitle.split(".").pop();
+  return languageMap.get(ext ?? "") ?? "plaintext";
+};

36-48: Add type guard for array check.

The array check could be more type-safe.

-export const customSchemaFieldsToObject = (array: CustomSchemaField[]) => {
+export const customSchemaFieldsToObject = (array: CustomSchemaField[] | undefined) => {
   if (Array.isArray(array)) {
     return array.reduce(
       (acc, item) => {
         const { id, ...rest } = item;
         acc[id as string] = rest;
         return acc;
       },
       {} as Record<string, unknown>
     );
   }
   return {};
 };
web/src/beta/features/PluginPlayground/Plugins/presets/custom/myPlugin.ts (1)

20-34: Consider adding validation constraints to schema fields.

The schema fields could benefit from additional validation constraints.

           - id: bgColor
             type: string
             title: Background Color
             name: Background Color
             ui: color
+            required: true
+            defaultValue: "#ffffff"
           - id: title 
             type: string
             title: Title
             name: Title
+            required: true
+            maxLength: 100
+            pattern: "^[a-zA-Z0-9\\s]+$"
web/src/beta/features/PluginPlayground/WidgetsList/index.tsx (3)

41-43: Use optional chaining for better readability.

The nested property access could be simplified using optional chaining.

-  const ymlFile =
-    selectedPlugin.files &&
-    selectedPlugin.files.find((f) => f.title.endsWith("reearth.yml"));
+  const ymlFile = selectedPlugin.files?.find((f) => f.title.endsWith("reearth.yml"));
🧰 Tools
🪛 Biome (1.9.4)

[error] 42-43: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


37-115: Consider memoizing the component for better performance.

Since the component receives props that could frequently change, memoization could improve performance.

-const WidgetsList: FC<Props> = ({
+const WidgetsList: FC<Props> = memo(({
   selectedPlugin,
   setUpdatedField
-}): JSX.Element => {
+}) => {
   // ... component logic ...
-};
+});
+
+WidgetsList.displayName = "WidgetsList";
🧰 Tools
🪛 Biome (1.9.4)

[error] 42-43: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


47-51: Centralize error messages for better maintainability.

Consider moving error messages to a centralized constants file.

// constants.ts
export const WIDGET_ERRORS = {
  NO_YML: "This plugin does not have a reearth.yml file.",
  INVALID_YML: "This plugin does not have a valid reearth.yml file.",
  NO_WIDGET: "This plugin does not have a valid widget extension.",
  NO_WIDGETS: "This plugin does not have any widgets."
} as const;

Also applies to: 59-61, 69-73, 84-88, 96-98

web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx (2)

57-73: Add value validation in handleChange.

The current implementation doesn't validate values before updating the state.

Add validation to ensure values match the expected type:

   const handleChange = ({
     newValue,
     fieldId
   }: {
     newValue:
       | boolean
       | LatLng
       | number
       | number[]
       | string
       | string[]
       | SpacingValues;
     fieldId: string;
   }): void => {
+    // Validate value based on field type
+    if (
+      (field.type === "number" && typeof newValue !== "number") ||
+      (field.type === "bool" && typeof newValue !== "boolean") ||
+      (field.type === "array" && !Array.isArray(newValue))
+    ) {
+      console.warn(`Invalid value type for field ${field.id}`);
+      return;
+    }
     setValue(newValue);
     setUpdatedField({ fieldId, value: newValue });
   };

205-210: Handle undefined values consistently in NumberField.

The current implementation uses a fallback of 0 for undefined values, which might not be appropriate for all number fields.

Consider using the field's minimum value as a fallback:

             onChange={(newValue?: number) =>
               handleChange({
-                newValue: newValue ?? 0,
+                newValue: newValue ?? field.min ?? 0,
                 fieldId: field.id
               })
             }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 48e26aa and 05e9457.

📒 Files selected for processing (7)
  • web/src/beta/features/PluginPlayground/Code/hook.ts (3 hunks)
  • web/src/beta/features/PluginPlayground/Plugins/presets/custom/myPlugin.ts (1 hunks)
  • web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/WidgetsList/index.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/hooks.tsx (3 hunks)
  • web/src/beta/features/PluginPlayground/types.ts (1 hunks)
  • web/src/beta/features/PluginPlayground/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/src/beta/features/PluginPlayground/hooks.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
web/src/beta/features/PluginPlayground/WidgetsList/index.tsx

[error] 42-43: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

web/src/beta/features/PluginPlayground/Code/hook.ts

[error] 211-211: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ci-web / ci
  • GitHub Check: ci-server / ci-server-lint
  • GitHub Check: ci-server / ci-server-test
🔇 Additional comments (3)
web/src/beta/features/PluginPlayground/utils.ts (1)

19-34: LGTM! Well-structured error handling.

The function properly handles empty files and YAML parsing errors with clear error messages.

web/src/beta/features/PluginPlayground/types.ts (1)

8-59: LGTM! Well-structured type definitions.

The types are comprehensive, properly nested, and follow TypeScript best practices.

web/src/beta/features/PluginPlayground/Code/hook.ts (1)

121-125: Improve type safety in widget property initialization.

The current implementation assumes schema fields are always defined when creating widget properties.

Add a null check before accessing schema fields:

                     property: {
-                      default: customSchemaFieldsToObject(
-                        schemaFields as CustomSchemaField[]
-                      )
+                      default: schemaFields ? 
+                        customSchemaFieldsToObject(schemaFields) : {}
                     },
✅ Verification successful

Error: No shell scripts or web queries found


Improve type safety by adding a null-check on schemaFields.
It’s confirmed that in file web/src/beta/features/PluginPlayground/Code/hook.ts (lines 121–125) the widget property is initialized using:

default: customSchemaFieldsToObject(schemaFields as CustomSchemaField[])

This directly assumes that schemaFields is always defined. The improvement suggested—checking if schemaFields exists before calling customSchemaFieldsToObject and defaulting to an empty object if not—enhances type safety and guards against potential runtime errors.

  • File to update: web/src/beta/features/PluginPlayground/Code/hook.ts (lines 121–125)
  • Suggested change:
                       property: {
    -                      default: customSchemaFieldsToObject(
    -                        schemaFields as CustomSchemaField[]
    -                      )
    +                      default: schemaFields ? 
    +                        customSchemaFieldsToObject(schemaFields) : {}
                       },

web/src/beta/features/PluginPlayground/Code/hook.ts Outdated Show resolved Hide resolved
web/src/beta/features/PluginPlayground/Code/hook.ts Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
web/src/beta/features/PluginPlayground/types.ts (1)

46-58: Consider adding validation constraints to FieldValue type.

While the type definition is correct, consider adding validation constraints or branded types for specific field types (e.g., range validation for numbers, pattern validation for strings).

web/src/beta/features/PluginPlayground/ExtensionSettings/index.tsx (1)

43-45: Improve optional chaining usage.

Optimize the code by using optional chaining operator.

-  const ymlFile =
-    selectedPlugin.files &&
-    selectedPlugin.files.find((f) => f.title.endsWith("reearth.yml"));
+  const ymlFile = selectedPlugin.files?.find((f) => f.title.endsWith("reearth.yml"));
🧰 Tools
🪛 Biome (1.9.4)

[error] 44-45: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (1)

58-198: Refactor conditional rendering for better maintainability.

The deep nesting of conditional rendering makes the code hard to maintain. Consider extracting each field type into a separate component.

Example refactor for string fields:

const StringField: FC<FieldProps> = ({ field, value, handleChange }) => {
  switch (field.ui) {
    case 'datetime':
      return <TimePointField ... />;
    case 'selection':
      return <SelectField ... />;
    // ... other cases
    default:
      return <InputField ... />;
  }
};
web/src/beta/features/PluginPlayground/Code/hook.ts (1)

230-230: Optimize useCallback dependencies.

The schemaFields dependency in the useCallback hook's dependency array might cause unnecessary re-renders as it's only used in the type assertion.

Remove the unnecessary dependency:

-  }, [updatedField, schemaFields, files, resetVisualizer, setNotification]);
+  }, [updatedField, files, resetVisualizer, setNotification]);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05e9457 and 5df7e0e.

📒 Files selected for processing (7)
  • web/src/beta/features/PluginPlayground/Code/hook.ts (3 hunks)
  • web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/ExtensionSettings/index.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/Plugins/presets/custom/myPlugin.ts (1 hunks)
  • web/src/beta/features/PluginPlayground/hooks.tsx (3 hunks)
  • web/src/beta/features/PluginPlayground/index.tsx (2 hunks)
  • web/src/beta/features/PluginPlayground/types.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/src/beta/features/PluginPlayground/index.tsx
  • web/src/beta/features/PluginPlayground/Plugins/presets/custom/myPlugin.ts
🧰 Additional context used
🪛 Biome (1.9.4)
web/src/beta/features/PluginPlayground/ExtensionSettings/index.tsx

[error] 44-45: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

web/src/beta/features/PluginPlayground/Code/hook.ts

[error] 209-209: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: ci-server / ci-server-lint
  • GitHub Check: ci-server / ci-server-test
  • GitHub Check: ci-web / ci
  • GitHub Check: Redirect rules - reearth-web
  • GitHub Check: Header rules - reearth-web
  • GitHub Check: Pages changed - reearth-web
🔇 Additional comments (7)
web/src/beta/features/PluginPlayground/types.ts (1)

10-31: LGTM! Well-structured type definition for ReearthYML.

The type definition is comprehensive and properly typed, with clear hierarchical structure for plugin configuration.

web/src/beta/features/PluginPlayground/hooks.tsx (1)

200-207: Avoid type casting and add runtime validation.

The type casting of schemaFields could be unsafe. Consider adding runtime validation before the cast.

web/src/beta/features/PluginPlayground/Code/hook.ts (5)

10-44: LGTM! Well-structured type definitions.

The type definitions are comprehensive and properly encapsulate all necessary functionality for the widget panel, including schema field management.


46-62: LGTM! Clean state management setup.

The state management for schema fields and field updates is well-organized and properly typed.


209-209: Fix performance issue in schema field accumulation.

The spread operator in the accumulator causes O(n²) time complexity. This can impact performance when dealing with a large number of schema fields.

🧰 Tools
🪛 Biome (1.9.4)

[error] 209-209: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)


212-227: Improve type safety in field value updates.

The current implementation assumes the value type is string when updating the field value, which could lead to type-related issues.


121-123: Add null check for schema fields.

The type assertion schemaFields as CustomSchemaField[] could be unsafe if schemaFields is undefined.

Add a null check or provide a default value:

-                      property: customSchemaFieldsToObject(
-                        schemaFields as CustomSchemaField[]
-                      ),
+                      property: customSchemaFieldsToObject(
+                        schemaFields ?? []
+                      ),
✅ Verification successful

Add null-check for schemaFields in hook.ts

The review comment is valid. Relying on a type assertion (schemaFields as CustomSchemaField[]) is unsafe if schemaFields is undefined, which could lead to runtime issues. Updating the code to use the nullish coalescing operator (i.e., schemaFields ?? []) ensures a safe default value is provided.

  • Location: web/src/beta/features/PluginPlayground/Code/hook.ts, lines 121–123
  • Action: Replace the type assertion with a null check:
    -                      property: customSchemaFieldsToObject(
    -                        schemaFields as CustomSchemaField[]
    -                      ),
    +                      property: customSchemaFieldsToObject(
    +                        schemaFields ?? []
    +                      ),

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (3)

23-33: Add JSDoc comments to document the Props type.

Consider adding JSDoc comments to document the purpose and usage of each prop for better maintainability.

+/**
+ * Props for the PropertyItem component
+ * @property {FieldValue} initialValue - The initial value of the field
+ * @property {SchemaField} field - The schema definition for the field
+ * @property {Function} setUpdatedField - Callback function to update the field value
+ */
 type Props = {
   initialValue: FieldValue;
   field: SchemaField;
   setUpdatedField: ({

37-47: Simplify the assetTypes computation logic.

The nested ternary operators make the code harder to read. Consider using a more straightforward approach.

-  const assetTypes: "image"[] | "file"[] | undefined = useMemo(
-    () =>
-      field.type === "url"
-        ? field.ui === "image"
-          ? ["image" as const]
-          : field.ui === "file"
-            ? ["file" as const]
-            : undefined
-        : undefined,
-    [field.type, field.ui]
-  );
+  const assetTypes = useMemo(() => {
+    if (field.type !== "url") return undefined;
+    if (field.ui === "image") return ["image" as const];
+    if (field.ui === "file") return ["file" as const];
+    return undefined;
+  }, [field.type, field.ui]);

63-63: Add type guards to avoid type assertions.

Replace type assertions with proper type guards to improve type safety.

const isStringValue = (value: FieldValue): value is string => 
  typeof value === 'string';

const isNumberValue = (value: FieldValue): value is number =>
  typeof value === 'number';

// Then in your JSX:
value={isStringValue(value) ? value : ''}

Also applies to: 71-71, 87-87, 97-97, 104-104, 119-119, 126-126, 137-137, 145-145, 155-155, 167-167, 175-175, 183-183

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5df7e0e and 23b64a6.

📒 Files selected for processing (1)
  • web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: ci-server / ci-server-lint
  • GitHub Check: ci-server / ci-server-test
  • GitHub Check: ci-web / ci
  • GitHub Check: Redirect rules - reearth-web
  • GitHub Check: Header rules - reearth-web
  • GitHub Check: Pages changed - reearth-web
🔇 Additional comments (1)
web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (1)

49-54: Replace setTimeout with proper debounce utility.

Using setTimeout for debouncing can lead to memory leaks. Consider using a proper debounce utility.

@mulengawilfred
Copy link
Contributor Author

Will put this as a WIP. Current challenge is updating the state of individual input fields as well as updating the corresponding value in the web/src/beta/features/PluginPlayground/Code/hook.ts. Seems like there is a race-condition for the state and not all input fields in web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx

@mulengawilfred mulengawilfred changed the title feat(web): add widget panel to plugin playground [WIP] feat(web): add widget panel to plugin playground Feb 6, 2025
@airslice airslice changed the title [WIP] feat(web): add widget panel to plugin playground feat(web): add extension settings panel to plugin playground Feb 6, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (1)

52-192: 🛠️ Refactor suggestion

Refactor conditional rendering logic for better maintainability.

The nested ternary operators and if-else chains make the code hard to maintain. This is a duplicate of a previous review comment, but it's still valid.

Additionally, consider adding error boundaries to handle potential runtime errors in field rendering:

+import { ErrorBoundary } from 'react-error-boundary';
+
+const FieldErrorFallback = ({ error, field }) => (
+  <div>
+    <p>Error rendering {field.name}: {error.message}</p>
+  </div>
+);
+
 const PropertyItem: FC<Props> = ({ id, value, field, onUpdate }) => {
   // ... existing code ...
   
   return (
+    <ErrorBoundary
+      FallbackComponent={({ error }) => (
+        <FieldErrorFallback error={error} field={field} />
+      )}
+    >
       {/* existing rendering logic */}
+    </ErrorBoundary>
   );
 };
🧹 Nitpick comments (4)
web/src/beta/features/PluginPlayground/ExtensionSettings/index.tsx (1)

31-33: Simplify with optional chaining.

The check for selectedPlugin.files can be simplified.

-  const ymlFile =
-    selectedPlugin.files &&
-    selectedPlugin.files.find((f) => f.title.endsWith("reearth.yml"));
+  const ymlFile = selectedPlugin.files?.find((f) => f.title.endsWith("reearth.yml"));
🧰 Tools
🪛 Biome (1.9.4)

[error] 32-33: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (1)

1-21: Consider organizing imports for better maintainability.

The imports could be better organized by grouping them into:

  1. External dependencies
  2. Internal UI components
  3. Types and utilities
+// External dependencies
 import { FC, useCallback, useMemo } from "react";
 
+// Internal types and utilities
 import { SpacingValues } from "@reearth/beta/ui/fields/SpacingField";
 import { Camera, LatLng } from "@reearth/beta/utils/value";
 import { SchemaField } from "@reearth/services/api/propertyApi/utils";
 import { FieldValue } from "../types";
 
+// UI components
 import {
   ColorField,
   InputField,
   SelectField,
   TimePointField,
   TextareaField,
   AssetField,
   SpacingField,
   SwitchField,
   SliderField,
   NumberField,
   TwinInputField,
   CameraField,
   RangeField
 } from "../../../ui/fields";
web/src/beta/features/PluginPlayground/hooks.tsx (2)

29-31: Consider persisting field values in local storage.

Based on the PR objectives mentioning "input field data will be stored locally", consider persisting the field values in local storage to maintain state across page reloads.

+import { useLocalStorage } from '@reearth/beta/hooks';
+
-const [fieldValues, setFieldValues] = useState<Record<string, FieldValue>>({});
+const [fieldValues, setFieldValues] = useLocalStorage<Record<string, FieldValue>>(
+  'plugin-playground-field-values',
+  {}
+);

197-204: Consider adding loading and error states.

The ExtensionSettingsPanel should handle loading and error states when interacting with field values.

 const ExtensionSettingsPanel: FC = () => (
+  <Suspense fallback={<div>Loading settings...</div>}>
+    <ErrorBoundary fallback={<div>Error loading settings</div>}>
       <ExtensionSettings
         selectedPlugin={selectedPlugin}
         selectedFile={selectedFile}
         fieldValues={fieldValues}
         setFieldValues={setFieldValues}
       />
+    </ErrorBoundary>
+  </Suspense>
 );
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f7a8c3 and 80dfe1e.

📒 Files selected for processing (7)
  • web/src/beta/features/PluginPlayground/Code/hook.ts (4 hunks)
  • web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/ExtensionSettings/index.tsx (1 hunks)
  • web/src/beta/features/PluginPlayground/Plugins/presets/extension/extensionProperty.ts (1 hunks)
  • web/src/beta/features/PluginPlayground/Plugins/presets/index.ts (2 hunks)
  • web/src/beta/features/PluginPlayground/hooks.tsx (4 hunks)
  • web/src/beta/features/PluginPlayground/index.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/src/beta/features/PluginPlayground/index.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
web/src/beta/features/PluginPlayground/ExtensionSettings/index.tsx

[error] 32-33: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Redirect rules - reearth-web
  • GitHub Check: Header rules - reearth-web
  • GitHub Check: Pages changed - reearth-web
🔇 Additional comments (6)
web/src/beta/features/PluginPlayground/Plugins/presets/extension/extensionProperty.ts (1)

1-67: LGTM! Well-structured plugin definition.

The implementation is clean and follows best practices:

  • Clear separation between schema (YAML) and UI (widget) code
  • Proper event handling for property updates
  • Good use of constants and types
web/src/beta/features/PluginPlayground/Plugins/presets/index.ts (1)

8-8: LGTM! Clean addition of extension category.

The changes properly integrate the new extension property plugin into the preset plugins structure.

Also applies to: 99-103

web/src/beta/features/PluginPlayground/ExtensionSettings/index.tsx (1)

25-102: LGTM! Well-structured component with proper error handling.

The component implementation:

  • Properly validates YAML structure
  • Handles errors gracefully
  • Uses appropriate React patterns
🧰 Tools
🪛 Biome (1.9.4)

[error] 32-33: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

web/src/beta/features/PluginPlayground/Code/hook.ts (1)

32-184: LGTM! Clean implementation of field value handling.

The hook implementation:

  • Properly integrates field values
  • Has good error handling
  • Uses appropriate React patterns with useCallback
🧰 Tools
🪛 Biome (1.9.4)

[error] 83-83: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)


[error] 135-135: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx (1)

43-50: Consider adding error handling for undefined values.

The handleChange callback silently ignores undefined values. Consider whether this is the intended behavior or if we should handle these cases explicitly.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for similar patterns in the codebase to verify the convention
rg -A 5 'const handleChange.*useCallback.*\(.*\).*=>' 

Length of output: 55


🏁 Script executed:

#!/bin/bash
# Let's search within the file to see the full context of handleChange and similar patterns.
rg -A 10 "const handleChange.*useCallback" web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx

Length of output: 305


Based on the information provided, the callback’s behavior is to simply ignore undefined values by not calling onUpdate when newValue is not provided. This pattern appears intentional and consistent with the function’s annotated behavior (using an optional parameter), as there’s no evidence elsewhere in the file (or from similar examples in the codebase) that suggests a need to treat undefined values as an error case.

Therefore, the current behavior seems acceptable if the intended design is to only trigger updates when a valid value is provided.

Final Recommendation:

  • The design choice to ignore undefined values appears deliberate.
  • No additional error handling seems necessary unless future requirements dictate stricter checking.
web/src/beta/features/PluginPlayground/hooks.tsx (1)

49-53: Verify the impact of fieldValues on code execution.

The PR comments mention a race condition affecting state management. Let's verify the usage of fieldValues in the useCode hook.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for fieldValues usage in useCode hook
ast-grep --pattern 'const useCode = ($params) => {
  $$$
  fieldValues
  $$$
}'

Length of output: 81


I'll generate additional scripts to search for the definition of the useCode hook and all its references to fieldValues in the codebase.


🏁 Script executed:

#!/bin/bash
echo "Searching for the definition of the useCode hook:"
rg -n "const useCode\\s*=" .

echo ""
echo "Searching for all occurrences of 'fieldValues' in the codebase:"
rg -n "fieldValues" .

Length of output: 1811


Subject: FieldValues Handling in useCode Hook is Appropriate

After re-examining the implementation across the PluginPlayground:

  • The fieldValues state is declared and managed in hooks.tsx and then passed to the useCode hook.
  • In web/src/beta/features/PluginPlayground/Code/hook.ts, fieldValues is consistently used—most notably as part of a dependency array (e.g., on line 184) and when computing derived values—ensuring updated state is properly captured.

These findings indicate that changes to fieldValues trigger the intended hook re-execution, mitigating the race condition concerns noted in the PR comments.

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

Successfully merging this pull request may close these issues.

2 participants