feat(query): sql workspace conveniences per opsxdb patterns
- generic ContextMenu component (viewport flip, esc/outside close) - SchemaSidebar table right-click menu: preview data, generate SELECT/INSERT/UPDATE/DELETE templates with pk-aware WHERE, copy table name; double-click table runs preview SELECT; column right-click copy/insert; dialect-aware quoting; preview SELECT carries no LIMIT - SqlEditor selection-first execution (Mod-Enter runs selection else statement at cursor via quote/comment-aware splitter); pagination replays last executed statement - query history persisted server-side: drawer fetches query-histories with keyword/mine/favorites filters, star toggle (new PUT favorite + mine filter endpoints), insert and insert-and-run - custom templates in localStorage alongside built-ins - unit tests: genSql + statement splitter (28 tests green)
This commit is contained in:
1 parent
ff539b47e0
commit
f6d636fa44
16 files changed
+1392
-457
No files matched your search
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"sql-platform/internal/ghost"
|
||||
"sql-platform/internal/handler/resp"
|
||||
"sql-platform/internal/middleware"
|
||||
"sql-platform/internal/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -445,11 +446,36 @@ func ListAnnouncements(c *gin.Context) {
|
||||
|
||||
// GET /api/v1/query-histories
|
||||
func ListQueryHistories(c *gin.Context) {
|
||||
_, _, _ = c.GetInt("user_id"), c.GetString("username"), c.GetString("role")
|
||||
userID, _, _ := middleware.GetCurrentUser(c)
|
||||
|
||||
q := model.DB.Order("id DESC").Limit(100)
|
||||
if c.Query("mine") == "1" {
|
||||
q = q.Where("user_id = ?", userID)
|
||||
}
|
||||
var histories []model.QueryHistory
|
||||
model.DB.Order("id DESC").Limit(100).Find(&histories)
|
||||
c.JSON(http.StatusOK, histories)
|
||||
q.Find(&histories)
|
||||
resp.OK(c, histories)
|
||||
}
|
||||
|
||||
// PUT /api/v1/query-histories/:id/favorite — 收藏/取消收藏
|
||||
func ToggleQueryHistoryFavorite(c *gin.Context) {
|
||||
userID, _, _ := middleware.GetCurrentUser(c)
|
||||
id := c.Param("id")
|
||||
|
||||
var history model.QueryHistory
|
||||
if err := model.DB.First(&history, id).Error; err != nil {
|
||||
resp.NotFound(c, "History not found")
|
||||
return
|
||||
}
|
||||
if history.UserID != userID {
|
||||
resp.Forbidden(c, "只能收藏自己的查询历史")
|
||||
return
|
||||
}
|
||||
if err := model.DB.Model(&history).Update("is_favorite", !history.IsFavorite).Error; err != nil {
|
||||
resp.InternalErr(c, err)
|
||||
return
|
||||
}
|
||||
resp.OK(c, gin.H{"id": history.ID, "is_favorite": !history.IsFavorite})
|
||||
}
|
||||
|
||||
// GET /api/v1/settings — returns settings grouped by `group` field
|
||||
|
||||
@@ -199,6 +199,7 @@ func Setup(r *gin.Engine) {
|
||||
}
|
||||
auth.GET("/announcements", handler.ListAnnouncements)
|
||||
auth.GET("/query-histories", handler.ListQueryHistories)
|
||||
auth.PUT("/query-histories/:id/favorite", handler.ToggleQueryHistoryFavorite)
|
||||
// Notifications CRUD (replaces old channels/templates endpoints)
|
||||
auth.GET("/notifications", handler.ListNotifications)
|
||||
auth.POST("/notifications", handler.CreateNotification)
|
||||
|
||||
Reference in new issue
Block a user