MCPcopy Index your code
hub / github.com/microsoft/data-formulator / DataSourceSidebarPanel

Function DataSourceSidebarPanel

src/views/DataSourceSidebar.tsx:353–2072  ·  view source on GitHub ↗
({ panelWidth, onOpenUploadDialog, onCollapse, initialTab = 'sources', connectorRefreshKey = 0, disableConnectors = false })

Source from the content-addressed store, hash-verified

351 connectorRefreshKey?: number;
352 disableConnectors?: boolean;
353}> = ({ panelWidth, onOpenUploadDialog, onCollapse, initialTab = 'sources', connectorRefreshKey = 0, disableConnectors = false }) => {
354 const { t } = useTranslation();
355 const dispatch = useDispatch<AppDispatch>();
356
357 const activeWorkspace = useSelector((state: DataFormulatorState) => state.activeWorkspace);
358 const identityKey = useSelector(
359 (state: DataFormulatorState) => `${state.identity.type}:${state.identity.id}`,
360 );
361
362 // Lightweight selector: only extract the fields we need from tables to avoid
363 // re-rendering the entire sidebar when table row data changes.
364 const tableIdentities = useSelector(
365 (state: DataFormulatorState) => state.tables.map(t => ({
366 id: t.id,
367 connectorId: t.source?.connectorId,
368 databaseTable: t.source?.databaseTable,
369 originalTableName: t.source?.originalTableName,
370 virtualTableId: t.virtual?.tableId,
371 })),
372 // Shallow-compare the mapped array by serializing — cheap because it's just IDs/strings
373 (a, b) => a.length === b.length && a.every((item, i) => item.id === b[i].id),
374 );
375
376 // Connector instances fetched from backend
377 const [connectors, setConnectors] = useState<ConnectorInstance[]>([]);
378 const [loadingConnectors, setLoadingConnectors] = useState(false);
379
380 // Catalog tree state per connector ID. Keep loading/error explicit instead
381 // of inferring it from whether a cache object exists.
382 const [catalogByConnector, setCatalogByConnector] = useState<Record<string, LoadableState<CatalogCache>>>({});
383 const catalogCache = useMemo(() => {
384 const cache: Record<string, CatalogCache> = {};
385 for (const [connectorId, state] of Object.entries(catalogByConnector)) {
386 if (state.data && state.status !== 'error') {
387 cache[connectorId] = state.data;
388 }
389 }
390 return cache;
391 }, [catalogByConnector]);
392
393 // Which source section is currently expanded (only one at a time —
394 // clicking a different connector switches the expansion). Catalog
395 // browsing is a focused activity; users don't need multiple trees open
396 // simultaneously, and keeping it single-expanded means layout above any
397 // focused row stays stable.
398 const [expandedConnectorId, setExpandedConnectorId] = useState<string | null>(null);
399
400 // Tree expanded items per connector
401 const [treeExpanded, setTreeExpanded] = useState<Record<string, string[]>>({});
402
403 // Preview popover state
404 const [preview, setPreview] = useState<PreviewState | null>(null);
405 const [previewAnchor, setPreviewAnchor] = useState<HTMLElement | null>(null);
406 const [importing, setImporting] = useState(false);
407
408 // Delete connector confirmation
409 const [deleteTarget, setDeleteTarget] = useState<ConnectorInstance | null>(null);
410 const [deleting, setDeleting] = useState(false);

Callers

nothing calls this directly

Calls 15

listWorkspacesFunction · 0.90
updateWorkspaceMetaFunction · 0.90
exportWorkspaceFunction · 0.90
generateUUIDFunction · 0.90
importWorkspaceFunction · 0.90
onWorkspaceListChangedFunction · 0.90
loadWorkspaceFunction · 0.90
deleteWorkspaceFunction · 0.90
apiRequestFunction · 0.90
connectorSortOrderFunction · 0.90
loadingLoadableFunction · 0.90
successLoadableFunction · 0.90

Tested by

no test coverage detected