DEV Community

Armaan Khan
Armaan Khan

Posted on

react

import React, { useState, useEffect } from 'react';
import { BarChart3, Database, Users, Clock, AlertCircle, CheckCircle, Activity, ArrowLeft, Eye, TrendingUp, Server } from 'lucide-react';

const API_BASE_URL = 'http://localhost:5000';

const WarehouseAnalyticsDashboard = () => {
  const [currentView, setCurrentView] = useState('warehouses');
  const [warehouses, setWarehouses] = useState([]);
  const [selectedWarehouse, setSelectedWarehouse] = useState(null);
  const [selectedMetric, setSelectedMetric] = useState(null);
  const [selectedUser, setSelectedUser] = useState(null);
  const [queriesByMetric, setQueriesByMetric] = useState({});
  const [userQueries, setUserQueries] = useState([]);
  const [queryDetails, setQueryDetails] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // Fetch warehouses data
  useEffect(() => {
    fetchWarehouses();
  }, []);

  const fetchWarehouses = async () => {
    try {
      setLoading(true);
      const response = await fetch(`${API_BASE_URL}/warehouses`);
      const data = await response.json();

      if (data.status === 'success') {
        setWarehouses(data.data);
        setError(null);
      } else {
        setError(data.error || 'Failed to fetch warehouses');
      }
    } catch (err) {
      setError('Failed to connect to backend. Make sure Flask server is running.');
    } finally {
      setLoading(false);
    }
  };

  const fetchQueriesByMetric = async (warehouseId, metric) => {
    try {
      setLoading(true);
      const response = await fetch(`${API_BASE_URL}/queries/by-warehouse/${warehouseId}/${metric}`);
      const data = await response.json();

      if (data.status === 'success') {
        setQueriesByMetric(data);
        setSelectedWarehouse(warehouseId);
        setSelectedMetric(metric);
        setCurrentView('queries-by-metric');
      }
    } catch (err) {
      setError('Failed to fetch queries');
    } finally {
      setLoading(false);
    }
  };

  const fetchUserQueries = async (warehouseId, metric, userName) => {
    try {
      setLoading(true);
      const response = await fetch(`${API_BASE_URL}/queries/by-user/${warehouseId}/${metric}/${encodeURIComponent(userName)}`);
      const data = await response.json();

      if (data.status === 'success') {
        setUserQueries(data.data);
        setSelectedUser(userName);
        setCurrentView('user-queries');
      }
    } catch (err) {
      setError('Failed to fetch user queries');
    } finally {
      setLoading(false);
    }
  };

  const fetchQueryDetails = async (queryId) => {
    try {
      setLoading(true);
      const response = await fetch(`${API_BASE_URL}/query/details/${queryId}`);
      const data = await response.json();

      if (data.status === 'success') {
        setQueryDetails(data.data);
        setCurrentView('query-details');
      }
    } catch (err) {
      setError('Failed to fetch query details');
    } finally {
      setLoading(false);
    }
  };

  const formatNumber = (num) => {
    if (num === null || num === undefined) return '0';
    return num.toLocaleString();
  };

  const formatDuration = (ms) => {
    if (!ms) return 'N/A';
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);

    if (hours > 0) return `${hours}h ${minutes % 60}m`;
    if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
    return `${seconds}s`;
  };

  const getMetricColor = (metric) => {
    const colors = {
      'queries-1-10-sec': 'text-green-600 bg-green-50',
      'queries-10-20-sec': 'text-blue-600 bg-blue-50',
      'queries-20-60-sec': 'text-yellow-600 bg-yellow-50',
      'queries-1-3-min': 'text-orange-600 bg-orange-50',
      'queries-3-5-min': 'text-red-600 bg-red-50',
      'queries-5-plus-min': 'text-red-800 bg-red-100',
      'failed-queries': 'text-red-600 bg-red-50',
      'successful-queries': 'text-green-600 bg-green-50',
      'queries-spilled-local': 'text-purple-600 bg-purple-50',
      'queries-spilled-remote': 'text-purple-800 bg-purple-100'
    };
    return colors[metric] || 'text-gray-600 bg-gray-50';
  };

  const getStatusIcon = (status) => {
    switch (status) {
      case 'SUCCESS': return <CheckCircle className="w-4 h-4 text-green-500" />;
      case 'FAIL': return <AlertCircle className="w-4 h-4 text-red-500" />;
      case 'RUNNING': return <Activity className="w-4 h-4 text-blue-500" />;
      default: return <Clock className="w-4 h-4 text-gray-500" />;
    }
  };

  if (loading) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="flex flex-col items-center space-y-4">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
          <p className="text-gray-600">Loading analytics data...</p>
        </div>
      </div>
    );
  }

  if (error) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="bg-white p-8 rounded-lg shadow-md max-w-md w-full">
          <AlertCircle className="w-12 h-12 text-red-500 mx-auto mb-4" />
          <h2 className="text-xl font-semibold text-gray-900 text-center mb-2">Connection Error</h2>
          <p className="text-gray-600 text-center mb-4">{error}</p>
          <button 
            onClick={fetchWarehouses}
            className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors"
          >
            Retry
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      {/* Header */}
      <header className="bg-white shadow-sm border-b border-gray-200">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="flex items-center justify-between h-16">
            <div className="flex items-center space-x-4">
              {currentView !== 'warehouses' && (
                <button
                  onClick={() => {
                    if (currentView === 'query-details') setCurrentView('user-queries');
                    else if (currentView === 'user-queries') setCurrentView('queries-by-metric');
                    else if (currentView === 'queries-by-metric') setCurrentView('warehouses');
                  }}
                  className="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
                >
                  <ArrowLeft className="w-5 h-5" />
                </button>
              )}
              <div className="flex items-center space-x-3">
                <Database className="w-8 h-8 text-blue-600" />
                <h1 className="text-2xl font-bold text-gray-900">Warehouse Analytics</h1>
              </div>
            </div>
            <div className="flex items-center space-x-2 text-sm text-gray-500">
              <Server className="w-4 h-4" />
              <span>{warehouses.length} Warehouses</span>
            </div>
          </div>
        </div>
      </header>

      <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
        {currentView === 'warehouses' && (
          <WarehousesView 
            warehouses={warehouses} 
            onMetricClick={fetchQueriesByMetric}
          />
        )}

        {currentView === 'queries-by-metric' && (
          <QueriesByMetricView 
            data={queriesByMetric}
            onUserClick={fetchUserQueries}
          />
        )}

        {currentView === 'user-queries' && (
          <UserQueriesView 
            queries={userQueries}
            userName={selectedUser}
            onQueryClick={fetchQueryDetails}
          />
        )}

        {currentView === 'query-details' && (
          <QueryDetailsView queryDetails={queryDetails} />
        )}
      </main>
    </div>
  );
};

