Skip to content

Commit

Permalink
feat: support C/D/A/V connections and nodes info (#519)
Browse files Browse the repository at this point in the history
Co-authored-by: Hu Yueh-Wei <[email protected]>
  • Loading branch information
shczhen and halajohn authored Jan 7, 2025
1 parent 47bd3cc commit 03d91e7
Show file tree
Hide file tree
Showing 27 changed files with 1,613 additions and 173 deletions.
Binary file modified core/src/ten_manager/designer_frontend/bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions core/src/ten_manager/designer_frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-navigation-menu": "^1.2.3",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-tabs": "^1.1.2",
"@tanstack/react-table": "^8.20.6",
"@xterm/addon-attach": "^0.11.0",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-unicode11": "^0.8.0",
Expand Down
103 changes: 60 additions & 43 deletions core/src/ten_manager/designer_frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
} from "@/flow/graph";
import Popup from "@/components/Popup/Popup";
import type { IGraph } from "@/types/graphs";
import { ReactFlowDataContext } from "@/context/ReactFlowDataContext";

const App: React.FC = () => {
const [graphs, setGraphs] = useState<IGraph[]>([]);
Expand Down Expand Up @@ -69,16 +70,30 @@ const App: React.FC = () => {

let initialNodes: CustomNodeType[] = processNodes(backendNodes);

const { initialEdges, nodeSourceCmdMap, nodeTargetCmdMap } =
processConnections(backendConnections);
const {
initialEdges,
nodeSourceCmdMap,
nodeSourceDataMap,
nodeSourceAudioFrameMap,
nodeSourceVideoFrameMap,
nodeTargetCmdMap,
nodeTargetDataMap,
nodeTargetAudioFrameMap,
nodeTargetVideoFrameMap,
} = processConnections(backendConnections);

// Write back the cmd information to nodes, so that CustomNode could
// generate corresponding handles.
initialNodes = enhanceNodesWithCommands(
initialNodes,
initialNodes = enhanceNodesWithCommands(initialNodes, {
nodeSourceCmdMap,
nodeTargetCmdMap
);
nodeTargetCmdMap,
nodeSourceDataMap,
nodeTargetDataMap,
nodeSourceAudioFrameMap,
nodeSourceVideoFrameMap,
nodeTargetAudioFrameMap,
nodeTargetVideoFrameMap,
});

// Fetch additional addon information for each node.
const nodesWithAddonInfo = await fetchAddonInfoForNodes(initialNodes);
Expand Down Expand Up @@ -136,43 +151,45 @@ const App: React.FC = () => {

return (
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
<AppBar
version={version}
onAutoLayout={performAutoLayout}
onOpenExistingGraph={handleOpenExistingGraph}
onSetBaseDir={handleSetBaseDir}
/>
<FlowCanvas
nodes={nodes}
edges={edges}
onNodesChange={handleNodesChange}
onEdgesChange={handleEdgesChange}
onConnect={(connection) => {
setEdges((eds) => addEdge(connection, eds));
}}
/>
{showGraphSelection && (
<Popup
title="Select a Graph"
onClose={() => setShowGraphSelection(false)}
resizable={false}
initialWidth={400}
initialHeight={300}
onCollapseToggle={() => {}}
>
<ul>
{graphs.map((graph) => (
<li
key={graph.name}
style={{ cursor: "pointer", padding: "5px 0" }}
onClick={() => handleSelectGraph(graph.name)}
>
{graph.name} {graph.auto_start ? "(Auto Start)" : ""}
</li>
))}
</ul>
</Popup>
)}
<ReactFlowDataContext.Provider value={{ nodes, edges }}>
<AppBar
version={version}
onAutoLayout={performAutoLayout}
onOpenExistingGraph={handleOpenExistingGraph}
onSetBaseDir={handleSetBaseDir}
/>
<FlowCanvas
nodes={nodes}
edges={edges}
onNodesChange={handleNodesChange}
onEdgesChange={handleEdgesChange}
onConnect={(connection) => {
setEdges((eds) => addEdge(connection, eds));
}}
/>
{showGraphSelection && (
<Popup
title="Select a Graph"
onClose={() => setShowGraphSelection(false)}
resizable={false}
initialWidth={400}
initialHeight={300}
onCollapseToggle={() => {}}
>
<ul>
{graphs.map((graph) => (
<li
key={graph.name}
style={{ cursor: "pointer", padding: "5px 0" }}
onClick={() => handleSelectGraph(graph.name)}
>
{graph.name} {graph.auto_start ? "(Auto Start)" : ""}
</li>
))}
</ul>
</Popup>
)}
</ReactFlowDataContext.Provider>
</ThemeProvider>
);
};
Expand Down
39 changes: 39 additions & 0 deletions core/src/ten_manager/designer_frontend/src/api/endpoints/graphs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,45 @@ export const ENDPOINT_GRAPHS = {
})
)
.optional(),
data: z
.array(
z.object({
name: z.string(),
dest: z.array(
z.object({
app: z.string(),
extension: z.string(),
})
),
})
)
.optional(),
audio_frame: z
.array(
z.object({
name: z.string(),
dest: z.array(
z.object({
app: z.string(),
extension: z.string(),
})
),
})
)
.optional(),
video_frame: z
.array(
z.object({
name: z.string(),
dest: z.array(
z.object({
app: z.string(),
extension: z.string(),
})
),
})
)
.optional(),
})
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Badge } from "@/components/ui/Badge";
import { FileMenu } from "@/components/AppBar/FileMenu";
import { EditMenu } from "@/components/AppBar/EditMenu";
import { HelpMenu } from "@/components/AppBar/HelpMenu";
import { AppStatus } from "@/components/AppBar/AppStatus";
import { cn } from "@/lib/utils";

