-
Notifications
You must be signed in to change notification settings - Fork 47
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
Conversation
WalkthroughThis 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
Possibly related PRs
Suggested reviewers
Poem
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
Documentation and Community
|
✅ Deploy Preview for reearth-web ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
There was a problem hiding this 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:
- Use descriptive IDs instead of numeric values (e.g., "text_field" instead of "1")
- Remove redundancy between
name
andtitle
properties as they serve similar purposesschema: 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: Booleanweb/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
📒 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 5Length 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:
- Centralizing type definitions
- 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.
web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx
Outdated
Show resolved
Hide resolved
web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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.
- Use optional chaining for better readability
- 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
📒 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.
web/src/beta/features/PluginPlayground/WidgetsList/PropertyItem.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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
📒 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 ifschemaFields
exists before callingcustomSchemaFieldsToObject
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/WidgetsList/PropertyItem.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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 theuseCallback
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
📒 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 ofO(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 ifschemaFields
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
inhook.ts
The review comment is valid. Relying on a type assertion (
schemaFields as CustomSchemaField[]
) is unsafe ifschemaFields
isundefined
, 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 ?? [] + ),
web/src/beta/features/PluginPlayground/ExtensionSettings/index.tsx
Outdated
Show resolved
Hide resolved
web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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
📒 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.
web/src/beta/features/PluginPlayground/ExtensionSettings/PropertyItem.tsx
Outdated
Show resolved
Hide resolved
Will put this as a |
There was a problem hiding this 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 suggestionRefactor 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:
- External dependencies
- Internal UI components
- 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
📒 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 ofO(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 ofO(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.tsxLength of output: 305
Based on the information provided, the callback’s behavior is to simply ignore
undefined
values by not callingonUpdate
whennewValue
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 treatundefined
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 tofieldValues
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 inhooks.tsx
and then passed to theuseCode
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.
There was a problem hiding this 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 (9)
web/src/beta/features/PluginPlayground/Plugins/presets/extension/extensionProperty.ts (1)
62-90
: Enhance error handling and user feedback.While the widget implementation is functional, consider these improvements:
- Add error handling for message parsing
- Provide visual feedback when properties are updated
const widgetFile: FileType = { id: "extension-property-widget", title: "extension-property-widget.js", sourceCode: `reearth.ui.show(\` ${PRESET_PLUGIN_COMMON_STYLE} <div id="wrapper"> <h2>Extension Property</h2> <h3 style="text-align:center">Input on Extension Settings and execute code again.</h3> <h3 style="text-align:center" id="text"></h3> + <div id="status" style="text-align:center; opacity: 0; transition: opacity 0.3s;"> + Properties updated! + </div> </div> <script> window.addEventListener("message", e => { - const msg = e.data; - if (msg.type === "getWidgetProperty") { - document.getElementById("text").textContent = msg.property?.default?.text ?? ""; - document.getElementById("text").style.color = msg.property?.default?.color ?? ""; + try { + const msg = e.data; + if (msg.type === "getWidgetProperty") { + document.getElementById("text").textContent = msg.property?.default?.text ?? ""; + document.getElementById("text").style.color = msg.property?.default?.color ?? ""; + + // Show status message + const status = document.getElementById("status"); + status.style.opacity = "1"; + setTimeout(() => { + status.style.opacity = "0"; + }, 2000); + } + } catch (error) { + console.error("Error processing message:", error); } }); </script>web/src/beta/features/PluginPlayground/types.ts (5)
10-31
: Add JSDoc documentation for better maintainability.Consider adding JSDoc comments to document the purpose and structure of the
ReearthYML
type and its properties.+/** + * Represents the structure of a Re:Earth plugin's YAML configuration. + */ export type ReearthYML = { + /** Unique identifier for the plugin */ id: string; + /** Display name of the plugin */ name: string; + /** Semantic version of the plugin */ version: string; + /** List of plugin extensions */ extensions?: { id: string; type: string; name: string; description: string; widgetLayout?: { extended: boolean; defaultLocation: { zone: WidgetLocation["zone"]; section: WidgetLocation["section"]; area: WidgetLocation["area"]; }; }; schema?: { groups: Group; }; }[]; };
33-33
: Add JSDoc documentation for the Widgets type.Consider adding a JSDoc comment to explain the purpose of this type alias.
+/** Type representing the widgets prop of the Visualizer component */ export type Widgets = ComponentProps<typeof Visualizer>["widgets"];
35-46
: Improve type safety and add documentation.
- The
property
field could be more type-safe by using theFieldValue
type.- Consider adding JSDoc comments for better documentation.
+/** + * Represents a custom infobox block extension. + */ export type CustomInfoboxBlock = { id: string; name: string; description: string; __REEARTH_SOURCECODE: string; extensionId: string; pluginId: string; - property: Record<string, unknown>; + property: Record<string, Record<string, FieldValue>>; extensionType: "storyBlock"; }; +/** Type alias for CustomInfoboxBlock used in story blocks */ export type CustomStoryBlock = CustomInfoboxBlock;
48-60
: Add JSDoc documentation for field-related types.Consider adding JSDoc comments to document the purpose of these types.
+/** Union type of all possible field values */ export type FieldValue = | string | number | boolean | LatLng | number[] | string[] | SpacingValues; +/** + * Extends the base Field type with additional properties for customization. + */ export interface CustomField extends Field { id?: string; ui?: string; defaultValue?: FieldValue; }
62-70
: Improve type naming and add documentation.
- Consider renaming
Group
toSchemaGroup
for better clarity.- Add JSDoc comments to document the purpose of these types.
+/** Extends SchemaField with an optional value property */ export interface CustomSchemaField extends SchemaField { value?: FieldValue; } -export type Group = { +/** Represents a group of schema fields */ +export type SchemaGroup = { id: string; title: string; fields: SchemaField[]; }[];web/src/beta/features/PluginPlayground/Code/hook.ts (3)
18-30
: Add JSDoc documentation for type definitions.Consider adding JSDoc comments to document the purpose of these types.
+/** Props for the plugin playground hook */ type Props = { files: FileType[]; fieldValues: Record<string, FieldValue>; resetVisualizer: () => void; }; +/** Return type for the plugin playground hook */ type HookReturnType = { executeCode: () => void; infoboxBlocks?: CustomInfoboxBlock[]; schemaFields?: CustomSchemaField[]; story?: Story; widgets?: Widgets; };
32-55
: Enhance generateProperty function with documentation and validation.Consider adding JSDoc documentation and improving input validation.
+/** + * Generates a property object from schema and field values. + * @param schema - The schema containing groups and fields + * @param fieldValues - Record of field values indexed by field ID + * @param pluginId - The plugin identifier + * @param extensionId - The extension identifier + * @returns Record of property values grouped by group ID + */ function generateProperty( schema: | { groups: Group; } | undefined, fieldValues: Record<string, FieldValue>, pluginId: string, extensionId: string -) { +): Record<string, Record<string, FieldValue>> { + if (!pluginId || !extensionId) { + throw new Error("Plugin ID and Extension ID are required"); + } + const property: Record<string, unknown> = {}; if (!schema || !schema.groups) return property;
220-220
: Optimize useCallback dependencies.Remove
setNotification
from the dependency array as it's stable (from useNotification hook).- }, [files, fieldValues, resetVisualizer, setNotification]); + }, [files, fieldValues, resetVisualizer]);
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
web/src/beta/features/PluginPlayground/Code/hook.ts
(6 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/types.ts
(1 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 (4)
- GitHub Check: deploy-server / deploy_test
- GitHub Check: Redirect rules - reearth-web
- GitHub Check: Header rules - reearth-web
- GitHub Check: Pages changed - reearth-web
🔇 Additional comments (5)
web/src/beta/features/PluginPlayground/Plugins/presets/extension/extensionProperty.ts (3)
1-2
: LGTM!The imports are clean and appropriate for the plugin implementation.
4-60
: Consider reducing schema duplication.The schema structure is identical across all three extensions (widget, infobox block, and story block). Consider extracting the common schema into a shared configuration to improve maintainability.
const yamlFile: FileType = { id: "extension-property-reearth-yml", title: "reearth.yml", + const commonSchema = { + groups: [{ + id: "default", + title: "Default", + fields: [ + { id: "text", type: "string", name: "Text" }, + { id: "color", type: "string", name: "Color", ui: "color" } + ] + }] + }; sourceCode: `id: extension-property-plugin name: Extension Property version: 1.0.0 extensions: - id: extension-property-widget type: widget name: Extension Property Widget description: Extension Property Widget - schema: - groups: - - id: default - title: Default - fields: - - id: text - type: string - name: Text - - id: color - type: string - name: Color - ui: color + schema: ${JSON.stringify(commonSchema, null, 2)} - id: infobox-block type: infoboxBlock name: Infobox Block - schema: - groups: - - id: default - title: Default - fields: - - id: text - type: string - name: Text - - id: color - type: string - name: Color - ui: color + schema: ${JSON.stringify(commonSchema, null, 2)} - id: story-block type: storyBlock name: Story Block - schema: - groups: - - id: default - title: Default - fields: - - id: text - type: string - name: Text - - id: color - type: string - name: Color - ui: color + schema: ${JSON.stringify(commonSchema, null, 2)}Verify field types coverage.
Based on the PR objectives, you mentioned that "only text, number, and boolean fields have been added". However, I notice that the schema only includes text fields (string and color). Consider if number and boolean fields should be added to this schema as well.
150-154
: LGTM!The plugin export is correctly structured with all necessary components.
web/src/beta/features/PluginPlayground/types.ts (1)
1-9
: LGTM!The imports are well-organized and properly separated into external and internal dependencies.
web/src/beta/features/PluginPlayground/Code/hook.ts (1)
167-169
: Address TODO comment regarding extensionType.The hardcoded "storyBlock" value for
extensionType
needs to be fixed. This appears to be a workaround for a type definition issue.Could you provide more context about the type definition error? This would help in implementing a proper fix instead of using a workaround.
web/src/beta/features/PluginPlayground/Plugins/presets/extension/extensionProperty.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
web/src/beta/features/PluginPlayground/types.ts (3)
10-31
: Add JSDoc comments to document the ReearthYML type.The
ReearthYML
type is well-structured but would benefit from documentation explaining its purpose and the significance of each field, especially for plugin developers.Add JSDoc comments like this:
+/** + * Represents the structure of a reearth.yml configuration file. + * This file defines the metadata and configuration for a Re:Earth plugin. + */ export type ReearthYML = { + /** Unique identifier for the plugin */ id: string; + /** Display name of the plugin */ name: string; + /** Semantic version of the plugin */ version: string; + /** List of plugin extensions */ extensions?: { id: string; type: string; name: string; description: string; widgetLayout?: { extended: boolean; defaultLocation: { zone: WidgetLocation["zone"]; section: WidgetLocation["section"]; area: WidgetLocation["area"]; }; }; schema?: { groups: Group; }; }[]; };
35-51
: Consider improving type safety and documentation for block types.Two suggestions for improvement:
- The
propertyForPluginAPI
field usesRecord<string, unknown>
which is too permissive and could lead to type-safety issues.- The block types would benefit from JSDoc documentation.
Consider these improvements:
+/** Base type for all block types with common properties */ type CommonBlock = { id: string; name: string; description: string; __REEARTH_SOURCECODE: string; extensionId: string; pluginId: string; - propertyForPluginAPI: Record<string, unknown>; + propertyForPluginAPI: Record<string, FieldValue>; }; +/** Block type for infobox extensions */ export type CustomInfoboxBlock = CommonBlock & { extensionType: "infoboxBlock"; }; +/** Block type for story extensions */ export type CustomStoryBlock = CommonBlock & { extensionType: "storyBlock"; };
71-75
: Consider making the array type more explicit.The
Group
type could be more clearly defined to show it's an array type.Consider this alternative definition:
-export type Group = { +export type GroupItem = { id: string; title: string; fields: SchemaField[]; -}[]; +}; +export type Group = GroupItem[];
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
web/src/beta/features/PluginPlayground/Code/hook.ts
(6 hunks)web/src/beta/features/PluginPlayground/Plugins/presets/extension/extensionProperty.ts
(1 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/Plugins/presets/extension/extensionProperty.ts
- web/src/beta/features/PluginPlayground/Code/hook.ts
⏰ 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-web / ci
- GitHub Check: ci-server / ci-server-lint
- GitHub Check: ci-server / ci-server-test
🔇 Additional comments (3)
web/src/beta/features/PluginPlayground/types.ts (3)
1-9
: LGTM!The imports are well-organized and logically grouped, with clear separation between external and internal dependencies.
33-33
: LGTM!The
Widgets
type is well-defined using React'sComponentProps
utility type.
53-69
: LGTM!The field-related types are well-defined:
FieldValue
provides a comprehensive and type-safe union of possible field valuesCustomField
implements the type-safedefaultValue
as suggested in past reviewsCustomSchemaField
extendsSchemaField
with an optionalvalue
property
There was a problem hiding this 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 (2)
web/src/beta/features/PluginPlayground/hooks.tsx (2)
41-43
: Enhance type safety for field values.While the implementation works, it could benefit from stronger type safety and validation.
Consider these improvements:
- const [fieldValues, setFieldValues] = useState<Record<string, FieldValue>>( - {} - ); + type FieldValues = Record<string, FieldValue>; + + const [fieldValues, setFieldValues] = useState<FieldValues>({}); + + const updateFieldValue = useCallback((key: string, value: FieldValue) => { + setFieldValues(prev => { + // Validate value based on field type + if (!isValidFieldValue(value)) return prev; + return { ...prev, [key]: value }; + }); + }, []);Also applies to: 63-63
208-215
: Optimize ExtensionSettingsPanel performance.The component could benefit from memoization to prevent unnecessary re-renders.
Apply this diff to optimize the component:
- const ExtensionSettingsPanel: FC = () => ( + const ExtensionSettingsPanel: FC = useMemo(() => ( <ExtensionSettings selectedPlugin={selectedPlugin} selectedFile={selectedFile} fieldValues={fieldValues} setFieldValues={setFieldValues} /> - ); + ), [selectedPlugin, selectedFile, fieldValues, setFieldValues]);Also applies to: 223-223
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
web/src/beta/features/PluginPlayground/SettingsList/index.tsx
(1 hunks)web/src/beta/features/PluginPlayground/hooks.tsx
(3 hunks)
⏰ 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 (2)
web/src/beta/features/PluginPlayground/SettingsList/index.tsx (1)
31-31
: LGTM! Improved state management pattern.The change from toggle-based to direct value assignment is a better practice as it:
- Relies on the actual checkbox value rather than inferring it
- Follows React's controlled component pattern more closely
web/src/beta/features/PluginPlayground/hooks.tsx (1)
7-7
: LGTM! Required imports for extension settings.The imports are correctly added to support the new extension settings panel functionality.
Also applies to: 13-13
const [enabledVisualizer, setEnabledVisualizer] = useState(true); | ||
const [showStoryPanel, setShowStoryPanel] = useState(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix potential race conditions in story panel state management.
The current implementation has several issues:
- Multiple timeouts running concurrently could lead to race conditions
- The timeout closure captures stale showStoryPanel state
- Timeouts might continue running after component unmount
Apply this diff to fix the issues:
- const resetVisualizer = useCallback(() => {
- setEnabledVisualizer(false);
- setShowStoryPanel(false);
- const timeoutId = setTimeout(() => {
- setEnabledVisualizer(true);
- }, 0);
- let showStoryPanelTimeout: NodeJS.Timeout | undefined;
- if (showStoryPanel) {
- showStoryPanelTimeout = setTimeout(() => {
- setShowStoryPanel(showStoryPanel);
- }, 100);
- }
-
- return () => {
- clearTimeout(timeoutId);
- clearTimeout(showStoryPanelTimeout);
- };
- }, [showStoryPanel]);
+ const resetVisualizer = useCallback(() => {
+ setEnabledVisualizer(false);
+ setShowStoryPanel(false);
+ const timeoutId = setTimeout(() => {
+ setEnabledVisualizer(true);
+ // Restore story panel state after visualizer is enabled
+ setShowStoryPanel(true);
+ }, 0);
+
+ return () => {
+ clearTimeout(timeoutId);
+ };
+ }, []);
Also applies to: 24-39
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
PropertyItem
, for rendering various input fields based on schema properties.ExtensionSettings
, to manage and display plugin settings.Refactor
showStoryPanel
within theSettingsList
component for more intuitive user interaction.