2024-05-21 00:57:15 +02:00
|
|
|
// Copyright 2024, Command Line Inc.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
package wstore
|
|
|
|
|
|
|
|
import (
|
2024-05-22 06:15:11 +02:00
|
|
|
"context"
|
2024-05-21 20:09:22 +02:00
|
|
|
"fmt"
|
2024-05-21 00:57:15 +02:00
|
|
|
|
2024-05-21 20:09:22 +02:00
|
|
|
"github.com/google/uuid"
|
2024-09-05 23:25:45 +02:00
|
|
|
"github.com/wavetermdev/waveterm/pkg/util/utilfn"
|
|
|
|
"github.com/wavetermdev/waveterm/pkg/waveobj"
|
2024-05-21 00:57:15 +02:00
|
|
|
)
|
|
|
|
|
2024-05-26 20:59:14 +02:00
|
|
|
func init() {
|
2024-08-20 23:56:48 +02:00
|
|
|
for _, rtype := range waveobj.AllWaveObjTypes() {
|
2024-05-27 08:05:11 +02:00
|
|
|
waveobj.RegisterType(rtype)
|
|
|
|
}
|
2024-05-26 20:59:14 +02:00
|
|
|
}
|
|
|
|
|
2024-08-20 23:56:48 +02:00
|
|
|
func CreateTab(ctx context.Context, workspaceId string, name string) (*waveobj.Tab, error) {
|
|
|
|
return WithTxRtn(ctx, func(tx *TxWrap) (*waveobj.Tab, error) {
|
|
|
|
ws, _ := DBGet[*waveobj.Workspace](tx.Context(), workspaceId)
|
2024-05-27 22:59:58 +02:00
|
|
|
if ws == nil {
|
|
|
|
return nil, fmt.Errorf("workspace not found: %q", workspaceId)
|
|
|
|
}
|
2024-08-15 03:40:41 +02:00
|
|
|
layoutStateId := uuid.NewString()
|
2024-08-20 23:56:48 +02:00
|
|
|
tab := &waveobj.Tab{
|
2024-08-15 03:40:41 +02:00
|
|
|
OID: uuid.NewString(),
|
|
|
|
Name: name,
|
|
|
|
BlockIds: []string{},
|
|
|
|
LayoutState: layoutStateId,
|
2024-06-06 02:21:40 +02:00
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
layoutState := &waveobj.LayoutState{
|
2024-08-15 03:40:41 +02:00
|
|
|
OID: layoutStateId,
|
2024-05-27 22:59:58 +02:00
|
|
|
}
|
|
|
|
ws.TabIds = append(ws.TabIds, tab.OID)
|
|
|
|
DBInsert(tx.Context(), tab)
|
2024-08-15 03:40:41 +02:00
|
|
|
DBInsert(tx.Context(), layoutState)
|
2024-05-27 22:59:58 +02:00
|
|
|
DBUpdate(tx.Context(), ws)
|
|
|
|
return tab, nil
|
|
|
|
})
|
2024-05-21 20:09:22 +02:00
|
|
|
}
|
|
|
|
|
2024-08-20 23:56:48 +02:00
|
|
|
func CreateWorkspace(ctx context.Context) (*waveobj.Workspace, error) {
|
|
|
|
ws := &waveobj.Workspace{
|
2024-06-06 02:21:40 +02:00
|
|
|
OID: uuid.NewString(),
|
2024-05-26 20:59:14 +02:00
|
|
|
TabIds: []string{},
|
2024-05-21 20:09:22 +02:00
|
|
|
}
|
2024-05-27 22:59:58 +02:00
|
|
|
DBInsert(ctx, ws)
|
2024-05-21 20:09:22 +02:00
|
|
|
return ws, nil
|
|
|
|
}
|
2024-05-22 06:15:11 +02:00
|
|
|
|
2024-06-18 06:50:33 +02:00
|
|
|
func UpdateWorkspaceTabIds(ctx context.Context, workspaceId string, tabIds []string) error {
|
|
|
|
return WithTx(ctx, func(tx *TxWrap) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
ws, _ := DBGet[*waveobj.Workspace](tx.Context(), workspaceId)
|
2024-06-18 06:50:33 +02:00
|
|
|
if ws == nil {
|
|
|
|
return fmt.Errorf("workspace not found: %q", workspaceId)
|
|
|
|
}
|
|
|
|
ws.TabIds = tabIds
|
|
|
|
DBUpdate(tx.Context(), ws)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-05-27 22:59:58 +02:00
|
|
|
func SetActiveTab(ctx context.Context, windowId string, tabId string) error {
|
|
|
|
return WithTx(ctx, func(tx *TxWrap) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
window, _ := DBGet[*waveobj.Window](tx.Context(), windowId)
|
2024-05-27 22:59:58 +02:00
|
|
|
if window == nil {
|
|
|
|
return fmt.Errorf("window not found: %q", windowId)
|
|
|
|
}
|
2024-05-28 01:33:31 +02:00
|
|
|
if tabId != "" {
|
2024-08-20 23:56:48 +02:00
|
|
|
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
|
2024-05-28 01:33:31 +02:00
|
|
|
if tab == nil {
|
|
|
|
return fmt.Errorf("tab not found: %q", tabId)
|
|
|
|
}
|
2024-05-27 22:59:58 +02:00
|
|
|
}
|
|
|
|
window.ActiveTabId = tabId
|
|
|
|
DBUpdate(tx.Context(), window)
|
|
|
|
return nil
|
|
|
|
})
|
2024-05-27 08:05:11 +02:00
|
|
|
}
|
|
|
|
|
2024-06-21 19:23:04 +02:00
|
|
|
func UpdateTabName(ctx context.Context, tabId, name string) error {
|
|
|
|
return WithTx(ctx, func(tx *TxWrap) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
|
2024-06-21 19:23:04 +02:00
|
|
|
if tab == nil {
|
|
|
|
return fmt.Errorf("tab not found: %q", tabId)
|
|
|
|
}
|
|
|
|
if tabId != "" {
|
|
|
|
tab.Name = name
|
|
|
|
DBUpdate(tx.Context(), tab)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-08-20 23:56:48 +02:00
|
|
|
func CreateBlock(ctx context.Context, tabId string, blockDef *waveobj.BlockDef, rtOpts *waveobj.RuntimeOpts) (*waveobj.Block, error) {
|
|
|
|
return WithTxRtn(ctx, func(tx *TxWrap) (*waveobj.Block, error) {
|
|
|
|
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
|
2024-05-28 00:44:57 +02:00
|
|
|
if tab == nil {
|
|
|
|
return nil, fmt.Errorf("tab not found: %q", tabId)
|
|
|
|
}
|
2024-06-06 02:21:40 +02:00
|
|
|
blockId := uuid.NewString()
|
2024-08-20 23:56:48 +02:00
|
|
|
blockData := &waveobj.Block{
|
2024-05-28 00:44:57 +02:00
|
|
|
OID: blockId,
|
|
|
|
BlockDef: blockDef,
|
|
|
|
RuntimeOpts: rtOpts,
|
|
|
|
Meta: blockDef.Meta,
|
|
|
|
}
|
|
|
|
DBInsert(tx.Context(), blockData)
|
|
|
|
tab.BlockIds = append(tab.BlockIds, blockId)
|
|
|
|
DBUpdate(tx.Context(), tab)
|
|
|
|
return blockData, nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-05-28 01:33:31 +02:00
|
|
|
func findStringInSlice(slice []string, val string) int {
|
|
|
|
for idx, v := range slice {
|
|
|
|
if v == val {
|
|
|
|
return idx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
2024-06-06 02:21:40 +02:00
|
|
|
func DeleteBlock(ctx context.Context, tabId string, blockId string) error {
|
2024-05-28 01:33:31 +02:00
|
|
|
return WithTx(ctx, func(tx *TxWrap) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
|
2024-05-28 01:33:31 +02:00
|
|
|
if tab == nil {
|
|
|
|
return fmt.Errorf("tab not found: %q", tabId)
|
|
|
|
}
|
|
|
|
blockIdx := findStringInSlice(tab.BlockIds, blockId)
|
|
|
|
if blockIdx == -1 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
tab.BlockIds = append(tab.BlockIds[:blockIdx], tab.BlockIds[blockIdx+1:]...)
|
|
|
|
DBUpdate(tx.Context(), tab)
|
2024-08-20 23:56:48 +02:00
|
|
|
DBDelete(tx.Context(), waveobj.OType_Block, blockId)
|
2024-05-28 01:33:31 +02:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-08-20 23:56:48 +02:00
|
|
|
// must delete all blocks individually first
|
|
|
|
// also deletes LayoutState
|
2024-06-20 04:10:53 +02:00
|
|
|
func DeleteTab(ctx context.Context, workspaceId string, tabId string) error {
|
2024-05-28 01:33:31 +02:00
|
|
|
return WithTx(ctx, func(tx *TxWrap) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
ws, _ := DBGet[*waveobj.Workspace](tx.Context(), workspaceId)
|
2024-05-28 01:33:31 +02:00
|
|
|
if ws == nil {
|
|
|
|
return fmt.Errorf("workspace not found: %q", workspaceId)
|
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
|
2024-05-28 01:33:31 +02:00
|
|
|
if tab == nil {
|
|
|
|
return fmt.Errorf("tab not found: %q", tabId)
|
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
if len(tab.BlockIds) != 0 {
|
|
|
|
return fmt.Errorf("tab has blocks, must delete blocks first")
|
|
|
|
}
|
2024-05-28 01:33:31 +02:00
|
|
|
tabIdx := findStringInSlice(ws.TabIds, tabId)
|
|
|
|
if tabIdx == -1 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
ws.TabIds = append(ws.TabIds[:tabIdx], ws.TabIds[tabIdx+1:]...)
|
|
|
|
DBUpdate(tx.Context(), ws)
|
2024-08-20 23:56:48 +02:00
|
|
|
DBDelete(tx.Context(), waveobj.OType_Tab, tabId)
|
|
|
|
DBDelete(tx.Context(), waveobj.OType_LayoutState, tab.LayoutState)
|
2024-05-28 01:33:31 +02:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-08-20 23:56:48 +02:00
|
|
|
func UpdateObjectMeta(ctx context.Context, oref waveobj.ORef, meta waveobj.MetaMapType) error {
|
2024-05-28 21:18:26 +02:00
|
|
|
return WithTx(ctx, func(tx *TxWrap) error {
|
2024-07-30 21:33:28 +02:00
|
|
|
if oref.IsEmpty() {
|
|
|
|
return fmt.Errorf("empty object reference")
|
2024-05-29 00:41:03 +02:00
|
|
|
}
|
|
|
|
obj, _ := DBGetORef(tx.Context(), oref)
|
|
|
|
if obj == nil {
|
2024-07-30 21:33:28 +02:00
|
|
|
return ErrNotFound
|
2024-05-29 00:41:03 +02:00
|
|
|
}
|
|
|
|
objMeta := waveobj.GetMeta(obj)
|
|
|
|
if objMeta == nil {
|
|
|
|
objMeta = make(map[string]any)
|
2024-05-28 21:18:26 +02:00
|
|
|
}
|
2024-08-28 03:49:49 +02:00
|
|
|
newMeta := waveobj.MergeMeta(objMeta, meta, false)
|
2024-07-30 21:33:28 +02:00
|
|
|
waveobj.SetMeta(obj, newMeta)
|
2024-05-29 00:41:03 +02:00
|
|
|
DBUpdate(tx.Context(), obj)
|
2024-05-28 21:18:26 +02:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-06-25 23:56:37 +02:00
|
|
|
func MoveBlockToTab(ctx context.Context, currentTabId string, newTabId string, blockId string) error {
|
|
|
|
return WithTx(ctx, func(tx *TxWrap) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
currentTab, _ := DBGet[*waveobj.Tab](tx.Context(), currentTabId)
|
2024-06-25 23:56:37 +02:00
|
|
|
if currentTab == nil {
|
|
|
|
return fmt.Errorf("current tab not found: %q", currentTabId)
|
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
newTab, _ := DBGet[*waveobj.Tab](tx.Context(), newTabId)
|
2024-06-25 23:56:37 +02:00
|
|
|
if newTab == nil {
|
|
|
|
return fmt.Errorf("new tab not found: %q", newTabId)
|
|
|
|
}
|
|
|
|
blockIdx := findStringInSlice(currentTab.BlockIds, blockId)
|
|
|
|
if blockIdx == -1 {
|
|
|
|
return fmt.Errorf("block not found in current tab: %q", blockId)
|
|
|
|
}
|
|
|
|
currentTab.BlockIds = utilfn.RemoveElemFromSlice(currentTab.BlockIds, blockId)
|
|
|
|
newTab.BlockIds = append(newTab.BlockIds, blockId)
|
|
|
|
DBUpdate(tx.Context(), currentTab)
|
|
|
|
DBUpdate(tx.Context(), newTab)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|