CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-admin

A frontend Framework for building admin applications on top of REST services, using ES6, React and Material UI

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

advanced.mddocs/

Advanced Features

React Admin provides powerful advanced features including data export functionality, application preferences system, persistent stores, caching strategies, and comprehensive utilities for building sophisticated admin applications.

Export Functionality

Export System Overview

React Admin provides built-in data export capabilities with customizable formats and processing.

import { Exporter } from 'react-admin';

type Exporter = (
  data: any[], 
  fetchRelatedRecords: FetchRelatedRecords, 
  dataProvider: DataProvider,
  resource?: string
) => void | Promise<void>;

type FetchRelatedRecords = (
  data: any[],
  field: string,
  resource: string
) => Promise<any[]>;

useExporter Hook

Hook for accessing export functionality in custom components.

import { useExporter } from 'react-admin';

const useExporter: () => {
  exporter: Exporter;
  loading: boolean;
  error: any;
};

ExportButton

Pre-built button for triggering data export.

import { ExportButton } from 'react-admin';

interface ExportButtonProps {
  disabled?: boolean;
  exporter?: Exporter;
  icon?: React.ReactElement;
  label?: string;
  maxResults?: number;
  resource?: string;
  sort?: SortPayload;
  filter?: any;
  className?: string;
  sx?: any;
}

const ExportButton: React.FC<ExportButtonProps>;

Built-in Export Functions

import { 
  defaultExporter, 
  downloadCSV, 
  fetchRelatedRecords 
} from 'react-admin';

const defaultExporter: Exporter;

const downloadCSV: (data: any[], filename?: string) => void;

const fetchRelatedRecords: FetchRelatedRecords;

Export Examples

import { 
  List, 
  Datagrid, 
  TextField,
  ExportButton,
  TopToolbar,
  downloadCSV,
  fetchRelatedRecords,
  useDataProvider
} from 'react-admin';

// Basic export with default CSV exporter
const PostListActions = () => (
  <TopToolbar>
    <ExportButton />
  </TopToolbar>
);

// Custom exporter with related data
const customPostExporter = async (posts, fetchRelatedRecords, dataProvider) => {
  // Fetch related categories and authors
  const postsWithCategories = await fetchRelatedRecords(posts, 'categoryId', 'categories');
  const postsWithAuthors = await fetchRelatedRecords(postsWithCategories, 'authorId', 'users');
  
  // Transform data for export
  const exportData = postsWithAuthors.map(post => ({
    id: post.id,
    title: post.title,
    status: post.status,
    category: post.category?.name || 'Unknown',
    author: post.author ? `${post.author.firstName} ${post.author.lastName}` : 'Unknown',
    createdAt: new Date(post.createdAt).toLocaleDateString(),
    wordCount: post.content?.split(' ').length || 0
  }));
  
  downloadCSV(exportData, 'posts-detailed');
};

const PostList = () => (
  <List actions={<PostListActions />} exporter={customPostExporter}>
    <Datagrid>
      <TextField source="title" />
      <TextField source="status" />
      <DateField source="createdAt" />
    </Datagrid>
  </List>
);

// Excel export example
import * as XLSX from 'xlsx';

const excelExporter = (data) => {
  const worksheet = XLSX.utils.json_to_sheet(data);
  const workbook = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(workbook, worksheet, 'Posts');
  XLSX.writeFile(workbook, 'posts.xlsx');
};

// PDF export example
import jsPDF from 'jspdf';
import 'jspdf-autotable';

const pdfExporter = (data) => {
  const doc = new jsPDF();
  
  doc.text('Posts Report', 20, 10);
  
  const tableData = data.map(post => [
    post.id,
    post.title,
    post.status,
    new Date(post.createdAt).toLocaleDateString()
  ]);
  
  doc.autoTable({
    head: [['ID', 'Title', 'Status', 'Created']],
    body: tableData,
    startY: 20
  });
  
  doc.save('posts.pdf');
};

Preferences System

Preference Hooks

React Admin provides a preferences system for storing user interface customizations.

import { usePreference } from 'react-admin';

interface UsePreferenceResult<T = any> {
  0: T;
  1: (value: T) => void;
  identity: T;
  setValue: (value: T) => void;
}

const usePreference: <T = any>(
  key: string, 
  defaultValue?: T
) => UsePreferenceResult<T>;

Preferences Editor

import { 
  usePreferencesEditor, 
  PreferencesEditorContext,
  PreferencesEditorContextProvider 
} from 'react-admin';

interface PreferencesEditorContextValue {
  isEnabled: boolean;
  enable: () => void;
  disable: () => void;
  preferenceKey: string;
  setPreferenceKey: (key: string) => void;
}

