From 7bf64fb26885f751f7c4f4215353569c746238e9 Mon Sep 17 00:00:00 2001 From: sawka Date: Mon, 24 Jun 2024 19:04:08 -0700 Subject: [PATCH] wsh view works -- uses a WS event to send to the frontend --- frontend/app/store/global.ts | 30 +++++++++++++++----- frontend/faraday/index.ts | 3 +- frontend/types/gotypes.d.ts | 7 +++++ pkg/blockcontroller/blockcontroller.go | 6 ++-- pkg/cmdqueue/cmdqueue.go | 38 ++++++++++++++++++++++---- pkg/eventbus/eventbus.go | 14 ++++++++++ pkg/tsgen/tsgen.go | 1 + pkg/wconfig/filewatcher.go | 2 +- pkg/wstore/wstore_dbops.go | 7 +++++ 9 files changed, 90 insertions(+), 18 deletions(-) diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts index a869ad3f..05845e65 100644 --- a/frontend/app/store/global.ts +++ b/frontend/app/store/global.ts @@ -1,7 +1,7 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -import { LayoutTreeActionType, LayoutTreeInsertNodeAction, newLayoutNode } from "@/faraday/index"; +import { LayoutTreeAction, LayoutTreeActionType, LayoutTreeInsertNodeAction, newLayoutNode } from "@/faraday/index"; import { getLayoutStateAtomForTab } from "@/faraday/lib/layoutAtom"; import { layoutTreeStateReducer } from "@/faraday/lib/layoutState"; @@ -216,6 +216,21 @@ function handleWSEventMessage(msg: WSEventType) { } return; } + if (msg.eventtype == "layoutaction") { + const layoutAction: WSLayoutAction = msg.data; + if (layoutAction.actiontype == LayoutTreeActionType.InsertNode) { + const insertNodeAction: LayoutTreeInsertNodeAction = { + type: LayoutTreeActionType.InsertNode, + node: newLayoutNode(undefined, undefined, undefined, { + blockId: layoutAction.blockid, + }), + }; + runLayoutAction(layoutAction.tabid, insertNodeAction); + } else { + console.log("unsupported layout action", layoutAction); + } + return; + } // we send to two subjects just eventType and eventType|oref // we don't use getORefSubject here because we don't want to create a new subject const eventSubject = eventSubjects.get(msg.eventtype); @@ -263,6 +278,12 @@ function getApi(): ElectronApi { return (window as any).api; } +function runLayoutAction(tabId: string, action: LayoutTreeAction) { + const layoutStateAtom = getLayoutStateAtomForTab(tabId, WOS.getWaveObjectAtom(WOS.makeORef("tab", tabId))); + const curState = globalStore.get(layoutStateAtom); + globalStore.set(layoutStateAtom, layoutTreeStateReducer(curState, action)); +} + async function createBlock(blockDef: BlockDef) { const rtOpts: RuntimeOpts = { termsize: { rows: 25, cols: 80 } }; const blockId = await services.ObjectService.CreateBlock(blockDef, rtOpts); @@ -271,12 +292,7 @@ async function createBlock(blockDef: BlockDef) { node: newLayoutNode(undefined, undefined, undefined, { blockId }), }; const activeTabId = globalStore.get(atoms.uiContext).activetabid; - const layoutStateAtom = getLayoutStateAtomForTab( - activeTabId, - WOS.getWaveObjectAtom(WOS.makeORef("tab", activeTabId)) - ); - const curState = globalStore.get(layoutStateAtom); - globalStore.set(layoutStateAtom, layoutTreeStateReducer(curState, insertNodeAction)); + runLayoutAction(activeTabId, insertNodeAction); } // when file is not found, returns {data: null, fileInfo: null} diff --git a/frontend/faraday/index.ts b/frontend/faraday/index.ts index 81673caf..b09734d0 100644 --- a/frontend/faraday/index.ts +++ b/frontend/faraday/index.ts @@ -15,7 +15,7 @@ import type { WritableLayoutNodeAtom, WritableLayoutTreeStateAtom, } from "./lib/model"; -import { LayoutTreeActionType } from "./lib/model"; +import { LayoutTreeAction, LayoutTreeActionType } from "./lib/model"; export { LayoutTreeActionType, @@ -27,6 +27,7 @@ export { }; export type { LayoutNode, + LayoutTreeAction, LayoutTreeCommitPendingAction, LayoutTreeComputeMoveNodeAction, LayoutTreeDeleteNodeAction, diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index a55d2630..7d9ea477 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -288,6 +288,13 @@ declare global { data64: string; }; + // eventbus.WSLayoutAction + type WSLayoutAction = { + tabid: string; + actiontype: string; + blockid: string; + }; + // wconfig.WatcherUpdate type WatcherUpdate = { file: string; diff --git a/pkg/blockcontroller/blockcontroller.go b/pkg/blockcontroller/blockcontroller.go index 248e2099..d5349b38 100644 --- a/pkg/blockcontroller/blockcontroller.go +++ b/pkg/blockcontroller/blockcontroller.go @@ -128,7 +128,7 @@ func (bc *BlockController) UpdateControllerAndSendUpdate(updateFn func() bool) { if sendUpdate { log.Printf("sending blockcontroller update %#v\n", bc.GetRuntimeStatus()) go eventbus.SendEvent(eventbus.WSEventType{ - EventType: "blockcontroller:status", + EventType: eventbus.WSEvent_BlockControllerStatus, ORef: waveobj.MakeORef(wstore.OType_Block, bc.BlockId).String(), Data: bc.GetRuntimeStatus(), }) @@ -146,7 +146,7 @@ func HandleTruncateBlockFile(blockId string, blockFile string) error { return fmt.Errorf("error truncating blockfile: %w", err) } eventbus.SendEvent(eventbus.WSEventType{ - EventType: "blockfile", + EventType: eventbus.WSEvent_BlockFile, ORef: waveobj.MakeORef(wstore.OType_Block, blockId).String(), Data: &eventbus.WSFileEventData{ ZoneId: blockId, @@ -166,7 +166,7 @@ func HandleAppendBlockFile(blockId string, blockFile string, data []byte) error return fmt.Errorf("error appending to blockfile: %w", err) } eventbus.SendEvent(eventbus.WSEventType{ - EventType: "blockfile", + EventType: eventbus.WSEvent_BlockFile, ORef: waveobj.MakeORef(wstore.OType_Block, blockId).String(), Data: &eventbus.WSFileEventData{ ZoneId: blockId, diff --git a/pkg/cmdqueue/cmdqueue.go b/pkg/cmdqueue/cmdqueue.go index d7dbc292..44792207 100644 --- a/pkg/cmdqueue/cmdqueue.go +++ b/pkg/cmdqueue/cmdqueue.go @@ -98,7 +98,7 @@ func handleSetView(ctx context.Context, cmd *wshutil.BlockSetViewCommand, cmdCtx return nil, fmt.Errorf("error getting block: %w", err) } eventbus.SendEvent(eventbus.WSEventType{ - EventType: "waveobj:update", + EventType: eventbus.WSEvent_WaveObjUpdate, ORef: waveobj.MakeORef(wstore.OType_Block, cmdCtx.BlockId).String(), Data: wstore.WaveObjUpdate{ UpdateType: wstore.UpdateType_Update, @@ -190,7 +190,7 @@ func handleSetMeta(ctx context.Context, cmd *wshutil.BlockSetMetaCommand, cmdCtx return nil, fmt.Errorf("error getting object (2): %w", err) } eventbus.SendEvent(eventbus.WSEventType{ - EventType: "waveobj:update", + EventType: eventbus.WSEvent_WaveObjUpdate, ORef: oref.String(), Data: wstore.WaveObjUpdate{ UpdateType: wstore.UpdateType_Update, @@ -210,7 +210,7 @@ func handleAppendBlockFile(blockId string, blockFile string, data []byte) error return fmt.Errorf("error appending to blockfile: %w", err) } eventbus.SendEvent(eventbus.WSEventType{ - EventType: "blockfile", + EventType: eventbus.WSEvent_BlockFile, ORef: waveobj.MakeORef(wstore.OType_Block, blockId).String(), Data: &eventbus.WSFileEventData{ ZoneId: blockId, @@ -236,7 +236,7 @@ func handleAppendIJsonFile(blockId string, blockFile string, cmd map[string]any, return fmt.Errorf("error appending to blockfile(ijson): %w", err) } eventbus.SendEvent(eventbus.WSEventType{ - EventType: "blockfile", + EventType: eventbus.WSEvent_BlockFile, ORef: waveobj.MakeORef(wstore.OType_Block, blockId).String(), Data: &eventbus.WSFileEventData{ ZoneId: blockId, @@ -248,14 +248,23 @@ func handleAppendIJsonFile(blockId string, blockFile string, cmd map[string]any, return nil } +func sendWStoreUpdatesToEventBus(updates wstore.UpdatesRtnType) { + for _, update := range updates { + eventbus.SendEvent(eventbus.WSEventType{ + EventType: eventbus.WSEvent_WaveObjUpdate, + ORef: waveobj.MakeORef(update.OType, update.OID).String(), + Data: update, + }) + } +} + func handleCreateBlock(ctx context.Context, cmd *wshutil.CreateBlockCommand, cmdCtx wshutil.CmdContextType) (map[string]any, error) { + ctx = wstore.ContextWithUpdates(ctx) tabId := cmdCtx.TabId if cmd.TabId != "" { tabId = cmd.TabId } - log.Printf("handleCreateBlock %s %v\n", tabId, cmd.BlockDef) blockData, err := wstore.CreateBlock(ctx, tabId, cmd.BlockDef, cmd.RtOpts) - log.Printf("blockData: %v err:%v\n", blockData, err) if err != nil { return nil, fmt.Errorf("error creating block: %w", err) } @@ -265,5 +274,22 @@ func handleCreateBlock(ctx context.Context, cmd *wshutil.CreateBlockCommand, cmd return nil, fmt.Errorf("error starting block controller: %w", err) } } + updates := wstore.ContextGetUpdatesRtn(ctx) + sendWStoreUpdatesToEventBus(updates) + windowId, err := wstore.DBFindWindowForTabId(ctx, tabId) + if err != nil { + return nil, fmt.Errorf("error finding window for tab: %w", err) + } + if windowId == "" { + return nil, fmt.Errorf("no window found for tab") + } + eventbus.SendEventToWindow(windowId, eventbus.WSEventType{ + EventType: eventbus.WSEvent_LayoutAction, + Data: &eventbus.WSLayoutActionData{ + ActionType: "insert", + TabId: tabId, + BlockId: blockData.OID, + }, + }) return map[string]any{"blockId": blockData.OID}, nil } diff --git a/pkg/eventbus/eventbus.go b/pkg/eventbus/eventbus.go index 741c91d0..18a2ac7a 100644 --- a/pkg/eventbus/eventbus.go +++ b/pkg/eventbus/eventbus.go @@ -9,6 +9,14 @@ import ( "github.com/wavetermdev/thenextwave/pkg/waveobj" ) +const ( + WSEvent_WaveObjUpdate = "waveobj:update" + WSEvent_BlockFile = "blockfile" + WSEvent_Config = "config" + WSEvent_BlockControllerStatus = "blockcontroller:status" + WSEvent_LayoutAction = "layoutaction" +) + type WSEventType struct { EventType string `json:"eventtype"` ORef string `json:"oref,omitempty"` @@ -33,6 +41,12 @@ type WindowWatchData struct { WatchedORefs map[waveobj.ORef]bool } +type WSLayoutActionData struct { + TabId string `json:"tabid"` + ActionType string `json:"actiontype"` + BlockId string `json:"blockid"` +} + var globalLock = &sync.Mutex{} var wsMap = make(map[string]*WindowWatchData) // websocketid => WindowWatchData diff --git a/pkg/tsgen/tsgen.go b/pkg/tsgen/tsgen.go index c4684537..5edcd4c8 100644 --- a/pkg/tsgen/tsgen.go +++ b/pkg/tsgen/tsgen.go @@ -31,6 +31,7 @@ var ExtraTypes = []any{ wstore.UIContext{}, eventbus.WSEventType{}, eventbus.WSFileEventData{}, + eventbus.WSLayoutActionData{}, filestore.WaveFile{}, wconfig.SettingsConfigType{}, wconfig.WatcherUpdate{}, diff --git a/pkg/wconfig/filewatcher.go b/pkg/wconfig/filewatcher.go index c0ad7d6e..4a95cc5c 100644 --- a/pkg/wconfig/filewatcher.go +++ b/pkg/wconfig/filewatcher.go @@ -160,7 +160,7 @@ func (w *Watcher) Close() { func (w *Watcher) broadcast(message WatcherUpdate) { // send to frontend eventbus.SendEvent(eventbus.WSEventType{ - EventType: "config", + EventType: eventbus.WSEvent_Config, Data: message, }) diff --git a/pkg/wstore/wstore_dbops.go b/pkg/wstore/wstore_dbops.go index 0f1285ea..89d6b7a8 100644 --- a/pkg/wstore/wstore_dbops.go +++ b/pkg/wstore/wstore_dbops.go @@ -256,3 +256,10 @@ func DBInsert(ctx context.Context, val waveobj.WaveObj) error { return nil }) } + +func DBFindWindowForTabId(ctx context.Context, tabId string) (string, error) { + return WithTxRtn(ctx, func(tx *TxWrap) (string, error) { + query := "SELECT oid FROM db_window WHERE data->>'activetabid' = ?" + return tx.GetString(query, tabId), nil + }) +}