interface AppBarProps {
Expand Down Expand Up @@ -67,8 +68,16 @@ const AppBar: React.FC<AppBarProps> = ({
</NavigationMenuList>
</NavigationMenu>

{/* Middle part is the status bar. */}
<AppStatus
className={cn(
"flex-1 flex justify-center items-center",
"text-xs text-muted-foreground"
)}
/>

{/* Right part is the logo. */}
<div className="ml-auto flex items-center gap-1.5">
<div className="flex items-center gap-1.5">
<LanguageToggle />
<ModeToggle />
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Copyright © 2025 Agora
// This file is part of TEN Framework, an open source project.
// Licensed under the Apache License, Version 2.0, with certain conditions.
// Refer to the "LICENSE" file in the root directory for more information.
//
import { SaveIcon, FilePenLineIcon, SaveOffIcon } from "lucide-react";

import { Button } from "@/components/ui/Button";
import { cn } from "@/lib/utils";

// eslint-disable-next-line react-refresh/only-export-components
export enum EAppStatus {
SAVED = "Saved",
UNSAVED = "Unsaved",
EDITING = "Editing",
}

export function AppStatus(props: { className?: string; status?: EAppStatus }) {
const { className, status } = props;
if (!status) {
return null;
}
return (
<div className={cn("flex items-center gap-2", "w-fit", className)}>
<div className="flex items-center">
{status === EAppStatus.SAVED && <SaveIcon className="w-4 h-4 me-2" />}
{status === EAppStatus.UNSAVED && (
<SaveOffIcon className="w-4 h-4 me-2" />
)}
{status === EAppStatus.EDITING && (
<FilePenLineIcon className="w-4 h-4 me-2" />
)}
{status}
</div>
{status === EAppStatus.EDITING && (
<div className="flex items-center text-primary">
<Button variant="outline" size="sm" className="">
<SaveIcon className="w-3 h-3" />
<span className="text-xs">Save</span>
</Button>
</div>
)}
</div>
);
}
Loading

0 comments on commit 03d91e7

Please sign in to comment.