Skip to content

fix: CRM report renders blank due to stale useState initialization#523

Merged
hotlong merged 3 commits intomainfrom
copilot/fix-empty-crm-reports
Feb 15, 2026
Merged

fix: CRM report renders blank due to stale useState initialization#523
hotlong merged 3 commits intomainfrom
copilot/fix-empty-crm-reports

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 15, 2026

ReportView initializes reportData via useState(initialReport) during first render, when metadata is still loading asynchronously (reports=[]). This captures undefined permanently — subsequent metadata loads update initialReport but never sync back to reportData, rendering a blank report.

Changes

  • State sync: Added useEffect to propagate initialReportreportData when metadata finishes loading or route changes
  • Loading guard: Check loading from useMetadata() and show spinner instead of false "Report Not Found"
// Before: reportData stuck as undefined after async load
const [reportData, setReportData] = useState(initialReport);

// After: sync when metadata resolves
useEffect(() => {
  setReportData(initialReport);
}, [initialReport]);

Note: reportData state is retained (not replaced with direct initialReport usage) because handleSave writes edited report data back into it.

Original prompt

crm 报表 显示为空白


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectui Error Error Feb 15, 2026 4:30am
objectui-demo Error Error Feb 15, 2026 4:30am
objectui-storybook Error Error Feb 15, 2026 4:30am

Request Review

Copilot AI and others added 2 commits February 15, 2026 04:23
…ding state

The ReportView component had a stale state bug where reportData was
initialized via useState(initialReport) on first render when metadata
was still loading (reports=[]), causing it to remain undefined even
after metadata loaded. Added useEffect to sync state and loading check.

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix blank display in CRM reports fix: CRM report renders blank due to stale useState initialization Feb 15, 2026
Copilot AI requested a review from hotlong February 15, 2026 04:26
@hotlong hotlong marked this pull request as ready for review February 15, 2026 04:34
Copilot AI review requested due to automatic review settings February 15, 2026 04:34
@github-actions github-actions Bot added the apps label Feb 15, 2026
@github-actions
Copy link
Copy Markdown
Contributor

❌ Console Performance Budget

Metric Value Budget
Main entry (gzip) ** KB** KB
Entry file ``
Status FAIL

📦 Bundle Size Report

Package Size Gzipped
create-plugin (index.js) 10.13KB 3.17KB
i18n (i18n.js) 2.03KB 0.77KB
i18n (index.js) 1.79KB 0.72KB
i18n (provider.js) 3.21KB 1.09KB
plugin-ai (index.js) 25.35KB 6.39KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 0.20KB 0.18KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 0.20KB 0.18KB
types (disclosure.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (index.js) 1.08KB 0.48KB
types (layout.js) 0.20KB 0.18KB
types (mobile.js) 0.20KB 0.18KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (tenant.js) 0.20KB 0.18KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 0.20KB 0.18KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB
types (workflow.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a critical bug where the CRM report view renders blank due to stale state initialization. The ReportView component was initializing reportData state with useState(initialReport) during the first render when metadata was still loading asynchronously, permanently capturing undefined. The fix adds a useEffect to synchronize state when metadata loads and a loading guard to show a spinner instead of a false "Report Not Found" error.

Changes:

  • Added useEffect to sync reportData state when initialReport changes (metadata loads or route changes)
  • Added loading state check with spinner UI to prevent false "Report Not Found" during async metadata fetch
  • Imported Loader2 icon for loading spinner and useEffect hook


// Sync reportData when metadata finishes loading or reportName changes
useEffect(() => {
setReportData(initialReport);
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

The useEffect should also reset the editing state when the report changes (either from metadata loading or navigation). Currently, if a user is editing "Report A" and navigates to "Report B", they remain in editing mode showing "Report B" data in the builder. This creates confusion as the edit UI doesn't reset. Add setIsEditing(false); inside this effect to ensure clean state transitions between reports.

Suggested change
setReportData(initialReport);
setReportData(initialReport);
setIsEditing(false);

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +42
const { reports, loading } = useMetadata();
const initialReport = reports?.find((r: any) => r.name === reportName);
const [reportData, setReportData] = useState(initialReport);

// Sync reportData when metadata finishes loading or reportName changes
useEffect(() => {
setReportData(initialReport);
}, [initialReport]);

if (loading) {
return (
<div className="h-full flex items-center justify-center p-8">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
);
}
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

The loading check occurs after the initialReport has already been computed from the potentially empty reports array. Since reports starts as [] during initial load, initialReport will be undefined even during loading. This means users will briefly see the loading spinner (correct), but the initialReport constant and reportData state will both be undefined until the next render after metadata loads. While the useEffect will fix reportData when metadata arrives, this pattern is inconsistent with how the metadata is used. Consider moving the loading check before computing initialReport to make the control flow clearer, or acknowledge that initialReport is recomputed on every render (which is fine but could be clarified with a comment).

Copilot uses AI. Check for mistakes.
@hotlong hotlong merged commit e5eff40 into main Feb 15, 2026
12 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants