Skip to content

Latest commit

 

History

History
717 lines (585 loc) · 17 KB

File metadata and controls

717 lines (585 loc) · 17 KB

Troubleshooting Guide

This guide helps you diagnose and resolve common issues with Adaptly. If you're experiencing problems, check this guide first before seeking additional help.

🚨 Common Issues

1. Component Not Found Errors

Error: Component type MetricCard not found in registry

Causes:

  • Component not properly exported
  • Component not registered in AdaptlyProvider
  • Component name mismatch between code and registry

Solutions:

  1. Check component export:
// ✅ Correct export
export function MetricCard(props: MetricCardProps) {
  return <div>...</div>;
}

// ❌ Incorrect export
export default function MetricCard(props: MetricCardProps) {
  return <div>...</div>;
}
  1. Check component registration:
// ✅ Correct registration
<AdaptlyProvider
  components={{ MetricCard, SalesChart, DataTable }}
  // ... other props
/>

// ❌ Incorrect registration
<AdaptlyProvider
  components={{ metricCard: MetricCard }} // Wrong key
  // ... other props
/>
  1. Check adaptly.json configuration:
{
  "components": {
    "MetricCard": {  // Must match component name
      "description": "Display key performance indicators",
      // ... other config
    }
  }
}

2. API Key Issues

Error: API key not found or Invalid API key

Causes:

  • Environment variable not set
  • Wrong environment variable name
  • Invalid API key
  • API key not accessible

Solutions:

  1. Check environment variable:
# .env.local (Next.js)
NEXT_PUBLIC_GOOGLE_GENERATIVE_AI_API_KEY=your_api_key_here

# .env (React)
REACT_APP_GOOGLE_GENERATIVE_AI_API_KEY=your_api_key_here
  1. Verify variable name:
// ✅ Correct usage
<AdaptlyProvider
  apiKey={process.env.NEXT_PUBLIC_GOOGLE_GENERATIVE_AI_API_KEY!}
  // ... other props
/>

// ❌ Incorrect usage
<AdaptlyProvider
  apiKey={process.env.GOOGLE_API_KEY!} // Wrong variable name
  // ... other props
/>
  1. Test API key:
// Test API key validity
const testApiKey = async () => {
  try {
    const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models', {
      headers: {
        'Authorization': `Bearer ${process.env.NEXT_PUBLIC_GOOGLE_GENERATIVE_AI_API_KEY}`
      }
    });
    console.log('API key valid:', response.ok);
  } catch (error) {
    console.error('API key test failed:', error);
  }
};

3. Storage Issues

Error: Storage not working or Data not persisting

Causes:

  • localStorage disabled
  • Storage quota exceeded
  • Version mismatch
  • Invalid data format

Solutions:

  1. Check localStorage availability:
const checkLocalStorage = () => {
  try {
    localStorage.setItem('test', 'test');
    localStorage.removeItem('test');
    console.log('localStorage is available');
    return true;
  } catch (error) {
    console.error('localStorage not available:', error);
    return false;
  }
};
  1. Check storage quota:
const checkStorageQuota = async () => {
  if ('storage' in navigator && 'estimate' in navigator.storage) {
    const estimate = await navigator.storage.estimate();
    console.log('Storage quota:', estimate.quota);
    console.log('Storage usage:', estimate.usage);
    console.log('Available space:', estimate.quota - estimate.usage);
  }
};
  1. Handle version mismatch:
// Clear storage on version mismatch
const handleVersionMismatch = () => {
  const currentVersion = '2.0.0';
  const storedVersion = localStorage.getItem('my-app-ui_version');
  
  if (storedVersion && storedVersion !== currentVersion) {
    console.log('Version mismatch detected, clearing storage');
    localStorage.removeItem('my-app-ui_1.0.0');
    localStorage.removeItem('my-app-ui_2.0.0');
  }
};

4. LLM Processing Issues

Error: LLM processing failed or AI not responding

Causes:

  • Network issues
  • API rate limits
  • Invalid model name
  • Insufficient API credits

Solutions:

  1. Check network connectivity:
const checkNetwork = async () => {
  try {
    const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models');
    console.log('Network connectivity:', response.ok);
  } catch (error) {
    console.error('Network error:', error);
  }
};
  1. Handle rate limits:
const handleRateLimit = (error: Error) => {
  if (error.message.includes('rate limit')) {
    console.log('Rate limit exceeded, waiting...');
    setTimeout(() => {
      // Retry request
    }, 60000); // Wait 1 minute
  }
};
  1. Check model availability:
