Add flag for specifying a new node as magnified on insert (#253)

This commit is contained in:
Evan Simkowitz 2024-08-20 20:14:14 -07:00 committed by GitHub
parent bd4bf93d4a
commit 23261a7a98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 62 additions and 34 deletions

View File

@ -14,6 +14,8 @@ import (
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshclient" "github.com/wavetermdev/thenextwave/pkg/wshrpc/wshclient"
) )
var editMagnified bool
var editCmd = &cobra.Command{ var editCmd = &cobra.Command{
Use: "edit", Use: "edit",
Short: "edit a file", Short: "edit a file",
@ -23,6 +25,7 @@ var editCmd = &cobra.Command{
} }
func init() { func init() {
editCmd.Flags().BoolVarP(&editMagnified, "magnified", "m", false, "open view in magnified mode")
rootCmd.AddCommand(editCmd) rootCmd.AddCommand(editCmd)
} }
@ -35,6 +38,7 @@ func editRun(cmd *cobra.Command, args []string) {
waveobj.MetaKey_File: fileArg, waveobj.MetaKey_File: fileArg,
}, },
}, },
Magnified: editMagnified,
} }
if RpcContext.Conn != "" { if RpcContext.Conn != "" {
wshCmd.BlockDef.Meta[waveobj.MetaKey_Connection] = RpcContext.Conn wshCmd.BlockDef.Meta[waveobj.MetaKey_Connection] = RpcContext.Conn

View File

@ -14,6 +14,8 @@ import (
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshclient" "github.com/wavetermdev/thenextwave/pkg/wshrpc/wshclient"
) )
var termMagnified bool
var termCmd = &cobra.Command{ var termCmd = &cobra.Command{
Use: "term", Use: "term",
Short: "open a terminal in directory", Short: "open a terminal in directory",
@ -23,6 +25,7 @@ var termCmd = &cobra.Command{
} }
func init() { func init() {
termCmd.Flags().BoolVarP(&termMagnified, "magnified", "m", false, "open view in magnified mode")
rootCmd.AddCommand(termCmd) rootCmd.AddCommand(termCmd)
} }
@ -53,6 +56,7 @@ func termRun(cmd *cobra.Command, args []string) {
waveobj.MetaKey_Controller: "shell", waveobj.MetaKey_Controller: "shell",
}, },
}, },
Magnified: termMagnified,
} }
if RpcContext.Conn != "" { if RpcContext.Conn != "" {
createBlockData.BlockDef.Meta[waveobj.MetaKey_Connection] = RpcContext.Conn createBlockData.BlockDef.Meta[waveobj.MetaKey_Connection] = RpcContext.Conn

View File

@ -15,6 +15,7 @@ import (
) )
var viewNewBlock bool var viewNewBlock bool
var viewMagnified bool
var viewCmd = &cobra.Command{ var viewCmd = &cobra.Command{
Use: "view", Use: "view",
@ -26,6 +27,7 @@ var viewCmd = &cobra.Command{
func init() { func init() {
viewCmd.Flags().BoolVarP(&viewNewBlock, "newblock", "n", false, "open view in a new block") viewCmd.Flags().BoolVarP(&viewNewBlock, "newblock", "n", false, "open view in a new block")
viewCmd.Flags().BoolVarP(&viewMagnified, "magnified", "m", false, "open view in magnified mode")
rootCmd.AddCommand(viewCmd) rootCmd.AddCommand(viewCmd)
} }
@ -41,6 +43,7 @@ func viewRun(cmd *cobra.Command, args []string) {
waveobj.MetaKey_Url: fileArg, waveobj.MetaKey_Url: fileArg,
}, },
}, },
Magnified: viewMagnified,
} }
} else { } else {
absFile, err := filepath.Abs(fileArg) absFile, err := filepath.Abs(fileArg)
@ -64,6 +67,7 @@ func viewRun(cmd *cobra.Command, args []string) {
waveobj.MetaKey_File: absFile, waveobj.MetaKey_File: absFile,
}, },
}, },
Magnified: viewMagnified,
} }
if conn != "" { if conn != "" {
wshCmd.BlockDef.Meta[waveobj.MetaKey_Connection] = conn wshCmd.BlockDef.Meta[waveobj.MetaKey_Connection] = conn

View File

@ -277,6 +277,7 @@ function handleWSEventMessage(msg: WSEventType) {
node: newLayoutNode(undefined, undefined, undefined, { node: newLayoutNode(undefined, undefined, undefined, {
blockId: layoutAction.blockid, blockId: layoutAction.blockid,
}), }),
magnified: layoutAction.magnified,
}; };
layoutModel.treeReducer(insertNodeAction); layoutModel.treeReducer(insertNodeAction);
break; break;
@ -304,6 +305,7 @@ function handleWSEventMessage(msg: WSEventType) {
blockId: layoutAction.blockid, blockId: layoutAction.blockid,
}), }),
indexArr: layoutAction.indexarr, indexArr: layoutAction.indexarr,
magnified: layoutAction.magnified,
}; };
layoutModel.treeReducer(insertAction); layoutModel.treeReducer(insertAction);
break; break;

