Merge branch 'main' of https://github.com/nyakang/nyaterm
This commit is contained in:
commit
540784da95
17 files changed
+80
-19
No files matched your search
@@ -146,6 +146,8 @@ $env:NYATERM_GITHUB_GIST_CLIENT_ID = "your_client_id"
|
||||
pnpm tauri build
|
||||
```
|
||||
|
||||
第三方发行包可以在构建时设置 `NYATERM_PACKAGE_MANAGER` 标识包管理器。应用会将该值写入支持信息,并把应用内更新交由外部包管理器处理;普通开发构建应保持未设置。
|
||||
|
||||
## 文档开发提示
|
||||
|
||||
如果你在修改 README 或 `docs-site/docs/` / `docs-site/i18n/en/` 下的文档,建议至少执行:
|
||||
|
||||
@@ -88,6 +88,8 @@ $env:NYATERM_GITHUB_GIST_CLIENT_ID = "your_client_id"
|
||||
pnpm tauri build
|
||||
```
|
||||
|
||||
Third-party distributors can set `NYATERM_PACKAGE_MANAGER` at build time to identify the package manager. The app includes this value in support information and leaves updates to the external package manager; leave it unset for ordinary development builds.
|
||||
|
||||
## Available Scripts
|
||||
|
||||
| Command | Description |
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-env-changed=NYATERM_GITHUB_GIST_CLIENT_ID");
|
||||
println!("cargo:rerun-if-env-changed=NYATERM_PACKAGE_MANAGER");
|
||||
|
||||
if let Ok(client_id) = std::env::var("NYATERM_GITHUB_GIST_CLIENT_ID") {
|
||||
println!("cargo:rustc-env=NYATERM_GITHUB_GIST_CLIENT_ID={client_id}");
|
||||
}
|
||||
|
||||
if let Ok(package_manager) = std::env::var("NYATERM_PACKAGE_MANAGER") {
|
||||
println!("cargo:rustc-env=NYATERM_PACKAGE_MANAGER={package_manager}");
|
||||
}
|
||||
|
||||
tauri_build::build();
|
||||
}
|
||||
@@ -110,17 +110,19 @@ pub struct AppSupportInfo {
|
||||
os: String,
|
||||
architecture: String,
|
||||
runtime: String,
|
||||
package_manager: Option<String>,
|
||||
#[cfg(windows)]
|
||||
conpty: crate::platform::windows_conpty::LocalConptyInfo,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_support_info(state: tauri::State<'_, crate::runtime::AppRuntime>) -> AppSupportInfo {
|
||||
let runtime = state.info().mode;
|
||||
let info = state.info();
|
||||
AppSupportInfo {
|
||||
os: operating_system_label(),
|
||||
architecture: std::env::consts::ARCH.to_string(),
|
||||
runtime,
|
||||
runtime: info.mode,
|
||||
package_manager: info.package_manager,
|
||||
#[cfg(windows)]
|
||||
conpty: crate::platform::windows_conpty::support_info(),
|
||||
}
|
||||
|
||||
@@ -12,9 +12,12 @@ const PORTABLE_KEY_FILE: &str = "portable.key";
|
||||
#[cfg(all(windows, target_vendor = "win7"))]
|
||||
const WIN7_WEBVIEW2_FIXED_RUNTIME_DIR: &str = "webview2-fixed-runtime";
|
||||
|
||||
const PACKAGE_MANAGER: Option<&str> = option_env!("NYATERM_PACKAGE_MANAGER");
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AppRuntime {
|
||||
portable: bool,
|
||||
package_manager: Option<String>,
|
||||
executable_dir: PathBuf,
|
||||
data_dir: PathBuf,
|
||||
config_dir: PathBuf,
|
||||
@@ -30,6 +33,7 @@ pub struct AppRuntime {
|
||||
pub struct AppRuntimeInfo {
|
||||
pub portable: bool,
|
||||
pub mode: String,
|
||||
pub package_manager: Option<String>,
|
||||
pub executable_dir: String,
|
||||
pub data_dir: String,
|
||||
pub config_dir: String,
|
||||
@@ -43,6 +47,10 @@ impl AppRuntime {
|
||||
self.portable
|
||||
}
|
||||
|
||||
pub fn package_manager(&self) -> Option<&str> {
|
||||
self.package_manager.as_deref()
|
||||
}
|
||||
|
||||
pub fn executable_dir(&self) -> &Path {
|
||||
&self.executable_dir
|
||||
}
|
||||
@@ -82,6 +90,7 @@ impl AppRuntime {
|
||||
} else {
|
||||
"installed".to_string()
|
||||
},
|
||||
package_manager: self.package_manager.clone(),
|
||||
executable_dir: path_to_string(&self.executable_dir),
|
||||
data_dir: path_to_string(&self.data_dir),
|
||||
config_dir: path_to_string(&self.config_dir),
|
||||
@@ -95,6 +104,13 @@ impl AppRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
fn package_manager_name() -> Option<String> {
|
||||
PACKAGE_MANAGER
|
||||
.map(str::trim)
|
||||
.filter(|name| !name.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
}
|
||||
|
||||
pub fn resolve() -> AppResult<AppRuntime> {
|
||||
let executable_dir = executable_dir()?;
|
||||
let portable_marker_path = executable_dir.join(PORTABLE_MARKER_FILE);
|
||||
@@ -184,6 +200,7 @@ fn resolve_portable(
|
||||
|
||||
Ok(AppRuntime {
|
||||
portable: true,
|
||||
package_manager: package_manager_name(),
|
||||
executable_dir,
|
||||
data_dir,
|
||||
config_dir,
|
||||
@@ -204,6 +221,7 @@ fn resolve_installed(executable_dir: PathBuf) -> AppResult<AppRuntime> {
|
||||
|
||||
Ok(AppRuntime {
|
||||
portable: false,
|
||||
package_manager: package_manager_name(),
|
||||
executable_dir,
|
||||
data_dir: config_dir.clone(),
|
||||
config_dir,
|
||||
|
||||
@@ -371,6 +371,9 @@ fn rebuild_root_menu(
|
||||
settings.general.minimize_to_tray,
|
||||
None::<&str>,
|
||||
)?;
|
||||
let is_package_managed = app
|
||||
.try_state::<crate::runtime::AppRuntime>()
|
||||
.is_some_and(|runtime| runtime.package_manager().is_some());
|
||||
let check_updates = new_menu_item(app, MENU_CHECK_UPDATES, strings.check_updates, true)?;
|
||||
let separator_3 = PredefinedMenuItem::separator(app)?;
|
||||
let quit = new_menu_item(app, MENU_QUIT, strings.quit, true)?;
|
||||
@@ -390,7 +393,9 @@ fn rebuild_root_menu(
|
||||
menu.append(&lock_screen)?;
|
||||
}
|
||||
|
||||
menu.append(&check_updates)?;
|
||||
if !is_package_managed {
|
||||
menu.append(&check_updates)?;
|
||||
}
|
||||
menu.append(&separator_3)?;
|
||||
menu.append(&quit)?;
|
||||
Ok(())
|
||||
|
||||
+2
-2
@@ -364,7 +364,7 @@ function App() {
|
||||
|
||||
// Background update check on startup
|
||||
useEffect(() => {
|
||||
if (!runtimeInfoLoaded) return;
|
||||
if (!runtimeInfoLoaded || runtimeInfo.packageManager) return;
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
checkForUpdate(portable)
|
||||
@@ -377,7 +377,7 @@ function App() {
|
||||
.catch(() => {});
|
||||
}, 3000);
|
||||
return () => clearTimeout(timer);
|
||||
}, [portable, runtimeInfoLoaded]);
|
||||
}, [portable, runtimeInfo.packageManager, runtimeInfoLoaded]);
|
||||
|
||||
const closeFloatingPanel = useCallback(
|
||||
(side: "left" | "right") => {
|
||||
|
||||
@@ -87,20 +87,27 @@ export default function AboutDialog({ open, onClose }: AboutDialogProps) {
|
||||
: conpty.lastUsed
|
||||
? t("about.conptyLastUsed", {
|
||||
source: conpty.lastUsed === "bundled" ? bundledLabel : systemLabel,
|
||||
})
|
||||
})
|
||||
: t("about.conptyNotStarted");
|
||||
|
||||
const packageManagerDisplay = supportInfo?.packageManager
|
||||
? `${supportInfo.packageManager.charAt(0).toUpperCase()}${supportInfo.packageManager.slice(1)}`
|
||||
: null;
|
||||
|
||||
const copySupportInfo = async () => {
|
||||
if (!appVersion || !supportInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const runtimeLabel =
|
||||
supportInfo.runtime === "portable" ? t("about.portable") : t("about.installed");
|
||||
const text = [
|
||||
"NyaTerm Support Information",
|
||||
`Version: ${appVersion}`,
|
||||
`Operating System: ${supportInfo.os}`,
|
||||
`Application Architecture: ${supportInfo.architecture}`,
|
||||
`Runtime: ${supportInfo.runtime === "portable" ? t("about.portable") : t("about.installed")}`,
|
||||
`Runtime: ${runtimeLabel}`,
|
||||
...(packageManagerDisplay ? [`Package Manager: ${packageManagerDisplay}`] : []),
|
||||
...(conptyDisplay ? [`Local Terminal ConPTY: ${conptyDisplay}`] : []),
|
||||
].join("\n");
|
||||
try {
|
||||
@@ -133,6 +140,7 @@ export default function AboutDialog({ open, onClose }: AboutDialogProps) {
|
||||
[t("about.operatingSystem"), osDisplay],
|
||||
[t("about.architecture"), architectureDisplay],
|
||||
[t("about.runtime"), runtimeDisplay],
|
||||
...(packageManagerDisplay ? [[t("about.packageManager"), packageManagerDisplay]] : []),
|
||||
...(conptyDisplay ? [[t("about.conpty"), conptyDisplay]] : []),
|
||||
];
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ function MarkdownContent({ content }: { content: string }) {
|
||||
|
||||
export default function UpdateDialog({ open, onClose, onUpdateFound }: UpdateDialogProps) {
|
||||
const { t } = useTranslation();
|
||||
const { runtimeInfo } = useApp();
|
||||
const { runtimeInfo, runtimeInfoLoaded } = useApp();
|
||||
const [status, setStatus] = useState<UpdateStatus>("checking");
|
||||
const [progress, setProgress] = useState<UpdateProgress>({ downloaded: 0, total: 0 });
|
||||
const [error, setError] = useState<string>("");
|
||||
@@ -158,7 +158,7 @@ export default function UpdateDialog({ open, onClose, onUpdateFound }: UpdateDia
|
||||
onUpdateFoundRef.current = onUpdateFound;
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
if (!open || !runtimeInfoLoaded || runtimeInfo.packageManager) return;
|
||||
|
||||
getVersion()
|
||||
.then(setCurrentVersion)
|
||||
@@ -191,10 +191,10 @@ export default function UpdateDialog({ open, onClose, onUpdateFound }: UpdateDia
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [open, runtimeInfo.portable]);
|
||||
}, [open, runtimeInfo.packageManager, runtimeInfo.portable, runtimeInfoLoaded]);
|
||||
|
||||
const handleUpdate = useCallback(async () => {
|
||||
if (isUpdating.current) return;
|
||||
if (isUpdating.current || runtimeInfo.packageManager) return;
|
||||
isUpdating.current = true;
|
||||
setStatus("downloading");
|
||||
setError("");
|
||||
@@ -209,7 +209,7 @@ export default function UpdateDialog({ open, onClose, onUpdateFound }: UpdateDia
|
||||
setStatus("error");
|
||||
isUpdating.current = false;
|
||||
}
|
||||
}, [runtimeInfo.portable]);
|
||||
}, [runtimeInfo.packageManager, runtimeInfo.portable]);
|
||||
|
||||
const handleRelaunch = useCallback(async () => {
|
||||
try {
|
||||
|
||||
@@ -756,7 +756,14 @@ export default function Header({
|
||||
}: HeaderProps) {
|
||||
const [appWindow] = useState(() => getCurrentWindow());
|
||||
const { themeName, setTheme, themeNames, terminalThemeName, setTerminalTheme } = useTheme();
|
||||
const { updateAppSettings, updateUi, appSettings, tabs } = useApp();
|
||||
const {
|
||||
updateAppSettings,
|
||||
updateUi,
|
||||
appSettings,
|
||||
tabs,
|
||||
runtimeInfo,
|
||||
runtimeInfoLoaded,
|
||||
} = useApp();
|
||||
const [showImportDialog, setShowImportDialog] = useState(false);
|
||||
const [isMaximized, setIsMaximized] = useState(false);
|
||||
const [showCloseConfirm, setShowCloseConfirm] = useState(false);
|
||||
@@ -1242,12 +1249,16 @@ export default function Header({
|
||||
icon: "menu_book",
|
||||
action: () => openUrl(`${packageJson.docspage}`),
|
||||
},
|
||||
{
|
||||
id: "help.checkUpdates",
|
||||
label: t("menu.checkForUpdates"),
|
||||
icon: hasUpdate ? "upgrade" : "update",
|
||||
action: onCheckForUpdates,
|
||||
},
|
||||
...(!runtimeInfoLoaded || runtimeInfo.packageManager
|
||||
? []
|
||||
: [
|
||||
{
|
||||
id: "help.checkUpdates",
|
||||
label: t("menu.checkForUpdates"),
|
||||
icon: hasUpdate ? "upgrade" : "update",
|
||||
action: onCheckForUpdates,
|
||||
},
|
||||
]),
|
||||
{
|
||||
id: "help.viewLogs",
|
||||
label: t("menu.viewLogs"),
|
||||
|
||||
@@ -276,6 +276,7 @@ const RECENT_CONNECTION_LIMIT = 10;
|
||||
const DEFAULT_RUNTIME_INFO: AppRuntimeInfo = {
|
||||
portable: false,
|
||||
mode: "installed",
|
||||
packageManager: null,
|
||||
executableDir: "",
|
||||
dataDir: "",
|
||||
configDir: "",
|
||||
|
||||
@@ -233,6 +233,7 @@ const DEFAULT_APP_SETTINGS: AppSettings = {
|
||||
const DEFAULT_RUNTIME_INFO: AppRuntimeInfo = {
|
||||
portable: false,
|
||||
mode: "installed",
|
||||
packageManager: null,
|
||||
executableDir: "",
|
||||
dataDir: "",
|
||||
configDir: "",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"installed": "Installed",
|
||||
"issues": "Issues",
|
||||
"operatingSystem": "Operating system",
|
||||
"packageManager": "Package manager",
|
||||
"portable": "Portable",
|
||||
"runtime": "Runtime",
|
||||
"supportInfo": "Support information",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"installed": "설치 버전",
|
||||
"issues": "이슈",
|
||||
"operatingSystem": "운영 체제",
|
||||
"packageManager": "패키지 관리자",
|
||||
"portable": "포터블 버전",
|
||||
"runtime": "실행 환경",
|
||||
"supportInfo": "지원 정보",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"installed": "安装版",
|
||||
"issues": "问题反馈",
|
||||
"operatingSystem": "操作系统",
|
||||
"packageManager": "包管理器",
|
||||
"portable": "便携版",
|
||||
"runtime": "运行环境",
|
||||
"supportInfo": "支持信息",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"installed": "安裝版",
|
||||
"issues": "問題回報",
|
||||
"operatingSystem": "作業系統",
|
||||
"packageManager": "套件管理器",
|
||||
"portable": "便攜版",
|
||||
"runtime": "執行環境",
|
||||
"supportInfo": "支援資訊",
|
||||
|
||||
Vendored
+2
@@ -30,6 +30,7 @@ export type { TemporaryLinkConfig } from "@/types/temporaryConnection";
|
||||
export interface AppRuntimeInfo {
|
||||
portable: boolean;
|
||||
mode: "installed" | "portable";
|
||||
packageManager?: string | null;
|
||||
executableDir: string;
|
||||
dataDir: string;
|
||||
configDir: string;
|
||||
@@ -42,6 +43,7 @@ export interface AppSupportInfo {
|
||||
os: string;
|
||||
architecture: string;
|
||||
runtime: "portable" | "installed";
|
||||
packageManager?: string | null;
|
||||
conpty?: {
|
||||
available: boolean;
|
||||
activeBundled: number;
|
||||
|
||||
Reference in new issue
Block a user