const checkModelAvailability = async (provider: string, model: string) => {
  try {
    const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}`);
    console.log('Model available:', response.ok);
  } catch (error) {
    console.error('Model not available:', error);
  }
};

5. Component Rendering Issues

Error: Component not rendering or Empty components

Causes:

  • Invalid component props
  • Missing required props
  • Component validation failures
  • Empty or invalid data

Solutions:

  1. Validate component props:
const validateComponentProps = (component: UIComponent, config: ComponentJsonConfig) => {
  const requiredProps = Object.entries(config.props)
    .filter(([_, propConfig]) => propConfig.required)
    .map(([name, _]) => name);

  for (const prop of requiredProps) {
    if (!component.props[prop]) {
      console.error(`Missing required prop: ${prop}`);
      return false;
    }
  }
  return true;
};
  1. Check component data:
const checkComponentData = (component: UIComponent) => {
  if (component.type === 'MetricCard') {
    const { title, value } = component.props;
    if (!title || !value || value === '$0' || value === '0') {
      console.warn('Invalid metric card data:', component.props);
      return false;
    }
  }
  return true;
};
  1. Debug component rendering:
const debugComponentRendering = (component: UIComponent) => {
  console.log('Rendering component:', component.type);
  console.log('Component props:', component.props);
  console.log('Component position:', component.position);
  console.log('Component visible:', component.visible);
};

🔍 Debugging Tools

1. Enable Debug Logging

<AdaptlyProvider
  // ... other props
  logging={{ enabled: true, level: 'debug' }}
/>

2. Component Inspector

function ComponentInspector() {
  const { adaptation } = useAdaptiveUI();

  return (
    <div className="p-4 bg-gray-100 rounded-lg">
      <h3 className="text-lg font-semibold mb-4">Component Inspector</h3>
      <div className="space-y-2">
        {adaptation.components.map(component => (
          <div key={component.id} className="p-2 bg-white rounded border">
            <div className="flex justify-between items-start">
              <div>
                <p className="font-medium">{component.type}</p>
                <p className="text-sm text-gray-600">ID: {component.id}</p>
                <p className="text-sm text-gray-600">
                  Position: {component.position.x}, {component.position.y} 
                  ({component.position.w}x{component.position.h})
                </p>
              </div>
              <div className="text-sm text-gray-500">
                {component.visible ? 'Visible' : 'Hidden'}
              </div>
            </div>
            <div className="mt-2">
              <p className="text-xs text-gray-500">Props:</p>
              <pre className="text-xs bg-gray-50 p-2 rounded">
                {JSON.stringify(component.props, null, 2)}
              </pre>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

3. Storage Inspector

function StorageInspector() {
  const { hasStoredData, loadFromStorage } = useAdaptiveUI();
  const [storageData, setStorageData] = useState<any>(null);

  const inspectStorage = () => {
    if (hasStoredData()) {
      const data = loadFromStorage();
      setStorageData(data);
    }
  };

  return (
    <div className="p-4 bg-gray-100 rounded-lg">
      <h3 className="text-lg font-semibold mb-4">Storage Inspector</h3>
      <button 
        onClick={inspectStorage}
        className="px-4 py-2 bg-blue-500 text-white rounded mb-4"
      >
        Inspect Storage
      </button>
      {storageData && (
        <div className="bg-white p-4 rounded border">
          <pre className="text-sm overflow-auto">
            {JSON.stringify(storageData, null, 2)}
          </pre>
        </div>
      )}
    </div>
  );
}

4. Performance Monitor

function PerformanceMonitor() {
  const [metrics, setMetrics] = useState({
    renderTime: 0,
    componentCount: 0,
    memoryUsage: 0
  });

  useEffect(() => {
    const startTime = performance.now();
    
    // Measure render time
    const endTime = performance.now();
    const renderTime = endTime - startTime;
    
    // Measure memory usage
    const memoryUsage = (performance as any).memory?.usedJSHeapSize || 0;
    
    setMetrics({
      renderTime,
      componentCount: document.querySelectorAll('[data-adaptly-component]').length,
      memoryUsage
    });
  }, []);

  return (
    <div className="p-4 bg-gray-100 rounded-lg">
      <h3 className="text-lg font-semibold mb-4">Performance Monitor</h3>
      <div className="grid grid-cols-3 gap-4">
        <div>
          <p className="text-sm text-gray-600">Render Time</p>
          <p className="text-lg font-semibold">{metrics.renderTime.toFixed(2)}ms</p>
        </div>
        <div>
          <p className="text-sm text-gray-600">Components</p>
          <p className="text-lg font-semibold">{metrics.componentCount}</p>
        </div>
        <div>
          <p className="text-sm text-gray-600">Memory</p>
          <p className="text-lg font-semibold">{(metrics.memoryUsage / 1024 / 1024).toFixed(2)}MB</p>
        </div>
      </div>
    </div>
  );
}

🛠️ Common Fixes

1. Reset to Default

function ResetButton() {
  const { resetToDefault, clearStorage } = useAdaptiveUI();

  const handleReset = () => {
    resetToDefault();
    clearStorage();
    console.log('Reset to default state');
  };

  return (
    <button 
      onClick={handleReset}
      className="px-4 py-2 bg-red-500 text-white rounded"
    >
      Reset to Default
    </button>
  );
}

2. Clear Storage

function ClearStorageButton() {
  const { clearStorage } = useAdaptiveUI();

  const handleClear = () => {
    const success = clearStorage();
    if (success) {
      console.log('Storage cleared successfully');
    } else {
      console.error('Failed to clear storage');
    }
  };

  return (
    <button 
      onClick={handleClear}
      className="px-4 py-2 bg-yellow-500 text-white rounded"
    >
      Clear Storage
    </button>
  );
}

3. Reload Components

function ReloadComponentsButton() {
  const { loadFromStorage } = useAdaptiveUI();

  const handleReload = () => {
    const savedData = loadFromStorage();
    if (savedData) {
      console.log('Components reloaded from storage');
    } else {
      console.log('No saved data to reload');
    }
  };

  return (
    <button 
      onClick={handleReload}
      className="px-4 py-2 bg-green-500 text-white rounded"
    >
      Reload Components
    </button>
  );
}

🚨 Error Handling

1. Global Error Boundary

class AdaptlyErrorBoundary extends React.Component {
  constructor(props: any) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: any) {
    console.error('Adaptly Error:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="p-4 bg-red-50 border border-red-200 rounded-lg">
          <h3 className="text-lg font-semibold text-red-800">Something went wrong</h3>
          <p className="text-red-600 mt-2">
            {this.state.error?.message || 'An unexpected error occurred'}
          </p>
          <button 
            onClick={() => this.setState({ hasError: false, error: null })}
            className="mt-4 px-4 py-2 bg-red-500 text-white rounded"
          >
            Try Again
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

// Use with AdaptlyProvider
<AdaptlyErrorBoundary>
  <AdaptlyProvider
    // ... props
  />
</AdaptlyErrorBoundary>

2. Error Recovery

function ErrorRecovery() {
  const { resetToDefault, clearStorage } = useAdaptiveUI();
  const [error, setError] = useState<Error | null>(null);

  const handleError = (error: Error) => {
    console.error('Adaptly error:', error);
    setError(error);
  };

  const recoverFromError = () => {
    try {
      resetToDefault();
      clearStorage();
      setError(null);
      console.log('Recovered from error');
    } catch (recoveryError) {
      console.error('Recovery failed:', recoveryError);
    }
  };

  if (error) {
    return (
      <div className="p-4 bg-red-50 border border-red-200 rounded-lg">
        <h3 className="text-lg font-semibold text-red-800">Error Detected</h3>
        <p className="text-red-600 mt-2">{error.message}</p>
        <button 
          onClick={recoverFromError}
          className="mt-4 px-4 py-2 bg-red-500 text-white rounded"
        >
          Recover
        </button>
      </div>
    );
  }

  return null;
}

📞 Getting Help

1. Check Documentation

2. Debug Information

When reporting issues, include:

function DebugInfo() {
  const { adaptation, config, currentLLMProvider } = useAdaptiveUI();

  const debugInfo = {
    version: '1.0.0',
    components: adaptation.components.length,
    layout: adaptation.layout,
    llmProvider: currentLLMProvider,
    storageEnabled: config?.storage?.enabled,
    storageKey: config?.storage?.key,
    storageVersion: config?.storage?.version,
    userAgent: navigator.userAgent,
    localStorage: typeof localStorage !== 'undefined',
    timestamp: new Date().toISOString()
  };

  return (
    <div className="p-4 bg-gray-100 rounded-lg">
      <h3 className="text-lg font-semibold mb-4">Debug Information</h3>
      <pre className="text-sm overflow-auto">
        {JSON.stringify(debugInfo, null, 2)}
      </pre>
    </div>
  );
}

3. Community Support

4. Common Solutions

Issue Solution
Component not found Check export and registration
API key error Verify environment variable
Storage not working Check localStorage availability
AI not responding Verify API key and model
Performance issues Enable memoization and debouncing
Version conflicts Clear storage and update version

🎯 Prevention

1. Best Practices

  • Always validate component props
  • Use TypeScript for type safety
  • Test with different providers
  • Monitor performance metrics
  • Handle errors gracefully
  • Keep documentation updated

2. Testing

// Test component registration
const testComponentRegistration = () => {
  const components = { MetricCard, SalesChart, DataTable };
  const componentNames = Object.keys(components);
  console.log('Registered components:', componentNames);
};

// Test API key
const testApiKey = async () => {
  try {
    const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models');
    console.log('API key test:', response.ok);
  } catch (error) {
    console.error('API key test failed:', error);
  }
};

// Test storage
const testStorage = () => {
  try {
    localStorage.setItem('test', 'test');
    localStorage.removeItem('test');
    console.log('Storage test: passed');
  } catch (error) {
    console.error('Storage test failed:', error);
  }
};

3. Monitoring

// Monitor component changes
useEffect(() => {
  console.log('Components changed:', adaptation.components.length);
}, [adaptation.components]);

// Monitor AI processing
useEffect(() => {
  if (isLLMProcessing) {
    console.log('AI processing started');
  } else {
    console.log('AI processing completed');
  }
}, [isLLMProcessing]);

// Monitor storage
useEffect(() => {
  console.log('Storage status:', hasStoredData());
}, [hasStoredData]);

Still having issues? Check out the GitHub Issues or GitHub Discussions for community support!