Skip to content
45 changes: 12 additions & 33 deletions api/routes/graphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pydantic import BaseModel
from redis import ResponseError

from api.routes.database import connect_database, DatabaseConnectionRequest
from api.agents import AnalysisAgent, RelevancyAgent, ResponseFormatterAgent, FollowUpAgent
from api.auth.user_management import token_required
from api.config import Config
Expand Down Expand Up @@ -799,45 +800,23 @@ async def refresh_graph_schema(request: Request, graph_id: str):
graph_id = _graph_name(request, graph_id)

try:
# Get database connection details
# Get database description and URL
_, db_url = await get_db_description(graph_id)

if not db_url or db_url == "No URL available for this database.":
return JSONResponse({
"success": False,
"error": "No database URL found for this graph"
}, status_code=400)
raise HTTPException(status_code=404, detail="No database URL found for this graph")

# Determine database type and get appropriate loader
db_type, loader_class = get_database_type_and_loader(db_url)
# Create a database connection request with the stored URL
db_request = DatabaseConnectionRequest(url=db_url)

if not loader_class:
return JSONResponse({
"success": False,
"error": "Unable to determine database type"
}, status_code=400)

# Perform schema refresh using the appropriate loader
success, _ = await loader_class.refresh_graph_schema(graph_id, db_url)

if success:
return JSONResponse({
"success": True,
"message": f"Graph schema refreshed successfully using {db_type}"
})

logging.error("Schema refresh failed") # nosemgrep
return JSONResponse({
"success": False,
"error": "Failed to refresh schema"
}, status_code=500)
# Call connect_database to refresh the schema by reconnecting
return await connect_database(request, db_request)

except Exception as e: # pylint: disable=broad-exception-caught
logging.error("Error in manual schema refresh: %s", e) # nosemgrep
return JSONResponse({
"success": False,
"error": "Error refreshing schema"
}, status_code=500)
except HTTPException:
raise
except Exception as e:
logging.error("Error in refresh_graph_schema: %s", str(e))
raise HTTPException(status_code=500, detail="Internal server error while refreshing schema") # pylint: disable=raise-missing-from

@graphs_router.delete("/{graph_id}")
@token_required
Expand Down
52 changes: 26 additions & 26 deletions app/public/css/menu.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@
border-color: var(--text-secondary);
}

#graph-select-refresh {
display: flex;
align-items: center;
justify-content: center;
}

#graph-select-refresh.loading svg {
animation: spin 0.5s linear infinite;
opacity: 0.5;
}

#graph-select-refresh svg {
height: 20px;
width: 20px;
#query-final-result-table {
border-collapse: collapse;
}
Expand All @@ -134,28 +148,9 @@
border-top: 1px solid var(--text-primary);
}

#graph-select {
height: 100%;
padding: 8px 12px;
border-radius: 6px;
border: 1px solid var(--text-primary);
font-size: 14px;
background-color: var(--falkor-secondary);
color: var(--text-primary);
transition: border-color 0.2s;
min-width: 180px;
appearance: none;
background-image: linear-gradient(45deg, transparent 50%, var(--text-secondary) 50%),
linear-gradient(135deg, var(--text-secondary) 50%, transparent 50%);
background-position: calc(100% - 20px) center, calc(100% - 15px) center;
background-size: 5px 5px, 5px 5px;
background-repeat: no-repeat;
cursor: pointer;
}

#schema-graph {
width: 100%;
height: 100%;
height: 100%;
}

#schema-content {
Expand Down Expand Up @@ -385,6 +380,7 @@
}

.graph-selected {
height: 100%;
padding: 8px 14px;
border-radius: 6px;
background: var(--falkor-quaternary);
Expand All @@ -398,25 +394,29 @@
min-width: 160px;
box-sizing: border-box;
font-size: 14px;
gap: 4px;
}

.graph-options {
position: absolute;
top: calc(100%);
left: 0;
right: 0;
top: calc(100% + 20px);
left: -20%;
right: -20%;
background: var(--falkor-secondary);
border: 1px solid var(--border-color);
border-radius: 6px;
border-top-left-radius: 0;
border-top-right-radius: 0;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
max-height: 260px;
overflow: auto;
display: none;
z-index: 50;
}

.graph-custom-dropdown {
height: 100%;
position: relative;
}

.dropdown-option {
display: flex;
align-items: center;
Expand Down Expand Up @@ -462,4 +462,4 @@

.graph-options.open {
display: block;
}
}
58 changes: 29 additions & 29 deletions app/public/css/responsive.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

