Skip to content

Commit 1cbf49d

Browse files
committed
feat: support recent run apps feature
1 parent 2de32fe commit 1cbf49d

File tree

11 files changed

+202
-31
lines changed

11 files changed

+202
-31
lines changed

core/src/ten_manager/designer_frontend/public/locales/en-US/common.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@
112112
"deleteConnectionSuccess": "Connection deleted successfully",
113113
"deleteConnectionFailed": "Failed to delete connection",
114114
"replaceNode": "Replace Node with ...",
115-
"manageApps": "Manage Apps"
115+
"manageApps": "Manage Apps",
116+
"runApp": "Run"
116117
},
117118
"toast": {
118119
"saveFileSuccess": "File saved successfully",

core/src/ten_manager/designer_frontend/public/locales/ja-JP/common.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@
112112
"deleteConnectionSuccess": "接続の削除に成功しました",
113113
"deleteConnectionFailed": "接続の削除に失敗しました",
114114
"replaceNode": "ノードを置き換え...",
115-
"manageApps": "アプリを管理"
115+
"manageApps": "アプリを管理",
116+
"runApp": "実行"
116117
},
117118
"toast": {
118119
"saveFileSuccess": "ファイルの保存に成功しました",

core/src/ten_manager/designer_frontend/public/locales/zh-CN/common.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@
112112
"deleteConnectionSuccess": "连接删除成功",
113113
"deleteConnectionFailed": "连接删除失败",
114114
"replaceNode": "替换节点...",
115-
"manageApps": "管理应用"
115+
"manageApps": "管理应用",
116+
"runApp": "运行"
116117
},
117118
"toast": {
118119
"saveFileSuccess": "文件保存成功",

core/src/ten_manager/designer_frontend/public/locales/zh-TW/common.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@
112112
"deleteConnectionSuccess": "連線刪除成功",
113113
"deleteConnectionFailed": "連線刪除失敗",
114114
"replaceNode": "替換節點...",
115-
"manageApps": "管理應用程式"
115+
"manageApps": "管理應用程式",
116+
"runApp": "執行"
116117
},
117118
"toast": {
118119
"saveFileSuccess": "檔案儲存成功",

core/src/ten_manager/designer_frontend/src/api/services/storage.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { makeAPIRequest, getTanstackQueryClient } from "@/api/services/utils";
1111
import { ENDPOINT_PREFERENCES, ENDPOINT_STORAGE } from "@/api/endpoints";
1212
import { ENDPOINT_METHOD } from "@/api/endpoints/constant";
1313
import { PERSISTENT_SCHEMA, PERSISTENT_DEFAULTS } from "@/constants/persistent";
14+
import { IRunAppParams } from "@/types/apps";
1415

1516
export const getPreferencesLogViewerLines = async () => {
1617
const template =
@@ -133,3 +134,21 @@ export const useStorage = (type?: "in-memory" | "persistent") => {
133134
mutate: mutation.mutate,
134135
};
135136
};
137+
138+
export const addRecentRunApp = async (app: IRunAppParams) => {
139+
const { base_dir, script_name, stdout_is_log, stderr_is_log, run_with_agent } = app;
140+
const data = await getStorageValueByKey();
141+
await setStorageValueByKey(undefined, {
142+
...data,
143+
recent_run_apps: [
144+
{
145+
base_dir: base_dir,
146+
script_name: script_name,
147+
stdout_is_log: stdout_is_log,
148+
stderr_is_log: stderr_is_log,
149+
run_with_agent: run_with_agent,
150+
},
151+
...(data?.recent_run_apps || []),
152+
].slice(0, 3) // keep only the first 3
153+
});
154+
}

core/src/ten_manager/designer_frontend/src/components/Popup/Default/App.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import { Separator } from "@/components/ui/Separator";
4949
import {
5050
RTCInteractionPopupTitle,
5151
} from "@/components/AppBar/Menu/ExtensionMenu";
52+
import { addRecentRunApp, setStorageValueByKey, useStorage } from "@/api/services/storage";
5253

5354
export const AppFolderPopupTitle = () => {
5455
const { t } = useTranslation();
@@ -146,11 +147,19 @@ export const AppRunPopupContent = (props: { widget: IDefaultWidget }) => {
146147
>(scripts?.[0] || undefined);
147148
const [runWithAgent, setRunWithAgent] = React.useState<boolean>(false);
148149

149-
const handleRun = () => {
150+
const handleRun = async () => {
150151
removeWidget(widget.widget_id);
151152

152153
const newAppStartWidgetId = "app-start-" + Date.now();
153154

155+
await addRecentRunApp({
156+
base_dir: baseDir || "",
157+
script_name: selectedScript || "",
158+
stdout_is_log: true,
159+
stderr_is_log: true,
160+
run_with_agent: runWithAgent,
161+
});
162+
154163
appendWidget({
155164
container_id: CONTAINER_DEFAULT_ID,
156165
group_id: GROUP_LOG_VIEWER_ID,

core/src/ten_manager/designer_frontend/src/components/Popup/Default/RTC.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,15 @@ export const RTCWidgetTitle = () => {
4747
const RTCWidgetContentInner = ({ widget }: { widget: IWidget }) => {
4848
const [ready, setReady] = useState(false);
4949
const { nodes } = useFlowStore();
50-
const isConnected = useIsConnected();
51-
const { data, error } = useRTCEnvVar();
50+
// const isConnected = useIsConnected();
51+
const { data, error: rtcEnvError } = useRTCEnvVar();
5252
const { appId, appCert } = data || {};
5353
const [channel, setChannel] = useState<string | null>(null);
5454
const [token, setToken] = useState<string | null>(null);
5555
const [uid, setUid] = useState<number | null>(null);
5656
const client = useRTCClient();
5757
const { chatItems, addChatItem } = useChatItemReducer();
5858

59-
React.useEffect(() => {
60-
if (error) {
61-
toast.error(error.message);
62-
}
63-
}, [error]);
64-
6559
// Register parser logic and hook up chat message updates
6660
useRTCMessageParser(client, uid, (newMsg) => {
6761
addChatItem(newMsg);
@@ -101,7 +95,7 @@ const RTCWidgetContentInner = ({ widget }: { widget: IWidget }) => {
10195
return () => { };
10296
}, [channel, appId, appCert, uid]);
10397

104-
useJoin(
98+
const {error:joinError} = useJoin(
10599
{
106100
appid: appId || "",
107101
channel: channel || "",
@@ -116,11 +110,11 @@ const RTCWidgetContentInner = ({ widget }: { widget: IWidget }) => {
116110
const [videoSourceType, setVideoSourceType] = useState<VideoSourceType>(
117111
VideoSourceType.CAMERA
118112
);
119-
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
120-
const { localCameraTrack } = useLocalCameraTrack(
113+
const { localMicrophoneTrack, error: micError } = useLocalMicrophoneTrack(micOn);
114+
const { localCameraTrack, error: camError } = useLocalCameraTrack(
121115
videoSourceType === VideoSourceType.CAMERA ? videoOn : false
122116
);
123-
const { screenTrack } = useLocalScreenTrack(
117+
const { screenTrack, error: screenError } = useLocalScreenTrack(
124118
videoSourceType === VideoSourceType.SCREEN ? videoOn : false,
125119
{},
126120
"disable" // withAudio: "enable" | "disable"
@@ -157,8 +151,16 @@ const RTCWidgetContentInner = ({ widget }: { widget: IWidget }) => {
157151
? [localMicrophoneTrack, localCameraTrack]
158152
: [localMicrophoneTrack, screenTrack];
159153

160-
usePublish(publishTracks);
154+
const {error: publishError} = usePublish(publishTracks);
161155

156+
157+
React.useEffect(() => {
158+
[rtcEnvError, joinError, publishError, micError, camError, screenError].forEach((error) => {
159+
if (error) {
160+
toast.error(error.message);
161+
}
162+
});
163+
}, [rtcEnvError, joinError, publishError, micError, camError, screenError]);
162164

163165
return (
164166
<div className="flex flex-col h-full w-full gap-2">

core/src/ten_manager/designer_frontend/src/constants/persistent.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,25 @@ export const PERSISTENT_SCHEMA = {
1717
type: "string",
1818
description: "Schema version",
1919
},
20+
recent_run_apps: {
21+
type: "array",
22+
items: {
23+
type: "object",
24+
properties: {
25+
base_dir: { type: "string", description: "Base Dir" },
26+
script_name: { type: "string", description: "Selected Script Name" },
27+
stdout_is_log: { type: "boolean", description: "Std Out Logs" },
28+
stderr_is_log: { type: "boolean", description: "Std Err Logs" },
29+
run_with_agent: { type: "boolean", description: "Run with Agent" },
30+
},
31+
required: ["base_dir", "script_name", "stdout_is_log", "stderr_is_log", "run_with_agent"],
32+
}
33+
}
2034
},
2135
required: ["version"],
2236
};
2337

2438
export const PERSISTENT_DEFAULTS = {
2539
version: "0.0.1",
40+
recent_run_apps: [],
2641
};

core/src/ten_manager/designer_frontend/src/flow/ContextMenu/PaneContextMenu.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
FolderTreeIcon,
1212
GitPullRequestCreateIcon,
1313
PackagePlusIcon,
14+
PlayIcon,
1415
// PinIcon,
1516
} from "lucide-react";
1617

@@ -19,6 +20,8 @@ import ContextMenu, {
1920
type IContextMenuItem,
2021
} from "@/flow/ContextMenu/ContextMenu";
2122
import { EGraphActions } from "@/types/graphs";
23+
import { useStorage } from "@/api/services/storage";
24+
import { IRunAppParams } from "@/types/apps";
2225

2326

2427
interface PaneContextMenuProps {
@@ -30,6 +33,7 @@ interface PaneContextMenuProps {
3033
onOpenExistingGraph?: () => void;
3134
onGraphAct?: (type: EGraphActions) => void;
3235
onAppManager?: () => void;
36+
onAppRun?: (app: IRunAppParams) => void;
3337
onClose: () => void;
3438
}
3539

@@ -42,9 +46,12 @@ const PaneContextMenu: React.FC<PaneContextMenuProps> = ({
4246
onOpenExistingGraph,
4347
onGraphAct,
4448
onAppManager,
49+
onAppRun, // Assuming you have a function to handle running the app
4550
onClose,
4651
}) => {
4752
const { t } = useTranslation();
53+
const { data } = useStorage();
54+
const { recent_run_apps = [] } = data || {};
4855

4956

5057

@@ -95,6 +102,24 @@ const PaneContextMenu: React.FC<PaneContextMenuProps> = ({
95102
onAppManager?.();
96103
},
97104
},
105+
...recent_run_apps.map((app: IRunAppParams) => ({
106+
_type: EContextMenuItemType.BUTTON,
107+
label: `${t("action.runApp")} ${app.base_dir} ${app.script_name}`,
108+
icon: <PlayIcon className="size-3" />,
109+
disabled: !graphId,
110+
onClick: () => {
111+
onClose();
112+
// Assuming you have a function to handle running the app
113+
// runApp(app);
114+
onAppRun?.({
115+
script_name: app.script_name,
116+
base_dir: app.base_dir,
117+
run_with_agent: app.run_with_agent, // Assuming default value, adjust as needed
118+
stderr_is_log: true, // Assuming default value, adjust as needed
119+
stdout_is_log: true, // Assuming default value, adjust as needed
120+
});
121+
},
122+
})),
98123
];
99124

100125
return <ContextMenu visible={visible} x={x} y={y} items={items} />;

0 commit comments

Comments
 (0)