Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

launcher block #1948

Merged
merged 10 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/app/block/block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
FullSubBlockProps,
SubBlockProps,
} from "@/app/block/blocktypes";
import { LauncherViewModel } from "@/app/view/launcher/launcher";
import { PreviewModel } from "@/app/view/preview/preview";
import { SysinfoViewModel } from "@/app/view/sysinfo/sysinfo";
import { VDomModel } from "@/app/view/vdom/vdom-model";
Expand Down Expand Up @@ -44,6 +45,7 @@ BlockRegistry.set("cpuplot", SysinfoViewModel);
BlockRegistry.set("sysinfo", SysinfoViewModel);
BlockRegistry.set("vdom", VDomModel);
BlockRegistry.set("help", HelpViewModel);
BlockRegistry.set("launcher", LauncherViewModel);

function makeViewModel(blockId: string, blockView: string, nodeModel: BlockNodeModel): ViewModel {
const ctor = BlockRegistry.get(blockView);
Expand Down
4 changes: 3 additions & 1 deletion frontend/app/block/blockframe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,8 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
const [magnifiedBlockOpacityAtom] = React.useState(() => getSettingsKeyAtom("window:magnifiedblockopacity"));
const magnifiedBlockOpacity = jotai.useAtomValue(magnifiedBlockOpacityAtom);
const connBtnRef = React.useRef<HTMLDivElement>();
const noHeader = util.useAtomValueSafe(viewModel?.noHeader);

React.useEffect(() => {
if (!manageConnection) {
return;
Expand Down Expand Up @@ -618,7 +620,7 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
/>
)}
<div className="block-frame-default-inner" style={innerStyle}>
<ErrorBoundary fallback={headerElemNoView}>{headerElem}</ErrorBoundary>
{noHeader || <ErrorBoundary fallback={headerElemNoView}>{headerElem}</ErrorBoundary>}
{preview ? previewElem : children}
</div>
{preview || viewModel == null || !connModalOpen ? null : (
Expand Down
26 changes: 25 additions & 1 deletion frontend/app/store/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {
newLayoutNode,
} from "@/layout/index";
import { getLayoutModelForStaticTab } from "@/layout/lib/layoutModelHooks";
import { LayoutTreeSplitHorizontalAction, LayoutTreeSplitVerticalAction } from "@/layout/lib/types";
import {
LayoutTreeReplaceNodeAction,
LayoutTreeSplitHorizontalAction,
LayoutTreeSplitVerticalAction,
} from "@/layout/lib/types";
import { getWebServerEndpoint } from "@/util/endpoints";
import { fetch } from "@/util/fetchutil";
import { deepCompareReturnPrev, getPrefixedSettings, isBlank } from "@/util/util";
Expand Down Expand Up @@ -447,6 +451,25 @@ async function createBlock(blockDef: BlockDef, magnified = false, ephemeral = fa
return blockId;
}

async function replaceBlock(blockId: string, blockDef: BlockDef): Promise<string> {
const tabId = globalStore.get(atoms.staticTabId);
const layoutModel = getLayoutModelForTabById(tabId);
const rtOpts: RuntimeOpts = { termsize: { rows: 25, cols: 80 } };
const newBlockId = await ObjectService.CreateBlock(blockDef, rtOpts);
const targetNodeId = layoutModel.getNodeByBlockId(blockId)?.id;
if (targetNodeId == null) {
throw new Error(`targetNodeId not found for blockId: ${blockId}`);
}
const replaceNodeAction: LayoutTreeReplaceNodeAction = {
type: LayoutTreeActionType.ReplaceNode,
targetNodeId: targetNodeId,
newNode: newLayoutNode(undefined, undefined, undefined, { blockId: newBlockId }),
focused: true,
};
layoutModel.treeReducer(replaceNodeAction);
return newBlockId;
}

// when file is not found, returns {data: null, fileInfo: null}
async function fetchWaveFile(
zoneId: string,
Expand Down Expand Up @@ -761,6 +784,7 @@ export {
removeFlashError,
removeNotification,
removeNotificationById,
replaceBlock,
setActiveTab,
setNodeFocus,
setPlatform,
Expand Down
60 changes: 22 additions & 38 deletions frontend/app/store/keymodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
getAllBlockComponentModels,
getApi,
getBlockComponentModel,
getSettingsKeyAtom,
globalStore,
refocusNode,
WOS,
Expand Down Expand Up @@ -176,7 +177,17 @@ function globalRefocus() {
refocusNode(blockId);
}

async function handleCmdN() {
function getDefaultNewBlockDef(): BlockDef {
const adnbAtom = getSettingsKeyAtom("app:defaultnewblock");
const adnb = globalStore.get(adnbAtom) ?? "term";
if (adnb == "launcher") {
return {
meta: {
view: "launcher",
},
};
}
// "term", blank, anything else, fall back to terminal
const termBlockDef: BlockDef = {
meta: {
view: "term",
Expand All @@ -197,59 +208,32 @@ async function handleCmdN() {
termBlockDef.meta.connection = blockData.meta.connection;
}
}
await createBlock(termBlockDef);
return termBlockDef;
}

async function handleCmdN() {
const blockDef = getDefaultNewBlockDef();
await createBlock(blockDef);
}

async function handleSplitHorizontal() {
// split horizontally
const termBlockDef: BlockDef = {
meta: {
view: "term",
controller: "shell",
},
};
const layoutModel = getLayoutModelForStaticTab();
const focusedNode = globalStore.get(layoutModel.focusedNode);
if (focusedNode == null) {
return;
}
const blockAtom = WOS.getWaveObjectAtom<Block>(WOS.makeORef("block", focusedNode.data?.blockId));
const blockData = globalStore.get(blockAtom);
if (blockData?.meta?.view == "term") {
if (blockData?.meta?.["cmd:cwd"] != null) {
termBlockDef.meta["cmd:cwd"] = blockData.meta["cmd:cwd"];
}
}
if (blockData?.meta?.connection != null) {
termBlockDef.meta.connection = blockData.meta.connection;
}
await createBlockSplitHorizontally(termBlockDef, focusedNode.data.blockId, "after");
const blockDef = getDefaultNewBlockDef();
await createBlockSplitHorizontally(blockDef, focusedNode.data.blockId, "after");
}

async function handleSplitVertical() {
// split horizontally
const termBlockDef: BlockDef = {
meta: {
view: "term",
controller: "shell",
},
};
const layoutModel = getLayoutModelForStaticTab();
const focusedNode = globalStore.get(layoutModel.focusedNode);
if (focusedNode == null) {
return;
}
const blockAtom = WOS.getWaveObjectAtom<Block>(WOS.makeORef("block", focusedNode.data?.blockId));
const blockData = globalStore.get(blockAtom);
if (blockData?.meta?.view == "term") {
if (blockData?.meta?.["cmd:cwd"] != null) {
termBlockDef.meta["cmd:cwd"] = blockData.meta["cmd:cwd"];
}
}
if (blockData?.meta?.connection != null) {
termBlockDef.meta.connection = blockData.meta.connection;
}
await createBlockSplitVertically(termBlockDef, focusedNode.data.blockId, "after");
const blockDef = getDefaultNewBlockDef();
await createBlockSplitVertically(blockDef, focusedNode.data.blockId, "after");
}

let lastHandledEvent: KeyboardEvent | null = null;
Expand Down
Loading
Loading