rill icon indicating copy to clipboard operation
rill copied to clipboard

Data Explorer UI

Open lovincyrus opened this issue 1 month ago • 9 comments

This PR adds a Data Explorer UI for Data Warehouse and Databases. Closes https://linear.app/rilldata/issue/APP-516/data-explorer-ui-for-data-warehouse-and-databases

Checklist:

  • [ ] Covered by tests
  • [x] Ran it and it works as intended
  • [x] Reviewed the diff before requesting a review
  • [ ] Checked for unhandled edge cases
  • [ ] Linked the issues it closes
  • [ ] Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • [ ] Intend to cherry-pick into the release branch
  • [x] I'm proud of this work!

lovincyrus avatar Nov 18 '25 11:11 lovincyrus

https://linear.app/rilldata/issue/APP-516/data-explorer-ui-for-data-warehouse-and-databases#comment-1feeaa3c

lovincyrus avatar Nov 20 '25 14:11 lovincyrus

Ready for product QA @royendo

lovincyrus avatar Nov 20 '25 14:11 lovincyrus

Athena: For some reason i was able to create connector even though it errored and took me to table explorer view Screenshot 2025-11-20 at 9 50 41

royendo avatar Nov 20 '25 14:11 royendo

Once we land https://github.com/rilldata/rill/pull/8389, I'll revert this commit: https://github.com/rilldata/rill/pull/8348/commits/d3a10e0b2ac846390bf0f835b70a310d51f2ddc0

lovincyrus avatar Nov 24 '25 19:11 lovincyrus

lmk when its ready for another round of reviews

royendo avatar Nov 24 '25 22:11 royendo

  • New XXX Connector in left panel (does the same as Back)

Can you rephrase this? Thank you!

lovincyrus avatar Nov 25 '25 15:11 lovincyrus

  • New XXX Connector in left panel (does the same as Back)

Can you rephrase this? Thank you!

As the design has in the left panel, theres a ui button to create new connector

royendo avatar Nov 25 '25 17:11 royendo

Component Complexity: AddDataForm.svelte needs refactoring before merge

The new explorer state tracking (lines 142-152) highlights a concerning architectural issue with AddDataForm.svelte that should be addressed before merging.

The Problem

This PR adds 5+ new state variables and a 30-line model creation function to an already complex component:

// Lines 142-152: New state for explorer step
let selectedConnectorForModel = "";
let selectedDatabaseForModel = "";
let selectedSchemaForModel = "";
let selectedTableForModel = "";
let creatingModel = false;
$: modelingSupportQuery = useIsModelingSupportedForConnector(...)
$: isModelingSupportedForSelected = $modelingSupportQuery.data || false;

// Lines 325-352: New handleCreateModel function (~30 lines)

Before this PR: 513 lines
After this PR: 592 lines (+15%)

Why This Matters

AddDataForm.svelte is now handling too many concerns:

  1. Form rendering and validation for multiple connector types
  2. Multi-step navigation (connector → source → explorer)
  3. Error management (DSN, params, connector-specific)
  4. File upload handling
  5. YAML preview computation
  6. "Save anyway" flow
  7. NEW: Table selection tracking (4 variables)
  8. NEW: Model creation logic with connector support detection

The explorer step has fundamentally different concerns than form submission:

  • Form steps: Validate inputs → Submit → Handle errors
  • Explorer step: Browse data → Select table → Create resource

These shouldn't share the same state container.

Required Changes

Option 1: Extract to Separate Component(Recommended)

Create AddDataExplorerStep.svelte to encapsulate all explorer-specific logic:

<!-- AddDataExplorerStep.svelte -->
<script lang="ts">
  export let connector: V1ConnectorDriver;
  export let onModelCreated: (path: string) => void;
  export let onBack: () => void;

  // All explorer state lives here
  let selectedConnector = "";
  let selectedDatabase = "";
  let selectedSchema = "";
  let selectedTable = "";
  let creatingModel = false;

  $: modelingSupportQuery = useIsModelingSupportedForConnector(
    instanceId,
    selectedConnector
  );

  async function handleCreateModel() {
    // Model creation logic (moved from AddDataForm)
    const [path] = await createModelFromTable(...);
    onModelCreated(path);
  }
</script>

<DataExplorerDialog
  connectorDriver={connector}
  onSelect={(detail) => {
    selectedConnector = detail.connector;
    selectedDatabase = detail.database;
    selectedSchema = detail.schema;
    selectedTable = detail.table;
  }}
/>

<Button
  disabled={!selectedTable || creatingModel}
  loading={creatingModel}
  onClick={handleCreateModel}
>
  Create model
</Button>

Then simplify AddDataForm.svelte:

{#if stepState.step === "explorer"}
  <AddDataExplorerStep 
    {connector} 
    onModelCreated={async (path) => {
      await goto(`/files${path}`);
      onClose();
    }}
    onBack={formManager.handleBack}
  />
{:else}
  <!-- Existing form steps - connector and source -->
{/if}

Benefits:

  • Reduces AddDataForm.svelte from 592 → ~520 lines
  • Clear separation of concerns (form logic vs. data browsing)
  • Explorer can be tested independently
  • State is colocated with the step that uses it
  • Easier to maintain and extend

Option 2: Extract to Utility Function (Minimum acceptable)

If you prefer not to create a new component, at minimum extract handleCreateModel to a separate utility:

// web-common/src/features/sources/modal/model-creation-utils.ts
export async function createModelFromExplorerSelection(
  queryClient: QueryClient,
  options: {
    connector: string;
    database: string;
    schema: string;
    table: string;
    isModelingSupported: boolean;
  }
): Promise<[string, string]> {
  return options.isModelingSupported
    ? await createSqlModelFromTable(
        queryClient,
        options.connector,
        options.database,
        options.schema,
        options.table
      )
    : await createYamlModelFromTable(
        queryClient,
        options.connector,
        options.database,
        options.schema,
        options.table
      );
}

This reduces duplication and makes the logic testable, but doesn't address the state management concern.

Recommendation

Please implement Option 1 (extract to separate component) before merging. This will:

  • Keep the codebase maintainable as features grow
  • Make testing easier
  • Follow single responsibility principle
  • Set a good precedent for future multi-step flows

The refactoring shouldn't take long since the logic is already written—it just needs to be moved into the right component boundary.


Developed in collaboration with Claude Code

ericpgreen2 avatar Nov 25 '25 22:11 ericpgreen2

Additionally, like we implemented in CloudStoarge, can you add the Already connected? Dialogue in the right panel? Screenshot 2025-12-10 at 10 03 58

royendo avatar Dec 10 '25 15:12 royendo

Additionally, like we implemented in CloudStoarge, can you add the Already connected? Dialogue in the right panel? Screenshot 2025-12-10 at 10 03 58

Since this is a change from https://github.com/rilldata/rill/pull/8467, we should wait for https://github.com/rilldata/rill/pull/8467 to land before duplicating the same lines of code.

lovincyrus avatar Dec 11 '25 17:12 lovincyrus

Closing this as we focus on the schema-driven refactor.

lovincyrus avatar Dec 22 '25 16:12 lovincyrus