mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
aa77b2c259
![image](https://github.com/user-attachments/assets/a4072368-b204-4eed-bb65-8e3884687f9a) This functions very similarly to VSCode's pinned tab feature. To pin a tab, you can right-click on it and select "Pin tab" from the context menu. Once pinned, a tab will be fixed to the left-most edge of the tab bar, in order of pinning. Pinned tabs can be dragged around like any others. If you drag an unpinned tab into the pinned tabs section (any index less than the highest-index pinned tab), it will be pinned. If you drag a pinned tab out of the pinned tab section, it will be unpinned. Pinned tabs' close button is replaced with a persistent pin button, which can be clicked to unpin them. This adds an extra barrier to accidentally closing a pinned tab. They can still be closed from the context menu.
212 lines
7.1 KiB
Go
212 lines
7.1 KiB
Go
package workspaceservice
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/wavetermdev/waveterm/pkg/blockcontroller"
|
|
"github.com/wavetermdev/waveterm/pkg/panichandler"
|
|
"github.com/wavetermdev/waveterm/pkg/tsgen/tsgenmeta"
|
|
"github.com/wavetermdev/waveterm/pkg/waveobj"
|
|
"github.com/wavetermdev/waveterm/pkg/wcore"
|
|
"github.com/wavetermdev/waveterm/pkg/wlayout"
|
|
"github.com/wavetermdev/waveterm/pkg/wps"
|
|
"github.com/wavetermdev/waveterm/pkg/wstore"
|
|
)
|
|
|
|
const DefaultTimeout = 2 * time.Second
|
|
|
|
type WorkspaceService struct{}
|
|
|
|
func (svc *WorkspaceService) GetWorkspace_Meta() tsgenmeta.MethodMeta {
|
|
return tsgenmeta.MethodMeta{
|
|
ArgNames: []string{"workspaceId"},
|
|
}
|
|
}
|
|
|
|
func (svc *WorkspaceService) GetWorkspace(workspaceId string) (*waveobj.Workspace, error) {
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
|
defer cancelFn()
|
|
ws, err := wstore.DBGet[*waveobj.Workspace](ctx, workspaceId)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error getting workspace: %w", err)
|
|
}
|
|
return ws, nil
|
|
}
|
|
|
|
func (svc *WorkspaceService) DeleteWorkspace_Meta() tsgenmeta.MethodMeta {
|
|
return tsgenmeta.MethodMeta{
|
|
ArgNames: []string{"workspaceId"},
|
|
}
|
|
}
|
|
|
|
func (svc *WorkspaceService) DeleteWorkspace(workspaceId string) (waveobj.UpdatesRtnType, error) {
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
|
defer cancelFn()
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
|
deleted, err := wcore.DeleteWorkspace(ctx, workspaceId, true)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error deleting workspace: %w", err)
|
|
}
|
|
if !deleted {
|
|
return nil, nil
|
|
}
|
|
updates := waveobj.ContextGetUpdatesRtn(ctx)
|
|
go func() {
|
|
defer panichandler.PanicHandler("WorkspaceService:DeleteWorkspace:SendUpdateEvents")
|
|
wps.Broker.SendUpdateEvents(updates)
|
|
}()
|
|
return updates, nil
|
|
}
|
|
|
|
func (svg *WorkspaceService) ListWorkspaces() (waveobj.WorkspaceList, error) {
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
|
defer cancelFn()
|
|
return wcore.ListWorkspaces(ctx)
|
|
}
|
|
|
|
func (svc *WorkspaceService) CreateTab_Meta() tsgenmeta.MethodMeta {
|
|
return tsgenmeta.MethodMeta{
|
|
ArgNames: []string{"workspaceId", "tabName", "activateTab", "pinned"},
|
|
ReturnDesc: "tabId",
|
|
}
|
|
}
|
|
|
|
func (svc *WorkspaceService) CreateTab(workspaceId string, tabName string, activateTab bool, pinned bool) (string, waveobj.UpdatesRtnType, error) {
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
|
defer cancelFn()
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
|
tabId, err := wcore.CreateTab(ctx, workspaceId, tabName, activateTab, pinned)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("error creating tab: %w", err)
|
|
}
|
|
err = wlayout.ApplyPortableLayout(ctx, tabId, wlayout.GetNewTabLayout())
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("error applying new tab layout: %w", err)
|
|
}
|
|
updates := waveobj.ContextGetUpdatesRtn(ctx)
|
|
go func() {
|
|
defer panichandler.PanicHandler("WorkspaceService:CreateTab:SendUpdateEvents")
|
|
wps.Broker.SendUpdateEvents(updates)
|
|
}()
|
|
return tabId, updates, nil
|
|
}
|
|
|
|
func (svc *WorkspaceService) ChangeTabPinning_Meta() tsgenmeta.MethodMeta {
|
|
return tsgenmeta.MethodMeta{
|
|
ArgNames: []string{"ctx", "workspaceId", "tabId", "pinned"},
|
|
}
|
|
}
|
|
|
|
func (svc *WorkspaceService) ChangeTabPinning(ctx context.Context, workspaceId string, tabId string, pinned bool) (waveobj.UpdatesRtnType, error) {
|
|
log.Printf("ChangeTabPinning %s %s %v\n", workspaceId, tabId, pinned)
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
|
err := wcore.ChangeTabPinning(ctx, workspaceId, tabId, pinned)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error toggling tab pinning: %w", err)
|
|
}
|
|
updates := waveobj.ContextGetUpdatesRtn(ctx)
|
|
go func() {
|
|
defer panichandler.PanicHandler("WorkspaceService:ChangeTabPinning:SendUpdateEvents")
|
|
wps.Broker.SendUpdateEvents(updates)
|
|
}()
|
|
return updates, nil
|
|
}
|
|
|
|
func (svc *WorkspaceService) UpdateTabIds_Meta() tsgenmeta.MethodMeta {
|
|
return tsgenmeta.MethodMeta{
|
|
ArgNames: []string{"uiContext", "workspaceId", "tabIds", "pinnedTabIds"},
|
|
}
|
|
}
|
|
|
|
func (svc *WorkspaceService) UpdateTabIds(uiContext waveobj.UIContext, workspaceId string, tabIds []string, pinnedTabIds []string) (waveobj.UpdatesRtnType, error) {
|
|
log.Printf("UpdateTabIds %s %v %v\n", workspaceId, tabIds, pinnedTabIds)
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
|
defer cancelFn()
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
|
err := wcore.UpdateWorkspaceTabIds(ctx, workspaceId, tabIds, pinnedTabIds)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error updating workspace tab ids: %w", err)
|
|
}
|
|
return waveobj.ContextGetUpdatesRtn(ctx), nil
|
|
}
|
|
|
|
func (svc *WorkspaceService) SetActiveTab_Meta() tsgenmeta.MethodMeta {
|
|
return tsgenmeta.MethodMeta{
|
|
ArgNames: []string{"workspaceId", "tabId"},
|
|
}
|
|
}
|
|
|
|
func (svc *WorkspaceService) SetActiveTab(workspaceId string, tabId string) (waveobj.UpdatesRtnType, error) {
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
|
defer cancelFn()
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
|
err := wcore.SetActiveTab(ctx, workspaceId, tabId)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error setting active tab: %w", err)
|
|
}
|
|
// check all blocks in tab and start controllers (if necessary)
|
|
tab, err := wstore.DBMustGet[*waveobj.Tab](ctx, tabId)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error getting tab: %w", err)
|
|
}
|
|
blockORefs := tab.GetBlockORefs()
|
|
blocks, err := wstore.DBSelectORefs(ctx, blockORefs)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error getting tab blocks: %w", err)
|
|
}
|
|
updates := waveobj.ContextGetUpdatesRtn(ctx)
|
|
go func() {
|
|
defer panichandler.PanicHandler("WorkspaceService:SetActiveTab:SendUpdateEvents")
|
|
wps.Broker.SendUpdateEvents(updates)
|
|
}()
|
|
var extraUpdates waveobj.UpdatesRtnType
|
|
extraUpdates = append(extraUpdates, updates...)
|
|
extraUpdates = append(extraUpdates, waveobj.MakeUpdate(tab))
|
|
extraUpdates = append(extraUpdates, waveobj.MakeUpdates(blocks)...)
|
|
return extraUpdates, nil
|
|
}
|
|
|
|
type CloseTabRtnType struct {
|
|
CloseWindow bool `json:"closewindow,omitempty"`
|
|
NewActiveTabId string `json:"newactivetabid,omitempty"`
|
|
}
|
|
|
|
func (svc *WorkspaceService) CloseTab_Meta() tsgenmeta.MethodMeta {
|
|
return tsgenmeta.MethodMeta{
|
|
ArgNames: []string{"ctx", "workspaceId", "tabId", "fromElectron"},
|
|
}
|
|
}
|
|
|
|
// returns the new active tabid
|
|
func (svc *WorkspaceService) CloseTab(ctx context.Context, workspaceId string, tabId string, fromElectron bool) (*CloseTabRtnType, waveobj.UpdatesRtnType, error) {
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
|
tab, err := wstore.DBMustGet[*waveobj.Tab](ctx, tabId)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("error getting tab: %w", err)
|
|
}
|
|
go func() {
|
|
for _, blockId := range tab.BlockIds {
|
|
blockcontroller.StopBlockController(blockId)
|
|
}
|
|
}()
|
|
newActiveTabId, err := wcore.DeleteTab(ctx, workspaceId, tabId, true)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("error closing tab: %w", err)
|
|
}
|
|
rtn := &CloseTabRtnType{}
|
|
if newActiveTabId == "" {
|
|
rtn.CloseWindow = true
|
|
} else {
|
|
rtn.NewActiveTabId = newActiveTabId
|
|
}
|
|
updates := waveobj.ContextGetUpdatesRtn(ctx)
|
|
go func() {
|
|
defer panichandler.PanicHandler("WorkspaceService:CloseTab:SendUpdateEvents")
|
|
wps.Broker.SendUpdateEvents(updates)
|
|
}()
|
|
return rtn, updates, nil
|
|
}
|