mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
working on playbooks and history view
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
DROP TABLE playbook;
|
||||
|
||||
DROP TABLE playbook_entry;
|
||||
@@ -0,0 +1,16 @@
|
||||
CREATE TABLE playbook (
|
||||
playbookid varchar(36) PRIMARY KEY,
|
||||
playbookname varchar(100) NOT NULL,
|
||||
description text NOT NULL,
|
||||
entryids json NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE playbook_entry (
|
||||
entryid varchar(36) PRIMARY KEY,
|
||||
playbookid varchar(36) NOT NULL,
|
||||
description text NOT NULL,
|
||||
alias varchar(50) NOT NULL,
|
||||
cmdstr text NOT NULL,
|
||||
createdts bigint NOT NULL,
|
||||
updatedts bigint NOT NULL
|
||||
);
|
||||
@@ -176,6 +176,7 @@ func init() {
|
||||
registerCmdFn("telemetry:show", TelemetryShowCommand)
|
||||
|
||||
registerCmdFn("history", HistoryCommand)
|
||||
registerCmdFn("history:viewall", HistoryViewAllCommand)
|
||||
|
||||
registerCmdFn("bookmarks:show", BookmarksShowCommand)
|
||||
|
||||
@@ -1809,6 +1810,35 @@ func ClearCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
|
||||
|
||||
}
|
||||
|
||||
func HistoryViewAllCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
_, err := resolveUiIds(ctx, pk, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offset, err := resolveNonNegInt(pk.Kwargs["offset"], 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := sstore.HistoryQueryOpts{MaxItems: 51, Offset: offset}
|
||||
if pk.Kwargs["text"] != "" {
|
||||
opts.SearchText = pk.Kwargs["text"]
|
||||
}
|
||||
hitems, err := sstore.GetHistoryItems(ctx, "", "", opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hvdata := &sstore.HistoryViewData{
|
||||
TotalCount: 0,
|
||||
Offset: offset,
|
||||
Items: hitems,
|
||||
}
|
||||
update := sstore.ModelUpdate{
|
||||
HistoryViewData: hvdata,
|
||||
MainView: sstore.MainViewHistory,
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
const DefaultMaxHistoryItems = 10000
|
||||
|
||||
func HistoryCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
@@ -1971,8 +2001,8 @@ func BookmarksShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
log.Printf("error updating current activity (bookmarks): %v\n", err)
|
||||
}
|
||||
update := sstore.ModelUpdate{
|
||||
BookmarksView: true,
|
||||
Bookmarks: bms,
|
||||
MainView: sstore.MainViewBookmarks,
|
||||
Bookmarks: bms,
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
+104
-2
@@ -223,6 +223,7 @@ func runHistoryQuery(tx *TxWrap, sessionId string, windowId string, opts History
|
||||
}
|
||||
hnumStr := ""
|
||||
whereClause := ""
|
||||
var queryArgs []interface{}
|
||||
if sessionId != "" && windowId != "" {
|
||||
whereClause = fmt.Sprintf("WHERE sessionid = '%s' AND windowid = '%s'", sessionId, windowId)
|
||||
hnumStr = "w"
|
||||
@@ -232,15 +233,26 @@ func runHistoryQuery(tx *TxWrap, sessionId string, windowId string, opts History
|
||||
} else {
|
||||
hnumStr = "g"
|
||||
}
|
||||
if opts.SearchText != "" {
|
||||
if whereClause == "" {
|
||||
whereClause = "WHERE cmdstr LIKE ? ESCAPE '\\'"
|
||||
} else {
|
||||
whereClause = whereClause + " AND cmdstr LIKE ? ESCAPE '\\'"
|
||||
}
|
||||
likeArg := opts.SearchText
|
||||
likeArg = strings.ReplaceAll(likeArg, "%", "\\%")
|
||||
likeArg = strings.ReplaceAll(likeArg, "_", "\\_")
|
||||
queryArgs = append(queryArgs, "%"+likeArg+"%")
|
||||
}
|
||||
maxItems := opts.MaxItems
|
||||
if maxItems == 0 {
|
||||
maxItems = DefaultMaxHistoryItems
|
||||
}
|
||||
query := fmt.Sprintf("SELECT %s, '%s' || row_number() OVER win AS historynum FROM history %s WINDOW win AS (ORDER BY ts, historyid) ORDER BY ts DESC, historyid DESC LIMIT %d", HistoryCols, hnumStr, whereClause, maxItems)
|
||||
query := fmt.Sprintf("SELECT %s, '%s' || row_number() OVER win AS historynum FROM history %s WINDOW win AS (ORDER BY ts, historyid) ORDER BY ts DESC, historyid DESC LIMIT %d OFFSET %d", HistoryCols, hnumStr, whereClause, maxItems, opts.Offset)
|
||||
if opts.FromTs > 0 {
|
||||
query = fmt.Sprintf("SELECT * FROM (%s) WHERE ts >= %d", query, opts.FromTs)
|
||||
}
|
||||
marr := tx.SelectMaps(query)
|
||||
marr := tx.SelectMaps(query, queryArgs...)
|
||||
rtn := make([]*HistoryItemType, len(marr))
|
||||
for idx, m := range marr {
|
||||
hitem := HistoryItemFromMap(m)
|
||||
@@ -2241,3 +2253,93 @@ func DeleteBookmark(ctx context.Context, bookmarkId string) error {
|
||||
})
|
||||
return txErr
|
||||
}
|
||||
|
||||
func CreatePlaybook(ctx context.Context, name string) (*PlaybookType, error) {
|
||||
var rtn *PlaybookType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT playbookid FROM playbook WHERE name = ?`
|
||||
if tx.Exists(query, name) {
|
||||
return fmt.Errorf("playbook %q already exists", name)
|
||||
}
|
||||
rtn = &PlaybookType{}
|
||||
rtn.PlaybookId = uuid.New().String()
|
||||
rtn.PlaybookName = name
|
||||
query = `INSERT INTO playbook ( playbookid, playbookname, description, entryids)
|
||||
VALUES (:playbookid,:playbookname,:description,:entryids)`
|
||||
tx.Exec(query, rtn.ToMap())
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
func selectPlaybook(tx *TxWrap, playbookId string) *PlaybookType {
|
||||
query := `SELECT * FROM playbook where playbookid = ?`
|
||||
m := tx.GetMap(query, playbookId)
|
||||
playbook := PlaybookFromMap(m)
|
||||
return playbook
|
||||
}
|
||||
|
||||
func AddPlaybookEntry(ctx context.Context, entry *PlaybookEntry) error {
|
||||
if entry.EntryId == "" {
|
||||
return fmt.Errorf("invalid entryid")
|
||||
}
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
playbook := selectPlaybook(tx, entry.PlaybookId)
|
||||
if playbook == nil {
|
||||
return fmt.Errorf("cannot add entry, playbook does not exist")
|
||||
}
|
||||
query := `SELECT entryid FROM playbook_entry WHERE entryid = ?`
|
||||
if tx.Exists(query, entry.EntryId) {
|
||||
return fmt.Errorf("cannot add entry, entryid already exists")
|
||||
}
|
||||
query = `INSERT INTO playbook_entry ( entryid, playbookid, description, alias, cmdstr, createdts, updatedts)
|
||||
VALUES (:entryid,:playbookid,:description,:alias,:cmdstr,:createdts,:updatedts)`
|
||||
tx.Exec(query, entry)
|
||||
playbook.EntryIds = append(playbook.EntryIds, entry.EntryId)
|
||||
query = `UPDATE playbook SET entryids = ? WHERE playbookid = ?`
|
||||
tx.Exec(query, quickJsonArr(playbook.EntryIds), entry.PlaybookId)
|
||||
return nil
|
||||
})
|
||||
return txErr
|
||||
}
|
||||
|
||||
func RemovePlaybookEntry(ctx context.Context, playbookId string, entryId string) error {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
playbook := selectPlaybook(tx, playbookId)
|
||||
if playbook == nil {
|
||||
return fmt.Errorf("cannot remove playbook entry, playbook does not exist")
|
||||
}
|
||||
query := `SELECT entryid FROM playbook_entry WHERE entryid = ?`
|
||||
if !tx.Exists(query, entryId) {
|
||||
return fmt.Errorf("cannot remove playbook entry, entry does not exist")
|
||||
}
|
||||
query = `DELETE FROM playbook_entry WHERE entryid = ?`
|
||||
tx.Exec(query, entryId)
|
||||
playbook.RemoveEntry(entryId)
|
||||
query = `UPDATE playbook SET entryids = ? WHERE playbookid = ?`
|
||||
tx.Exec(query, quickJsonArr(playbook.EntryIds), playbookId)
|
||||
return nil
|
||||
})
|
||||
return txErr
|
||||
}
|
||||
|
||||
func GetPlaybookById(ctx context.Context, playbookId string) (*PlaybookType, error) {
|
||||
var rtn *PlaybookType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
rtn = selectPlaybook(tx, playbookId)
|
||||
if rtn == nil {
|
||||
return nil
|
||||
}
|
||||
query := `SELECT * FROM playbook_entry WHERE playbookid = ?`
|
||||
tx.Select(&rtn.Entries, query, playbookId)
|
||||
rtn.OrderEntries()
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
+86
-2
@@ -39,6 +39,12 @@ const DefaultScreenWindowName = "w1"
|
||||
|
||||
const DefaultCwd = "~"
|
||||
|
||||
const (
|
||||
MainViewSession = "session"
|
||||
MainViewBookmarks = "bookmarks"
|
||||
MainViewHistory = "history"
|
||||
)
|
||||
|
||||
const (
|
||||
CmdStatusRunning = "running"
|
||||
CmdStatusDetached = "detached"
|
||||
@@ -525,8 +531,10 @@ type HistoryItemType struct {
|
||||
}
|
||||
|
||||
type HistoryQueryOpts struct {
|
||||
MaxItems int
|
||||
FromTs int64
|
||||
Offset int
|
||||
MaxItems int
|
||||
FromTs int64
|
||||
SearchText string
|
||||
}
|
||||
|
||||
type TermOpts struct {
|
||||
@@ -674,6 +682,82 @@ type LineType struct {
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
type PlaybookType struct {
|
||||
PlaybookId string `json:"playbookid"`
|
||||
PlaybookName string `json:"playbookname"`
|
||||
Description string `json:"description"`
|
||||
EntryIds []string `json:"entryids"`
|
||||
|
||||
// this is not persisted to DB, just for transport to FE
|
||||
Entries []*PlaybookEntry `json:"entries"`
|
||||
}
|
||||
|
||||
func (p *PlaybookType) ToMap() map[string]interface{} {
|
||||
rtn := make(map[string]interface{})
|
||||
rtn["playbookid"] = p.PlaybookId
|
||||
rtn["playbookname"] = p.PlaybookName
|
||||
rtn["description"] = p.Description
|
||||
rtn["entryids"] = quickJsonArr(p.EntryIds)
|
||||
return rtn
|
||||
}
|
||||
|
||||
func PlaybookFromMap(m map[string]interface{}) *PlaybookType {
|
||||
if len(m) == 0 {
|
||||
return nil
|
||||
}
|
||||
var p PlaybookType
|
||||
quickSetStr(&p.PlaybookId, m, "playbookid")
|
||||
quickSetStr(&p.PlaybookName, m, "playbookname")
|
||||
quickSetStr(&p.Description, m, "description")
|
||||
quickSetJsonArr(&p.Entries, m, "entries")
|
||||
return &p
|
||||
}
|
||||
|
||||
// reorders p.Entries to match p.EntryIds
|
||||
func (p *PlaybookType) OrderEntries() {
|
||||
if len(p.Entries) == 0 {
|
||||
return
|
||||
}
|
||||
m := make(map[string]*PlaybookEntry)
|
||||
for _, entry := range p.Entries {
|
||||
m[entry.EntryId] = entry
|
||||
}
|
||||
newList := make([]*PlaybookEntry, 0, len(p.EntryIds))
|
||||
for _, entryId := range p.EntryIds {
|
||||
entry := m[entryId]
|
||||
if entry != nil {
|
||||
newList = append(newList, entry)
|
||||
}
|
||||
}
|
||||
p.Entries = newList
|
||||
}
|
||||
|
||||
// removes from p.EntryIds (not from p.Entries)
|
||||
func (p *PlaybookType) RemoveEntry(entryIdToRemove string) {
|
||||
if len(p.EntryIds) == 0 {
|
||||
return
|
||||
}
|
||||
newList := make([]string, 0, len(p.EntryIds)-1)
|
||||
for _, entryId := range p.EntryIds {
|
||||
if entryId == entryIdToRemove {
|
||||
continue
|
||||
}
|
||||
newList = append(newList, entryId)
|
||||
}
|
||||
p.EntryIds = newList
|
||||
}
|
||||
|
||||
type PlaybookEntry struct {
|
||||
PlaybookId string `json:"playbookid"`
|
||||
EntryId string `json:"entryid"`
|
||||
Alias string `json:"alias"`
|
||||
CmdStr string `json:"cmdstr"`
|
||||
UpdatedTs int64 `json:"updatedts"`
|
||||
CreatedTs int64 `json:"createdts"`
|
||||
Description string `json:"description"`
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
type BookmarkType struct {
|
||||
BookmarkId string `json:"bookmarkid"`
|
||||
CreatedTs int64 `json:"createdts"`
|
||||
|
||||
@@ -43,8 +43,9 @@ type ModelUpdate struct {
|
||||
History *HistoryInfoType `json:"history,omitempty"`
|
||||
Interactive bool `json:"interactive"`
|
||||
Connect bool `json:"connect,omitempty"`
|
||||
BookmarksView bool `json:"bookmarksview,omitempty"`
|
||||
MainView string `json:"mainview,omitempty"`
|
||||
Bookmarks []*BookmarkType `json:"bookmarks,omitempty"`
|
||||
HistoryViewData *HistoryViewData `json:"historyviewdata,omitempty"`
|
||||
ClientData *ClientData `json:"clientdata,omitempty"`
|
||||
}
|
||||
|
||||
@@ -74,6 +75,12 @@ func InfoMsgUpdate(infoMsgFmt string, args ...interface{}) *ModelUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
type HistoryViewData struct {
|
||||
TotalCount int `json:"totalcount"`
|
||||
Offset int `json:"offset"`
|
||||
Items []*HistoryItemType `json:"items"`
|
||||
}
|
||||
|
||||
type RemoteEditType struct {
|
||||
RemoteEdit bool `json:"remoteedit"`
|
||||
RemoteId string `json:"remoteid,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user