mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-11-28 05:00:26 +08:00
Massive PR, over 13k LOC updated, 128 commits to implement the first pass at the new Wave AI panel. Two backend adapters (OpenAI and Anthropic), layout changes to support the panel, keyboard shortcuts, and a huge focus/layout change to integrate the panel seamlessly into the UI. Also fixes some small issues found during the Wave AI journey (zoom fixes, documentation, more scss removal, circular dependency issues, settings, etc)
76 lines
2.6 KiB
TypeScript
76 lines
2.6 KiB
TypeScript
// Copyright 2025, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import { Block } from "@/app/block/block";
|
|
import { CenteredDiv } from "@/element/quickelems";
|
|
import { ContentRenderer, NodeModel, PreviewRenderer, TileLayout } from "@/layout/index";
|
|
import { TileLayoutContents } from "@/layout/lib/types";
|
|
import { atoms, getApi } from "@/store/global";
|
|
import * as services from "@/store/services";
|
|
import * as WOS from "@/store/wos";
|
|
import { atom, useAtomValue } from "jotai";
|
|
import * as React from "react";
|
|
import { useMemo } from "react";
|
|
|
|
const tileGapSizeAtom = atom((get) => {
|
|
const settings = get(atoms.settingsAtom);
|
|
return settings["window:tilegapsize"];
|
|
});
|
|
|
|
const TabContent = React.memo(({ tabId }: { tabId: string }) => {
|
|
const oref = useMemo(() => WOS.makeORef("tab", tabId), [tabId]);
|
|
const loadingAtom = useMemo(() => WOS.getWaveObjectLoadingAtom(oref), [oref]);
|
|
const tabLoading = useAtomValue(loadingAtom);
|
|
const tabAtom = useMemo(() => WOS.getWaveObjectAtom<Tab>(oref), [oref]);
|
|
const tabData = useAtomValue(tabAtom);
|
|
const tileGapSize = useAtomValue(tileGapSizeAtom);
|
|
|
|
const tileLayoutContents = useMemo(() => {
|
|
const renderContent: ContentRenderer = (nodeModel: NodeModel) => {
|
|
return <Block key={nodeModel.blockId} nodeModel={nodeModel} preview={false} />;
|
|
};
|
|
|
|
const renderPreview: PreviewRenderer = (nodeModel: NodeModel) => {
|
|
return <Block key={nodeModel.blockId} nodeModel={nodeModel} preview={true} />;
|
|
};
|
|
|
|
function onNodeDelete(data: TabLayoutData) {
|
|
return services.ObjectService.DeleteBlock(data.blockId);
|
|
}
|
|
|
|
return {
|
|
renderContent,
|
|
renderPreview,
|
|
tabId,
|
|
onNodeDelete,
|
|
gapSizePx: tileGapSize,
|
|
} as TileLayoutContents;
|
|
}, [tabId, tileGapSize]);
|
|
|
|
let innerContent;
|
|
|
|
if (tabLoading) {
|
|
innerContent = <CenteredDiv>Tab Loading</CenteredDiv>;
|
|
} else if (!tabData) {
|
|
innerContent = <CenteredDiv>Tab Not Found</CenteredDiv>;
|
|
} else if (tabData?.blockids?.length == 0) {
|
|
innerContent = null;
|
|
} else {
|
|
innerContent = (
|
|
<TileLayout
|
|
key={tabId}
|
|
contents={tileLayoutContents}
|
|
tabAtom={tabAtom}
|
|
getCursorPoint={getApi().getCursorPoint}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-row flex-grow min-h-0 w-full items-center justify-center overflow-hidden relative pt-[3px] pr-[3px]">
|
|
{innerContent}
|
|
</div>
|
|
);
|
|
});
|
|
|
|
export { TabContent };
|