const usePreferencesEditor: () => PreferencesEditorContextValue;

Configurable Components

import { Configurable } from 'react-admin';

interface ConfigurableProps {
  children: React.ReactNode;
  editor?: React.ComponentType<ConfigurableEditorProps>;
  preferenceKey?: string;
  sx?: any;
}

const Configurable: React.FC<ConfigurableProps>;

Preference Examples

import { 
  usePreference, 
  Configurable, 
  List, 
  Datagrid, 
  TextField,
  BooleanField
} from 'react-admin';

// Custom component with preferences
const CustomizableDashboard = () => {
  const [showStats, setShowStats] = usePreference('dashboard.showStats', true);
  const [refreshInterval, setRefreshInterval] = usePreference('dashboard.refreshInterval', 30000);
  const [layout, setLayout] = usePreference('dashboard.layout', 'grid');
  
  return (
    <Configurable preferenceKey="dashboard">
      <div>
        <div>
          <label>
            <input 
              type="checkbox" 
              checked={showStats} 
              onChange={(e) => setShowStats(e.target.checked)}
            />
            Show Statistics
          </label>
        </div>
        
        <div>
          <label>
            Refresh Interval:
            <select 
              value={refreshInterval} 
              onChange={(e) => setRefreshInterval(Number(e.target.value))}
            >
              <option value={15000}>15 seconds</option>
              <option value={30000}>30 seconds</option>
              <option value={60000}>1 minute</option>
            </select>
          </label>
        </div>
        
        {showStats && <StatsWidget refreshInterval={refreshInterval} />}
        
        <div className={`layout-${layout}`}>
          <MainContent />
        </div>
      </div>
    </Configurable>
  );
};

// Configurable field visibility
const ConfigurablePostList = () => {
  const [showId, setShowId] = usePreference('postList.showId', false);
  const [showDate, setShowDate] = usePreference('postList.showDate', true);
  
  return (
    <List>
      <Datagrid>
        {showId && <TextField source="id" />}
        <TextField source="title" />
        <TextField source="status" />
        {showDate && <DateField source="createdAt" />}
      </Datagrid>
    </List>
  );
};

Store Management

Store Interface

React Admin provides persistent storage for application state.

import { Store } from 'react-admin';

interface Store {
  getItem: (key: string) => any;
  setItem: (key: string, value: any) => void;
  removeItem: (key: string) => void;
  removeItems: (keys: string[]) => void;
  reset: () => void;
}

Built-in Store Implementations

import { localStorageStore, memoryStore } from 'react-admin';

const localStorageStore: Store;
const memoryStore: Store;

Store Hooks

import { 
  useStore, 
  useStoreContext, 
  useRemoveFromStore,
  useRemoveItemsFromStore,
  useResetStore 
} from 'react-admin';

const useStore: <T = any>(key: string, defaultValue?: T) => [T, (value: T) => void];
const useStoreContext: () => Store;
const useRemoveFromStore: () => (key: string) => void;
const useRemoveItemsFromStore: () => (keys: string[]) => void;
const useResetStore: () => () => void;

Custom Store Implementation

import { Store } from 'react-admin';

// Custom store with encryption
class EncryptedLocalStorageStore implements Store {
  private encrypt(value: any): string {
    return btoa(JSON.stringify(value));
  }
  
  private decrypt(encrypted: string): any {
    try {
      return JSON.parse(atob(encrypted));
    } catch {
      return null;
    }
  }
  
  getItem(key: string): any {
    const encrypted = localStorage.getItem(key);
    return encrypted ? this.decrypt(encrypted) : null;
  }
  
  setItem(key: string, value: any): void {
    localStorage.setItem(key, this.encrypt(value));
  }
  
  removeItem(key: string): void {
    localStorage.removeItem(key);
  }
  
  removeItems(keys: string[]): void {
    keys.forEach(key => localStorage.removeItem(key));
  }
  
  reset(): void {
    localStorage.clear();
  }
}

const encryptedStore = new EncryptedLocalStorageStore();

// Usage in Admin
<Admin store={encryptedStore} dataProvider={dataProvider}>
  <Resource name="posts" list={PostList} />
</Admin>

Store Usage Examples

import { useStore, useResetStore } from 'react-admin';

