diff --git a/api/core/schema_loader.py b/api/core/schema_loader.py
index bb4dcedb..93c9494b 100644
--- a/api/core/schema_loader.py
+++ b/api/core/schema_loader.py
@@ -142,23 +142,31 @@ async def generate():
return generate()
-async def list_databases(user_id: str, general_prefix: Optional[str] = None) -> list[str]:
+async def list_databases(
+ user_id: str, general_prefix: Optional[str] = None
+) -> list[dict]:
"""
- This route is used to list all the graphs (databases names) that are available in the database.
+ List all graphs (database names) available for the user.
+
+ Returns a list of dicts with keys ``id`` (the full FalkorDB graph name
+ used for API calls), ``name`` (the display name with namespace prefix
+ stripped) and ``is_demo`` (whether the graph is a shared demo graph).
"""
user_graphs = await db.list_graphs()
- # Only include graphs that start with user_id + '_', and strip the prefix
- filtered_graphs = [
- graph[len(f"{user_id}_") :]
- for graph in user_graphs
- if graph.startswith(f"{user_id}_")
- ]
+ result: list[dict] = []
+
+ # User-owned graphs: strip the user_id prefix for display
+ for graph in user_graphs:
+ if graph.startswith(f"{user_id}_"):
+ display_name = graph[len(f"{user_id}_"):]
+ result.append({"id": display_name, "name": display_name, "is_demo": False})
+ # Demo/shared graphs: strip the general prefix for display
if general_prefix:
- demo_graphs = [
- graph for graph in user_graphs if graph.startswith(general_prefix)
- ]
- filtered_graphs = filtered_graphs + demo_graphs
+ for graph in user_graphs:
+ if graph.startswith(general_prefix):
+ display_name = graph[len(general_prefix):]
+ result.append({"id": graph, "name": display_name, "is_demo": True})
- return filtered_graphs
+ return result
diff --git a/app/src/components/chat/ChatInterface.tsx b/app/src/components/chat/ChatInterface.tsx
index 6f43691a..5bd4dcd4 100644
--- a/app/src/components/chat/ChatInterface.tsx
+++ b/app/src/components/chat/ChatInterface.tsx
@@ -522,8 +522,8 @@ const ChatInterface = ({
{/* Bottom Section with Suggestions and Input */}
- {/* Suggestion Cards - Only show for DEMO_CRM database */}
- {(selectedGraph?.id === 'DEMO_CRM' || selectedGraph?.name === 'DEMO_CRM') && (
+ {/* Suggestion Cards - Only show for demo databases */}
+ {selectedGraph?.is_demo && (
{
}
};
- const handleDeleteGraph = async (graphId: string, graphName: string, event: React.MouseEvent) => {
+ const handleDeleteGraph = async (graphId: string, graphName: string, isDemo: boolean, event: React.MouseEvent) => {
event.stopPropagation(); // Prevent dropdown from closing/selecting
-
- // Check if this is a demo database
- const isDemo = graphId.startsWith('general_');
-
+
if (isRefreshingSchema) return;
// Show the delete confirmation modal
setDatabaseToDelete({ id: graphId, name: graphName, isDemo });
@@ -532,7 +529,7 @@ const Index = () => {
Graph-Powered Text-to-SQL
{selectedGraph ? (
- {selectedGraph.name === 'DEMO_CRM' ? 'CRM' : selectedGraph.name}
+ {selectedGraph.name}
) : (
@@ -570,7 +567,7 @@ const Index = () => {
{graphs.map((graph) => {
- const isDemo = graph.id.startsWith('general_');
+ const isDemo = graph.is_demo || false;
return (
{
className={`h-6 w-6 p-0 opacity-0 group-hover:opacity-100 transition-opacity ${
isDemo || isRefreshingSchema || isChatProcessing ? 'cursor-not-allowed opacity-40' : 'hover:bg-red-600 hover:text-white'
}`}
- onClick={(e) => { if (isDemo || isRefreshingSchema || isChatProcessing) return; handleDeleteGraph(graph.id, graph.name, e); }}
+ onClick={(e) => { if (isDemo || isRefreshingSchema || isChatProcessing) return; handleDeleteGraph(graph.id, graph.name, isDemo, e); }}
disabled={isDemo || isRefreshingSchema}
title={isDemo ? 'Demo databases cannot be deleted' : (isRefreshingSchema ? 'Refreshing schema...' : `Delete ${graph.name}`)}
data-testid={`delete-graph-btn-${graph.id}`}
diff --git a/app/src/services/database.ts b/app/src/services/database.ts
index a74f4e96..f1ff046c 100644
--- a/app/src/services/database.ts
+++ b/app/src/services/database.ts
@@ -37,21 +37,19 @@ export class DatabaseService {
const data = await response.json();
console.log('Graphs data received:', data);
- // Backend returns array of strings like ["northwind", "chinook"]
- // Transform to Graph objects
+ // Backend returns array of objects with id, name, is_demo
const graphNames = data.graphs || data || [];
-
+
if (Array.isArray(graphNames) && graphNames.length > 0 && typeof graphNames[0] === 'string') {
- // Transform string array to Graph objects
+ // Legacy fallback: transform string array to Graph objects
return graphNames.map((name: string) => ({
id: name,
name: name,
- created_at: new Date().toISOString(),
- updated_at: new Date().toISOString(),
+ is_demo: false,
}));
}
-
- // If already objects, return as is
+
+ // Already objects from the backend
return graphNames;
} catch (error) {
// Backend not available - return empty array for demo mode
diff --git a/app/src/types/api.ts b/app/src/types/api.ts
index 02dea66d..a0207b45 100644
--- a/app/src/types/api.ts
+++ b/app/src/types/api.ts
@@ -20,8 +20,9 @@ export interface Graph {
id: string;
name: string;
description?: string;
- created_at: string;
- updated_at: string;
+ created_at?: string;
+ updated_at?: string;
+ is_demo: boolean;
table_count?: number;
schema?: any;
}
diff --git a/e2e/logic/api/apiCalls.ts b/e2e/logic/api/apiCalls.ts
index 993fd56b..5e9520b1 100644
--- a/e2e/logic/api/apiCalls.ts
+++ b/e2e/logic/api/apiCalls.ts
@@ -8,6 +8,7 @@ import type {
LoginResponse,
SignupResponse,
LogoutResponse,
+ GraphListItem,
GraphsListResponse,
GraphDataResponse,
GraphUploadResponse,
@@ -156,7 +157,12 @@ export default class ApiCalls {
undefined,
this.defaultRequestContext
);
- return await response.json();
+ const data = await response.json();
+ // Backend now returns objects with {id, name, is_demo}; extract ids for backward compat
+ if (Array.isArray(data) && data.length > 0 && typeof data[0] === 'object') {
+ return (data as GraphListItem[]).map((g) => g.id);
+ }
+ return data;
} catch (error) {
throw new Error(
`Failed to get graphs. \n Error: ${(error as Error).message}`
diff --git a/e2e/logic/api/apiResponses.ts b/e2e/logic/api/apiResponses.ts
index b2a1bb38..ebcbc8bd 100644
--- a/e2e/logic/api/apiResponses.ts
+++ b/e2e/logic/api/apiResponses.ts
@@ -31,6 +31,12 @@ export interface LogoutResponse {
// ==================== GRAPH/DATABASE RESPONSES ====================
+export interface GraphListItem {
+ id: string;
+ name: string;
+ is_demo: boolean;
+}
+
export type GraphsListResponse = string[];
export interface GraphColumn {