Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:TobikoData Sqlmesh FileExplorer Context

From Leeroopedia


Knowledge Sources
Domains Web_UI, File_Management, State_Management
Last Updated 2026-02-07 20:00 GMT

Overview

Concrete tool for managing file explorer state and operations through React Context in the SQLMesh web client.

Description

This module provides a React Context provider that centralizes all file explorer operations including creating, renaming, moving, and deleting files and directories. It manages the artifact rename state, range selection logic, and confirmation dialogs for destructive operations. The context integrates with the backend API for persistence and handles duplicate name detection and loading states.

Key features include:

  • FileExplorerContext with comprehensive file operation methods
  • createDirectory and createFile with unique name generation
  • renameArtifact with duplicate detection and path updates
  • removeArtifacts with confirmation dialog for destructive actions
  • moveArtifacts with drag-drop support and duplicate handling
  • selectArtifactsInRange for Shift+click multi-selection
  • Position detection (top/middle/bottom) for visual feedback in range selections
  • Loading state management to prevent concurrent operations
  • Error handling integrated with notification system

Usage

Wrap the file explorer UI with FileExplorerProvider and access operations via the useFileExplorer hook. The context handles all state updates and API calls, providing a clean interface for file operations.

Code Reference

Source Location

  • Repository: TobikoData_Sqlmesh
  • File: web/client/src/library/components/fileExplorer/context.tsx

Signature

// Provider component
function FileExplorerProvider({ children }: { children: React.ReactNode }): JSX.Element

// Hook to access context
function useFileExplorer(): FileExplorer

// Context interface
interface FileExplorer {
  artifactRename?: ModelArtifact
  setArtifactRename: (artifact?: ModelArtifact) => void
  selectArtifactsInRange: (to: ModelArtifact) => void
  createDirectory: (parent: ModelDirectory) => void
  createFile: (parent: ModelDirectory, extension?: string) => void
  renameArtifact: (artifact: ModelArtifact, newName?: string) => void
  removeArtifacts: (artifacts: ModelArtifact[]) => void
  removeArtifactWithConfirmation: (artifact: ModelArtifact) => void
  moveArtifacts: (artifacts: ModelArtifact[], target: ModelDirectory) => void
  isTopGroupInActiveRange: (artifact: ModelArtifact) => boolean
  isBottomGroupInActiveRange: (artifact: ModelArtifact) => boolean
  isMiddleGroupInActiveRange: (artifact: ModelArtifact) => boolean
}

// Constants
const EnumFileExplorerChange = {
  Added: 1,
  Modified: 2,
  Deleted: 3,
} as const

Import

import FileExplorerProvider, { useFileExplorer } from '@components/fileExplorer/context'

I/O Contract

Inputs

Name Type Required Description
parent ModelDirectory Yes (for create ops) Parent directory for new files/folders
artifact ModelArtifact Yes (for ops) Target artifact for rename/remove/move
artifacts ModelArtifact[] Yes (for move/remove) Array of artifacts to operate on
target ModelDirectory Yes (for move) Destination directory for move operation
newName string No New name for rename operation
extension string No File extension for createFile (auto-detected if omitted)

Outputs

Name Type Description
context FileExplorer Object with all file operation methods and state

Usage Examples

import FileExplorerProvider, { useFileExplorer } from '@components/fileExplorer/context'
import { ModelDirectory } from '~/models/directory'

// Example 1: Setup with provider
function App() {
  return (
    <FileExplorerProvider>
      <FileExplorerUI />
    </FileExplorerProvider>
  )
}

// Example 2: Using context in components
function FileExplorerUI() {
  const {
    createFile,
    createDirectory,
    renameArtifact,
    removeArtifactWithConfirmation,
    moveArtifacts,
    selectArtifactsInRange,
    artifactRename,
    setArtifactRename,
  } = useFileExplorer()

  const handleNewFile = (parent: ModelDirectory) => {
    // Auto-detects extension based on parent type
    // models/ -> .sql, tests/ -> .yaml, others -> .py
    createFile(parent)
  }

  const handleNewFolder = (parent: ModelDirectory) => {
    createDirectory(parent) // Creates "new_directory" or "new_directory_1" etc.
  }

  const handleRename = (artifact: ModelArtifact, newName: string) => {
    renameArtifact(artifact, newName)
    // Handles duplicate detection
    // Updates file paths in backend
    // Refreshes file tree
  }

  const handleDelete = (artifact: ModelArtifact) => {
    // Shows confirmation dialog automatically
    removeArtifactWithConfirmation(artifact)
  }

  return (
    <div>
      <button onClick={() => handleNewFile(rootDir)}>New File</button>
      <button onClick={() => handleNewFolder(rootDir)}>New Folder</button>
    </div>
  )
}

// Example 3: Range selection for multi-select
function DirectoryItem({ directory }: { directory: ModelDirectory }) {
  const { selectArtifactsInRange } = useFileExplorer()

  const handleClick = (e: React.MouseEvent) => {
    if (e.shiftKey) {
      selectArtifactsInRange(directory)
      // Selects all artifacts between first selected and current
    }
  }

  return <div onClick={handleClick}>{directory.name}</div>
}

// Example 4: Move artifacts with drag-drop
function DraggableFile({ file }: { file: ModelFile }) {
  const { moveArtifacts } = useFileExplorer()
  const activeRange = useStoreProject(s => s.activeRange)
  const inActiveRange = useStoreProject(s => s.inActiveRange)

  const handleDrop = (target: ModelDirectory) => {
    const artifacts = inActiveRange(file) ? activeRange : [file]
    moveArtifacts(artifacts, target)
    // Checks for duplicates
    // Shows confirmation if needed
    // Updates paths in backend
  }

  return <div>{file.name}</div>
}

// Example 5: Rename flow
function RenameFlow() {
  const { artifactRename, setArtifactRename, renameArtifact } = useFileExplorer()

  // User right-clicks directory, selects "Rename"
  // -> setArtifactRename(directory) called
  // -> Input field shown inline

  const handleSubmit = (newName: string) => {
    if (artifactRename) {
      renameArtifact(artifactRename, newName)
      setArtifactRename(undefined) // Exit rename mode
    }
  }

  return artifactRename ? (
    <input
      defaultValue={artifactRename.name}
      onBlur={(e) => handleSubmit(e.target.value)}
    />
  ) : null
}

// Example 6: Delete with confirmation
function DeleteWithConfirmation({ artifact }: { artifact: ModelArtifact }) {
  const { removeArtifactWithConfirmation } = useFileExplorer()

  // Clicking delete shows modal:
  // "Are you sure you want to remove the file 'my_model.sql'?"
  // [Yes, Remove] [No, Cancel]

  return (
    <button onClick={() => removeArtifactWithConfirmation(artifact)}>
      Delete
    </button>
  )
}

// Example 7: Position detection for visual feedback
function ArtifactItem({ artifact }: { artifact: ModelArtifact }) {
  const {
    isTopGroupInActiveRange,
    isMiddleGroupInActiveRange,
    isBottomGroupInActiveRange,
  } = useFileExplorer()

  const isTop = isTopGroupInActiveRange(artifact)
  const isMiddle = isMiddleGroupInActiveRange(artifact)
  const isBottom = isBottomGroupInActiveRange(artifact)

  // Use for border radius styling:
  // - Top: rounded top corners
  // - Middle: no rounded corners
  // - Bottom: rounded bottom corners

  return (
    <div className={clsx(
      isTop && 'rounded-t',
      isMiddle && 'rounded-none',
      isBottom && 'rounded-b'
    )}>
      {artifact.name}
    </div>
  )
}

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment