feat: add column sort, SQL formatter, table stats, insert dialog, saved queries & sessions monitor

- Column sort by header click in table view (ASC/DESC/none cycle, server-side)
- SQL formatter with Format button and Shift+Alt+F keybinding (sql-formatter)
- Table size and row count display in schema tree via pg_class
- Insert row dialog with column type hints and auto-skip for identity columns
- Saved queries (bookmarks) with CRUD backend, sidebar panel, and save dialog
- Active sessions monitor (pg_stat_activity) with auto-refresh, cancel & terminate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 11:52:05 +03:00
parent ab72eeee80
commit 9d54167023
29 changed files with 1223 additions and 18 deletions

View File

@@ -507,3 +507,83 @@ pub async fn manage_role_membership(
Ok(())
}
#[tauri::command]
pub async fn list_sessions(
state: State<'_, AppState>,
connection_id: String,
) -> TuskResult<Vec<SessionInfo>> {
let pools = state.pools.read().await;
let pool = pools
.get(&connection_id)
.ok_or(TuskError::NotConnected(connection_id))?;
let rows = sqlx::query(
"SELECT pid, usename, datname, state, query, \
query_start::text, wait_event_type, wait_event, \
client_addr::text \
FROM pg_stat_activity \
WHERE datname IS NOT NULL \
ORDER BY query_start DESC NULLS LAST",
)
.fetch_all(pool)
.await
.map_err(TuskError::Database)?;
let sessions = rows
.iter()
.map(|row| SessionInfo {
pid: row.get("pid"),
usename: row.get("usename"),
datname: row.get("datname"),
state: row.get("state"),
query: row.get("query"),
query_start: row.get("query_start"),
wait_event_type: row.get("wait_event_type"),
wait_event: row.get("wait_event"),
client_addr: row.get("client_addr"),
})
.collect();
Ok(sessions)
}
#[tauri::command]
pub async fn cancel_query(
state: State<'_, AppState>,
connection_id: String,
pid: i32,
) -> TuskResult<bool> {
let pools = state.pools.read().await;
let pool = pools
.get(&connection_id)
.ok_or(TuskError::NotConnected(connection_id))?;
let row = sqlx::query("SELECT pg_cancel_backend($1)")
.bind(pid)
.fetch_one(pool)
.await
.map_err(TuskError::Database)?;
Ok(row.get::<bool, _>(0))
}
#[tauri::command]
pub async fn terminate_backend(
state: State<'_, AppState>,
connection_id: String,
pid: i32,
) -> TuskResult<bool> {
let pools = state.pools.read().await;
let pool = pools
.get(&connection_id)
.ok_or(TuskError::NotConnected(connection_id))?;
let row = sqlx::query("SELECT pg_terminate_backend($1)")
.bind(pid)
.fetch_one(pool)
.await
.map_err(TuskError::Database)?;
Ok(row.get::<bool, _>(0))
}