2024-12-11 00:18:14 +01:00
|
|
|
// Copyright 2024, Command Line Inc.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
2024-12-02 19:56:56 +01:00
|
|
|
package wcore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
2024-12-03 18:38:46 +01:00
|
|
|
"github.com/wavetermdev/waveterm/pkg/eventbus"
|
2024-12-02 19:56:56 +01:00
|
|
|
"github.com/wavetermdev/waveterm/pkg/telemetry"
|
|
|
|
"github.com/wavetermdev/waveterm/pkg/util/utilfn"
|
|
|
|
"github.com/wavetermdev/waveterm/pkg/waveobj"
|
2024-12-09 23:48:16 +01:00
|
|
|
"github.com/wavetermdev/waveterm/pkg/wconfig"
|
2024-12-07 00:33:00 +01:00
|
|
|
"github.com/wavetermdev/waveterm/pkg/wps"
|
2024-12-02 19:56:56 +01:00
|
|
|
"github.com/wavetermdev/waveterm/pkg/wshrpc"
|
|
|
|
"github.com/wavetermdev/waveterm/pkg/wstore"
|
|
|
|
)
|
|
|
|
|
2024-12-13 02:21:09 +01:00
|
|
|
var WorkspaceColors = [...]string{
|
|
|
|
"#58C142", // Green (accent)
|
|
|
|
"#00FFDB", // Teal
|
|
|
|
"#429DFF", // Blue
|
|
|
|
"#BF55EC", // Purple
|
|
|
|
"#FF453A", // Red
|
|
|
|
"#FF9500", // Orange
|
|
|
|
"#FFE900", // Yellow
|
|
|
|
}
|
|
|
|
|
|
|
|
var WorkspaceIcons = [...]string{
|
|
|
|
"custom@wave-logo-solid",
|
|
|
|
"triangle",
|
|
|
|
"star",
|
|
|
|
"heart",
|
|
|
|
"bolt",
|
|
|
|
"solid@cloud",
|
|
|
|
"moon",
|
|
|
|
"layer-group",
|
|
|
|
"rocket",
|
|
|
|
"flask",
|
|
|
|
"paperclip",
|
|
|
|
"chart-line",
|
|
|
|
"graduation-cap",
|
|
|
|
"mug-hot",
|
|
|
|
}
|
|
|
|
|
|
|
|
func CreateWorkspace(ctx context.Context, name string, icon string, color string, applyDefaults bool, isInitialLaunch bool) (*waveobj.Workspace, error) {
|
2024-12-02 19:56:56 +01:00
|
|
|
ws := &waveobj.Workspace{
|
2024-12-04 22:34:22 +01:00
|
|
|
OID: uuid.NewString(),
|
|
|
|
TabIds: []string{},
|
|
|
|
PinnedTabIds: []string{},
|
2024-12-13 02:21:09 +01:00
|
|
|
Name: "",
|
|
|
|
Icon: "",
|
|
|
|
Color: "",
|
2024-12-02 19:56:56 +01:00
|
|
|
}
|
2024-12-07 00:33:00 +01:00
|
|
|
err := wstore.DBInsert(ctx, ws)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error inserting workspace: %w", err)
|
|
|
|
}
|
2024-12-09 23:24:02 +01:00
|
|
|
_, err = CreateTab(ctx, ws.OID, "", true, false, isInitialLaunch)
|
2024-12-07 00:33:00 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error creating tab: %w", err)
|
|
|
|
}
|
2024-12-10 00:22:41 +01:00
|
|
|
|
|
|
|
wps.Broker.Publish(wps.WaveEvent{
|
|
|
|
Event: wps.Event_WorkspaceUpdate})
|
|
|
|
|
2024-12-13 02:21:09 +01:00
|
|
|
return UpdateWorkspace(ctx, ws.OID, name, icon, color, applyDefaults)
|
|
|
|
}
|
|
|
|
|
|
|
|
func UpdateWorkspace(ctx context.Context, workspaceId string, name string, icon string, color string, applyDefaults bool) (*waveobj.Workspace, error) {
|
|
|
|
ws, err := GetWorkspace(ctx, workspaceId)
|
2024-12-07 00:33:00 +01:00
|
|
|
if err != nil {
|
2024-12-13 02:21:09 +01:00
|
|
|
return nil, fmt.Errorf("workspace %s not found: %w", workspaceId, err)
|
|
|
|
}
|
|
|
|
if name != "" {
|
|
|
|
ws.Name = name
|
|
|
|
} else if applyDefaults && ws.Name == "" {
|
|
|
|
ws.Name = fmt.Sprintf("New Workspace (%s)", ws.OID[0:5])
|
|
|
|
}
|
|
|
|
if icon != "" {
|
|
|
|
ws.Icon = icon
|
|
|
|
} else if applyDefaults && ws.Icon == "" {
|
|
|
|
ws.Icon = WorkspaceIcons[0]
|
|
|
|
}
|
|
|
|
if color != "" {
|
|
|
|
ws.Color = color
|
|
|
|
} else if applyDefaults && ws.Color == "" {
|
|
|
|
wsList, err := ListWorkspaces(ctx)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("error listing workspaces: %v", err)
|
|
|
|
wsList = waveobj.WorkspaceList{}
|
|
|
|
}
|
|
|
|
ws.Color = WorkspaceColors[len(wsList)%len(WorkspaceColors)]
|
2024-12-07 00:33:00 +01:00
|
|
|
}
|
2024-12-13 02:21:09 +01:00
|
|
|
wstore.DBUpdate(ctx, ws)
|
2024-12-02 19:56:56 +01:00
|
|
|
return ws, nil
|
|
|
|
}
|
|
|
|
|
2024-12-04 03:39:06 +01:00
|
|
|
// If force is true, it will delete even if workspace is named.
|
|
|
|
// If workspace is empty, it will be deleted, even if it is named.
|
|
|
|
// Returns true if workspace was deleted, false if it was not deleted.
|
2024-12-02 19:56:56 +01:00
|
|
|
func DeleteWorkspace(ctx context.Context, workspaceId string, force bool) (bool, error) {
|
|
|
|
log.Printf("DeleteWorkspace %s\n", workspaceId)
|
|
|
|
workspace, err := wstore.DBMustGet[*waveobj.Workspace](ctx, workspaceId)
|
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("error getting workspace: %w", err)
|
|
|
|
}
|
2024-12-07 00:33:00 +01:00
|
|
|
if workspace.Name != "" && workspace.Icon != "" && !force && (len(workspace.TabIds) > 0 || len(workspace.PinnedTabIds) > 0) {
|
2024-12-02 19:56:56 +01:00
|
|
|
log.Printf("Ignoring DeleteWorkspace for workspace %s as it is named\n", workspaceId)
|
|
|
|
return false, nil
|
|
|
|
}
|
2024-12-04 22:34:22 +01:00
|
|
|
|
|
|
|
// delete all pinned and unpinned tabs
|
|
|
|
for _, tabId := range append(workspace.TabIds, workspace.PinnedTabIds...) {
|
2024-12-02 19:56:56 +01:00
|
|
|
log.Printf("deleting tab %s\n", tabId)
|
2024-12-04 03:39:06 +01:00
|
|
|
_, err := DeleteTab(ctx, workspaceId, tabId, false)
|
2024-12-02 19:56:56 +01:00
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("error closing tab: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = wstore.DBDelete(ctx, waveobj.OType_Workspace, workspaceId)
|
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("error deleting workspace: %w", err)
|
|
|
|
}
|
|
|
|
log.Printf("deleted workspace %s\n", workspaceId)
|
2024-12-07 00:33:00 +01:00
|
|
|
wps.Broker.Publish(wps.WaveEvent{
|
|
|
|
Event: wps.Event_WorkspaceUpdate})
|
2024-12-02 19:56:56 +01:00
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetWorkspace(ctx context.Context, wsID string) (*waveobj.Workspace, error) {
|
|
|
|
return wstore.DBMustGet[*waveobj.Workspace](ctx, wsID)
|
|
|
|
}
|
|
|
|
|
2024-12-09 23:48:16 +01:00
|
|
|
func getTabPresetMeta() (waveobj.MetaMapType, error) {
|
|
|
|
settings := wconfig.GetWatcher().GetFullConfig()
|
|
|
|
tabPreset := settings.Settings.TabPreset
|
|
|
|
if tabPreset == "" {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
presetMeta := settings.Presets[tabPreset]
|
|
|
|
return presetMeta, nil
|
|
|
|
}
|
|
|
|
|
2024-12-02 19:56:56 +01:00
|
|
|
// returns tabid
|
2024-12-09 23:24:02 +01:00
|
|
|
func CreateTab(ctx context.Context, workspaceId string, tabName string, activateTab bool, pinned bool, isInitialLaunch bool) (string, error) {
|
2024-12-02 19:56:56 +01:00
|
|
|
if tabName == "" {
|
2024-12-02 21:59:03 +01:00
|
|
|
ws, err := GetWorkspace(ctx, workspaceId)
|
2024-12-02 19:56:56 +01:00
|
|
|
if err != nil {
|
2024-12-02 21:59:03 +01:00
|
|
|
return "", fmt.Errorf("workspace %s not found: %w", workspaceId, err)
|
2024-12-02 19:56:56 +01:00
|
|
|
}
|
2024-12-04 23:00:19 +01:00
|
|
|
tabName = "T" + fmt.Sprint(len(ws.TabIds)+len(ws.PinnedTabIds)+1)
|
2024-12-02 19:56:56 +01:00
|
|
|
}
|
2024-12-09 23:24:02 +01:00
|
|
|
|
|
|
|
// The initial tab for the initial launch should be pinned
|
|
|
|
tab, err := createTabObj(ctx, workspaceId, tabName, pinned || isInitialLaunch)
|
2024-12-02 19:56:56 +01:00
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error creating tab: %w", err)
|
|
|
|
}
|
|
|
|
if activateTab {
|
|
|
|
err = SetActiveTab(ctx, workspaceId, tab.OID)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error setting active tab: %w", err)
|
|
|
|
}
|
|
|
|
}
|
2024-12-09 23:24:02 +01:00
|
|
|
|
|
|
|
// No need to apply an initial layout for the initial launch, since the starter layout will get applied after TOS modal dismissal
|
|
|
|
if !isInitialLaunch {
|
|
|
|
err = ApplyPortableLayout(ctx, tab.OID, GetNewTabLayout())
|
|
|
|
if err != nil {
|
|
|
|
return tab.OID, fmt.Errorf("error applying new tab layout: %w", err)
|
|
|
|
}
|
2024-12-09 23:48:16 +01:00
|
|
|
presetMeta, presetErr := getTabPresetMeta()
|
|
|
|
if presetErr != nil {
|
|
|
|
log.Printf("error getting tab preset meta: %v\n", presetErr)
|
|
|
|
} else if presetMeta != nil && len(presetMeta) > 0 {
|
|
|
|
tabORef := waveobj.ORefFromWaveObj(tab)
|
|
|
|
wstore.UpdateObjectMeta(ctx, *tabORef, presetMeta, true)
|
|
|
|
}
|
2024-12-09 23:24:02 +01:00
|
|
|
}
|
2024-12-02 19:56:56 +01:00
|
|
|
telemetry.GoUpdateActivityWrap(wshrpc.ActivityUpdate{NewTab: 1}, "createtab")
|
|
|
|
return tab.OID, nil
|
|
|
|
}
|
|
|
|
|
2024-12-04 22:34:22 +01:00
|
|
|
func createTabObj(ctx context.Context, workspaceId string, name string, pinned bool) (*waveobj.Tab, error) {
|
|
|
|
ws, err := GetWorkspace(ctx, workspaceId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("workspace %s not found: %w", workspaceId, err)
|
|
|
|
}
|
|
|
|
layoutStateId := uuid.NewString()
|
|
|
|
tab := &waveobj.Tab{
|
|
|
|
OID: uuid.NewString(),
|
|
|
|
Name: name,
|
|
|
|
BlockIds: []string{},
|
|
|
|
LayoutState: layoutStateId,
|
|
|
|
}
|
|
|
|
layoutState := &waveobj.LayoutState{
|
|
|
|
OID: layoutStateId,
|
|
|
|
}
|
|
|
|
if pinned {
|
|
|
|
ws.PinnedTabIds = append(ws.PinnedTabIds, tab.OID)
|
|
|
|
} else {
|
|
|
|
ws.TabIds = append(ws.TabIds, tab.OID)
|
|
|
|
}
|
|
|
|
wstore.DBInsert(ctx, tab)
|
|
|
|
wstore.DBInsert(ctx, layoutState)
|
|
|
|
wstore.DBUpdate(ctx, ws)
|
|
|
|
return tab, nil
|
|
|
|
}
|
|
|
|
|
2024-12-02 21:59:03 +01:00
|
|
|
// Must delete all blocks individually first.
|
|
|
|
// Also deletes LayoutState.
|
2024-12-04 03:39:06 +01:00
|
|
|
// recursive: if true, will recursively close parent window, workspace, if they are empty.
|
2024-12-02 21:59:03 +01:00
|
|
|
// Returns new active tab id, error.
|
2024-12-04 03:39:06 +01:00
|
|
|
func DeleteTab(ctx context.Context, workspaceId string, tabId string, recursive bool) (string, error) {
|
2024-12-02 19:56:56 +01:00
|
|
|
ws, _ := wstore.DBGet[*waveobj.Workspace](ctx, workspaceId)
|
|
|
|
if ws == nil {
|
2024-12-02 21:59:03 +01:00
|
|
|
return "", fmt.Errorf("workspace not found: %q", workspaceId)
|
2024-12-02 19:56:56 +01:00
|
|
|
}
|
2024-12-04 22:34:22 +01:00
|
|
|
|
|
|
|
// ensure tab is in workspace
|
|
|
|
tabIdx := utilfn.FindStringInSlice(ws.TabIds, tabId)
|
|
|
|
tabIdxPinned := utilfn.FindStringInSlice(ws.PinnedTabIds, tabId)
|
|
|
|
if tabIdx != -1 {
|
|
|
|
ws.TabIds = append(ws.TabIds[:tabIdx], ws.TabIds[tabIdx+1:]...)
|
|
|
|
} else if tabIdxPinned != -1 {
|
|
|
|
ws.PinnedTabIds = append(ws.PinnedTabIds[:tabIdxPinned], ws.PinnedTabIds[tabIdxPinned+1:]...)
|
|
|
|
} else {
|
|
|
|
return "", fmt.Errorf("tab %s not found in workspace %s", tabId, workspaceId)
|
|
|
|
}
|
|
|
|
|
|
|
|
// close blocks (sends events + stops block controllers)
|
2024-12-02 19:56:56 +01:00
|
|
|
tab, _ := wstore.DBGet[*waveobj.Tab](ctx, tabId)
|
|
|
|
if tab == nil {
|
2024-12-02 21:59:03 +01:00
|
|
|
return "", fmt.Errorf("tab not found: %q", tabId)
|
2024-12-02 19:56:56 +01:00
|
|
|
}
|
|
|
|
for _, blockId := range tab.BlockIds {
|
2024-12-04 03:39:06 +01:00
|
|
|
err := DeleteBlock(ctx, blockId, false)
|
2024-12-02 19:56:56 +01:00
|
|
|
if err != nil {
|
2024-12-02 21:59:03 +01:00
|
|
|
return "", fmt.Errorf("error deleting block %s: %w", blockId, err)
|
2024-12-02 19:56:56 +01:00
|
|
|
}
|
|
|
|
}
|
2024-12-04 22:34:22 +01:00
|
|
|
|
|
|
|
// if the tab is active, determine new active tab
|
2024-12-02 21:59:03 +01:00
|
|
|
newActiveTabId := ws.ActiveTabId
|
2024-12-04 22:34:22 +01:00
|
|
|
if ws.ActiveTabId == tabId {
|
|
|
|
if len(ws.TabIds) > 0 && tabIdx != -1 {
|
2024-12-02 21:59:03 +01:00
|
|
|
newActiveTabId = ws.TabIds[max(0, min(tabIdx-1, len(ws.TabIds)-1))]
|
2024-12-04 22:34:22 +01:00
|
|
|
} else if len(ws.PinnedTabIds) > 0 {
|
|
|
|
newActiveTabId = ws.PinnedTabIds[0]
|
|
|
|
} else {
|
|
|
|
newActiveTabId = ""
|
2024-12-02 21:59:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ws.ActiveTabId = newActiveTabId
|
|
|
|
|
2024-12-02 19:56:56 +01:00
|
|
|
wstore.DBUpdate(ctx, ws)
|
|
|
|
wstore.DBDelete(ctx, waveobj.OType_Tab, tabId)
|
|
|
|
wstore.DBDelete(ctx, waveobj.OType_LayoutState, tab.LayoutState)
|
2024-12-03 18:38:46 +01:00
|
|
|
|
2024-12-04 22:34:22 +01:00
|
|
|
// if no tabs remaining, close window
|
2024-12-07 00:33:00 +01:00
|
|
|
if recursive && newActiveTabId == "" {
|
2024-12-04 22:34:22 +01:00
|
|
|
log.Printf("no tabs remaining in workspace %s, closing window\n", workspaceId)
|
2024-12-03 18:38:46 +01:00
|
|
|
windowId, err := wstore.DBFindWindowForWorkspaceId(ctx, workspaceId)
|
|
|
|
if err != nil {
|
|
|
|
return newActiveTabId, fmt.Errorf("unable to find window for workspace id %v: %w", workspaceId, err)
|
|
|
|
}
|
|
|
|
err = CloseWindow(ctx, windowId, false)
|
|
|
|
if err != nil {
|
|
|
|
return newActiveTabId, err
|
|
|
|
}
|
|
|
|
}
|
2024-12-02 21:59:03 +01:00
|
|
|
return newActiveTabId, nil
|
2024-12-02 19:56:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func SetActiveTab(ctx context.Context, workspaceId string, tabId string) error {
|
2024-12-04 22:34:22 +01:00
|
|
|
if tabId != "" && workspaceId != "" {
|
2024-12-02 21:59:03 +01:00
|
|
|
workspace, err := GetWorkspace(ctx, workspaceId)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("workspace %s not found: %w", workspaceId, err)
|
|
|
|
}
|
2024-12-02 19:56:56 +01:00
|
|
|
tab, _ := wstore.DBGet[*waveobj.Tab](ctx, tabId)
|
|
|
|
if tab == nil {
|
|
|
|
return fmt.Errorf("tab not found: %q", tabId)
|
|
|
|
}
|
2024-12-02 21:59:03 +01:00
|
|
|
workspace.ActiveTabId = tabId
|
|
|
|
wstore.DBUpdate(ctx, workspace)
|
2024-12-02 19:56:56 +01:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-12-04 22:34:22 +01:00
|
|
|
func ChangeTabPinning(ctx context.Context, workspaceId string, tabId string, pinned bool) error {
|
|
|
|
if tabId != "" && workspaceId != "" {
|
|
|
|
workspace, err := GetWorkspace(ctx, workspaceId)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("workspace %s not found: %w", workspaceId, err)
|
|
|
|
}
|
|
|
|
if pinned && utilfn.FindStringInSlice(workspace.PinnedTabIds, tabId) == -1 {
|
|
|
|
if utilfn.FindStringInSlice(workspace.TabIds, tabId) == -1 {
|
|
|
|
return fmt.Errorf("tab %s not found in workspace %s", tabId, workspaceId)
|
|
|
|
}
|
|
|
|
workspace.TabIds = utilfn.RemoveElemFromSlice(workspace.TabIds, tabId)
|
|
|
|
workspace.PinnedTabIds = append(workspace.PinnedTabIds, tabId)
|
|
|
|
} else if !pinned && utilfn.FindStringInSlice(workspace.PinnedTabIds, tabId) != -1 {
|
|
|
|
if utilfn.FindStringInSlice(workspace.PinnedTabIds, tabId) == -1 {
|
|
|
|
return fmt.Errorf("tab %s not found in workspace %s", tabId, workspaceId)
|
|
|
|
}
|
|
|
|
workspace.PinnedTabIds = utilfn.RemoveElemFromSlice(workspace.PinnedTabIds, tabId)
|
|
|
|
workspace.TabIds = append([]string{tabId}, workspace.TabIds...)
|
|
|
|
}
|
|
|
|
wstore.DBUpdate(ctx, workspace)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-12-03 18:38:46 +01:00
|
|
|
func SendActiveTabUpdate(ctx context.Context, workspaceId string, newActiveTabId string) {
|
|
|
|
eventbus.SendEventToElectron(eventbus.WSEventType{
|
|
|
|
EventType: eventbus.WSEvent_ElectronUpdateActiveTab,
|
|
|
|
Data: &waveobj.ActiveTabUpdate{WorkspaceId: workspaceId, NewActiveTabId: newActiveTabId},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-12-04 22:34:22 +01:00
|
|
|
func UpdateWorkspaceTabIds(ctx context.Context, workspaceId string, tabIds []string, pinnedTabIds []string) error {
|
2024-12-02 19:56:56 +01:00
|
|
|
ws, _ := wstore.DBGet[*waveobj.Workspace](ctx, workspaceId)
|
|
|
|
if ws == nil {
|
|
|
|
return fmt.Errorf("workspace not found: %q", workspaceId)
|
|
|
|
}
|
|
|
|
ws.TabIds = tabIds
|
2024-12-04 22:34:22 +01:00
|
|
|
ws.PinnedTabIds = pinnedTabIds
|
2024-12-02 19:56:56 +01:00
|
|
|
wstore.DBUpdate(ctx, ws)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ListWorkspaces(ctx context.Context) (waveobj.WorkspaceList, error) {
|
|
|
|
workspaces, err := wstore.DBGetAllObjsByType[*waveobj.Workspace](ctx, waveobj.OType_Workspace)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Println("got workspaces")
|
|
|
|
|
|
|
|
windows, err := wstore.DBGetAllObjsByType[*waveobj.Window](ctx, waveobj.OType_Window)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
workspaceToWindow := make(map[string]string)
|
|
|
|
for _, window := range windows {
|
|
|
|
workspaceToWindow[window.WorkspaceId] = window.OID
|
|
|
|
}
|
|
|
|
|
|
|
|
var wl waveobj.WorkspaceList
|
|
|
|
for _, workspace := range workspaces {
|
|
|
|
if workspace.Name == "" || workspace.Icon == "" || workspace.Color == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
windowId, ok := workspaceToWindow[workspace.OID]
|
|
|
|
if !ok {
|
|
|
|
windowId = ""
|
|
|
|
}
|
|
|
|
wl = append(wl, &waveobj.WorkspaceListEntry{
|
|
|
|
WorkspaceId: workspace.OID,
|
|
|
|
WindowId: windowId,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return wl, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetIcon(workspaceId string, icon string) error {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
ws, e := wstore.DBGet[*waveobj.Workspace](ctx, workspaceId)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
if ws == nil {
|
|
|
|
return fmt.Errorf("workspace not found: %q", workspaceId)
|
|
|
|
}
|
|
|
|
ws.Icon = icon
|
|
|
|
wstore.DBUpdate(ctx, ws)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetColor(workspaceId string, color string) error {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
ws, e := wstore.DBGet[*waveobj.Workspace](ctx, workspaceId)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
if ws == nil {
|
|
|
|
return fmt.Errorf("workspace not found: %q", workspaceId)
|
|
|
|
}
|
|
|
|
ws.Color = color
|
|
|
|
wstore.DBUpdate(ctx, ws)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetName(workspaceId string, name string) error {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
ws, e := wstore.DBGet[*waveobj.Workspace](ctx, workspaceId)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
if ws == nil {
|
|
|
|
return fmt.Errorf("workspace not found: %q", workspaceId)
|
|
|
|
}
|
|
|
|
ws.Name = name
|
|
|
|
wstore.DBUpdate(ctx, ws)
|
|
|
|
return nil
|
|
|
|
}
|