@object-ui/plugin-view 3.1.3 → 3.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,7 @@
22
22
  * - ViewSwitcher for toggling between view types
23
23
  */
24
24
 
25
- import React, { useEffect, useState, useCallback, useMemo } from 'react';
25
+ import React, { useEffect, useState, useCallback, useMemo, useRef } from 'react';
26
26
  import type {
27
27
  ObjectViewSchema,
28
28
  ObjectGridSchema,
@@ -57,20 +57,13 @@ import {
57
57
  } from '@object-ui/components';
58
58
  import { Plus } from 'lucide-react';
59
59
  import { buildExpandFields } from '@object-ui/core';
60
+ import { SchemaRenderer as ImportedSchemaRenderer } from '@object-ui/react';
60
61
  import { ViewSwitcher } from './ViewSwitcher';
61
62
 
62
63
  /**
63
- * Attempt to import SchemaRenderer from @object-ui/react.
64
- * Falls back to null if not available.
64
+ * SchemaRenderer from @object-ui/react, used to render sub-view schemas.
65
65
  */
66
- let SchemaRendererComponent: React.FC<any> | null = null;
67
- try {
68
- // eslint-disable-next-line @typescript-eslint/no-require-imports
69
- const mod = require('@object-ui/react');
70
- SchemaRendererComponent = mod.SchemaRenderer || null;
71
- } catch {
72
- // @object-ui/react not available
73
- }
66
+ const SchemaRendererComponent: React.FC<any> = ImportedSchemaRenderer;
74
67
 
75
68
  export interface ObjectViewProps {
76
69
  /**
@@ -219,6 +212,11 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
219
212
  onViewAction,
220
213
  }) => {
221
214
  const [objectSchema, setObjectSchema] = useState<Record<string, unknown> | null>(null);
215
+ // Assigned in the render body (not in an effect) so the fetchData effect always
216
+ // reads the latest objectSchema without needing it as a dependency. This matches
217
+ // the same pattern used in ObjectCalendar's objectSchemaRef.
218
+ const objectSchemaRef = useRef<Record<string, unknown> | null>(null);
219
+ objectSchemaRef.current = objectSchema;
222
220
  const [isFormOpen, setIsFormOpen] = useState(false);
223
221
  const [formMode, setFormMode] = useState<FormMode>('create');
224
222
  const [selectedRecord, setSelectedRecord] = useState<Record<string, unknown> | null>(null);
@@ -294,8 +292,12 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
294
292
  let isMounted = true;
295
293
 
296
294
  const fetchData = async () => {
295
+ // When renderListView is provided, the custom list view (e.g. ListView)
296
+ // handles its own data fetching — skip to avoid duplicate requests and
297
+ // unnecessary re-renders that can cause duplicate records in child views.
298
+ if (renderListView) return;
297
299
  // Only fetch for non-grid views (ObjectGrid has its own data fetching)
298
- if (currentViewType === 'grid' && !renderListView) return;
300
+ if (currentViewType === 'grid') return;
299
301
  if (!dataSource || !schema.objectName) return;
300
302
 
301
303
  setLoading(true);
@@ -322,8 +324,11 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
322
324
  ? sortConfig.map(s => ({ field: s.field, order: s.direction }))
323
325
  : (currentNamedViewConfig?.sort || activeView?.sort || schema.table?.defaultSort || undefined);
324
326
 
325
- // Auto-inject $expand for lookup/master_detail fields
326
- const expand = buildExpandFields((objectSchema as any)?.fields);
327
+ // Auto-inject $expand for lookup/master_detail fields.
328
+ // Use a ref instead of the state variable to avoid re-running this effect
329
+ // every time the object schema loads — that would cause a double-fetch and
330
+ // duplicate events in child views like the calendar.
331
+ const expand = buildExpandFields((objectSchemaRef.current as any)?.fields);
327
332
  const results = await dataSource.find(schema.objectName, {
328
333
  $filter: finalFilter.length > 0 ? finalFilter : undefined,
329
334
  $orderby: sort,
@@ -339,6 +344,8 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
339
344
  items = (results as any).data;
340
345
  } else if (Array.isArray((results as any).records)) {
341
346
  items = (results as any).records;
347
+ } else if (Array.isArray((results as any).value)) {
348
+ items = (results as any).value;
342
349
  }
343
350
  }
344
351
 
@@ -352,8 +359,9 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
352
359
 
353
360
  fetchData();
354
361
  return () => { isMounted = false; };
362
+ // objectSchema intentionally omitted from deps — read via ref to prevent double-fetch
355
363
  // eslint-disable-next-line react-hooks/exhaustive-deps
356
- }, [schema.objectName, dataSource, currentViewType, filterValues, sortConfig, refreshKey, currentNamedViewConfig, activeView, renderListView, objectSchema]);
364
+ }, [schema.objectName, dataSource, currentViewType, filterValues, sortConfig, refreshKey, currentNamedViewConfig, activeView, renderListView]);
357
365
 
358
366
  // Determine layout mode
359
367
  const layout = schema.layout || 'drawer';
package/src/index.tsx CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  import React, { useContext } from 'react';
10
10
  import { ComponentRegistry } from '@object-ui/core';
11
+ import { SchemaRendererContext as ImportedSchemaRendererContext } from '@object-ui/react';
11
12
  import { ObjectView } from './ObjectView';
12
13
  import { ViewSwitcher } from './ViewSwitcher';
13
14
  import { FilterUI } from './FilterUI';
@@ -25,22 +26,9 @@ export type { SharedViewLinkProps } from './SharedViewLink';
25
26
 
26
27
  /**
27
28
  * SchemaRendererContext is created by @object-ui/react.
28
- * We import it dynamically to avoid a circular dependency.
29
29
  * The context value provides { dataSource }.
30
- * A fallback context is created so hooks are never called conditionally.
31
30
  */
32
- const FallbackContext = React.createContext<any>(null);
33
- let SchemaRendererContext: React.Context<any> = FallbackContext;
34
- try {
35
- // eslint-disable-next-line @typescript-eslint/no-require-imports
36
- const mod = require('@object-ui/react');
37
- // The context is re-exported from @object-ui/react
38
- if (mod.SchemaRendererContext) {
39
- SchemaRendererContext = mod.SchemaRendererContext;
40
- }
41
- } catch {
42
- // @object-ui/react not available — registry-based dataSource only
43
- }
31
+ const SchemaRendererContext: React.Context<any> = ImportedSchemaRendererContext;
44
32
 
45
33
  // Register object-view component
46
34
  const ObjectViewRenderer: React.FC<{ schema: any }> = ({ schema }) => {