-
Notifications
You must be signed in to change notification settings - Fork 110
refactor(core): move schema initializers to module-web #701
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
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThis update introduces a comprehensive schema initializer system for a schema-driven UI framework, primarily within the Changes
Sequence Diagram(s)sequenceDiagram
participant App
participant PluginManager
participant SchemaInitializerPlugin
participant UIComponents
participant SchemaInitializerManager
App->>PluginManager: Add SchemaInitializerPlugin (async)
PluginManager->>SchemaInitializerPlugin: load()
SchemaInitializerPlugin->>UIComponents: Register components (blocks, actions, fields)
SchemaInitializerPlugin->>SchemaInitializerManager: Register initializer groups (blocks, actions, etc)
Note over App,SchemaInitializerManager: App now supports dynamic schema initialization via registered components and initializers
Estimated code review effort5 (~2+ hours): The changes are extensive, introducing many new files, components, hooks, and utilities, along with complex schema manipulation logic and type refactoring across the codebase. Possibly related PRs
Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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
CodeRabbit Configuration File (
|
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: 47
♻️ Duplicate comments (3)
packages/module-web/src/client/schema-initializer/items/RecordAssociationDetailsBlockInitializer.tsx (1)
25-37: Add consistent error handlingThis component has the same async error handling issue as other initializers.
packages/module-web/src/client/schema-initializer/items/RecordAssociationGridCardBlockInitializer.tsx (1)
52-64: Apply consistent null checking patternLike other association block creators, this should include defensive null checks.
packages/module-web/src/client/schema-initializer/items/RecordAssociationFormBlockInitializer.tsx (1)
27-50: Add error handling for async template fetching.Same issue as in RecordReadPrettyAssociationFormBlockInitializer - the async call could fail without proper error handling.
🧹 Nitpick comments (36)
packages/client/src/schema-component/antd/action/index.tsx (1)
11-12: Export looks good – remember to re-export typingsThe new named export matches existing usage in
schema-initializer/components/CreateRecordAction.tsx.
EnsurelinkageAction’s TypeScript types are also exported from./utilsto avoidanyleakage.packages/module-web/src/client/schema-initializer/components/assigned-field/index.ts (1)
1-1: Minor: maintain naming consistencyElsewhere barrel files are named
index.tsx; here it’sindex.ts.
Not harmful, but using the same extension across packages avoids needless double compilation.packages/module-web/src/client/schema-initializer/items/FilterBlockInitializer.tsx (1)
1-3: Consider documenting the alias relationship.While the alias export pattern is syntactically correct, consider adding a comment explaining why
FilterBlockInitializeris aliased toDataBlockInitializer. This would help future maintainers understand the relationship and prevent confusion about whether these should diverge in functionality.+// FilterBlockInitializer is currently an alias for DataBlockInitializer +// TODO: Consider if FilterBlockInitializer should have specialized behavior import { DataBlockInitializer } from './DataBlockInitializer'; export const FilterBlockInitializer = DataBlockInitializer;packages/module-web/src/client/schema-initializer/components/DeletedField.tsx (1)
5-5: Consider using CSS classes instead of inline styles.For better maintainability and consistency with design systems, consider using CSS classes or styled components instead of inline styles.
- return <div style={{ color: '#ccc' }}>{t('The field has been deleted')}</div>; + return <div className="deleted-field-message">{t('The field has been deleted')}</div>;packages/module-web/src/client/schema-initializer/items/SubmitActionInitializer.tsx (1)
10-10: Consider removing or documenting the commented code.The commented
x-designerline should either be removed if it's no longer needed or documented with a TODO comment explaining why it's temporarily disabled.- // 'x-designer': 'Action.Designer', + // TODO: Re-enable when Action.Designer is available + // 'x-designer': 'Action.Designer',packages/module-web/src/client/schema-initializer/items/G2PlotInitializer.tsx (1)
5-18: Consider adding error boundary or validation.The component assumes
useSchemaInitializerItemanduseSchemaInitializerwill always return valid objects. Consider adding basic validation to make the component more robust.export const G2PlotInitializer = () => { const itemConfig = useSchemaInitializerItem(); const { insert } = useSchemaInitializer(); + + if (!itemConfig || !insert) { + return null; + } + return ( <SchemaInitializerItem {...itemConfig} onClick={() => { insert({ ...(itemConfig.schema || {}), }); }} /> ); };packages/module-web/src/client/schema-initializer/items/CustomizeActionInitializer.tsx (2)
8-8: Clarify duplicate prop passing pattern.The component passes
itemConfigboth as spread props ({...itemConfig}) and as an explicititemprop. This could lead to confusion or unintended prop overrides.Consider clarifying the intent or removing redundancy:
- return <BlockInitializer {...itemConfig} item={itemConfig} />; + return <BlockInitializer item={itemConfig} />;Or if both patterns are needed, add a comment explaining why:
+ // Pass itemConfig as both spread props and item prop for BlockInitializer compatibility return <BlockInitializer {...itemConfig} item={itemConfig} />;
6-9: Consider adding error handling.Like other initializer components, this could benefit from basic validation to handle cases where the hook returns undefined.
export const CustomizeActionInitializer = () => { const itemConfig = useSchemaInitializerItem(); + + if (!itemConfig) { + return null; + } + return <BlockInitializer {...itemConfig} item={itemConfig} />; };packages/module-web/src/client/schema-initializer/hooks/useGetAriaLabelOfSchemaInitializer.ts (1)
12-12: Consider migrating from deprecated hook.The hook uses
useCollection_deprecatedwhich suggests there's a newer version available. Consider updating to the non-deprecated alternative if available.packages/module-web/src/client/schema-initializer/buttons/CustomFormItemInitializers.tsx (2)
10-10: Replace Chinese comment with English.The comment should be in English for better maintainability in an international codebase.
-// 表单里配置字段 +// Configure fields in form
7-7: Consider adding type annotations for better maintainability.The component lacks proper TypeScript type annotations which could help catch potential runtime errors.
-export const InitializerWithSwitch = (props) => { +interface InitializerWithSwitchProps { + type: string; + schema?: any; + item: any; + remove?: () => void; + disabled?: boolean; +} + +export const InitializerWithSwitch: React.FC<InitializerWithSwitchProps> = (props) => {packages/module-web/src/client/schema-initializer/items/TableActionColumnInitializer.tsx (2)
7-34: Add proper TypeScript types for better maintainability.The component lacks type annotations which could help prevent runtime errors and improve developer experience.
+interface TableActionColumnInitializerProps { + // Add props interface based on usage +} + -export const TableActionColumnInitializer = () => { +export const TableActionColumnInitializer: React.FC<TableActionColumnInitializerProps> = () => {
13-16: Consider making component properties configurable.The hardcoded width and fixed position values could benefit from being configurable through props or context.
'x-component-props': { - width: 150, - fixed: 'right', + width: props.width ?? 150, + fixed: props.fixed ?? 'right', },packages/module-web/src/client/schema-initializer/items/SelectActionInitializer.tsx (2)
5-5: Add TypeScript interface for props.The component lacks proper type annotations for its props.
+interface SelectActionInitializerProps { + [key: string]: any; // Based on ActionInitializer props +} + -export const SelectActionInitializer = (props) => { +export const SelectActionInitializer: React.FC<SelectActionInitializerProps> = (props) => {
6-59: Consider extracting large schema definition.The schema object is quite large and complex. Consider extracting it to improve readability and reusability.
+const SELECT_ACTION_SCHEMA = { + type: 'void', + title: '{{ t("Select") }}', + 'x-action': 'update', + // ... rest of schema +}; + export const SelectActionInitializer: React.FC<SelectActionInitializerProps> = (props) => { - const schema = { - type: 'void', - title: '{{ t("Select") }}', - // ... large schema object - }; - return <ActionInitializer {...props} schema={schema} />; + return <ActionInitializer {...props} schema={SELECT_ACTION_SCHEMA} />; };packages/module-web/src/client/schema-initializer/buttons/SubTableActionInitializers.tsx (1)
3-35: Consider adding type annotations for the schema initializer configuration.While the current configuration works, adding proper TypeScript types would improve maintainability and catch potential configuration errors.
+import type { SchemaInitializerOptions } from '@tachybase/client'; + +const subTableActionInitializerConfig: SchemaInitializerOptions = { name: 'subTable:configureActions', title: "{{t('Configure actions')}}", icon: 'SettingOutlined', // ... rest of configuration +}; + -export const subTableActionInitializers = new SchemaInitializer({ - name: 'subTable:configureActions', - // ... configuration -}); +export const subTableActionInitializers = new SchemaInitializer(subTableActionInitializerConfig);packages/module-web/src/client/schema-initializer/items/BlockInitializer.tsx (1)
15-15: Add error handling for optional method calls.The optional chaining for
item?.schemaInitialize?.(s)is good, but consider adding error handling in case the method throws an exception.const s = merge(schema || {}, item.schema || {}); - item?.schemaInitialize?.(s); + try { + item?.schemaInitialize?.(s); + } catch (error) { + console.error('Schema initialization failed:', error); + } insert(s);packages/module-web/src/client/schema-initializer/items/RecordAssociationListBlockInitializer.tsx (1)
23-23: Icon doesn't match the block typeThe component uses
TableOutlinedicon for a List block initializer. Consider using a more appropriate icon likeUnorderedListOutlinedorOrderedListOutlinedto better represent the list block type.- icon={<TableOutlined />} + icon={<UnorderedListOutlined />}Don't forget to import the new icon:
-import { TableOutlined } from '@ant-design/icons'; +import { UnorderedListOutlined } from '@ant-design/icons';packages/module-web/src/client/schema-initializer/SchemaInitializerPlugin.ts (1)
3-63: Clean up commented importsThere are 60+ lines of commented imports. If these are planned features, consider adding a TODO comment explaining the timeline. If they're no longer needed, remove them to improve code clarity.
Would you like me to help identify which of these commented imports are still needed based on the current codebase?
packages/module-web/src/client/schema-initializer/items/RecordAssociationDetailsBlockInitializer.tsx (1)
22-22: Consider more appropriate icon for Details blockUsing
FormOutlinedfor a Details block might be misleading. Consider usingFileTextOutlinedorProfileOutlinedwhich better represents detail views.- icon={<FormOutlined />} + icon={<FileTextOutlined />}packages/client/src/schema-settings/VariableInput/hooks/useBaseVariable.tsx (1)
151-206: Consider using requestIdleCallback instead of setTimeoutUsing
setTimeoutwith a 5ms delay to prevent UI blocking is a workaround. Consider usingrequestIdleCallbackfor better performance optimization or proper async handling.return new Promise((resolve) => { - setTimeout(() => { + const processChildren = () => { const children = ( getChildren(returnFields(getFilterOptions(target, dataSource), option), { // ... parameters }) || [] ) // ... sorting logic if (children.length === 0) { option.disabled = true; option.isLeaf = true; resolve(); return; } option.children = children; resolve(); - }, 5); + }; + + if ('requestIdleCallback' in window) { + requestIdleCallback(processChildren); + } else { + setTimeout(processChildren, 0); + } });packages/module-web/src/client/schema-initializer/items/RecordAssociationGridCardBlockInitializer.tsx (1)
26-26: Icon consistency for GridCardUsing
TableOutlinedfor a GridCard block. Consider usingAppstoreOutlinedwhich better represents a grid/card layout.- icon={<TableOutlined />} + icon={<AppstoreOutlined />}packages/module-web/src/client/schema-initializer/items/RecordReadPrettyAssociationFormBlockInitializer.tsx (1)
61-103: Consider extracting shared schema creation logic.There's significant code duplication between the component's onClick handler and the hook's callbacks. Both implement similar logic for creating details UI schemas with templates.
Consider extracting the shared logic into a utility function:
function createDetailsSchemaWithTemplate(params: { collection: any; association: string; templateSchema?: any; mode?: string; componentName?: string; }) { const { collection, association, templateSchema, mode, componentName } = params; if (templateSchema && componentName === 'ReadPrettyFormItem') { const blockSchema = createDetailsUISchema({ dataSource: collection.dataSource, association, templateSchema, }); if (mode === 'reference') { blockSchema['x-template-key'] = templateSchema.key; } return blockSchema; } return templateSchema || createDetailsUISchema({ dataSource: collection.dataSource, association, }); }This would reduce duplication and make the code more maintainable.
packages/module-web/src/client/schema-initializer/buttons/RecordBlockInitializers.tsx (1)
357-366: Remove commented code.Commented-out code should be removed to keep the codebase clean. Version control preserves the history if needed.
- // { - // type: 'itemGroup', - // name: 'relationshipBlocks', - // title: '{{t("Relationship blocks")}}', - // useChildren: useRelationFields, - // useVisible() { - // const res = useRelationFields(); - // return res.length > 0; - // }, - // },packages/module-web/src/client/schema-initializer/buttons/FormItemInitializers.tsx (3)
23-32: Use map instead of forEach with push.The current pattern of using forEach with push can be simplified using map and filter.
- const res = []; - inheritFields.forEach((inherit) => { - Object.values(inherit)[0].length && - res.push({ - type: 'itemGroup', - divider: true, - title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')', - children: Object.values(inherit)[0], - }); - }); + const res = inheritFields + .filter((inherit) => Object.values(inherit)[0].length > 0) + .map((inherit) => ({ + type: 'itemGroup', + divider: true, + title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')', + children: Object.values(inherit)[0], + }));
70-81: Simplify nested ternary operators for better readability.The nested ternary operators make the code hard to read and maintain.
-'x-component-props': isFileCollection - ? { - fieldNames: { - label: 'preview', - value: 'id', - }, - } - : isAssociationField && fieldNames - ? { - fieldNames: { ...fieldNames, label: targetCollection?.titleField || fieldNames.label }, - } - : {}, +'x-component-props': (() => { + if (isFileCollection) { + return { + fieldNames: { + label: 'preview', + value: 'id', + }, + }; + } + if (isAssociationField && fieldNames) { + return { + fieldNames: { + ...fieldNames, + label: targetCollection?.titleField || fieldNames.label + }, + }; + } + return {}; +})(),
136-145: Use map for consistency with suggested refactoring.Apply the same map pattern for consistency if the previous suggestion is accepted.
- const res = []; - if (inheritFields?.length > 0) { - inheritFields.forEach((inherit) => { - Object.values(inherit)[0].length && - res.push({ - divider: true, - type: 'itemGroup', - title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')', - children: Object.values(inherit)[0], - }); - }); - } + const res = inheritFields?.length > 0 + ? inheritFields + .filter((inherit) => Object.values(inherit)[0].length > 0) + .map((inherit) => ({ + divider: true, + type: 'itemGroup', + title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')', + children: Object.values(inherit)[0], + })) + : [];packages/module-web/src/client/schema-initializer/components/CreateRecordAction.tsx (2)
25-102: Consolidate duplicate style definitions.The
designerandactionDesignerstyles are nearly identical. Consider extracting common styles.const useStyles = createStyles(({ css }) => { const commonStyle = css` position: relative; &:hover { .general-schema-designer { display: block; } } .general-schema-designer { position: absolute; z-index: 999; top: 0; bottom: 0; left: 0; right: 0; display: none; background: var(--colorBgSettingsHover); border: 0; pointer-events: none; > .general-schema-designer-icons { position: absolute; right: 2px; top: 2px; line-height: 16px; pointer-events: all; .ant-space-item { background-color: var(--colorSettings); color: #fff; line-height: 16px; width: 16px; padding-left: 1px; align-self: stretch; } } } `; return { designer: commonStyle, actionDesigner: commonStyle, }; });
383-383: Update function call to match suggested rename.If the
getLinkageCollectionfunction is renamed as suggested, update the call here.- const collectionName = getLinkageCollection(linkageFromForm, form, field); + const collectionName = parseLinkageCollectionVariable(linkageFromForm, form, field);packages/module-web/src/client/schema-initializer/components/assigned-field/AssignedField.tsx (3)
60-62: Remove commented codeDead code should be removed to improve code maintainability.
- // if (!field.validator && uiSchema['x-validator']) { - // field.validator = uiSchema['x-validator']; - // }
76-76: Optimize useEffect dependencyUsing
JSON.stringify(uiSchema)in the dependency array is inefficient as it runs on every render. Consider using a deep comparison hook or memoizing the stringified value.- }, [JSON.stringify(uiSchema)]); + }, [uiSchema]);If deep comparison is needed, consider using a custom hook like
useDeepCompareEffector memoizing the value:const uiSchemaKey = useMemo(() => JSON.stringify(uiSchema), [uiSchema]); useEffect(() => { // effect logic }, [uiSchemaKey]);
136-136: Optimize dependency array in useCallbackUsing
JSON.stringifywith_.omitin the dependency array is inefficient and runs on every render.Consider memoizing the filtered props:
const memoizedProps = useMemo(() => _.omit(props, 'value'), [props]); const renderSchemaComponent = useCallback( ({ value, onChange }): React.JSX.Element => { return <CollectionField {...props} value={value} onChange={onChange} />; }, [memoizedProps], );packages/module-web/src/client/schema-initializer/items/DataBlockInitializer.tsx (2)
103-105: Replace delete operator with undefined assignmentThe delete operator can impact performance. Use undefined assignment instead.
- delete container.style.height; + container.style.height = undefined;
116-126: Add return type annotation for hookThe hook should have a proper return type for better type safety.
-export function useMenuSearch({ +export function useMenuSearch({ data, openKeys, showType, hideSearch, }: { data: any[]; openKeys: string[]; showType?: boolean; hideSearch?: boolean; -}) { +}): MenuProps['items'] {packages/module-web/src/client/schema-initializer/items/CustomFilterFormItemInitializer.tsx (1)
162-322: Refactor long handleClick functionThis function is very long (160 lines) and handles multiple responsibilities. Consider breaking it down into smaller, more focused functions.
Consider extracting the schema generation and dialog configuration into separate functions:
const createFieldSchema = (values, cm, getInterface) => { const { title, component, collection, associationField, props } = values; const defaultSchema = getInterface(component)?.default?.uiSchema || {}; const titleField = cm.getCollection(collection)?.titleField; const name = uid(); return { ...defaultSchema, type: 'string', title: title, name: '__custom.' + name, // ... rest of schema }; }; const createDialogSchema = (fieldComponents, allCollection, t) => { return { properties: { name: { type: 'string', required: true }, // ... rest of properties } }; };packages/module-web/src/client/schema-initializer/buttons/TabPaneInitializers.tsx (1)
30-36: Replace delete operators with undefined assignmentsUsing the delete operator can impact performance. Assign undefined instead.
const deleteUid = (s: ISchema) => { - delete s['name']; - delete s['x-uid']; + s['name'] = undefined; + s['x-uid'] = undefined; Object.keys(s.properties || {}).forEach((key) => { deleteUid(s.properties[key]); }); };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (51)
apps/tego/src/plugin-presets.ts(1 hunks)package.json(1 hunks)packages/client/src/built-in/index.tsx(0 hunks)packages/client/src/schema-component/antd/action/index.tsx(1 hunks)packages/client/src/schema-component/common/index.ts(1 hunks)packages/client/src/schema-initializer/components/assigned-field/AssignedField.tsx(2 hunks)packages/client/src/schema-settings/SchemaSettingsDefaultValue.tsx(4 hunks)packages/client/src/schema-settings/VariableInput/VariableInput.tsx(3 hunks)packages/client/src/schema-settings/VariableInput/hooks/useBaseVariable.tsx(6 hunks)packages/client/src/schema-settings/VariableInput/hooks/useContextAssociationFields.tsx(5 hunks)packages/client/src/schema-settings/VariableInput/index.ts(1 hunks)packages/client/src/schema-settings/VariableInput/type.ts(1 hunks)packages/module-web/src/client/index.tsx(2 hunks)packages/module-web/src/client/schema-initializer/SchemaInitializerPlugin.ts(1 hunks)packages/module-web/src/client/schema-initializer/buttons/CustomFormItemInitializers.tsx(1 hunks)packages/module-web/src/client/schema-initializer/buttons/FormItemInitializers.tsx(1 hunks)packages/module-web/src/client/schema-initializer/buttons/RecordBlockInitializers.tsx(1 hunks)packages/module-web/src/client/schema-initializer/buttons/SubTableActionInitializers.tsx(1 hunks)packages/module-web/src/client/schema-initializer/buttons/TabPaneInitializers.tsx(1 hunks)packages/module-web/src/client/schema-initializer/buttons/index.ts(1 hunks)packages/module-web/src/client/schema-initializer/components/CreateRecordAction.tsx(1 hunks)packages/module-web/src/client/schema-initializer/components/DeletedField.tsx(1 hunks)packages/module-web/src/client/schema-initializer/components/assigned-field/AssignedField.tsx(1 hunks)packages/module-web/src/client/schema-initializer/components/assigned-field/index.ts(1 hunks)packages/module-web/src/client/schema-initializer/components/index.ts(1 hunks)packages/module-web/src/client/schema-initializer/hooks/useGetAriaLabelOfSchemaInitializer.ts(1 hunks)packages/module-web/src/client/schema-initializer/index.md(1 hunks)packages/module-web/src/client/schema-initializer/index.ts(1 hunks)packages/module-web/src/client/schema-initializer/items/ActionInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/BlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/CreateFilterActionInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/CreateResetActionInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/CustomFilterFormItemInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/CustomizeActionInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/DataBlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/DeleteEventActionInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/FilterBlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/G2PlotInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/InitializerWithSwitch.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/RecordAssociationBlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/RecordAssociationDetailsBlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/RecordAssociationFormBlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/RecordAssociationGridCardBlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/RecordAssociationListBlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/RecordReadPrettyAssociationFormBlockInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/SelectActionInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/SubmitActionInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/TableActionColumnInitializer.tsx(1 hunks)packages/module-web/src/client/schema-initializer/items/index.tsx(1 hunks)packages/module-web/src/client/schema-initializer/style.ts(1 hunks)packages/module-web/src/client/schema-initializer/utils.ts(1 hunks)
💤 Files with no reviewable changes (1)
- packages/client/src/built-in/index.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
packages/module-web/src/client/schema-initializer/items/CustomFilterFormItemInitializer.tsx
[error] 414-414: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
packages/module-web/src/client/schema-initializer/items/DataBlockInitializer.tsx
[error] 116-119: Avoid the delete operator which can impact performance.
Unsafe fix: Use an undefined assignment instead.
(lint/performance/noDelete)
packages/module-web/src/client/schema-initializer/buttons/TabPaneInitializers.tsx
[error] 31-31: Avoid the delete operator which can impact performance.
Unsafe fix: Use an undefined assignment instead.
(lint/performance/noDelete)
[error] 32-32: Avoid the delete operator which can impact performance.
Unsafe fix: Use an undefined assignment instead.
(lint/performance/noDelete)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: CI
🔇 Additional comments (28)
apps/tego/src/plugin-presets.ts (1)
18-20: Re-orderingwebcan affect plugin dependency resolution – re-verify boot sequence
webis now loaded immediately afterfileinstead of much later.
If any built-in/local plugin implicitly assumes thatwebis registered after something (e.g. it monkey-patches hooks exported byweb), this silent reorder could break runtime.
No problems are obvious from this diff alone, but please run an integration smoke-test (all presets enabled) before merging.packages/module-web/src/client/schema-initializer/components/index.ts (1)
1-2: 👍 Consolidated barrel exportBarrel file keeps import paths short; no issues spotted.
packages/client/src/schema-component/common/index.ts (1)
3-3: LGTM - Clean export addition.The export follows the existing pattern and makes the
parseVariablesutility publicly available, which aligns with the schema initializer refactoring objectives.packages/client/src/schema-initializer/components/assigned-field/AssignedField.tsx (2)
16-16: LGTM - Type system improvement.The change from
OptiontoVariableInputOptionprovides better type specificity and aligns with the broader type system refinements mentioned in the AI summary.
115-115: LGTM - Consistent type annotation update.The type annotation update correctly corresponds to the import change, maintaining type consistency throughout the callback function.
packages/module-web/src/client/schema-initializer/items/SubmitActionInitializer.tsx (1)
5-19: LGTM - Well-structured submit action schema.The component properly defines a submit action schema with appropriate properties:
- Correct action type and component
- Proper toolbar and settings configuration
- HTML submit behavior configured correctly
- Props are properly forwarded to ActionInitializer
The implementation follows good React patterns and schema conventions.
packages/client/src/schema-settings/VariableInput/index.ts (1)
3-4: LGTM! Clean export consolidation.The new exports for
formatVariableScoputils andVariableInputOptiontype are correctly formatted and align with the broader type refactoring effort across the codebase.packages/client/src/schema-settings/SchemaSettingsDefaultValue.tsx (3)
24-24: LGTM! Consistent type refactoring.The import change from
OptiontoVariableInputOptionaligns with the broader type standardization effort across the codebase.
80-80: LGTM! Type annotation updated correctly.The parameter type change to
VariableInputOption[]maintains consistency with the imported type.
117-117: LGTM! Clean object spread simplification.Removing the redundant fallback expressions
|| {}simplifies the code without changing behavior, as the spread operator handles undefined values appropriately.Also applies to: 158-158
packages/module-web/src/client/schema-initializer/style.ts (1)
3-17: LGTM! Well-structured styling module.The style definitions are clean and appropriate for menu components:
- Reasonable 50vh max-height constraint prevents overly tall menus
- Vertical scrolling enables navigation of long menu lists
- Proper use of theme tokens for consistent design system integration
- Descriptive naming convention for style objects
packages/module-web/src/client/schema-initializer/items/DeleteEventActionInitializer.tsx (1)
16-16: CalendarV2.DeleteEvent is properly exported and available at runtime
- packages/plugin-block-calendar/src/client/calendar/DeleteEvent.tsx defines and exports
DeleteEvent- packages/plugin-block-calendar/src/client/calendar/index.ts attaches it via
Calendar.DeleteEvent = DeleteEventand then aliasesconst CalendarV2 = Calendar- The schema initializer’s
'x-component': 'CalendarV2.DeleteEvent'will resolve correctlyNo further changes required.
packages/client/src/schema-settings/VariableInput/type.ts (1)
5-18: LGTM! Improved type name clarity.The rename from
OptiontoVariableInputOptionprovides better semantic clarity and reduces potential naming conflicts. All internal references have been consistently updated.packages/module-web/src/client/schema-initializer/items/index.tsx (1)
1-24: LGTM! Well-organized index file.The index file provides a clean consolidation of schema initializer exports with good organization:
- Clear separation of association filter exports with comments
- Logical grouping of related initializers
- Consistent export patterns
packages/module-web/src/client/index.tsx (2)
2-2: LGTM: Proper import of SchemaInitializerPlugin.The import statement correctly includes the new
SchemaInitializerPluginfor integration into the module.
27-33: Verify async support inPlugin.afterAddI wasn’t able to locate the base
Pluginclass or itsafterAddsignature in the codebase. Please ensure that theafterAddhook in yourPluginbase class is declared to support async operations (i.e., markedasyncor returning aPromise<void>) so that awaiting in subclasses works correctly.
- Confirm the
afterAddmethod signature in thePluginbase class- Update it to
async afterAdd()orafterAdd(): Promise<void>if neededpackages/module-web/src/client/schema-initializer/buttons/index.ts (1)
1-8: LGTM: Well-organized barrel export file.The export structure is clean and follows good practices:
- Clear grouping of related button initializers
- Descriptive comment for the association filter export
- Consistent use of wildcard exports for related modules
packages/module-web/src/client/schema-initializer/index.md (1)
1-72: Excellent comprehensive documentation.This documentation file provides thorough coverage of the SchemaInitializer feature:
- Clear explanation of insertion positions with visual code examples
- Well-organized sections covering basic to advanced usage
- Multiple practical examples with references to demo files
- Good coverage of customization options and dynamic features
The documentation will be valuable for developers using this schema initializer system.
packages/module-web/src/client/schema-initializer/buttons/SubTableActionInitializers.tsx (1)
19-19: String references verified – no changes needed.Confirmed that both
CreateActionInitializerandBulkDestroyActionInitializerare exported in
packages/client/src/modules/actions/... and imported & registered in
packages/client/src/schema-initializer/SchemaInitializerPlugin.ts. The string keys in
SubTableActionInitializers.tsx will resolve correctly at runtime.packages/client/src/schema-settings/VariableInput/VariableInput.tsx (1)
17-17: LGTM! Type refinement improves specificity.The consistent replacement of the generic
Optiontype withVariableInputOptionthroughout the file enhances type safety and specificity without altering functionality.Also applies to: 60-60, 246-246, 253-253
packages/client/src/schema-settings/VariableInput/hooks/useContextAssociationFields.tsx (1)
8-8: LGTM! Consistent type refinement across the hook.The systematic replacement of
OptionwithVariableInputOptionmaintains consistency with the broader type refinement effort while preserving all functionality.Also applies to: 25-25, 34-34, 36-36, 82-82, 136-136
packages/module-web/src/client/schema-initializer/items/RecordAssociationBlockInitializer.tsx (2)
11-14: Question: Why is new component immediately deprecated?It's unusual to introduce a new component with a
@deprecatedannotation. This suggests the component might be transitional or part of a migration strategy. Consider documenting the migration path or timeline for replacement.
6-6: Note: Usage of deprecated collection manager hooks.The component uses
useCollectionManager_deprecatedwhich suggests this code might need updating when the deprecated hook is removed. Monitor for migration opportunities to the non-deprecated version.Also applies to: 19-19, 48-48
packages/module-web/src/client/schema-initializer/index.ts (1)
1-21: LGTM! Clean module organization with appropriate export structure.The barrel export pattern provides a clean public API and logical grouping of related functionality. The mix of wildcard and named exports is appropriate for the different module types.
packages/client/src/schema-settings/VariableInput/hooks/useBaseVariable.tsx (1)
7-7: Type refinement looks goodThe change from generic
Optionto specificVariableInputOptionimproves type safety and code clarity.packages/module-web/src/client/schema-initializer/items/RecordAssociationGridCardBlockInitializer.tsx (1)
11-14: Clarify deprecation statusThis component is marked as deprecated but is being added as new code. This is confusing - why introduce already-deprecated functionality? Consider either:
- Removing the deprecation if this is intended for use
- Not adding this component if it's truly deprecated
- Adding more context about the deprecation timeline and migration path
packages/module-web/src/client/schema-initializer/buttons/FormItemInitializers.tsx (1)
46-47: Address the FIXME comment.The FIXME comment indicates unresolved technical debt that should be addressed.
Could you provide more context about what needs to be fixed with the
readPrettyvalue? This will help in properly addressing the issue.packages/module-web/src/client/schema-initializer/items/CustomFilterFormItemInitializer.tsx (1)
389-401: Add protection against potential infinite loopThe while loop could run indefinitely if there are circular references in the field relationships.
let cName: any = collectionName; let field: any; let title = Schema.compile(collection?.title, { t: i18n.t }); + const visited = new Set<string>(); while (cName && fieldNames.length > 0) { + if (visited.has(cName)) { + console.warn('Circular reference detected in collection fields'); + break; + } + visited.add(cName); const fileName = fieldNames.shift(); field = getCollectionField(`${cName}.${fileName}`);Likely an incorrect or invalid review comment.
| "dependencies": { | ||
| "ts-morph": "^26.0.0" | ||
| }, |
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.
💡 Verification agent
🧩 Analysis chain
ts-morph is heavy – confirm it’s really needed at runtime
ts-morph (~13 MB install, many transitive deps) has been added to the main dependencies block, which means:
- It ships to production containers/functions even if used only in build-time tooling.
- It increases cold-start size for serverless environments.
If the new schema-initializer code imports ts-morph only during code-gen/build (e.g. inside a CLI), move it to devDependencies:
- "dependencies": {
- "ts-morph": "^26.0.0"
- },
+ "devDependencies": {
+ "ts-morph": "^26.0.0",
+ ...
+ },Keep it here only when the browser / Node runtime dynamically requires it at execution time.
🏁 Script executed:
#!/bin/bash
# Find ts-morph entry in package.json
rg -n '"ts-morph"' -n package.json
# Search for any imports or requires of ts-morph in the codebase
rg -n "from ['\"]ts-morph['\"]|require\(['\"]ts-morph['\"]\)" .Length of output: 139
Move ts-morph into devDependencies
We searched the repo and found no import or require of ts-morph in runtime code, so it isn’t used in production. To avoid bloating your production bundle/container, please relocate it to devDependencies.
• File: package.json (line 40)
"dependencies": {
- "ts-morph": "^26.0.0"
},
+ "devDependencies": {
+ "ts-morph": "^26.0.0",
+ …other dev deps…
+ },📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "dependencies": { | |
| "ts-morph": "^26.0.0" | |
| }, | |
| "dependencies": { | |
| }, | |
| "devDependencies": { | |
| "ts-morph": "^26.0.0", | |
| …other dev deps… | |
| }, |
🤖 Prompt for AI Agents
In package.json around lines 39 to 41, the dependency "ts-morph" is currently
listed under "dependencies" but is not used in production runtime code. Move
"ts-morph" from the "dependencies" section to the "devDependencies" section to
prevent it from being included in the production bundle or container.
| inheritFields.forEach((inherit) => { | ||
| Object.values(inherit)[0].length && | ||
| res.push({ | ||
| type: 'itemGroup', | ||
| divider: true, | ||
| title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')', | ||
| children: Object.values(inherit)[0], | ||
| }); | ||
| }); |
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.
🛠️ Refactor suggestion
Simplify complex object manipulation and improve type safety.
The current implementation has complex nested object access patterns that could be fragile and lacks proper type safety.
Consider refactoring for better readability and type safety:
- const res = [];
- inheritFields.forEach((inherit) => {
- Object.values(inherit)[0].length &&
- res.push({
- type: 'itemGroup',
- divider: true,
- title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')',
- children: Object.values(inherit)[0],
- });
- });
+ const res = inheritFields.reduce((acc, inherit) => {
+ const [collectionName, fields] = Object.entries(inherit)[0];
+ if (fields?.length > 0) {
+ acc.push({
+ type: 'itemGroup',
+ divider: true,
+ title: `${t('Parent collection fields')} (${compile(collectionName)})`,
+ children: fields,
+ });
+ }
+ return acc;
+ }, []);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| inheritFields.forEach((inherit) => { | |
| Object.values(inherit)[0].length && | |
| res.push({ | |
| type: 'itemGroup', | |
| divider: true, | |
| title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')', | |
| children: Object.values(inherit)[0], | |
| }); | |
| }); | |
| const res = inheritFields.reduce((acc, inherit) => { | |
| const [collectionName, fields] = Object.entries(inherit)[0]; | |
| if (fields?.length > 0) { | |
| acc.push({ | |
| type: 'itemGroup', | |
| divider: true, | |
| title: `${t('Parent collection fields')} (${compile(collectionName)})`, | |
| children: fields, | |
| }); | |
| } | |
| return acc; | |
| }, []); |
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/buttons/CustomFormItemInitializers.tsx
around lines 17 to 25, the code uses complex nested object access with
Object.values and Object.keys which is fragile and not type-safe. Refactor by
explicitly typing the inheritFields array and destructuring the objects to
access keys and values directly. Replace Object.values(inherit)[0] and
Object.keys(inherit)[0] with clearer variable names and direct property access
to improve readability and ensure type safety.
| const recursiveParent = (schema: Schema) => { | ||
| if (!schema) return null; | ||
|
|
||
| if (schema['x-decorator']?.endsWith('BlockProvider')) { | ||
| return schema['x-decorator-props']?.['collection']; | ||
| } else { | ||
| return recursiveParent(schema.parent); | ||
| } | ||
| }; |
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.
Add recursion depth limit to prevent stack overflow.
The recursiveParent function could cause stack overflow with deeply nested or circular schema references.
Consider adding a depth limit:
-const recursiveParent = (schema: Schema) => {
+const recursiveParent = (schema: Schema, depth = 0, maxDepth = 50) => {
if (!schema) return null;
+ if (depth > maxDepth) {
+ console.warn('Maximum recursion depth reached in recursiveParent');
+ return null;
+ }
if (schema['x-decorator']?.endsWith('BlockProvider')) {
return schema['x-decorator-props']?.['collection'];
} else {
- return recursiveParent(schema.parent);
+ return recursiveParent(schema.parent, depth + 1, maxDepth);
}
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const recursiveParent = (schema: Schema) => { | |
| if (!schema) return null; | |
| if (schema['x-decorator']?.endsWith('BlockProvider')) { | |
| return schema['x-decorator-props']?.['collection']; | |
| } else { | |
| return recursiveParent(schema.parent); | |
| } | |
| }; | |
| const recursiveParent = (schema: Schema, depth = 0, maxDepth = 50) => { | |
| if (!schema) return null; | |
| if (depth > maxDepth) { | |
| console.warn('Maximum recursion depth reached in recursiveParent'); | |
| return null; | |
| } | |
| if (schema['x-decorator']?.endsWith('BlockProvider')) { | |
| return schema['x-decorator-props']?.['collection']; | |
| } else { | |
| return recursiveParent(schema.parent, depth + 1, maxDepth); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/buttons/RecordBlockInitializers.tsx
around lines 25 to 33, the recursiveParent function lacks a recursion depth
limit, risking stack overflow on deeply nested or circular schema references.
Modify the function to accept a depth parameter that increments with each
recursive call and add a maximum depth check to stop recursion and return null
if the limit is exceeded, preventing infinite recursion and stack overflow.
| export const canMakeAssociationBlock = (field) => { | ||
| return ['linkTo', 'subTable', 'o2m', 'm2m', 'obo', 'oho', 'o2o', 'm2o'].includes(field.interface); | ||
| }; |
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.
Add null check for field parameter.
The function doesn't validate the field parameter before accessing its properties.
export const canMakeAssociationBlock = (field) => {
+ if (!field?.interface) return false;
return ['linkTo', 'subTable', 'o2m', 'm2m', 'obo', 'oho', 'o2o', 'm2o'].includes(field.interface);
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const canMakeAssociationBlock = (field) => { | |
| return ['linkTo', 'subTable', 'o2m', 'm2m', 'obo', 'oho', 'o2o', 'm2o'].includes(field.interface); | |
| }; | |
| export const canMakeAssociationBlock = (field) => { | |
| if (!field?.interface) return false; | |
| return ['linkTo', 'subTable', 'o2m', 'm2m', 'obo', 'oho', 'o2o', 'm2o'].includes(field.interface); | |
| }; |
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/buttons/RecordBlockInitializers.tsx
around lines 35 to 37, the function canMakeAssociationBlock accesses
field.interface without checking if field is null or undefined. Add a null check
for the field parameter at the start of the function to ensure it is not null or
undefined before accessing its properties, returning false if the check fails.
| createBlockSchema: ({ item, fromOthersInPopup }) => { | ||
| if (fromOthersInPopup) { | ||
| return createFormBlock({ item, fromOthersInPopup }); | ||
| } | ||
| createAssociationFormBlock({ item }); | ||
| }, |
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.
Add missing return statements in createBlockSchema.
The createBlockSchema function doesn't return values from the function calls, which might cause issues if the caller expects a return value.
createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
return createFormBlock({ item, fromOthersInPopup });
}
- createAssociationFormBlock({ item });
+ return createAssociationFormBlock({ item });
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| createBlockSchema: ({ item, fromOthersInPopup }) => { | |
| if (fromOthersInPopup) { | |
| return createFormBlock({ item, fromOthersInPopup }); | |
| } | |
| createAssociationFormBlock({ item }); | |
| }, | |
| createBlockSchema: ({ item, fromOthersInPopup }) => { | |
| if (fromOthersInPopup) { | |
| return createFormBlock({ item, fromOthersInPopup }); | |
| } | |
| return createAssociationFormBlock({ item }); | |
| }, |
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/buttons/RecordBlockInitializers.tsx
around lines 163 to 168, the createBlockSchema function is missing return
statements for the createAssociationFormBlock call. Add a return statement
before createAssociationFormBlock({ item }) so that both branches of the
conditional return their results, ensuring the function consistently returns a
value.
| const createAssociationListBlock = useCallback( | ||
| ({ item }) => { | ||
| const field = item.associationField; | ||
| const collection = getCollection(field.target); | ||
|
|
||
| insert( | ||
| createListBlockUISchema({ | ||
| rowKey: collection.filterTargetKey, | ||
| dataSource: collection.dataSource, | ||
| association: `${field.collectionName}.${field.name}`, | ||
| }), | ||
| ); | ||
| }, |
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.
🛠️ Refactor suggestion
Add defensive null checks
The callback directly accesses nested properties without checking if they exist, which could cause runtime errors.
({ item }) => {
const field = item.associationField;
+ if (!field || !field.target) {
+ console.warn('Invalid association field provided');
+ return;
+ }
const collection = getCollection(field.target);
+ if (!collection) {
+ console.warn('Collection not found for target:', field.target);
+ return;
+ }
insert(
createListBlockUISchema({
rowKey: collection.filterTargetKey,
dataSource: collection.dataSource,
association: `${field.collectionName}.${field.name}`,
}),
);
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const createAssociationListBlock = useCallback( | |
| ({ item }) => { | |
| const field = item.associationField; | |
| const collection = getCollection(field.target); | |
| insert( | |
| createListBlockUISchema({ | |
| rowKey: collection.filterTargetKey, | |
| dataSource: collection.dataSource, | |
| association: `${field.collectionName}.${field.name}`, | |
| }), | |
| ); | |
| }, | |
| const createAssociationListBlock = useCallback( | |
| ({ item }) => { | |
| const field = item.associationField; | |
| if (!field || !field.target) { | |
| console.warn('Invalid association field provided'); | |
| return; | |
| } | |
| const collection = getCollection(field.target); | |
| if (!collection) { | |
| console.warn('Collection not found for target:', field.target); | |
| return; | |
| } | |
| insert( | |
| createListBlockUISchema({ | |
| rowKey: collection.filterTargetKey, | |
| dataSource: collection.dataSource, | |
| association: `${field.collectionName}.${field.name}`, | |
| }), | |
| ); | |
| }, | |
| [getCollection, insert], | |
| ); |
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/items/RecordAssociationListBlockInitializer.tsx
around lines 48 to 60, the createAssociationListBlock callback accesses nested
properties like item.associationField and field.target without null checks,
risking runtime errors. Add defensive checks to ensure item,
item.associationField, and field.target exist before accessing their properties,
and handle cases where these might be undefined to prevent crashes.
| onClick={async ({ item }) => { | ||
| if (item.template) { | ||
| const s = await getTemplateSchemaByMode(item); | ||
| if (item.template.componentName === 'ReadPrettyFormItem') { | ||
| const blockSchema = createDetailsUISchema({ | ||
| dataSource: collection.dataSource, | ||
| association: resource, | ||
| templateSchema: s, | ||
| }); | ||
| if (item.mode === 'reference') { | ||
| blockSchema['x-template-key'] = item.template.key; | ||
| } | ||
| insert(blockSchema); | ||
| } else { | ||
| insert(s); | ||
| } |
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.
Add error handling for async template fetching.
The async call to getTemplateSchemaByMode could fail, but there's no error handling. This could cause unhandled promise rejections.
Consider wrapping the async operation in a try-catch block:
onClick={async ({ item }) => {
+ try {
if (item.template) {
const s = await getTemplateSchemaByMode(item);
if (item.template.componentName === 'ReadPrettyFormItem') {
const blockSchema = createDetailsUISchema({
dataSource: collection.dataSource,
association: resource,
templateSchema: s,
});
if (item.mode === 'reference') {
blockSchema['x-template-key'] = item.template.key;
}
insert(blockSchema);
} else {
insert(s);
}
} else {
insert(
createDetailsUISchema({
association: resource,
dataSource: collection.dataSource,
}),
);
}
+ } catch (error) {
+ console.error('Failed to create block schema:', error);
+ // Consider showing user-friendly error message
+ }
}}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onClick={async ({ item }) => { | |
| if (item.template) { | |
| const s = await getTemplateSchemaByMode(item); | |
| if (item.template.componentName === 'ReadPrettyFormItem') { | |
| const blockSchema = createDetailsUISchema({ | |
| dataSource: collection.dataSource, | |
| association: resource, | |
| templateSchema: s, | |
| }); | |
| if (item.mode === 'reference') { | |
| blockSchema['x-template-key'] = item.template.key; | |
| } | |
| insert(blockSchema); | |
| } else { | |
| insert(s); | |
| } | |
| onClick={async ({ item }) => { | |
| try { | |
| if (item.template) { | |
| const s = await getTemplateSchemaByMode(item); | |
| if (item.template.componentName === 'ReadPrettyFormItem') { | |
| const blockSchema = createDetailsUISchema({ | |
| dataSource: collection.dataSource, | |
| association: resource, | |
| templateSchema: s, | |
| }); | |
| if (item.mode === 'reference') { | |
| blockSchema['x-template-key'] = item.template.key; | |
| } | |
| insert(blockSchema); | |
| } else { | |
| insert(s); | |
| } | |
| } else { | |
| insert( | |
| createDetailsUISchema({ | |
| association: resource, | |
| dataSource: collection.dataSource, | |
| }), | |
| ); | |
| } | |
| } catch (error) { | |
| console.error('Failed to create block schema:', error); | |
| // Consider showing user-friendly error message | |
| } | |
| }} |
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/items/RecordReadPrettyAssociationFormBlockInitializer.tsx
around lines 31 to 46, the async call to getTemplateSchemaByMode lacks error
handling, risking unhandled promise rejections. Wrap the entire async onClick
handler logic in a try-catch block to catch any errors from
getTemplateSchemaByMode or subsequent code, and handle or log the error
appropriately to prevent unhandled exceptions.
| async load() { | ||
| this.app.addComponents({ | ||
| ...initializerComponents, | ||
| ...items, | ||
| DestroyActionInitializer, | ||
| CreateFormBlockInitializer, | ||
| FormBlockInitializer, | ||
| RecordFormBlockInitializer, | ||
| TableBlockInitializer, | ||
| TableSelectorInitializer, | ||
| RecordReadPrettyFormBlockInitializer, | ||
| DetailsBlockInitializer, | ||
| ListBlockInitializer, | ||
| GridCardBlockInitializer, | ||
| FilterFormBlockInitializer, | ||
| FilterTreeBlockInitializer, | ||
| FilterCollapseBlockInitializer, | ||
| MarkdownBlockInitializer, | ||
| MarkdownFormItemInitializer, | ||
| TableCollectionFieldInitializer, | ||
| CollectionFieldInitializer, | ||
| CreateActionInitializer, | ||
| CustomizeAddRecordActionInitializer, | ||
| CreateChildInitializer, | ||
| ViewActionInitializer, | ||
| UpdateActionInitializer, | ||
| PopupActionInitializer, | ||
| SaveRecordActionInitializer, | ||
| UpdateRecordActionInitializer, | ||
| CreateSubmitActionInitializer, | ||
| UpdateSubmitActionInitializer, | ||
| BulkDestroyActionInitializer, | ||
| ExpandableActionInitializer, | ||
| DisassociateActionInitializer, | ||
| FilterActionInitializer, | ||
| RefreshActionInitializer, | ||
| FilterFormItemCustom, | ||
| AssociateActionInitializer, | ||
| AssociateActionProvider, | ||
| } as any); | ||
|
|
||
| this.app.schemaInitializerManager.add(blockInitializers); | ||
| this.app.schemaInitializerManager.add(tableActionInitializers); | ||
| this.app.schemaInitializerManager.add(tableColumnInitializers); | ||
| this.app.schemaInitializerManager.add(tableActionColumnInitializers); | ||
| this.app.schemaInitializerManager.add(formItemInitializers); | ||
| this.app.schemaInitializerManager.add(formActionInitializers); | ||
| this.app.schemaInitializerManager.add(detailsActionInitializers); | ||
| this.app.schemaInitializerManager.add(readPrettyFormItemInitializers); | ||
| this.app.schemaInitializerManager.add(readPrettyFormActionInitializers); | ||
| this.app.schemaInitializerManager.add(createFormBlockInitializers); | ||
| this.app.schemaInitializerManager.add(customizeCreateFormBlockInitializers); | ||
| this.app.schemaInitializerManager.add(customFormItemInitializers); | ||
| this.app.schemaInitializerManager.add(filterFormActionInitializers); | ||
| this.app.schemaInitializerManager.add(filterTreeActionInitializers); | ||
| this.app.schemaInitializerManager.add(createFormActionInitializers); | ||
| this.app.schemaInitializerManager.add(updateFormActionInitializers); | ||
| this.app.schemaInitializerManager.add(filterFormItemInitializers); | ||
| this.app.schemaInitializerManager.add(gridCardActionInitializers); | ||
| this.app.schemaInitializerManager.add(gridCardItemActionInitializers); | ||
|
|
||
| this.app.schemaInitializerManager.add(listActionInitializers); | ||
| this.app.schemaInitializerManager.add(listItemActionInitializers); | ||
| this.app.schemaInitializerManager.add(recordBlockInitializers); | ||
| this.app.schemaInitializerManager.add(recordFormBlockInitializers); | ||
| this.app.schemaInitializerManager.add(subTableActionInitializers); | ||
| this.app.schemaInitializerManager.add(tableSelectorInitializers); | ||
| this.app.schemaInitializerManager.add(tabPaneInitializers_deprecated); | ||
| this.app.schemaInitializerManager.add(tabPaneInitializersForRecordBlock); | ||
| this.app.schemaInitializerManager.add(tabPaneInitializersForBulkEditFormBlock); | ||
| this.app.schemaInitializerManager.add(menuItemInitializer); | ||
| this.app.schemaInitializerManager.add(tabPaneInitializers); | ||
| } | ||
| } |
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.
🛠️ Refactor suggestion
Add error handling for plugin loading
The async load method could fail during component or initializer registration but lacks error handling.
async load() {
+ try {
this.app.addComponents({
// ... components
});
this.app.schemaInitializerManager.add(blockInitializers);
// ... other initializers
+ } catch (error) {
+ console.error('Failed to load SchemaInitializerPlugin:', error);
+ throw error; // Re-throw to notify the plugin system
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async load() { | |
| this.app.addComponents({ | |
| ...initializerComponents, | |
| ...items, | |
| DestroyActionInitializer, | |
| CreateFormBlockInitializer, | |
| FormBlockInitializer, | |
| RecordFormBlockInitializer, | |
| TableBlockInitializer, | |
| TableSelectorInitializer, | |
| RecordReadPrettyFormBlockInitializer, | |
| DetailsBlockInitializer, | |
| ListBlockInitializer, | |
| GridCardBlockInitializer, | |
| FilterFormBlockInitializer, | |
| FilterTreeBlockInitializer, | |
| FilterCollapseBlockInitializer, | |
| MarkdownBlockInitializer, | |
| MarkdownFormItemInitializer, | |
| TableCollectionFieldInitializer, | |
| CollectionFieldInitializer, | |
| CreateActionInitializer, | |
| CustomizeAddRecordActionInitializer, | |
| CreateChildInitializer, | |
| ViewActionInitializer, | |
| UpdateActionInitializer, | |
| PopupActionInitializer, | |
| SaveRecordActionInitializer, | |
| UpdateRecordActionInitializer, | |
| CreateSubmitActionInitializer, | |
| UpdateSubmitActionInitializer, | |
| BulkDestroyActionInitializer, | |
| ExpandableActionInitializer, | |
| DisassociateActionInitializer, | |
| FilterActionInitializer, | |
| RefreshActionInitializer, | |
| FilterFormItemCustom, | |
| AssociateActionInitializer, | |
| AssociateActionProvider, | |
| } as any); | |
| this.app.schemaInitializerManager.add(blockInitializers); | |
| this.app.schemaInitializerManager.add(tableActionInitializers); | |
| this.app.schemaInitializerManager.add(tableColumnInitializers); | |
| this.app.schemaInitializerManager.add(tableActionColumnInitializers); | |
| this.app.schemaInitializerManager.add(formItemInitializers); | |
| this.app.schemaInitializerManager.add(formActionInitializers); | |
| this.app.schemaInitializerManager.add(detailsActionInitializers); | |
| this.app.schemaInitializerManager.add(readPrettyFormItemInitializers); | |
| this.app.schemaInitializerManager.add(readPrettyFormActionInitializers); | |
| this.app.schemaInitializerManager.add(createFormBlockInitializers); | |
| this.app.schemaInitializerManager.add(customizeCreateFormBlockInitializers); | |
| this.app.schemaInitializerManager.add(customFormItemInitializers); | |
| this.app.schemaInitializerManager.add(filterFormActionInitializers); | |
| this.app.schemaInitializerManager.add(filterTreeActionInitializers); | |
| this.app.schemaInitializerManager.add(createFormActionInitializers); | |
| this.app.schemaInitializerManager.add(updateFormActionInitializers); | |
| this.app.schemaInitializerManager.add(filterFormItemInitializers); | |
| this.app.schemaInitializerManager.add(gridCardActionInitializers); | |
| this.app.schemaInitializerManager.add(gridCardItemActionInitializers); | |
| this.app.schemaInitializerManager.add(listActionInitializers); | |
| this.app.schemaInitializerManager.add(listItemActionInitializers); | |
| this.app.schemaInitializerManager.add(recordBlockInitializers); | |
| this.app.schemaInitializerManager.add(recordFormBlockInitializers); | |
| this.app.schemaInitializerManager.add(subTableActionInitializers); | |
| this.app.schemaInitializerManager.add(tableSelectorInitializers); | |
| this.app.schemaInitializerManager.add(tabPaneInitializers_deprecated); | |
| this.app.schemaInitializerManager.add(tabPaneInitializersForRecordBlock); | |
| this.app.schemaInitializerManager.add(tabPaneInitializersForBulkEditFormBlock); | |
| this.app.schemaInitializerManager.add(menuItemInitializer); | |
| this.app.schemaInitializerManager.add(tabPaneInitializers); | |
| } | |
| } | |
| async load() { | |
| try { | |
| this.app.addComponents({ | |
| ...initializerComponents, | |
| ...items, | |
| DestroyActionInitializer, | |
| CreateFormBlockInitializer, | |
| FormBlockInitializer, | |
| RecordFormBlockInitializer, | |
| TableBlockInitializer, | |
| TableSelectorInitializer, | |
| RecordReadPrettyFormBlockInitializer, | |
| DetailsBlockInitializer, | |
| ListBlockInitializer, | |
| GridCardBlockInitializer, | |
| FilterFormBlockInitializer, | |
| FilterTreeBlockInitializer, | |
| FilterCollapseBlockInitializer, | |
| MarkdownBlockInitializer, | |
| MarkdownFormItemInitializer, | |
| TableCollectionFieldInitializer, | |
| CollectionFieldInitializer, | |
| CreateActionInitializer, | |
| CustomizeAddRecordActionInitializer, | |
| CreateChildInitializer, | |
| ViewActionInitializer, | |
| UpdateActionInitializer, | |
| PopupActionInitializer, | |
| SaveRecordActionInitializer, | |
| UpdateRecordActionInitializer, | |
| CreateSubmitActionInitializer, | |
| UpdateSubmitActionInitializer, | |
| BulkDestroyActionInitializer, | |
| ExpandableActionInitializer, | |
| DisassociateActionInitializer, | |
| FilterActionInitializer, | |
| RefreshActionInitializer, | |
| FilterFormItemCustom, | |
| AssociateActionInitializer, | |
| AssociateActionProvider, | |
| } as any); | |
| this.app.schemaInitializerManager.add(blockInitializers); | |
| this.app.schemaInitializerManager.add(tableActionInitializers); | |
| this.app.schemaInitializerManager.add(tableColumnInitializers); | |
| this.app.schemaInitializerManager.add(tableActionColumnInitializers); | |
| this.app.schemaInitializerManager.add(formItemInitializers); | |
| this.app.schemaInitializerManager.add(formActionInitializers); | |
| this.app.schemaInitializerManager.add(detailsActionInitializers); | |
| this.app.schemaInitializerManager.add(readPrettyFormItemInitializers); | |
| this.app.schemaInitializerManager.add(readPrettyFormActionInitializers); | |
| this.app.schemaInitializerManager.add(createFormBlockInitializers); | |
| this.app.schemaInitializerManager.add(customizeCreateFormBlockInitializers); | |
| this.app.schemaInitializerManager.add(customFormItemInitializers); | |
| this.app.schemaInitializerManager.add(filterFormActionInitializers); | |
| this.app.schemaInitializerManager.add(filterTreeActionInitializers); | |
| this.app.schemaInitializerManager.add(createFormActionInitializers); | |
| this.app.schemaInitializerManager.add(updateFormActionInitializers); | |
| this.app.schemaInitializerManager.add(filterFormItemInitializers); | |
| this.app.schemaInitializerManager.add(gridCardActionInitializers); | |
| this.app.schemaInitializerManager.add(gridCardItemActionInitializers); | |
| this.app.schemaInitializerManager.add(listActionInitializers); | |
| this.app.schemaInitializerManager.add(listItemActionInitializers); | |
| this.app.schemaInitializerManager.add(recordBlockInitializers); | |
| this.app.schemaInitializerManager.add(recordFormBlockInitializers); | |
| this.app.schemaInitializerManager.add(subTableActionInitializers); | |
| this.app.schemaInitializerManager.add(tableSelectorInitializers); | |
| this.app.schemaInitializerManager.add(tabPaneInitializers_deprecated); | |
| this.app.schemaInitializerManager.add(tabPaneInitializersForRecordBlock); | |
| this.app.schemaInitializerManager.add(tabPaneInitializersForBulkEditFormBlock); | |
| this.app.schemaInitializerManager.add(menuItemInitializer); | |
| this.app.schemaInitializerManager.add(tabPaneInitializers); | |
| } catch (error) { | |
| console.error('Failed to load SchemaInitializerPlugin:', error); | |
| throw error; // Re-throw to notify the plugin system | |
| } | |
| } |
🤖 Prompt for AI Agents
In packages/module-web/src/client/schema-initializer/SchemaInitializerPlugin.ts
between lines 78 and 151, the async load method lacks error handling for
potential failures during component or initializer registration. Wrap the entire
load method's logic in a try-catch block to catch any errors, and in the catch
block, log or handle the error appropriately to prevent unhandled promise
rejections and improve robustness.
| this.app.addComponents({ | ||
| ...initializerComponents, | ||
| ...items, | ||
| DestroyActionInitializer, | ||
| CreateFormBlockInitializer, | ||
| FormBlockInitializer, | ||
| RecordFormBlockInitializer, | ||
| TableBlockInitializer, | ||
| TableSelectorInitializer, | ||
| RecordReadPrettyFormBlockInitializer, | ||
| DetailsBlockInitializer, | ||
| ListBlockInitializer, | ||
| GridCardBlockInitializer, | ||
| FilterFormBlockInitializer, | ||
| FilterTreeBlockInitializer, | ||
| FilterCollapseBlockInitializer, | ||
| MarkdownBlockInitializer, | ||
| MarkdownFormItemInitializer, | ||
| TableCollectionFieldInitializer, | ||
| CollectionFieldInitializer, | ||
| CreateActionInitializer, | ||
| CustomizeAddRecordActionInitializer, | ||
| CreateChildInitializer, | ||
| ViewActionInitializer, | ||
| UpdateActionInitializer, | ||
| PopupActionInitializer, | ||
| SaveRecordActionInitializer, | ||
| UpdateRecordActionInitializer, | ||
| CreateSubmitActionInitializer, | ||
| UpdateSubmitActionInitializer, | ||
| BulkDestroyActionInitializer, | ||
| ExpandableActionInitializer, | ||
| DisassociateActionInitializer, | ||
| FilterActionInitializer, | ||
| RefreshActionInitializer, | ||
| FilterFormItemCustom, | ||
| AssociateActionInitializer, | ||
| AssociateActionProvider, | ||
| } as any); |
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.
Remove unsafe type assertion
Using as any bypasses TypeScript's type checking and could hide type errors. Consider properly typing the components object.
this.app.addComponents({
...initializerComponents,
...items,
DestroyActionInitializer,
// ... other components
AssociateActionInitializer,
AssociateActionProvider,
- } as any);
+ });If there are type conflicts, address them properly rather than using as any.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| this.app.addComponents({ | |
| ...initializerComponents, | |
| ...items, | |
| DestroyActionInitializer, | |
| CreateFormBlockInitializer, | |
| FormBlockInitializer, | |
| RecordFormBlockInitializer, | |
| TableBlockInitializer, | |
| TableSelectorInitializer, | |
| RecordReadPrettyFormBlockInitializer, | |
| DetailsBlockInitializer, | |
| ListBlockInitializer, | |
| GridCardBlockInitializer, | |
| FilterFormBlockInitializer, | |
| FilterTreeBlockInitializer, | |
| FilterCollapseBlockInitializer, | |
| MarkdownBlockInitializer, | |
| MarkdownFormItemInitializer, | |
| TableCollectionFieldInitializer, | |
| CollectionFieldInitializer, | |
| CreateActionInitializer, | |
| CustomizeAddRecordActionInitializer, | |
| CreateChildInitializer, | |
| ViewActionInitializer, | |
| UpdateActionInitializer, | |
| PopupActionInitializer, | |
| SaveRecordActionInitializer, | |
| UpdateRecordActionInitializer, | |
| CreateSubmitActionInitializer, | |
| UpdateSubmitActionInitializer, | |
| BulkDestroyActionInitializer, | |
| ExpandableActionInitializer, | |
| DisassociateActionInitializer, | |
| FilterActionInitializer, | |
| RefreshActionInitializer, | |
| FilterFormItemCustom, | |
| AssociateActionInitializer, | |
| AssociateActionProvider, | |
| } as any); | |
| this.app.addComponents({ | |
| ...initializerComponents, | |
| ...items, | |
| DestroyActionInitializer, | |
| CreateFormBlockInitializer, | |
| FormBlockInitializer, | |
| RecordFormBlockInitializer, | |
| TableBlockInitializer, | |
| TableSelectorInitializer, | |
| RecordReadPrettyFormBlockInitializer, | |
| DetailsBlockInitializer, | |
| ListBlockInitializer, | |
| GridCardBlockInitializer, | |
| FilterFormBlockInitializer, | |
| FilterTreeBlockInitializer, | |
| FilterCollapseBlockInitializer, | |
| MarkdownBlockInitializer, | |
| MarkdownFormItemInitializer, | |
| TableCollectionFieldInitializer, | |
| CollectionFieldInitializer, | |
| CreateActionInitializer, | |
| CustomizeAddRecordActionInitializer, | |
| CreateChildInitializer, | |
| ViewActionInitializer, | |
| UpdateActionInitializer, | |
| PopupActionInitializer, | |
| SaveRecordActionInitializer, | |
| UpdateRecordActionInitializer, | |
| CreateSubmitActionInitializer, | |
| UpdateSubmitActionInitializer, | |
| BulkDestroyActionInitializer, | |
| ExpandableActionInitializer, | |
| DisassociateActionInitializer, | |
| FilterActionInitializer, | |
| RefreshActionInitializer, | |
| FilterFormItemCustom, | |
| AssociateActionInitializer, | |
| AssociateActionProvider, | |
| }); |
🤖 Prompt for AI Agents
In packages/module-web/src/client/schema-initializer/SchemaInitializerPlugin.ts
between lines 79 and 117, the use of 'as any' to type cast the components object
disables TypeScript's type checking and may hide type errors. To fix this,
define or import the correct type for the components object expected by
this.app.addComponents and apply it explicitly instead of using 'as any'. If
there are type conflicts, resolve them by adjusting the component types or the
expected type rather than bypassing type checking.
| DestroyActionInitializer, | ||
| CreateFormBlockInitializer, | ||
| FormBlockInitializer, | ||
| RecordFormBlockInitializer, | ||
| TableBlockInitializer, | ||
| TableSelectorInitializer, | ||
| RecordReadPrettyFormBlockInitializer, | ||
| DetailsBlockInitializer, | ||
| ListBlockInitializer, | ||
| GridCardBlockInitializer, | ||
| FilterFormBlockInitializer, | ||
| FilterTreeBlockInitializer, | ||
| FilterCollapseBlockInitializer, | ||
| MarkdownBlockInitializer, | ||
| MarkdownFormItemInitializer, | ||
| TableCollectionFieldInitializer, | ||
| CollectionFieldInitializer, | ||
| CreateActionInitializer, | ||
| CustomizeAddRecordActionInitializer, | ||
| CreateChildInitializer, | ||
| ViewActionInitializer, | ||
| UpdateActionInitializer, | ||
| PopupActionInitializer, | ||
| SaveRecordActionInitializer, | ||
| UpdateRecordActionInitializer, | ||
| CreateSubmitActionInitializer, | ||
| UpdateSubmitActionInitializer, | ||
| BulkDestroyActionInitializer, | ||
| ExpandableActionInitializer, | ||
| DisassociateActionInitializer, | ||
| FilterActionInitializer, | ||
| RefreshActionInitializer, | ||
| FilterFormItemCustom, | ||
| AssociateActionInitializer, | ||
| AssociateActionProvider, | ||
| } as any); |
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.
💡 Verification agent
🧩 Analysis chain
Runtime errors from undefined components
Many components being registered (like DestroyActionInitializer, CreateFormBlockInitializer, etc.) are from commented imports and will be undefined at runtime, causing errors.
🏁 Script executed:
#!/bin/bash
# Check if these components are defined elsewhere or will cause runtime errors
rg -A 2 "DestroyActionInitializer|CreateFormBlockInitializer|FormBlockInitializer|RecordFormBlockInitializer" --type ts --glob "!*.d.ts" --glob "!node_modules/**"Length of output: 39978
🏁 Script executed:
#!/bin/bash
sed -n '1,200p' packages/module-web/src/client/schema-initializer/SchemaInitializerPlugin.tsLength of output: 9857
🏁 Script executed:
#!/bin/bash
find packages/module-web/src/client/schema-initializer/components -maxdepth 1 -type fLength of output: 319
Fix missing component imports in SchemaInitializerPlugin
The load() method in
packages/module-web/src/client/schema-initializer/SchemaInitializerPlugin.ts
references many initializers whose imports are commented out, causing compile-time “Cannot find name” errors and potential runtime failures. Please:
-
Uncomment or add imports for these identifiers from their respective modules:
- DestroyActionInitializer
- CreateFormBlockInitializer
- FormBlockInitializer
- RecordFormBlockInitializer
- TableBlockInitializer
- TableSelectorInitializer
- RecordReadPrettyFormBlockInitializer
- DetailsBlockInitializer
- ListBlockInitializer
- GridCardBlockInitializer
- FilterFormBlockInitializer
- FilterTreeBlockInitializer
- FilterCollapseBlockInitializer
- MarkdownBlockInitializer
- MarkdownFormItemInitializer
- TableCollectionFieldInitializer
- CollectionFieldInitializer
- CreateActionInitializer
- CustomizeAddRecordActionInitializer
- CreateChildInitializer
- ViewActionInitializer
- UpdateActionInitializer
- PopupActionInitializer
- SaveRecordActionInitializer
- UpdateRecordActionInitializer
- CreateSubmitActionInitializer
- UpdateSubmitActionInitializer
- BulkDestroyActionInitializer
- ExpandableActionInitializer
- DisassociateActionInitializer
- FilterActionInitializer
- RefreshActionInitializer
- AssociateActionInitializer
- AssociateActionProvider
-
Or ensure these exports are included in the spread imports (
initializerComponents/items) instead of listing them manually. -
Add error handling (e.g. try/catch) around the async
load()implementation to capture and report initialization failures.
🤖 Prompt for AI Agents
In packages/module-web/src/client/schema-initializer/SchemaInitializerPlugin.ts
between lines 82 and 117, the load() method references many initializers whose
imports are currently commented out or missing, causing compile errors. To fix
this, uncomment or add explicit import statements for all the listed
initializers from their respective modules, or alternatively include them in the
existing spread imports like initializerComponents or items to avoid manual
listing. Additionally, wrap the async load() method's implementation in a
try/catch block to handle and log any initialization errors gracefully.
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.
Review continued from previous batch...
| /** | ||
| * @deprecated | ||
| */ | ||
| export const tabPaneInitializers_deprecated = new SchemaInitializer({ | ||
| name: 'TabPaneInitializers', | ||
| Component: TabPaneInitializers, | ||
| popover: false, | ||
| }); | ||
|
|
||
| export const tabPaneInitializers = new SchemaInitializer({ | ||
| name: 'popup:addTab', | ||
| ...commonOptions, | ||
| }); | ||
|
|
||
| /** | ||
| * @deprecated | ||
| */ | ||
| export const tabPaneInitializersForRecordBlock = new SchemaInitializer({ | ||
| name: 'TabPaneInitializersForCreateFormBlock', | ||
| Component: TabPaneInitializersForCreateFormBlock, | ||
| popover: false, | ||
| }); | ||
|
|
||
| /** | ||
| * @deprecated | ||
| */ | ||
| export const tabPaneInitializersForBulkEditFormBlock = new SchemaInitializer({ | ||
| name: 'TabPaneInitializersForBulkEditFormBlock', | ||
| Component: TabPaneInitializersForBulkEditFormBlock, | ||
| popover: 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.
🛠️ Refactor suggestion
Provide migration guidance for deprecated exports
The deprecated exports should include information about what to use instead.
/**
* @deprecated
+ * Use `tabPaneInitializers` instead
*/
export const tabPaneInitializers_deprecated = new SchemaInitializer({Consider adding a console warning when these deprecated exports are used:
export const tabPaneInitializers_deprecated = new SchemaInitializer({
name: 'TabPaneInitializers',
Component: (...args) => {
console.warn('tabPaneInitializers_deprecated is deprecated. Use tabPaneInitializers instead.');
return TabPaneInitializers(...args);
},
popover: false,
});🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/buttons/TabPaneInitializers.tsx
between lines 192 and 222, the deprecated exports lack guidance on what to use
instead. Update each deprecated export to wrap their Component property with a
function that logs a console warning indicating the deprecation and suggesting
the preferred alternative. This will inform developers at runtime about the
deprecation and the recommended replacement.
| const extra = useMemo(() => { | ||
| return typeof field.description === 'string' ? ( | ||
| <div | ||
| dangerouslySetInnerHTML={{ | ||
| __html: HTMLEncode(field.description).split('\n').join('<br/>'), | ||
| }} | ||
| /> | ||
| ) : ( | ||
| field.description | ||
| ); | ||
| }, [field.description]); |
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.
Avoid using dangerouslySetInnerHTML for security
Using dangerouslySetInnerHTML can expose users to XSS attacks. Consider a safer approach for rendering line breaks.
- const extra = useMemo(() => {
- return typeof field.description === 'string' ? (
- <div
- dangerouslySetInnerHTML={{
- __html: HTMLEncode(field.description).split('\n').join('<br/>'),
- }}
- />
- ) : (
- field.description
- );
- }, [field.description]);
+ const extra = useMemo(() => {
+ if (typeof field.description === 'string') {
+ return (
+ <div style={{ whiteSpace: 'pre-wrap' }}>
+ {field.description}
+ </div>
+ );
+ }
+ return field.description;
+ }, [field.description]);Alternatively, you can split the description and render each line separately:
const extra = useMemo(() => {
if (typeof field.description === 'string') {
return (
<div>
{field.description.split('\n').map((line, index) => (
<React.Fragment key={index}>
{line}
{index < field.description.split('\n').length - 1 && <br />}
</React.Fragment>
))}
</div>
);
}
return field.description;
}, [field.description]);🧰 Tools
🪛 Biome (1.9.4)
[error] 414-414: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/items/CustomFilterFormItemInitializer.tsx
around lines 411 to 421, the code uses dangerouslySetInnerHTML to render
field.description with line breaks, which poses an XSS security risk. Replace
this by splitting the description string on newline characters and rendering
each line inside a div with explicit <br /> elements between lines, avoiding the
use of dangerouslySetInnerHTML entirely. This ensures safe rendering of line
breaks without exposing to XSS.
| // 1. 组件在第一次渲染时自动 focus,提高用户体验 | ||
| inputRef.current.input.focus(); |
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.
🛠️ Refactor suggestion
Translate Chinese comments to English
- // 1. 组件在第一次渲染时自动 focus,提高用户体验
+ // 1. Auto-focus on first render to improve user experience
inputRef.current.input.focus();
- // 2. 当组件已经渲染,并再次显示时,自动 focus
+ // 2. Auto-focus when component is already rendered and shown againCommittable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/items/DataBlockInitializer.tsx
around lines 35 to 36, translate the Chinese comment above the focus call into
English. Replace the comment with a clear English version that explains the
component automatically focuses on the input on first render to improve user
experience.
| // 判断滚动是否到达底部 | ||
| if (Math.abs(container.scrollHeight - container.scrollTop - container.clientHeight) <= MENU_ITEM_HEIGHT) { |
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.
🛠️ Refactor suggestion
Translate Chinese comment to English
- // 判断滚动是否到达底部
+ // Check if scroll has reached the bottom
if (Math.abs(container.scrollHeight - container.scrollTop - container.clientHeight) <= MENU_ITEM_HEIGHT) {
- // 到达底部,执行加载更多的操作
+ // Reached bottom, execute load more operation
loadMore();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // 判断滚动是否到达底部 | |
| if (Math.abs(container.scrollHeight - container.scrollTop - container.clientHeight) <= MENU_ITEM_HEIGHT) { | |
| // Check if scroll has reached the bottom | |
| if (Math.abs(container.scrollHeight - container.scrollTop - container.clientHeight) <= MENU_ITEM_HEIGHT) { | |
| // Reached bottom, execute load more operation | |
| loadMore(); |
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/items/DataBlockInitializer.tsx
at lines 86 to 87, translate the Chinese comment "// 判断滚动是否到达底部" to English.
Replace it with a clear English comment such as "// Check if scroll has reached
the bottom" to maintain code clarity and consistency.
| const items = | ||
| itemsFromProps || | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useCollectionDataSourceItems({ | ||
| componentName: componentType, | ||
| filter, | ||
| filterDataSource, | ||
| onlyCurrentDataSource, | ||
| showAssociationFields, | ||
| dataBlockInitializerProps: props, | ||
| hideOtherRecordsInPopup, | ||
| }); |
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 conditional hook usage
The useCollectionDataSourceItems hook is called conditionally, which violates React's Rules of Hooks. Hooks must be called at the top level.
- const items =
- itemsFromProps ||
- // eslint-disable-next-line react-hooks/rules-of-hooks
- useCollectionDataSourceItems({
+ const defaultItems = useCollectionDataSourceItems({
componentName: componentType,
filter,
filterDataSource,
onlyCurrentDataSource,
showAssociationFields,
dataBlockInitializerProps: props,
hideOtherRecordsInPopup,
});
+ const items = itemsFromProps || defaultItems;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const items = | |
| itemsFromProps || | |
| // eslint-disable-next-line react-hooks/rules-of-hooks | |
| useCollectionDataSourceItems({ | |
| componentName: componentType, | |
| filter, | |
| filterDataSource, | |
| onlyCurrentDataSource, | |
| showAssociationFields, | |
| dataBlockInitializerProps: props, | |
| hideOtherRecordsInPopup, | |
| }); | |
| const defaultItems = useCollectionDataSourceItems({ | |
| componentName: componentType, | |
| filter, | |
| filterDataSource, | |
| onlyCurrentDataSource, | |
| showAssociationFields, | |
| dataBlockInitializerProps: props, | |
| hideOtherRecordsInPopup, | |
| }); | |
| const items = itemsFromProps || defaultItems; |
🤖 Prompt for AI Agents
In
packages/module-web/src/client/schema-initializer/items/DataBlockInitializer.tsx
around lines 331 to 342, the hook useCollectionDataSourceItems is called
conditionally inside a logical OR expression, violating React's Rules of Hooks.
To fix this, call useCollectionDataSourceItems unconditionally at the top level
and then use the result conditionally by assigning items to either
itemsFromProps or the hook result afterward.
| export const findTableColumn = (schema: Schema, key: string, action: string, deepth = 0) => { | ||
| return schema.reduceProperties((buf, s) => { | ||
| if (s[key] === action) { | ||
| return s; | ||
| } | ||
| const c = s.reduceProperties((buf, s) => { | ||
| if (s[key] === action) { | ||
| return s; | ||
| } | ||
| return buf; | ||
| }); | ||
| if (c) { | ||
| return c; | ||
| } | ||
| return buf; | ||
| }); | ||
| }; |
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 typo and implement depth protection in recursive function
The deepth parameter has a typo and is not being used, which could lead to stack overflow.
-export const findTableColumn = (schema: Schema, key: string, action: string, deepth = 0) => {
+export const findTableColumn = (schema: Schema, key: string, action: string, depth = 0) => {
+ const MAX_DEPTH = 10;
+ if (depth > MAX_DEPTH) {
+ console.warn('Maximum depth reached in findTableColumn');
+ return null;
+ }
return schema.reduceProperties((buf, s) => {
if (s[key] === action) {
return s;
}
- const c = s.reduceProperties((buf, s) => {
- if (s[key] === action) {
- return s;
- }
- return buf;
- });
+ const c = findTableColumn(s, key, action, depth + 1);
if (c) {
return c;
}
return buf;
});
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const findTableColumn = (schema: Schema, key: string, action: string, deepth = 0) => { | |
| return schema.reduceProperties((buf, s) => { | |
| if (s[key] === action) { | |
| return s; | |
| } | |
| const c = s.reduceProperties((buf, s) => { | |
| if (s[key] === action) { | |
| return s; | |
| } | |
| return buf; | |
| }); | |
| if (c) { | |
| return c; | |
| } | |
| return buf; | |
| }); | |
| }; | |
| export const findTableColumn = (schema: Schema, key: string, action: string, depth = 0) => { | |
| const MAX_DEPTH = 10; | |
| if (depth > MAX_DEPTH) { | |
| console.warn('Maximum depth reached in findTableColumn'); | |
| return null; | |
| } | |
| return schema.reduceProperties((buf, s) => { | |
| if (s[key] === action) { | |
| return s; | |
| } | |
| const c = findTableColumn(s, key, action, depth + 1); | |
| if (c) { | |
| return c; | |
| } | |
| return buf; | |
| }); | |
| }; |
🤖 Prompt for AI Agents
In packages/module-web/src/client/schema-initializer/utils.ts lines 70 to 86,
fix the typo in the parameter name from "deepth" to "depth" and implement a
check to limit recursion depth using this parameter. Modify the function to
decrement the depth on each recursive call and stop recursion when depth reaches
zero to prevent potential stack overflow.
| * @deprecated | ||
| * 已弃用,请使用 createDetailsUISchema 和 createDetailsWithPaginationUISchema 替代 | ||
| * @param options | ||
| * @returns | ||
| */ | ||
| export const createDetailsBlockSchema = (options: { | ||
| collection: string; | ||
| dataSource: string; | ||
| rowKey?: string; | ||
| formItemInitializers?: string; | ||
| actionInitializers?: string; | ||
| association?: string; | ||
| template?: any; | ||
| settings?: string; | ||
| action?: string; | ||
| [key: string]: any; | ||
| }) => { | ||
| const { |
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.
🛠️ Refactor suggestion
Add deprecation warnings to deprecated functions
Deprecated functions should log warnings to help developers migrate.
export const createDetailsBlockSchema = (options: {
collection: string;
dataSource: string;
rowKey?: string;
formItemInitializers?: string;
actionInitializers?: string;
association?: string;
template?: any;
settings?: string;
action?: string;
[key: string]: any;
}) => {
+ console.warn(
+ 'createDetailsBlockSchema is deprecated. Use createDetailsUISchema or createDetailsWithPaginationUISchema instead.'
+ );
const {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| * @deprecated | |
| * 已弃用,请使用 createDetailsUISchema 和 createDetailsWithPaginationUISchema 替代 | |
| * @param options | |
| * @returns | |
| */ | |
| export const createDetailsBlockSchema = (options: { | |
| collection: string; | |
| dataSource: string; | |
| rowKey?: string; | |
| formItemInitializers?: string; | |
| actionInitializers?: string; | |
| association?: string; | |
| template?: any; | |
| settings?: string; | |
| action?: string; | |
| [key: string]: any; | |
| }) => { | |
| const { | |
| export const createDetailsBlockSchema = (options: { | |
| collection: string; | |
| dataSource: string; | |
| rowKey?: string; | |
| formItemInitializers?: string; | |
| actionInitializers?: string; | |
| association?: string; | |
| template?: any; | |
| settings?: string; | |
| action?: string; | |
| [key: string]: any; | |
| }) => { | |
| console.warn( | |
| 'createDetailsBlockSchema is deprecated. Use createDetailsUISchema or createDetailsWithPaginationUISchema instead.' | |
| ); | |
| const { | |
| // …rest of the implementation |
🤖 Prompt for AI Agents
In packages/module-web/src/client/schema-initializer/utils.ts around lines 1045
to 1062, the deprecated function createDetailsBlockSchema lacks a deprecation
warning. Add a console warning or logger message at the start of the function to
notify developers that this function is deprecated and suggest using
createDetailsUISchema or createDetailsWithPaginationUISchema instead.
Summary by CodeRabbit
New Features
Documentation
Chores
Refactor
Style