// Warehouses View Component
const WarehousesView = ({ warehouses, onMetricClick }) => {
  const formatNumber = (num) => num ? num.toLocaleString() : '0';

  const getClickableMetrics = (warehouse) => [
    { key: 'QUERIES_1_10_SEC', label: '1-10 sec', value: warehouse.QUERIES_1_10_SEC, apiKey: '1-10-seconds' },
    { key: 'QUERIES_10_20_SEC', label: '10-20 sec', value: warehouse.QUERIES_10_20_SEC, apiKey: '10-20-seconds' },
    { key: 'QUERIES_20_60_SEC', label: '20-60 sec', value: warehouse.QUERIES_20_60_SEC, apiKey: '20-60-seconds' },
    { key: 'QUERIES_1_3_MIN', label: '1-3 min', value: warehouse.QUERIES_1_3_MIN, apiKey: '1-3-minutes' },
    { key: 'QUERIES_3_5_MIN', label: '3-5 min', value: warehouse.QUERIES_3_5_MIN, apiKey: '3-5-minutes' },
    { key: 'QUERIES_5_PLUS_MIN', label: '5+ min', value: warehouse.QUERIES_5_PLUS_MIN, apiKey: '5-plus-minutes' },
    { key: 'FAILED_QUERIES', label: 'Failed', value: warehouse.FAILED_QUERIES, apiKey: 'failed-queries' },
    { key: 'SUCCESSFUL_QUERIES', label: 'Success', value: warehouse.SUCCESSFUL_QUERIES, apiKey: 'successful-queries' },
    { key: 'QUERIES_SPILLED_LOCAL', label: 'Spilled Local', value: warehouse.QUERIES_SPILLED_LOCAL, apiKey: 'spilled-local' },
    { key: 'QUERIES_SPILLED_REMOTE', label: 'Spilled Remote', value: warehouse.QUERIES_SPILLED_REMOTE, apiKey: 'spilled-remote' }
  ];

  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <h2 className="text-3xl font-bold text-gray-900">Data Warehouses</h2>
        <div className="text-sm text-gray-500">Click on any metric to drill down</div>
      </div>

      <div className="grid gap-6">
        {warehouses.map((warehouse) => (
          <div key={warehouse.WAREHOUSE_ID} className="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden">
            <div className="px-6 py-4 bg-gray-50 border-b border-gray-200">
              <div className="flex items-center justify-between">
                <div>
                  <h3 className="text-xl font-semibold text-gray-900">{warehouse.WAREHOUSE_NAME}</h3>
                  <p className="text-sm text-gray-600">ID: {warehouse.WAREHOUSE_ID}</p>
                </div>
                <div className="text-right">
                  <div className="text-2xl font-bold text-blue-600">{formatNumber(warehouse.TOTAL_QUERIES)}</div>
                  <div className="text-sm text-gray-500">Total Queries</div>
                </div>
              </div>
            </div>

            <div className="p-6">
              <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4">
                {getClickableMetrics(warehouse).map((metric) => (
                  <div
                    key={metric.key}
                    onClick={() => metric.value > 0 && onMetricClick(warehouse.WAREHOUSE_ID, metric.apiKey)}
                    className={`p-4 rounded-lg border transition-all duration-200 ${
                      metric.value > 0 
                        ? 'cursor-pointer hover:shadow-md hover:scale-105 border-blue-200 bg-blue-50' 
                        : 'border-gray-200 bg-gray-50'
                    }`}
                  >
                    <div className="text-2xl font-bold text-gray-900">{formatNumber(metric.value)}</div>
                    <div className="text-sm text-gray-600 mt-1">{metric.label}</div>
                    {metric.value > 0 && (
                      <div className="text-xs text-blue-600 mt-2 flex items-center">
                        <TrendingUp className="w-3 h-3 mr-1" />
                        Click to explore
                      </div>
                    )}
                  </div>
                ))}
              </div>

              <div className="mt-6 pt-4 border-t border-gray-200">
                <div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
                  <div>
                    <span className="text-gray-500">Size:</span> 
                    <span className="ml-2 font-medium">{warehouse.WAREHOUSE_SIZE || 'N/A'}</span>
                  </div>
                  <div>
                    <span className="text-gray-500">Type:</span> 
                    <span className="ml-2 font-medium">{warehouse.WAREHOUSE_TYPE || 'N/A'}</span>
                  </div>
                  <div>
                    <span className="text-gray-500">Credits Used:</span> 
                    <span className="ml-2 font-medium">{formatNumber(warehouse.TOTAL_CREDITS_USED)}</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

// Queries by Metric View Component
const QueriesByMetricView = ({ data, onUserClick }) => {
  const formatNumber = (num) => num ? num.toLocaleString() : '0';

  return (
    <div className="space-y-6">
      <div className="bg-white rounded-lg shadow-md p-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-4">
          Queries by {data.metric_type?.replace(/-/g, ' ')} - Warehouse {data.warehouse_id}
        </h2>
        <div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm bg-gray-50 p-4 rounded-lg">
          <div><span className="text-gray-500">Total Queries:</span> <span className="font-semibold ml-2">{formatNumber(data.count)}</span></div>
          <div><span className="text-gray-500">Users:</span> <span className="font-semibold ml-2">{formatNumber(data.users)}</span></div>
          <div><span className="text-gray-500">Metric:</span> <span className="font-semibold ml-2 capitalize">{data.metric_type?.replace(/-/g, ' ')}</span></div>
        </div>
      </div>

      <div className="grid gap-4">
        {Object.entries(data.data || {}).map(([userName, queries]) => (
          <div
            key={userName}
            onClick={() => onUserClick(data.warehouse_id, data.metric_type, userName)}
            className="bg-white rounded-lg shadow-md p-6 cursor-pointer hover:shadow-lg hover:bg-gray-50 transition-all duration-200 border border-gray-200 hover:border-blue-300"
          >
            <div className="flex items-center justify-between">
              <div className="flex items-center space-x-3">
                <Users className="w-6 h-6 text-blue-600" />
                <div>
                  <h3 className="text-lg font-semibold text-gray-900">{userName}</h3>
                  <p className="text-sm text-gray-600">{queries.length} queries in this category</p>
                </div>
              </div>
              <div className="text-right">
                <div className="text-2xl font-bold text-blue-600">{queries.length}</div>
                <div className="text-xs text-blue-600 flex items-center justify-end mt-1">
                  <Eye className="w-3 h-3 mr-1" />
                  View Details
                </div>
              </div>
            </div>
          </div>
        ))}
      </div>

      {Object.keys(data.data || {}).length === 0 && (
        <div className="text-center py-12 bg-white rounded-lg shadow-md">
          <AlertCircle className="w-12 h-12 text-gray-400 mx-auto mb-4" />
          <h3 className="text-lg font-medium text-gray-900 mb-2">No queries found</h3>
          <p className="text-gray-600">No queries match this metric for the selected warehouse.</p>
        </div>
      )}
    </div>
  );
};

// User Queries View Component
const UserQueriesView = ({ queries, userName, onQueryClick }) => {
  const formatDuration = (ms) => {
    if (!ms) return 'N/A';
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    return minutes > 0 ? `${minutes}m ${seconds % 60}s` : `${seconds}s`;
  };

  const getStatusIcon = (status) => {
    switch (status) {
      case 'SUCCESS': return <CheckCircle className="w-4 h-4 text-green-500" />;
      case 'FAIL': return <AlertCircle className="w-4 h-4 text-red-500" />;
      case 'RUNNING': return <Activity className="w-4 h-4 text-blue-500" />;
      default: return <Clock className="w-4 h-4 text-gray-500" />;
    }
  };

  return (
    <div className="space-y-6">
      <div className="bg-white rounded-lg shadow-md p-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-4">Queries for {userName}</h2>
        <p className="text-gray-600">{queries.length} queries found</p>
      </div>

      <div className="bg-white rounded-lg shadow-md overflow-hidden">
        <div className="overflow-x-auto">
          <table className="w-full">
            <thead className="bg-gray-50">
              <tr>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Query</th>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Duration</th>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Start Time</th>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
              </tr>
            </thead>
            <tbody className="bg-white divide-y divide-gray-200">
              {queries.map((query, index) => (
                <tr key={query.QUERY_ID} className="hover:bg-gray-50">
                  <td className="px-6 py-4">
                    <div className="text-sm font-medium text-gray-900 truncate max-w-xs">
                      {query.QUERY_TEXT_PREVIEW || query.QUERY_TYPE || 'N/A'}
                    </div>
                    <div className="text-xs text-gray-500">ID: {query.QUERY_ID}</div>
                  </td>
                  <td className="px-6 py-4">
                    <div className="flex items-center space-x-2">
                      {getStatusIcon(query.EXECUTION_STATUS)}
                      <span className="text-sm text-gray-900">{query.EXECUTION_STATUS}</span>
                    </div>
                  </td>
                  <td className="px-6 py-4 text-sm text-gray-900">
                    {formatDuration(query.TOTAL_ELAPSED_TIME)}
                  </td>
                  <td className="px-6 py-4 text-sm text-gray-900">
                    {query.START_TIME ? new Date(query.START_TIME).toLocaleString() : 'N/A'}
                  </td>
                  <td className="px-6 py-4">
                    <button
                      onClick={() => onQueryClick(query.QUERY_ID)}
                      className="inline-flex items-center px-3 py-1 text-xs font-medium text-blue-600 bg-blue-100 rounded-full hover:bg-blue-200 transition-colors"
                    >
                      <Eye className="w-3 h-3 mr-1" />
                      Details
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
};

// Query Details View Component
const QueryDetailsView = ({ queryDetails }) => {
  const formatDuration = (ms) => {
    if (!ms) return 'N/A';
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    return minutes > 0 ? `${minutes}m ${seconds % 60}s` : `${seconds}s`;
  };

  const formatBytes = (bytes) => {
    if (!bytes) return 'N/A';
    const units = ['B', 'KB', 'MB', 'GB', 'TB'];
    let size = bytes;
    let unitIndex = 0;

    while (size >= 1024 && unitIndex < units.length - 1) {
      size /= 1024;
      unitIndex++;
    }

    return `${size.toFixed(2)} ${units[unitIndex]}`;
  };

  const formatNumber = (num) => num ? num.toLocaleString() : 'N/A';

  return (
    <div className="space-y-6">
      <div className="bg-white rounded-lg shadow-md p-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-4">Query Details</h2>
        <div className="text-sm text-gray-600 bg-gray-50 p-3 rounded-lg">
          <strong>Query ID:</strong> {queryDetails.QUERY_ID}
        </div>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
        {/* Basic Information */}
        <div className="bg-white rounded-lg shadow-md p-6">
          <h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
            <BarChart3 className="w-5 h-5 mr-2 text-blue-600" />
            Basic Information
          </h3>
          <div className="space-y-3">
            <div><span className="text-gray-500">Query Type:</span> <span className="ml-2 font-medium">{queryDetails.QUERY_TYPE}</span></div>
            <div><span className="text-gray-500">Status:</span> <span className="ml-2 font-medium">{queryDetails.EXECUTION_STATUS}</span></div>
            <div><span className="text-gray-500">User:</span> <span className="ml-2 font-medium">{queryDetails.USER_NAME}</span></div>
            <div><span className="text-gray-500">Role:</span> <span className="ml-2 font-medium">{queryDetails.ROLE_NAME}</span></div>
            <div><span className="text-gray-500">Database:</span> <span className="ml-2 font-medium">{queryDetails.DATABASE_NAME}</span></div>
            <div><span className="text-gray-500">Schema:</span> <span className="ml-2 font-medium">{queryDetails.SCHEMA_NAME}</span></div>
          </div>
        </div>

        {/* Performance Metrics */}
        <div className="bg-white rounded-lg shadow-md p-6">
          <h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
            <TrendingUp className="w-5 h-5 mr-2 text-green-600" />
            Performance Metrics
          </h3>
          <div className="space-y-3">
            <div><span className="text-gray-500">Total Duration:</span> <span className="ml-2 font-medium">{formatDuration(queryDetails.TOTAL_ELAPSED_TIME)}</span></div>
            <div><span className="text-gray-500">Execution Time:</span> <span className="ml-2 font-medium">{formatDuration(queryDetails.EXECUTION_TIME)}</span></div>
            <div><span className="text-gray-500">Compilation Time:</span> <span className="ml-2 font-medium">{formatDuration(queryDetails.COMPILATION_TIME)}</span></div>
            <div><span className="text-gray-500">Rows Produced:</span> <span className="ml-2 font-medium">{formatNumber(queryDetails.ROWS_PRODUCED)}</span></div>
            <div><span className="text-gray-500">Bytes Scanned:</span> <span className="ml-2 font-medium">{formatBytes(queryDetails.BYTES_SCANNED)}</span></div>
            <div><span className="text-gray-500">Cache Hit %:</span> <span className="ml-2 font-medium">{queryDetails.PERCENTAGE_SCANNED_FROM_CACHE}%</span></div>
          </div>
        </div>

        {/* Warehouse Information */}
        <div className="bg-white rounded-lg shadow-md p-6">
          <h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
            <Server className="w-5 h-5 mr-2 text-purple-600" />
            Warehouse Information
          </h3>
          <div className="space-y-3">
            <div><span className="text-gray-500">Warehouse:</span> <span className="ml-2 font-medium">{queryDetails.WAREHOUSE_NAME}</span></div>
            <div><span className="text-gray-500">Size:</span> <span className="ml-2 font-medium">{queryDetails.WAREHOUSE_SIZE}</span></div>
            <div><span className="text-gray-500">Type:</span> <span className="ml-2 font-medium">{queryDetails.WAREHOUSE_TYPE}</span></div>
            <div><span className="text-gray-500">Credits Used:</span> <span className="ml-2 font-medium">{queryDetails.CREDITS_USED_CLOUD_SERVICES}</span></div>
            <div><span className="text-gray-500">Local Spill:</span> <span className="ml-2 font-medium">{formatBytes(queryDetails.BYTES_SPILLED_TO_LOCAL_STORAGE)}</span></div>
            <div><span className="text-gray-500">Remote Spill:</span> <span className="ml-2 font-medium">{formatBytes(queryDetails.BYTES_SPILLED_TO_REMOTE_STORAGE)}</span></div>
          </div>
        </div>

        {/* Timing Details */}
        <div className="bg-white rounded-lg shadow-md p-6">
          <h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
            <Clock className="w-5 h-5 mr-2 text-orange-600" />
            Timing Details
          </h3>
          <div className="space-y-3">
            <div><span className="text-gray-500">Start Time:</span> <span className="ml-2 font-medium">{queryDetails.START_TIME ? new Date(queryDetails.START_TIME).toLocaleString() : 'N/A'}</span></div>
            <div><span className="text-gray-500">End Time:</span> <span className="ml-2 font-medium">{queryDetails.END_TIME ? new Date(queryDetails.END_TIME).toLocaleString() : 'N/A'}</span></div>
            <div><span className="text-gray-500">Queue Time:</span> <span className="ml-2 font-medium">{formatDuration(queryDetails.QUEUED_PROVISIONING_TIME)}</span></div>
            <div><span className="text-gray-500">Blocked Time:</span> <span className="ml-2 font-medium">{formatDuration(queryDetails.TRANSACTION_BLOCKED_TIME)}</span></div>
            <div><span className="text-gray-500">Performance:</span> <span className="ml-2 font-medium">{queryDetails.PERFORMANCE_CATEGORY}</span></div>
            <div><span className="text-gray-500">Cache Efficiency:</span> <span className="ml-2 font-medium">{queryDetails.CACHE_EFFICIENCY}</span></div>
          </div>
        </div>
      </div>

      {/* Query Text */}
      {queryDetails.QUERY_TEXT && (
        <div className="bg-white rounded-lg shadow-md p-6">
          <h3 className="text-lg font-semibold text-gray-900 mb-4">Query Text</h3>
          <div className="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto">
            <pre className="text-sm whitespace-pre-wrap">{queryDetails.QUERY_TEXT}</pre>
          </div>
        </div>
      )}

      {/* Error Information */}
      {queryDetails.ERROR_MESSAGE && (
        <div className="bg-white rounded-lg shadow-md p-6">
          <h3 className="text-lg font-semibold text-red-600 mb-4 flex items-center">
            <AlertCircle className="w-5 h-5 mr-2" />
            Error Information
          </h3>
          <div className="space-y-3">
            <div><span className="text-gray-500">Error Code:</span> <span className="ml-2 font-medium text-red-600">{queryDetails.ERROR_CODE}</span></div>
            <div className="bg-red-50 p-4 rounded-lg">
              <span className="text-red-800">{queryDetails.ERROR_MESSAGE}</span>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

export default WarehouseAnalyticsDashboard;
Enter fullscreen mode Exit fullscreen mode

Top comments (0)