docs: improve legacy windows and linux install guidance

This commit is contained in:
zipg
2026-09-02 17:34:23 +08:00
committed by GitHub
parent 2c14016828
commit 0333b3b389
13 changed files with 382 additions and 38 deletions
+1 -1
View File
@@ -200,7 +200,7 @@ jobs:
needs: changes
if: needs.changes.outputs.windows_win7_bundle == 'true'
runs-on: windows-2022
timeout-minutes: 90
timeout-minutes: 120
env:
CARGO_INCREMENTAL: "0"
RUSTFLAGS: -C debuginfo=line-tables-only -C target-feature=+crt-static
@@ -17,6 +17,25 @@ const ciWorkflow = readFileSync(resolve(process.cwd(), ".github/workflows/ci.yml
const releaseWorkflow = readFileSync(resolve(process.cwd(), ".github/workflows/release.yml"), "utf8");
describe("Windows offline installer template", () => {
it("routes supported legacy Windows users from generic installers to the fixed-runtime package", () => {
expect(template).toContain("ManifestSupportedOS all");
expect(template).toContain("!include WinVer.nsh");
expect(template).toContain('!if "${INSTALLWEBVIEW2MODE}" != "fixedRuntime"');
expect(template).toContain("${If} ${IsWin7}");
expect(template).toContain("${OrIf} ${IsWin2012R2}");
expect(template).toContain('MessageBox MB_ICONSTOP|MB_YESNO|MB_DEFBUTTON1 "$(dbxWin7InstallerRequired)" IDYES dbx_open_win7_installer');
expect(template).toContain("https://dl.dbxio.com/releases/v${VERSION}/DBX_${VERSION}_x64-win7-server2012r2-webview2-109-offline-setup.exe?v=${VERSION}");
expect(template).toContain("SetErrorLevel 1633");
expect(template).toContain("${OrIf} $PassiveMode = 1");
});
it("localizes the Windows 7 package guidance in every installer language", () => {
expect(template.match(/LangString dbxWin7InstallerRequired/g)).toHaveLength(3);
expect(template).toContain("This installer does not support Windows 7 or Windows Server 2012 R2.");
expect(template).toContain("此安装包不支持 Windows 7 或 Windows Server 2012 R2。");
expect(template).toContain("此安裝套件不支援 Windows 7 或 Windows Server 2012 R2。");
});
it.each([
{
name: "continues after installer failure when a compatible Runtime remains",
+1 -1
View File
@@ -417,7 +417,7 @@ fn export_agents_offline_unlocked(
let plan = inspect_offline_package(package)?;
let expected = drivers.iter().map(|driver| driver.db_type.clone()).collect::<BTreeSet<_>>();
let actual = plan.driver_keys.into_iter().collect::<BTreeSet<_>>();
if expected != actual || plan.includes_jre != !jres.is_empty() {
if expected != actual || plan.includes_jre == jres.is_empty() {
return Err("Generated offline Agent package failed compatibility validation".to_string());
}
Ok(())
+3 -4
View File
@@ -5840,7 +5840,7 @@ async fn list_objects_once(
let db_config = connection_config(state, connection_id).await;
let force_local_table_name_filter = table_name_filter.is_some_and(|filter| !filter.is_empty());
let (mysql_limit, mysql_offset) = if filter.is_none_or(|value| value.trim().is_empty())
&& !table_name_filter.is_some_and(|filter| !filter.is_empty())
&& table_name_filter.is_none_or(|filter| filter.is_empty())
{
(limit, offset)
} else {
@@ -9429,10 +9429,9 @@ fn postgres_missing_prokind_error(err: &str) -> bool {
// PostgreSQL localizes the undefined-column message (for example, Chinese
// servers report "字段 p.prokind 不存在"). Keep the column context so an
// unrelated relation named `prokind` cannot trigger this compatibility path.
let undefined_column = lower.contains("sqlstate 42703")
lower.contains("sqlstate 42703")
|| (lower.contains("does not exist") && lower.contains("column"))
|| (err.contains("不存在") && (err.contains("字段") || err.contains("列 p.prokind")));
undefined_column
|| (err.contains("不存在") && (err.contains("字段") || err.contains("列 p.prokind")))
}
fn opengauss_sequence_cache_metadata_error(err: &str) -> bool {
@@ -209,9 +209,9 @@ pub fn build_table_data_select_sql_with_database(
let table = if let Some(database) = jdbc_tdengine_database {
qualified_table_name(Some(DatabaseType::Tdengine), Some(database), &options.table_name)
// Doris / StarRocks multi-catalog: prefix the catalog for external-catalog tables.
} else if database_type == Some(DatabaseType::Iris) {
table_data_qualified_table_name(database_type, schema, &options.table_name, options.identifier_quote.as_deref())
} else if uses_connection_identifier_quote(database_type, options.identifier_quote.as_deref()) {
} else if database_type == Some(DatabaseType::Iris)
|| uses_connection_identifier_quote(database_type, options.identifier_quote.as_deref())
{
table_data_qualified_table_name(database_type, schema, &options.table_name, options.identifier_quote.as_deref())
} else if include_database_name {
database_qualified_table_name(
+1 -1
View File
@@ -93,7 +93,7 @@ impl RuntimeConfig {
validate_path(&path)?;
let is_loopback = ip.is_loopback();
if !is_loopback && !(allow_remote && explicit_allow_remote) {
if !(is_loopback || (allow_remote && explicit_allow_remote)) {
return Err(
"non-loopback HTTP binding requires both DBX_MCP_HTTP_ALLOW_REMOTE=1 and --http-allow-remote".into()
);
+1 -1
View File
@@ -224,7 +224,7 @@ async fn execute_query_injects_and_omits_timeout_secs_from_policy() {
let captured = captured_query_arguments(backend, json!({ "connection_id": "scoped", "sql": "SELECT 1" })).await;
assert_eq!(captured.len(), 1, "expected one captured execute_query call");
assert!(
!captured[0].get("timeout_secs").is_some(),
captured[0].get("timeout_secs").is_none(),
"no timeout_secs must be injected when the policy inherits the connection: {}",
captured[0]
);
+18
View File
@@ -755,6 +755,24 @@ a {
color: var(--color-landing-ink);
}
.landing-install-download-link:focus-visible {
border-radius: 8px;
outline: 2px solid rgba(255, 255, 255, 0.72);
outline-offset: -3px;
}
.landing-install-driver-link {
color: #69c9ff;
text-decoration-color: rgba(105, 201, 255, 0.78);
transition: color 0.16s ease;
}
.landing-install-driver-link:hover,
.landing-install-driver-link:focus-visible {
color: #a7e3ff;
text-decoration-color: currentColor;
}
.landing-install-option svg {
fill: currentColor;
stroke-width: 1.8;
+212 -13
View File
@@ -1,8 +1,9 @@
"use client";
import { ChevronDown, Download, Server } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { createInstallOptions } from "@/lib/downloadLinks";
import { Check, ChevronDown, ChevronRight, Copy, Download, Server, X } from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { createInstallOptions, type InstallOption } from "@/lib/downloadLinks";
import { detectPlatformId, type DownloadPlatformId } from "@/lib/platformDetection";
type InstallTabsProps = {
@@ -14,8 +15,45 @@ const downloadLabel = { en: "Download DBX", cn: "下载 DBX" };
const selectDownloadLabel = { en: "Choose a version", cn: "选择下载版本" };
const selectMacLabel = { en: "Choose a macOS version", cn: "选择 macOS 版本" };
const offlineHint = {
en: "Offline network or Windows 7? Choose an offline installer",
cn: "无法联网或使用 Windows 7?选择专用离线安装包",
en: "Installing offline or using legacy Windows? View the matching installer",
cn: "需要离线安装或使用旧版 Windows?查看对应安装包",
};
const browserStaticText = {
en: {
eyebrow: "Linux browser package",
intro: "For Kylin, UnionTech UOS, and other Linux distributions. DBX runs locally and opens in your browser.",
extract: "Extract and enter the package directory",
start: "Start DBX",
open: "Open in your local browser",
port: "Need a different port?",
portHint: "Replace 8080 with any available local port.",
browserStyle: "Page layout looks incorrect?",
browserStyleHint: [
"Some browsers in intranet or enterprise Linux environments use older browser engines that may not fully support the modern web standards used by DBX, resulting in missing or incorrect styles.",
"For example, older QiAnXin browser versions based on Chromium 90 can show this behavior.",
"Update the browser to its latest version, or use a current version of Chrome, Edge, or Firefox.",
],
download: "Download",
close: "Close installation guide",
copy: "Copy command",
copied: "Copied",
},
cn: {
eyebrow: "Linux 浏览器版",
intro: "适用于麒麟、统信 UOS 等 Linux 发行版。DBX 在本机运行,通过浏览器访问。",
extract: "解压并进入安装目录",
start: "启动 DBX",
open: "在本机浏览器打开",
port: "需要修改默认端口?",
portHint: "将 8080 替换为其他可用端口即可。",
browserStyle: "网页样式显示异常?",
browserStyleHint: ["部分信创或内网环境使用的浏览器内核版本较旧,可能无法完整支持 DBX 使用的现代 Web 标准,从而出现布局错位、样式缺失等问题。", "例如,基于 Chromium 90 内核的旧版奇安信浏览器可能出现此类情况。", "请优先升级当前浏览器;环境允许时,也可以改用新版 Chrome、Edge 或 Firefox。"],
download: "下载",
close: "关闭安装说明",
copy: "复制命令",
copied: "已复制",
},
};
const platformIconPaths = {
@@ -26,6 +64,7 @@ const platformIconPaths = {
"macos-intel": "/icons/platform/macos.png",
"macos-unknown": "/icons/platform/macos.png",
windows: "/icons/platform/windows.png",
"windows-legacy": "/icons/platform/windows-legacy.png",
},
light: {
"linux-arm": "/icons/platform/linux.svg",
@@ -34,6 +73,7 @@ const platformIconPaths = {
"macos-intel": "/icons/platform/macos-white.png",
"macos-unknown": "/icons/platform/macos-white.png",
windows: "/icons/platform/windows.png",
"windows-legacy": "/icons/platform/windows-legacy.png",
},
};
@@ -43,10 +83,141 @@ function PlatformIcon({ id, size, variant }: { id: string; size: number; variant
return <img alt="" aria-hidden="true" height={size} src={src} width={size} />;
}
function BrowserStaticDialog({ lang, option, version, onClose }: { lang: "en" | "cn"; option: InstallOption; version: string; onClose: () => void }) {
const closeButtonRef = useRef<HTMLButtonElement>(null);
const [copiedCommand, setCopiedCommand] = useState<string | null>(null);
const text = browserStaticText[lang];
const archiveName = `DBX_${version}_*-browser-static.tar.gz`;
const packageDirectory = "dbx-linux-*-browser-static";
const extractCommand = `tar -xzf ${archiveName}\ncd ${packageDirectory}`;
const downloads = option.browserStaticDownloads ?? [{ arch: "x64" as const, href: option.href }];
useEffect(() => {
const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
const previousOverflow = document.body.style.overflow;
document.body.style.overflow = "hidden";
closeButtonRef.current?.focus();
const closeOnEscape = (event: KeyboardEvent) => {
if (event.key === "Escape") onClose();
};
window.addEventListener("keydown", closeOnEscape);
return () => {
window.removeEventListener("keydown", closeOnEscape);
document.body.style.overflow = previousOverflow;
previousFocus?.focus();
};
}, [onClose]);
const copyCommand = (command: string) => {
void navigator.clipboard
.writeText(command)
.then(() => {
setCopiedCommand(command);
window.setTimeout(() => setCopiedCommand((current) => (current === command ? null : current)), 1600);
})
.catch(() => undefined);
};
const commandBlock = (command: string) => (
<div className="grid grid-cols-[minmax(0,1fr)_34px] items-start gap-2 rounded-md border border-white/10 bg-black/30 p-2 pl-3">
<code className="min-w-0 overflow-x-auto whitespace-pre font-mono text-xs leading-relaxed text-[#dce5ee]">{command}</code>
<button
type="button"
aria-label={copiedCommand === command ? text.copied : text.copy}
className="grid size-[34px] place-items-center rounded-md border-0 bg-white/[0.06] text-white/65 cursor-pointer hover:bg-white/10 hover:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/70"
title={copiedCommand === command ? text.copied : text.copy}
onClick={() => copyCommand(command)}
>
{copiedCommand === command ? <Check size={15} /> : <Copy size={15} />}
</button>
</div>
);
if (typeof document === "undefined") return null;
return createPortal(
<div
className="fixed inset-0 z-[100] grid place-items-center overflow-y-auto bg-black/70 px-4 py-6 backdrop-blur-sm"
role="presentation"
onMouseDown={(event) => {
if (event.target === event.currentTarget) onClose();
}}
>
<section aria-labelledby="browser-static-dialog-title" aria-modal="true" className="w-[min(560px,calc(100vw-32px))] max-h-[calc(100vh-48px)] overflow-y-auto rounded-lg border border-white/15 bg-[#111419] text-white shadow-[0_28px_90px_rgba(0,0,0,0.58)]" role="dialog">
<header className="grid grid-cols-[minmax(0,1fr)_36px] gap-4 border-b border-white/10 px-5 py-4">
<div className="min-w-0">
<small className="text-[11px] font-semibold text-[#69c9ff]">{text.eyebrow}</small>
<h2 className="mt-1 text-lg font-semibold leading-tight" id="browser-static-dialog-title">
{option.label}
</h2>
<p className="mt-2 text-sm leading-relaxed text-white/55">{text.intro}</p>
</div>
<button
ref={closeButtonRef}
type="button"
aria-label={text.close}
className="grid size-9 place-items-center rounded-md border-0 bg-white/[0.06] text-white/65 cursor-pointer hover:bg-white/10 hover:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/70"
title={text.close}
onClick={onClose}
>
<X size={17} />
</button>
</header>
<div className="grid gap-4 px-5 py-4">
<section>
<h3 className="mb-2 text-sm font-semibold">1. {text.extract}</h3>
{commandBlock(extractCommand)}
</section>
<section>
<h3 className="mb-2 text-sm font-semibold">2. {text.start}</h3>
{commandBlock("./dbx")}
</section>
<section>
<h3 className="mb-2 text-sm font-semibold">3. {text.open}</h3>
<a className="inline-flex text-sm font-semibold text-[#69c9ff] underline underline-offset-4 hover:text-[#9dddff]" href="http://127.0.0.1:4224" target="_blank" rel="noreferrer">
http://127.0.0.1:4224
</a>
</section>
<details className="group border-t border-white/10 pt-3">
<summary className="w-fit cursor-pointer text-xs font-medium text-white/45 hover:text-white/70 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white/60">{text.port}</summary>
<div className="mt-3">
{commandBlock("DBX_PORT=8080 ./dbx")}
<p className="mt-2 text-xs leading-relaxed text-white/45">{text.portHint}</p>
</div>
</details>
<details className="group border-t border-white/10 pt-3">
<summary className="w-fit cursor-pointer text-xs font-medium text-white/45 hover:text-white/70 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white/60">{text.browserStyle}</summary>
<div className="mt-3 grid gap-2 text-xs leading-relaxed text-white/55">
{text.browserStyleHint.map((paragraph) => (
<p key={paragraph}>{paragraph}</p>
))}
</div>
</details>
</div>
<footer className="flex flex-wrap justify-end gap-2 border-t border-white/10 px-5 py-4">
{downloads.map((download) => (
<a className="inline-flex min-h-10 items-center gap-2 rounded-md bg-white px-4 text-sm font-semibold text-[#111419] hover:bg-[#e9f5fb] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#69c9ff]" href={download.href} key={download.arch}>
<Download size={16} />
{text.download} {download.arch === "arm64" ? "ARM64" : "x64"}
</a>
))}
</footer>
</section>
</div>,
document.body,
);
}
export function InstallTabs({ lang, version }: InstallTabsProps) {
const options = useMemo(() => createInstallOptions(lang, version), [lang, version]);
const [open, setOpen] = useState(false);
const [platformId, setPlatformId] = useState<DownloadPlatformId>("unknown");
const [browserStaticOption, setBrowserStaticOption] = useState<InstallOption | null>(null);
const closeBrowserStaticDialog = useCallback(() => setBrowserStaticOption(null), []);
useEffect(() => {
let cancelled = false;
@@ -129,23 +300,50 @@ export function InstallTabs({ lang, version }: InstallTabsProps) {
</button>
</div>
<div
className="landing-install-menu absolute z-30 top-[calc(100%+12px)] left-1/2 -translate-x-1/2 grid w-[min(380px,calc(100vw-32px))] border border-[rgba(173,176,182,0.17)] rounded-xl py-1.5 max-[760px]:left-auto max-[760px]:translate-x-0"
className="landing-install-menu absolute z-30 top-[calc(100%+12px)] left-1/2 -translate-x-1/2 grid max-h-[min(680px,calc(100vh-140px))] w-[min(410px,calc(100vw-32px))] overflow-y-auto overscroll-contain border border-[rgba(173,176,182,0.17)] rounded-xl py-1.5 max-[760px]:left-auto max-[760px]:translate-x-0"
id="landing-install-menu"
role="menu"
aria-label={lang === "cn" ? "下载选项" : "Download options"}
>
{menuOptions.map((item) => (
<a className="landing-install-option grid grid-cols-[24px_minmax(0,1fr)_18px] gap-3 items-center min-h-11 min-w-0 border-0 px-[18px] py-3 bg-transparent text-left cursor-pointer" href={item.href} key={item.id} role="menuitem">
<div className="landing-install-option relative grid grid-cols-[24px_minmax(0,1fr)_18px] gap-3 items-center min-h-11 min-w-0 border-0 px-[18px] py-3 bg-transparent text-left cursor-pointer" key={item.id} role="none">
{item.action === "instructions" ? (
<button
type="button"
aria-label={lang === "cn" ? `查看 ${item.label} 安装说明` : `View installation guide for ${item.label}`}
className="landing-install-download-link absolute inset-0 border-0 bg-transparent cursor-pointer"
role="menuitem"
onClick={() => {
setOpen(false);
setBrowserStaticOption(item);
}}
/>
) : (
<a aria-label={lang === "cn" ? `下载 ${item.label}` : `Download ${item.label}`} className="landing-install-download-link absolute inset-0" href={item.href} role="menuitem" />
)}
<PlatformIcon id={item.iconId} size={20} variant="light" />
<span className="grid min-w-0 gap-1">
<span className="flex min-w-0 items-center gap-2">
<strong className="overflow-hidden text-sm font-[640] leading-[1.2] truncate">{item.label}</strong>
{item.badge ? <small className="shrink-0 rounded-full bg-white/10 px-2 py-0.5 text-[10px] font-[680] leading-none text-white/70">{item.badge}</small> : null}
<span className="flex min-w-0 items-start gap-2">
<strong className="min-w-0 text-sm font-[640] leading-[1.2]">{item.label}</strong>
{item.badge ? <small className={`shrink-0 rounded-full bg-white/10 px-2 py-0.5 text-[10px] font-[680] leading-none text-white/70 ${item.id === "windows-7-offline" ? "max-[400px]:hidden" : ""}`}>{item.badge}</small> : null}
</span>
{item.description ? <small className="overflow-hidden text-xs leading-[1.3] text-white/45 truncate">{item.description}</small> : null}
{item.description ? (
<small className="pointer-events-none text-xs leading-[1.35] text-white/45">
{item.description}
{item.driverLinkLabel ? (
<>
{lang === "en" ? " " : null}
<a className="landing-install-driver-link pointer-events-auto relative z-10 underline underline-offset-2" href={`/${lang}/drivers`}>
{item.driverLinkLabel}
</a>
</>
) : null}
{item.descriptionSuffix}
</small>
) : null}
</span>
<Download size={15} aria-hidden="true" />
</a>
{item.action === "instructions" ? <ChevronRight size={15} aria-hidden="true" /> : <Download size={15} aria-hidden="true" />}
</div>
))}
</div>
</div>
@@ -159,6 +357,7 @@ export function InstallTabs({ lang, version }: InstallTabsProps) {
{offlineHint[lang]}
</button>
) : null}
{browserStaticOption ? <BrowserStaticDialog lang={lang} option={browserStaticOption} version={version} onClose={closeBrowserStaticDialog} /> : null}
</div>
);
}
+52 -8
View File
@@ -4,29 +4,47 @@ import { test } from "vitest";
import { createInstallOptions } from "./downloadLinks";
test("Windows downloads include standard, offline, and Windows 7 installers", () => {
const windowsOptions = createInstallOptions("cn", "0.5.82").filter((option) => option.iconId === "windows");
const windowsOptions = createInstallOptions("cn", "0.5.82").filter((option) => option.id.startsWith("windows"));
assert.deepEqual(
windowsOptions.map(({ id, label, description, badge, href }) => ({ id, label, description, badge, href })),
windowsOptions.map(({ id, iconId, label, description, driverLinkLabel, descriptionSuffix, badge, href }) => ({
id,
iconId,
label,
description,
driverLinkLabel,
descriptionSuffix,
badge,
href,
})),
[
{
id: "windows",
iconId: "windows",
label: "Windows 10/11 (x64)",
description: "标准在线安装包",
driverLinkLabel: undefined,
descriptionSuffix: undefined,
badge: "推荐",
href: "https://dl.dbxio.com/releases/v0.5.82/DBX_0.5.82_x64-setup.exe?v=0.5.82",
},
{
id: "windows-offline",
label: "Windows 完整离线安装包",
description: "内置 WebView2 · 适用于内网部署或运行库缺失",
badge: "离线",
iconId: "windows",
label: "Windows10内网环境安装包",
description: "内置 WebView2 离线运行库 · 不含",
driverLinkLabel: "数据库离线驱动",
descriptionSuffix: undefined,
badge: "内网",
href: "https://dl.dbxio.com/releases/v0.5.82/DBX_0.5.82_x64-webview2-offline-setup.exe?v=0.5.82",
},
{
id: "windows-7-offline",
label: "Windows 7 / Server 2012 R2 离线安装包",
description: "内置 WebView2 109 · 仅支持 x64",
iconId: "windows-legacy",
label: "Windows 7 / Server\u00a02012\u00a0R2 专用包",
description: "内置 WebView2 离线运行库 · 不含",
driverLinkLabel: "数据库离线驱动",
descriptionSuffix: undefined,
badge: "旧系统",
href: "https://dl.dbxio.com/releases/v0.5.82/DBX_0.5.82_x64-win7-server2012r2-webview2-109-offline-setup.exe?v=0.5.82",
},
@@ -37,7 +55,33 @@ test("Windows downloads include standard, offline, and Windows 7 installers", ()
test("all downloads use immutable versioned release paths", () => {
const options = createInstallOptions("en", "0.5.82");
assert.equal(options.length, 7);
assert.equal(options.length, 8);
assert.ok(options.every((option) => option.href.startsWith("https://dl.dbxio.com/releases/v0.5.82/DBX_0.5.82_")));
assert.ok(options.every((option) => !option.href.includes("/releases/latest/")));
});
test("browser static package opens one guide with both architecture downloads", () => {
const options = createInstallOptions("cn", "0.6.0").filter((option) => option.action === "instructions");
assert.deepEqual(
options.map(({ id, iconId, label, href, browserStaticDownloads }) => ({ id, iconId, label, href, browserStaticDownloads })),
[
{
id: "linux-browser",
iconId: "linux",
label: "Linux 浏览器版",
href: "https://dl.dbxio.com/releases/v0.6.0/DBX_0.6.0_x64-browser-static.tar.gz?v=0.6.0",
browserStaticDownloads: [
{
arch: "x64",
href: "https://dl.dbxio.com/releases/v0.6.0/DBX_0.6.0_x64-browser-static.tar.gz?v=0.6.0",
},
{
arch: "arm64",
href: "https://dl.dbxio.com/releases/v0.6.0/DBX_0.6.0_arm64-browser-static.tar.gz?v=0.6.0",
},
],
},
],
);
});
+44 -6
View File
@@ -1,12 +1,22 @@
export type InstallLang = "en" | "cn";
export type BrowserStaticArch = "x64" | "arm64";
export type BrowserStaticDownload = {
arch: BrowserStaticArch;
href: string;
};
export type InstallOption = {
id: string;
iconId: string;
label: string;
description?: string;
driverLinkLabel?: string;
descriptionSuffix?: string;
badge?: string;
href: string;
action?: "download" | "instructions";
browserStaticDownloads?: BrowserStaticDownload[];
};
type DownloadArtifact = {
@@ -14,8 +24,12 @@ type DownloadArtifact = {
iconId: string;
labels: Record<InstallLang, string>;
descriptions?: Record<InstallLang, string>;
driverLinkLabels?: Record<InstallLang, string>;
descriptionSuffixes?: Record<InstallLang, string>;
badges?: Record<InstallLang, string>;
suffix: string;
action?: "download" | "instructions";
browserStaticSuffixes?: Record<BrowserStaticArch, string>;
};
const DOWNLOAD_BASE_URL = "https://dl.dbxio.com/releases";
@@ -44,16 +58,18 @@ const downloadArtifacts: DownloadArtifact[] = [
{
id: "windows-offline",
iconId: "windows",
labels: { en: "Windows complete offline installer", cn: "Windows 完整离线安装包" },
descriptions: { en: "Includes WebView2 · For offline deployment or missing runtime", cn: "内置 WebView2 · 适用于内网部署或运行库缺失" },
badges: { en: "Offline", cn: "离线" },
labels: { en: "Windows 10 intranet environment installer", cn: "Windows10内网环境安装包" },
descriptions: { en: "Includes WebView2 offline runtime · Does not include", cn: "内置 WebView2 离线运行库 · 不含" },
driverLinkLabels: { en: "offline database drivers", cn: "数据库离线驱动" },
badges: { en: "Intranet", cn: "内网" },
suffix: "x64-webview2-offline-setup.exe",
},
{
id: "windows-7-offline",
iconId: "windows",
labels: { en: "Windows 7 / Server 2012 R2 offline installer", cn: "Windows 7 / Server 2012 R2 离线安装包" },
descriptions: { en: "Includes WebView2 109 · x64 only", cn: "内置 WebView2 109 · 仅支持 x64" },
iconId: "windows-legacy",
labels: { en: "Windows 7 / Server\u00a02012\u00a0R2 package", cn: "Windows 7 / Server\u00a02012\u00a0R2 专用包" },
descriptions: { en: "Includes WebView2 offline runtime · Does not include", cn: "内置 WebView2 离线运行库 · 不含" },
driverLinkLabels: { en: "offline database drivers", cn: "数据库离线驱动" },
badges: { en: "Legacy", cn: "旧系统" },
suffix: "x64-win7-server2012r2-webview2-109-offline-setup.exe",
},
@@ -69,6 +85,19 @@ const downloadArtifacts: DownloadArtifact[] = [
labels: { en: "For Linux ARM64", cn: "适用于 Linux ARM64" },
suffix: "aarch64.AppImage",
},
{
id: "linux-browser",
iconId: "linux",
labels: { en: "Linux browser package", cn: "Linux 浏览器版" },
descriptions: { en: "For Kylin, UnionTech UOS, and other Linux distributions", cn: "适用于麒麟、统信 UOS 等 Linux 发行版" },
badges: { en: "Guide", cn: "安装说明" },
suffix: "x64-browser-static.tar.gz",
action: "instructions",
browserStaticSuffixes: {
x64: "x64-browser-static.tar.gz",
arm64: "arm64-browser-static.tar.gz",
},
},
];
export function createInstallOptions(lang: InstallLang, version: string): InstallOption[] {
@@ -77,7 +106,16 @@ export function createInstallOptions(lang: InstallLang, version: string): Instal
iconId: artifact.iconId,
label: artifact.labels[lang],
description: artifact.descriptions?.[lang],
driverLinkLabel: artifact.driverLinkLabels?.[lang],
descriptionSuffix: artifact.descriptionSuffixes?.[lang],
badge: artifact.badges?.[lang],
href: `${DOWNLOAD_BASE_URL}/v${version}/DBX_${version}_${artifact.suffix}?v=${version}`,
action: artifact.action ?? "download",
browserStaticDownloads: artifact.browserStaticSuffixes
? Object.entries(artifact.browserStaticSuffixes).map(([arch, suffix]) => ({
arch: arch as BrowserStaticArch,
href: `${DOWNLOAD_BASE_URL}/v${version}/DBX_${version}_${suffix}?v=${version}`,
}))
: undefined,
}));
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+27
View File
@@ -1,5 +1,6 @@
Unicode true
ManifestDPIAware true
ManifestSupportedOS all
; Add in `dpiAwareness` `PerMonitorV2` to manifest for Windows 10 1607+ (note this should not affect lower versions since they should be able to ignore this and pick up `dpiAware` `true` set by `ManifestDPIAware true`)
; Currently undocumented on NSIS's website but is in the Docs folder of source tree, see
; https://github.com/kichik/nsis/blob/5fc0b87b819a9eec006df4967d08e522ddd651c9/Docs/src/attributes.but#L286-L300
@@ -16,6 +17,7 @@ ManifestDPIAwareness PerMonitorV2
!include MUI2.nsh
!include FileFunc.nsh
!include x64.nsh
!include WinVer.nsh
!include WordFunc.nsh
!include "utils.nsh"
!include "FileAssociation.nsh"
@@ -503,6 +505,9 @@ LangString dbxFileWriteError ${LANG_SIMPCHINESE} "无法打开要写入的文件
LangString dbxFileWriteErrorNoIgnore ${LANG_SIMPCHINESE} "无法打开要写入的文件:$\r$\n$\r$\n$0$\r$\n$\r$\n如果正在升级安装于 Program Files 的 DBX,请取消本次安装,然后右键单击安装程序并选择“以管理员身份运行”。$\r$\n$\r$\n单击“重试”再次尝试,或$\r$\n单击“取消”停止安装。"
LangString dbxFileWriteError ${LANG_TRADCHINESE} "無法開啟要寫入的檔案:$\r$\n$\r$\n$0$\r$\n$\r$\n如果正在升級安裝於 Program Files 的 DBX,請中止本次安裝,然後以滑鼠右鍵按一下安裝程式並選擇「以系統管理員身分執行」。$\r$\n$\r$\n按一下「中止」以停止安裝,$\r$\n按一下「重試」以再次嘗試,或$\r$\n按一下「忽略」以略過此檔案。"
LangString dbxFileWriteErrorNoIgnore ${LANG_TRADCHINESE} "無法開啟要寫入的檔案:$\r$\n$\r$\n$0$\r$\n$\r$\n如果正在升級安裝於 Program Files 的 DBX,請取消本次安裝,然後以滑鼠右鍵按一下安裝程式並選擇「以系統管理員身分執行」。$\r$\n$\r$\n按一下「重試」以再次嘗試,或$\r$\n按一下「取消」以停止安裝。"
LangString dbxWin7InstallerRequired ${LANG_ENGLISH} "This installer does not support Windows 7 or Windows Server 2012 R2.$\r$\n$\r$\nPlease use the dedicated Windows 7 / Server 2012 R2 package instead.$\r$\n$\r$\nOpen the download now?"
LangString dbxWin7InstallerRequired ${LANG_SIMPCHINESE} "此安装包不支持 Windows 7 或 Windows Server 2012 R2。$\r$\n$\r$\n请改用 Windows 7 / Server 2012 R2 专用包。$\r$\n$\r$\n是否立即打开下载地址?"
LangString dbxWin7InstallerRequired ${LANG_TRADCHINESE} "此安裝套件不支援 Windows 7 或 Windows Server 2012 R2。$\r$\n$\r$\n請改用 Windows 7 / Server 2012 R2 專用套件。$\r$\n$\r$\n是否立即開啟下載網址?"
FileErrorText "$(dbxFileWriteError)" "$(dbxFileWriteErrorNoIgnore)"
Function .onInit
@@ -525,6 +530,28 @@ Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
!endif
; Evergreen WebView2 installers no longer run on Windows 7. Route interactive
; users to the fixed WebView2 109 bundle before the generic installer fails.
!if "${INSTALLWEBVIEW2MODE}" != "fixedRuntime"
${If} ${IsWin7}
${OrIf} ${IsWin2012R2}
${If} ${Silent}
${OrIf} $PassiveMode = 1
SetErrorLevel 1633
Quit
${EndIf}
MessageBox MB_ICONSTOP|MB_YESNO|MB_DEFBUTTON1 "$(dbxWin7InstallerRequired)" IDYES dbx_open_win7_installer
SetErrorLevel 1633
Quit
dbx_open_win7_installer:
ExecShell "open" "https://dl.dbxio.com/releases/v${VERSION}/DBX_${VERSION}_x64-win7-server2012r2-webview2-109-offline-setup.exe?v=${VERSION}"
SetErrorLevel 1633
Quit
${EndIf}
!endif
!insertmacro SetContext
${If} $INSTDIR == "${PLACEHOLDER_INSTALL_DIR}"