/* Layout Responsive */
@media (max-width: 768px) {

/* When left toolbar is open, push content to make room */
body.left-toolbar-open .chat-container {
max-width: calc(100vw - 48px);
Expand Down Expand Up @@ -42,13 +43,14 @@

/* Ensure chat header elements are properly positioned when toolbar is open */
body.left-toolbar-open .chat-header {
padding-left: 15px; /* Add extra padding to prevent overlap */
padding-left: 15px;
/* Add extra padding to prevent overlap */
width: 100%;
box-sizing: border-box;
}

/* Ensure dropdown and buttons in header don't get cut off */
body.left-toolbar-open .chat-header > * {
body.left-toolbar-open .chat-header>* {
margin-left: 0;
width: 100%;
}
Expand Down Expand Up @@ -84,15 +86,15 @@
padding: 10px 12px;
font-size: 14px;
}

.chat-header h1 {
font-size: 18px;
}

#message-input {
font-size: 16px !important;
}

#message-input::placeholder {
font-size: 16px !important;
}
Expand All @@ -110,14 +112,13 @@
flex-wrap: nowrap;
align-items: stretch;
}

/* Hide vertical separators on mobile */
.vertical-separator {
display: none;
}

/* Make selectors and buttons fit screen width */
#graph-select,
#custom-file-upload {
flex: 1;
min-width: 0;
Expand All @@ -129,11 +130,7 @@
height: 40px;
box-sizing: border-box;
}

#graph-select {
max-width: 30%;
}


#custom-file-upload {
max-width: 35%;
text-align: center;
Expand All @@ -142,12 +139,12 @@
justify-content: center;
cursor: pointer;
}

.header-button {
width: 100%;
height: 40px;
}

.dropdown-selected {
padding: 8px 6px;
font-size: 13px;
Expand All @@ -157,14 +154,14 @@
align-items: center;
justify-content: space-between;
}

.dropdown-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
flex: 1;
}

.dropdown-arrow {
margin-left: 4px;
flex-shrink: 0;
Expand All @@ -176,18 +173,17 @@
padding: 0;
gap: 5px;
}

#graph-select,

#custom-file-upload {
padding: 6px 4px;
font-size: 12px;
height: 36px;
}

.header-button {
height: 36px;
}

.dropdown-selected {
padding: 6px 4px;
font-size: 12px;
Expand All @@ -211,7 +207,7 @@
transform: none;
margin-left: 10px;
}

#reset-button svg {
width: 18px;
height: 18px;
Expand All @@ -229,13 +225,16 @@
/* Reduce padding on mobile to maximize input space */
padding: 8px;
gap: 4px;
min-width: 0; /* Allow container to shrink */
min-width: 0;
/* Allow container to shrink */
flex-shrink: 1;
}

#message-input {
font-size: 16px !important; /* Prevent zoom on iOS */
min-width: 0; /* Allow input to shrink */
font-size: 16px !important;
/* Prevent zoom on iOS */
min-width: 0;
/* Allow input to shrink */
}

#message-input::placeholder {
Expand All @@ -246,7 +245,8 @@
.input-button {
width: 40px;
height: 40px;
flex-shrink: 0; /* Prevent buttons from shrinking */
flex-shrink: 0;
/* Prevent buttons from shrinking */
}
}

Expand All @@ -266,15 +266,15 @@
width: 40px;
height: 40px;
}

#github-link-btn {
top: 15px;
right: 60px;
padding: 6px 8px;
font-size: 12px;
height: 40px;
}

.theme-icon {
width: 18px;
height: 18px;
Expand Down Expand Up @@ -306,4 +306,4 @@
min-width: 90vw;
margin: 0 5vw;
}
}
}
16 changes: 11 additions & 5 deletions app/templates/components/chat_header.j2
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,28 @@
<img src="/static/icons/queryweaver.webp" alt="Chat Logo" class="logo">
<h1>Natural Language to SQL Generator</h1>
<div class="button-container">
<!-- Custom dropdown to show per-item delete action on hover -->
<button class="action-button" id="graph-select-refresh">
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="none" stroke="currentColor" stroke-width="2"
d="M20,8 C18.5974037,5.04031171 15.536972,3 12,3 C7.02943725,3 3,7.02943725 3,12 C3,16.9705627 7.02943725,21 12,21 L12,21 C16.9705627,21 21,16.9705627 21,12 M21,3 L21,9 L15,9" />
</svg>
</button>
<div id="graph-custom-dropdown" class="graph-custom-dropdown">
<div id="graph-selected" class="graph-selected dropdown-selected" title="Select Database">
<span class="dropdown-text">Select Database</span>
<div id="graph-selected" class="graph-selected dropdown-selected" title="No database">
<span class="dropdown-text">No database</span>
<span class="dropdown-arrow">▼</span>
</div>
<div id="graph-options" class="graph-options dropdown-options" aria-hidden="true"></div>
</div>

<!-- styles for the graph dropdown moved to app/public/css/menu.css -->
<div class="vertical-separator"></div>
<input title="Upload Schema" id="schema-upload" type="file" accept=".json" style="display: none;" tabindex="-1" disabled/>
<input title="Upload Schema" id="schema-upload" type="file" accept=".json" style="display: none;" tabindex="-1"
disabled />
<label for="schema-upload" id="custom-file-upload">
Upload Schema
</label>
<div class="vertical-separator"></div>
<button class="connect-database-btn header-button">Connect Database</button>
</div>
</div>
</div>
Loading