const UserPreferences = () => {
  const [theme, setTheme] = useStore('user.theme', 'light');
  const [sidebar, setSidebar] = useStore('user.sidebarCollapsed', false);
  const [language, setLanguage] = useStore('user.language', 'en');
  const resetStore = useResetStore();
  
  return (
    <div>
      <h2>User Preferences</h2>
      
      <div>
        <label>
          Theme:
          <select value={theme} onChange={(e) => setTheme(e.target.value)}>
            <option value="light">Light</option>
            <option value="dark">Dark</option>
          </select>
        </label>
      </div>
      
      <div>
        <label>
          <input 
            type="checkbox" 
            checked={sidebar} 
            onChange={(e) => setSidebar(e.target.checked)}
          />
          Collapse Sidebar
        </label>
      </div>
      
      <button onClick={resetStore}>
        Reset All Preferences
      </button>
    </div>
  );
};

// Persistent form draft
const DraftManager = () => {
  const [draft, setDraft] = useStore('form.postDraft', {});
  
  const saveDraft = (formData) => {
    setDraft({
      ...formData,
      savedAt: new Date().toISOString()
    });
  };
  
  const clearDraft = () => {
    setDraft({});
  };
  
  return { draft, saveDraft, clearDraft };
};

Application Update Management

Update Detection and Notification

import { 
  useCheckForApplicationUpdate, 
  CheckForApplicationUpdate,
  ApplicationUpdatedNotification 
} from 'react-admin';

const useCheckForApplicationUpdate: () => {
  updateAvailable: boolean;
  checkForUpdate: () => void;
};

const CheckForApplicationUpdate: React.FC<{
  interval?: number;
  url?: string;
  disabled?: boolean;
}>;

const ApplicationUpdatedNotification: React.FC;

Update Management Example

import { 
  Layout, 
  CheckForApplicationUpdate, 
  ApplicationUpdatedNotification 
} from 'react-admin';

const CustomLayout = ({ children, ...props }) => (
  <>
    <Layout {...props}>
      {children}
    </Layout>
    <CheckForApplicationUpdate interval={60000} />
    <ApplicationUpdatedNotification />
  </>
);

// Manual update checking
const UpdateChecker = () => {
  const { updateAvailable, checkForUpdate } = useCheckForApplicationUpdate();
  
  return (
    <div>
      <button onClick={checkForUpdate}>
        Check for Updates
      </button>
      {updateAvailable && (
        <div style={{ color: 'orange' }}>
          Update available! Please refresh the page.
        </div>
      )}
    </div>
  );
};

Utility Functions and Helpers

Data Utilities

import { 
  removeEmpty, 
  removeKey, 
  getMutationMode,
  linkToRecord,
  escapePath
} from 'react-admin';

const removeEmpty: (object: any) => any;
const removeKey: (object: any, key: string) => any;
const getMutationMode: () => 'pessimistic' | 'optimistic' | 'undoable';
const linkToRecord: (basePath: string, id: Identifier, type?: string) => string;
const escapePath: (path: string) => string;

Async Utilities

import { asyncDebounce } from 'react-admin';

const asyncDebounce: <T extends (...args: any[]) => Promise<any>>(
  func: T,
  delay: number
) => T;

React Utilities

import { mergeRefs, shallowEqual } from 'react-admin';

const mergeRefs: <T = any>(...refs: React.Ref<T>[]) => React.RefCallback<T>;
const shallowEqual: (a: any, b: any) => boolean;

Development Utilities

import { useWhyDidYouUpdate, useEvent } from 'react-admin';

const useWhyDidYouUpdate: (name: string, props: Record<string, any>) => void;
const useEvent: <T extends (...args: any[]) => any>(handler: T) => T;

Advanced Integration Examples

Custom Data Pipeline

import { 
  useDataProvider, 
  useStore, 
  useNotify,
  asyncDebounce 
} from 'react-admin';

const useAdvancedDataManager = () => {
  const dataProvider = useDataProvider();
  const [cache, setCache] = useStore('dataCache', {});
  const notify = useNotify();
  
  // Debounced search function
  const debouncedSearch = asyncDebounce(async (query: string) => {
    try {
      const { data } = await dataProvider.getList('posts', {
        pagination: { page: 1, perPage: 10 },
        sort: { field: 'score', order: 'DESC' },
        filter: { q: query }
      });
      
      return data;
    } catch (error) {
      notify('Search failed', { type: 'error' });
      return [];
    }
  }, 300);
  
  // Cached data fetcher
  const getCachedData = async (resource: string, id: string) => {
    const cacheKey = `${resource}:${id}`;
    
    if (cache[cacheKey]) {
      return cache[cacheKey];
    }
    
    try {
      const { data } = await dataProvider.getOne(resource, { id });
      setCache({ ...cache, [cacheKey]: data });
      return data;
    } catch (error) {
      notify(`Failed to fetch ${resource}`, { type: 'error' });
      return null;
    }
  };
  
  return {
    search: debouncedSearch,
    getCachedData,
    clearCache: () => setCache({})
  };
};