View File

@ -175,7 +175,6 @@ const DisplayNode = ({ layoutModel, layoutNode, contents }: DisplayNodeProps) =>
const addlProps = useLayoutNode(layoutModel, layoutNode); const addlProps = useLayoutNode(layoutModel, layoutNode);
const activeDrag = useAtomValue(layoutModel.activeDrag); const activeDrag = useAtomValue(layoutModel.activeDrag);
const globalReady = useAtomValue(layoutModel.ready); const globalReady = useAtomValue(layoutModel.ready);
const layoutGeneration = useAtomValue(layoutModel.generationAtom);
const devicePixelRatio = useDevicePixelRatio(); const devicePixelRatio = useDevicePixelRatio();
@ -183,12 +182,12 @@ const DisplayNode = ({ layoutModel, layoutNode, contents }: DisplayNodeProps) =>
() => ({ () => ({
type: dragItemType, type: dragItemType,
item: () => layoutNode, item: () => layoutNode,
canDrag: () => !layoutModel?.treeState?.magnifiedNodeId, canDrag: () => !addlProps?.isMagnifiedNode,
collect: (monitor) => ({ collect: (monitor) => ({
isDragging: monitor.isDragging(), isDragging: monitor.isDragging(),
}), }),
}), }),
[layoutNode, layoutGeneration] [layoutNode, addlProps]
); );
const [previewElementGeneration, setPreviewElementGeneration] = useState(0); const [previewElementGeneration, setPreviewElementGeneration] = useState(0);
@ -249,7 +248,7 @@ const DisplayNode = ({ layoutModel, layoutNode, contents }: DisplayNodeProps) =>
{contents.renderContent( {contents.renderContent(
layoutNode.data, layoutNode.data,
globalReady, globalReady,
layoutNode.id === layoutModel.treeState.magnifiedNodeId, addlProps?.isMagnifiedNode ?? false,
activeDrag, activeDrag,
() => layoutModel.magnifyNodeToggle(layoutNode), () => layoutModel.magnifyNodeToggle(layoutNode),
() => layoutModel.closeNode(layoutNode), () => layoutModel.closeNode(layoutNode),
@ -258,13 +257,13 @@ const DisplayNode = ({ layoutModel, layoutNode, contents }: DisplayNodeProps) =>
</div> </div>
) )
); );
}, [layoutNode, globalReady, layoutGeneration, activeDrag, addlProps]); }, [layoutNode, globalReady, activeDrag, addlProps]);
return ( return (
<div <div
className={clsx("tile-node", { className={clsx("tile-node", {
dragging: isDragging, dragging: isDragging,
magnified: layoutModel.treeState.magnifiedNodeId === layoutNode.id, magnified: addlProps?.isMagnifiedNode,
"last-magnified": addlProps?.isLastMagnifiedNode, "last-magnified": addlProps?.isLastMagnifiedNode,
})} })}
ref={tileNodeRef} ref={tileNodeRef}

View File

@ -130,6 +130,10 @@ export class LayoutModel {
*/ */
overlayTransform: Atom<CSSProperties>; overlayTransform: Atom<CSSProperties>;
/**
* The currently magnified node.
*/
magnifiedNodeId: string;
/** /**
* The last node to be magnified, other than the current magnified node, if set. This node should sit at a higher z-index than the others so that it floats above the other nodes as it returns to its original position. * The last node to be magnified, other than the current magnified node, if set. This node should sit at a higher z-index than the others so that it floats above the other nodes as it returns to its original position.
*/ */
@ -314,6 +318,10 @@ export class LayoutModel {
} }
if (stateChanged) { if (stateChanged) {
console.log("state changed", this.treeState); console.log("state changed", this.treeState);
if (this.magnifiedNodeId !== this.treeState.magnifiedNodeId) {
this.lastMagnifiedNodeId = this.magnifiedNodeId;
this.magnifiedNodeId = this.treeState.magnifiedNodeId;
}
this.updateTree(); this.updateTree();
this.treeState.generation++; this.treeState.generation++;
this.setter(this.treeStateAtom, this.treeState); this.setter(this.treeStateAtom, this.treeState);
@ -393,7 +401,7 @@ export class LayoutModel {
leafs.push(node); leafs.push(node);
const addlProps = additionalPropsMap[node.id]; const addlProps = additionalPropsMap[node.id];
if (addlProps) { if (addlProps) {
if (this.treeState.magnifiedNodeId === node.id) { if (this.magnifiedNodeId === node.id) {
const boundingRect = getBoundingRect(); const boundingRect = getBoundingRect();
const transform = setTransform( const transform = setTransform(
{ {
@ -405,6 +413,7 @@ export class LayoutModel {
true true
); );
addlProps.transform = transform; addlProps.transform = transform;
addlProps.isMagnifiedNode = true;
} }
addlProps.isLastMagnifiedNode = this.lastMagnifiedNodeId === node.id; addlProps.isLastMagnifiedNode = this.lastMagnifiedNodeId === node.id;
} }
@ -578,12 +587,6 @@ export class LayoutModel {
nodeId: node.id, nodeId: node.id,
}; };
// If the node is already magnified, then it is being un-magnified and should be set as the last-magnified node to ensure it has a higher z-index as it transitions back to its original position.
if (this.treeState.magnifiedNodeId === node.id) {
console.log("new last-magnified-node", node.id);
this.lastMagnifiedNodeId = node.id;
}
this.treeReducer(action); this.treeReducer(action);
} }

View File

@ -43,6 +43,8 @@ export function useLayoutModel(tabAtom: Atom<Tab>): LayoutModel {
} }
export function useTileLayout(tabAtom: Atom<Tab>, tileContent: TileLayoutContents): LayoutModel { export function useTileLayout(tabAtom: Atom<Tab>, tileContent: TileLayoutContents): LayoutModel {
// Use tab data to ensure we can reload if the tab is disposed and remade (such as during Hot Module Reloading)
useAtomValue(tabAtom);
const layoutModel = useLayoutModel(tabAtom); const layoutModel = useLayoutModel(tabAtom);
useResizeObserver(layoutModel?.displayContainerRef, layoutModel?.onContainerResize); useResizeObserver(layoutModel?.displayContainerRef, layoutModel?.onContainerResize);
useEffect(() => layoutModel.registerTileLayout(tileContent), [tileContent]); useEffect(() => layoutModel.registerTileLayout(tileContent), [tileContent]);

View File

@ -5,7 +5,6 @@ import { lazy } from "@/util/util";
import { import {
addChildAt, addChildAt,
addIntermediateNode, addIntermediateNode,
balanceNode,
findInsertLocationFromIndexArr, findInsertLocationFromIndexArr,
findNextInsertLocation, findNextInsertLocation,
findNode, findNode,
@ -256,8 +255,6 @@ export function moveNode(layoutState: LayoutTreeState, action: LayoutTreeMoveNod
if (oldParent) { if (oldParent) {
removeChild(oldParent, node, startingIndex); removeChild(oldParent, node, startingIndex);
} }
layoutState.rootNode = balanceNode(layoutState.rootNode);
} }
export function insertNode(layoutState: LayoutTreeState, action: LayoutTreeInsertNodeAction) { export function insertNode(layoutState: LayoutTreeState, action: LayoutTreeInsertNodeAction) {
@ -266,12 +263,14 @@ export function insertNode(layoutState: LayoutTreeState, action: LayoutTreeInser
return; return;
} }
if (!layoutState.rootNode) { if (!layoutState.rootNode) {
layoutState.rootNode = balanceNode(action.node); layoutState.rootNode = action.node;
return; return;
} }
const insertLoc = findNextInsertLocation(layoutState.rootNode, 5); const insertLoc = findNextInsertLocation(layoutState.rootNode, 5);
addChildAt(insertLoc.node, insertLoc.index, action.node); addChildAt(insertLoc.node, insertLoc.index, action.node);
layoutState.rootNode = balanceNode(layoutState.rootNode); if (action.magnified) {
layoutState.magnifiedNodeId = action.node.id;
}
} }
export function insertNodeAtIndex(layoutState: LayoutTreeState, action: LayoutTreeInsertNodeAtIndexAction) { export function insertNodeAtIndex(layoutState: LayoutTreeState, action: LayoutTreeInsertNodeAtIndexAction) {
@ -280,7 +279,7 @@ export function insertNodeAtIndex(layoutState: LayoutTreeState, action: LayoutTr
return; return;
} }
if (!layoutState.rootNode) { if (!layoutState.rootNode) {
layoutState.rootNode = balanceNode(action.node); layoutState.rootNode = action.node;
return; return;
} }
const insertLoc = findInsertLocationFromIndexArr(layoutState.rootNode, action.indexArr); const insertLoc = findInsertLocationFromIndexArr(layoutState.rootNode, action.indexArr);
@ -289,7 +288,9 @@ export function insertNodeAtIndex(layoutState: LayoutTreeState, action: LayoutTr
return; return;
} }
addChildAt(insertLoc.node, insertLoc.index + 1, action.node); addChildAt(insertLoc.node, insertLoc.index + 1, action.node);
layoutState.rootNode = balanceNode(layoutState.rootNode); if (action.magnified) {
layoutState.magnifiedNodeId = action.node.id;
}
} }
export function swapNode(layoutState: LayoutTreeState, action: LayoutTreeSwapNodeAction) { export function swapNode(layoutState: LayoutTreeState, action: LayoutTreeSwapNodeAction) {
@ -323,8 +324,6 @@ export function swapNode(layoutState: LayoutTreeState, action: LayoutTreeSwapNod
parentNode1.children[parentNode1Index] = node2; parentNode1.children[parentNode1Index] = node2;
parentNode2.children[parentNode2Index] = node1; parentNode2.children[parentNode2Index] = node1;
layoutState.rootNode = balanceNode(layoutState.rootNode);
} }
export function deleteNode(layoutState: LayoutTreeState, action: LayoutTreeDeleteNodeAction) { export function deleteNode(layoutState: LayoutTreeState, action: LayoutTreeDeleteNodeAction) {
@ -349,7 +348,6 @@ export function deleteNode(layoutState: LayoutTreeState, action: LayoutTreeDelet
} else { } else {
console.error("unable to delete node, not found in tree"); console.error("unable to delete node, not found in tree");
} }
layoutState.rootNode = balanceNode(layoutState.rootNode);
} }
export function resizeNode(layoutState: LayoutTreeState, action: LayoutTreeResizeNodeAction) { export function resizeNode(layoutState: LayoutTreeState, action: LayoutTreeResizeNodeAction) {

View File

@ -93,24 +93,30 @@ export interface LayoutTreeSwapNodeAction extends LayoutTreeAction {
node2Id: string; node2Id: string;
} }
interface InsertNodeOperation {
/**
* The node to insert.
*/
node: LayoutNode;
/**
* Whether the inserted node should be magnified.
*/
magnified?: boolean;
}
/** /**
* Action for inserting a new node to the layout tree. * Action for inserting a new node to the layout tree.
* *
*/ */
export interface LayoutTreeInsertNodeAction extends LayoutTreeAction { export interface LayoutTreeInsertNodeAction extends LayoutTreeAction, InsertNodeOperation {
type: LayoutTreeActionType.InsertNode; type: LayoutTreeActionType.InsertNode;
node: LayoutNode;
} }
/** /**
* Action for inserting a node into the layout tree at the specified index. * Action for inserting a node into the layout tree at the specified index.
*/ */
export interface LayoutTreeInsertNodeAtIndexAction extends LayoutTreeAction { export interface LayoutTreeInsertNodeAtIndexAction extends LayoutTreeAction, InsertNodeOperation {
type: LayoutTreeActionType.InsertNodeAtIndex; type: LayoutTreeActionType.InsertNodeAtIndex;
/**
* The node to insert.
*/
node: LayoutNode;
/** /**
* The array of indices to traverse when inserting the node. * The array of indices to traverse when inserting the node.
* The last index is the index within the parent node where the node should be inserted. * The last index is the index within the parent node where the node should be inserted.
@ -274,5 +280,6 @@ export interface LayoutNodeAdditionalProps {
rect?: Dimensions; rect?: Dimensions;
pixelToSizeRatio?: number; pixelToSizeRatio?: number;
resizeHandles?: ResizeHandleProps[]; resizeHandles?: ResizeHandleProps[];
isMagnifiedNode?: boolean;
isLastMagnifiedNode?: boolean; isLastMagnifiedNode?: boolean;
} }

View File

@ -95,7 +95,8 @@ declare global {
type CommandCreateBlockData = { type CommandCreateBlockData = {
tabid: string; tabid: string;
blockdef: BlockDef; blockdef: BlockDef;
rtopts: RuntimeOpts; rtopts?: RuntimeOpts;
magnified?: boolean;
}; };
// wshrpc.CommandDeleteBlockData // wshrpc.CommandDeleteBlockData
@ -522,6 +523,7 @@ declare global {
blockid: string; blockid: string;
nodesize?: number; nodesize?: number;
indexarr?: number[]; indexarr?: number[];
magnified?: boolean;
}; };
// webcmd.WSRpcCommand // webcmd.WSRpcCommand

View File

@ -62,6 +62,7 @@ type WSLayoutActionData struct {
BlockId string `json:"blockid"` BlockId string `json:"blockid"`
NodeSize uint `json:"nodesize,omitempty"` NodeSize uint `json:"nodesize,omitempty"`
IndexArr []int `json:"indexarr,omitempty"` IndexArr []int `json:"indexarr,omitempty"`
Magnified bool `json:"magnified,omitempty"`
} }
var globalLock = &sync.Mutex{} var globalLock = &sync.Mutex{}

View File

@ -185,9 +185,10 @@ type CommandResolveIdsRtnData struct {
} }
type CommandCreateBlockData struct { type CommandCreateBlockData struct {
TabId string `json:"tabid" wshcontext:"TabId"` TabId string `json:"tabid" wshcontext:"TabId"`
BlockDef *waveobj.BlockDef `json:"blockdef"` BlockDef *waveobj.BlockDef `json:"blockdef"`
RtOpts *waveobj.RuntimeOpts `json:"rtopts"` RtOpts *waveobj.RuntimeOpts `json:"rtopts,omitempty"`
Magnified bool `json:"magnified,omitempty"`
} }
type CommandBlockSetViewData struct { type CommandBlockSetViewData struct {

View File

@ -293,6 +293,7 @@ func (ws *WshServer) CreateBlockCommand(ctx context.Context, data wshrpc.Command
ActionType: "insert", ActionType: "insert",
TabId: tabId, TabId: tabId,
BlockId: blockData.OID, BlockId: blockData.OID,
Magnified: data.Magnified,
}, },
}) })
return &waveobj.ORef{OType: waveobj.OType_Block, OID: blockData.OID}, nil return &waveobj.ORef{OType: waveobj.OType_Block, OID: blockData.OID}, nil