Analytics Integration

import { useStore, useDataProvider } from 'react-admin';

const useAnalytics = () => {
  const [events, setEvents] = useStore('analytics.events', []);
  const dataProvider = useDataProvider();
  
  const trackEvent = (eventType: string, data: any) => {
    const event = {
      type: eventType,
      data,
      timestamp: new Date().toISOString(),
      userId: getCurrentUserId()
    };
    
    setEvents([...events, event]);
    
    // Send to analytics service
    sendToAnalytics(event);
  };
  
  const trackPageView = (resource: string, action: string) => {
    trackEvent('page_view', { resource, action });
  };
  
  const trackUserAction = (action: string, resource: string, recordId?: string) => {
    trackEvent('user_action', { action, resource, recordId });
  };
  
  return {
    trackEvent,
    trackPageView,
    trackUserAction,
    events
  };
};

// Usage in components
const AnalyticsWrapper = ({ children, resource, action }) => {
  const { trackPageView } = useAnalytics();
  
  useEffect(() => {
    trackPageView(resource, action);
  }, [resource, action]);
  
  return children;
};

Performance Monitoring

import { useWhyDidYouUpdate, useEvent } from 'react-admin';

const usePerformanceMonitor = (componentName: string, props: any) => {
  const [renderCount, setRenderCount] = useState(0);
  const [renderTimes, setRenderTimes] = useState<number[]>([]);
  
  // Track renders in development
  if (process.env.NODE_ENV === 'development') {
    useWhyDidYouUpdate(componentName, props);
  }
  
  useEffect(() => {
    const startTime = performance.now();
    
    return () => {
      const endTime = performance.now();
      const renderTime = endTime - startTime;
      
      setRenderCount(prev => prev + 1);
      setRenderTimes(prev => [...prev.slice(-19), renderTime]); // Keep last 20 renders
    };
  });
  
  const avgRenderTime = renderTimes.length > 0 
    ? renderTimes.reduce((sum, time) => sum + time, 0) / renderTimes.length 
    : 0;
  
  return {
    renderCount,
    avgRenderTime,
    lastRenderTime: renderTimes[renderTimes.length - 1] || 0
  };
};

// Performance dashboard component
const PerformanceDashboard = () => {
  const [metrics, setMetrics] = useStore('performance.metrics', {});
  
  return (
    <div>
      <h2>Performance Metrics</h2>
      {Object.entries(metrics).map(([component, data]) => (
        <div key={component}>
          <h3>{component}</h3>
          <p>Renders: {data.renderCount}</p>
          <p>Avg Time: {data.avgRenderTime.toFixed(2)}ms</p>
        </div>
      ))}
    </div>
  );
};

Feature Flags System

import { useStore } from 'react-admin';

const useFeatureFlags = () => {
  const [flags, setFlags] = useStore('featureFlags', {});
  
  const isEnabled = (feature: string): boolean => {
    return flags[feature] === true;
  };
  
  const enableFeature = (feature: string) => {
    setFlags({ ...flags, [feature]: true });
  };
  
  const disableFeature = (feature: string) => {
    setFlags({ ...flags, [feature]: false });
  };
  
  const toggleFeature = (feature: string) => {
    setFlags({ ...flags, [feature]: !flags[feature] });
  };
  
  return {
    flags,
    isEnabled,
    enableFeature,
    disableFeature,
    toggleFeature
  };
};

// Feature flag wrapper component
const FeatureGuard = ({ feature, children, fallback = null }) => {
  const { isEnabled } = useFeatureFlags();
  
  return isEnabled(feature) ? children : fallback;
};

// Usage
const AdminPanel = () => (
  <div>
    <FeatureGuard feature="advancedAnalytics">
      <AdvancedAnalyticsWidget />
    </FeatureGuard>
    
    <FeatureGuard 
      feature="betaFeatures" 
      fallback={<div>Beta features coming soon!</div>}
    >
      <BetaFeaturePanel />
    </FeatureGuard>
  </div>
);

React Admin's advanced features provide powerful capabilities for building sophisticated, production-ready admin applications with comprehensive data management, user customization, performance monitoring, and extensibility options.

Install with Tessl CLI

npx tessl i tessl/npm-react-admin

docs

admin-core.md

advanced.md

auth.md

data-management.md

detail-views.md

forms-inputs.md

i18n.md

index.md

layout-navigation.md

lists-data-display.md

ui-components.md

tile.json