Refactor Windows installer scripts and enhance Electron navigation
- Added macros for uninstalling previous Farm Control installations in the NSIS installer. - Updated the MSI wrapped configuration to include custom actions for handling previous installations. - Improved the Electron navigation by modifying CSS classes for better drag-and-drop functionality. - Enhanced build scripts to include the WixUtilExtension for improved MSI packaging.
This commit is contained in:
parent
37fe489b07
commit
f90ef10b78
@ -104,14 +104,8 @@
|
||||
line-height: 0.7;
|
||||
}
|
||||
|
||||
.electron-navigation-wrapper {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.electron-navigation-wrapper li,
|
||||
.electron-navigation-wrapper button,
|
||||
.electron-navigation-wrapper .ant-tag {
|
||||
-webkit-app-region: no-drag;
|
||||
.electron-navigation-wrapper.electrobun-webkit-app-region-drag {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.electron-navigation {
|
||||
|
||||
@ -43,6 +43,7 @@ Function .onInit
|
||||
${If} ${Silent}
|
||||
SetAutoClose true
|
||||
${EndIf}
|
||||
!insertmacro uninstallPreviousFarmControl
|
||||
FunctionEnd
|
||||
|
||||
Section "Farm Control" SecMain
|
||||
|
||||
@ -1,3 +1,33 @@
|
||||
!macro quitFarmControl
|
||||
DetailPrint "Stopping running Farm Control processes..."
|
||||
ExecWait 'taskkill /F /IM launcher.exe /T' $R0
|
||||
!macroend
|
||||
|
||||
!macro uninstallPreviousFarmControl
|
||||
ClearErrors
|
||||
ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" "UninstallString"
|
||||
StrCmp $R0 "" check_install_dir run_uninstall
|
||||
|
||||
check_install_dir:
|
||||
ReadRegStr $R0 HKLM "Software\Tom Butcher\Farm Control" "InstallDir"
|
||||
StrCmp $R0 "" check_default_dir
|
||||
StrCpy $R0 "$R0\Uninstall.exe"
|
||||
Goto run_uninstall
|
||||
|
||||
check_default_dir:
|
||||
StrCpy $R0 "$PROGRAMFILES64\Farm Control\Uninstall.exe"
|
||||
IfFileExists $R0 run_uninstall done_uninstall
|
||||
|
||||
run_uninstall:
|
||||
IfFileExists $R0 0 done_uninstall
|
||||
DetailPrint "Removing previous Farm Control installation..."
|
||||
!insertmacro quitFarmControl
|
||||
ExecWait '$R0 /S' $R1
|
||||
DetailPrint "Previous installation removed (exit code: $R1)"
|
||||
|
||||
done_uninstall:
|
||||
!macroend
|
||||
|
||||
!macro createDesktopShortcut
|
||||
CreateShortCut "$DESKTOP\Farm Control.lnk" "$INSTDIR\bin\launcher.exe"
|
||||
!macroend
|
||||
|
||||
@ -23,8 +23,42 @@
|
||||
<Property Id="DISABLEADVTSHORTCUTS" Value="1" />
|
||||
<Property Id="MSIINSTALLPERUSER" Value="1" />
|
||||
|
||||
<Property Id="PREVIOUS_UNINSTALL_CMD">
|
||||
<RegistrySearch
|
||||
Id="PreviousUninstallCmdSearch"
|
||||
Root="HKLM"
|
||||
Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control"
|
||||
Name="UninstallString"
|
||||
Type="raw" />
|
||||
</Property>
|
||||
|
||||
<Property Id="PREVIOUS_INSTALL_DIR">
|
||||
<RegistrySearch
|
||||
Id="PreviousInstallDirSearch"
|
||||
Root="HKLM"
|
||||
Key="Software\Tom Butcher\Farm Control"
|
||||
Name="InstallDir"
|
||||
Type="directory" />
|
||||
</Property>
|
||||
|
||||
<Binary Id="WrappedExe" SourceFile="__SETUP_EXE__" />
|
||||
|
||||
<CustomAction
|
||||
Id="KillFarmControl"
|
||||
BinaryKey="WixCA"
|
||||
DllEntry="WixQuietExec"
|
||||
Execute="deferred"
|
||||
Impersonate="no"
|
||||
Return="ignore" />
|
||||
|
||||
<CustomAction
|
||||
Id="UninstallPrevious"
|
||||
BinaryKey="WixCA"
|
||||
DllEntry="WixQuietExec"
|
||||
Execute="deferred"
|
||||
Impersonate="no"
|
||||
Return="ignore" />
|
||||
|
||||
<CustomAction
|
||||
Id="RunInstaller"
|
||||
BinaryKey="WrappedExe"
|
||||
@ -45,8 +79,33 @@
|
||||
<ComponentRef Id="EmptyComponent" />
|
||||
</Feature>
|
||||
|
||||
<CustomAction
|
||||
Id="SetKillFarmControl"
|
||||
Property="QtKillFarmControl"
|
||||
Value="taskkill.exe /F /IM launcher.exe /T"
|
||||
Execute="immediate" />
|
||||
|
||||
<CustomAction
|
||||
Id="SetUninstallPreviousFromRegistry"
|
||||
Property="QtUninstallPrevious"
|
||||
Value=""[PREVIOUS_UNINSTALL_CMD]" /S"
|
||||
Execute="immediate" />
|
||||
|
||||
<CustomAction
|
||||
Id="SetUninstallPreviousFromInstallDir"
|
||||
Property="QtUninstallPrevious"
|
||||
Value=""[PREVIOUS_INSTALL_DIR]Uninstall.exe" /S"
|
||||
Execute="immediate" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="RunInstaller" After="ProcessComponents">NOT Installed</Custom>
|
||||
<Custom Action="SetKillFarmControl" Before="KillFarmControl">NOT Installed</Custom>
|
||||
<Custom Action="KillFarmControl" After="SetKillFarmControl">NOT Installed</Custom>
|
||||
<Custom Action="SetUninstallPreviousFromRegistry" After="KillFarmControl">NOT Installed AND PREVIOUS_UNINSTALL_CMD</Custom>
|
||||
<Custom Action="SetUninstallPreviousFromInstallDir" After="KillFarmControl">NOT Installed AND NOT PREVIOUS_UNINSTALL_CMD AND PREVIOUS_INSTALL_DIR</Custom>
|
||||
<Custom Action="UninstallPrevious" After="SetUninstallPreviousFromRegistry">NOT Installed AND (PREVIOUS_UNINSTALL_CMD OR PREVIOUS_INSTALL_DIR)</Custom>
|
||||
<Custom Action="UninstallPrevious" After="SetUninstallPreviousFromInstallDir">NOT Installed AND (PREVIOUS_UNINSTALL_CMD OR PREVIOUS_INSTALL_DIR)</Custom>
|
||||
<Custom Action="RunInstaller" After="UninstallPrevious">NOT Installed AND (PREVIOUS_UNINSTALL_CMD OR PREVIOUS_INSTALL_DIR)</Custom>
|
||||
<Custom Action="RunInstaller" After="KillFarmControl">NOT Installed AND NOT PREVIOUS_UNINSTALL_CMD AND NOT PREVIOUS_INSTALL_DIR</Custom>
|
||||
</InstallExecuteSequence>
|
||||
</Product>
|
||||
</Wix>
|
||||
|
||||
@ -103,12 +103,12 @@ $wixObj = Join-Path $workDir "project.wixobj"
|
||||
|
||||
Push-Location $workDir
|
||||
try {
|
||||
& $wix.Candle "-arch" "x64" $projectWxs
|
||||
& $wix.Candle "-arch" "x64" "-ext" "WixUtilExtension" $projectWxs
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "candle.exe failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
& $wix.Light "-out" $outputMsiPath "-spdb" "-sw1076" $wixObj
|
||||
& $wix.Light "-out" $outputMsiPath "-spdb" "-sw1076" "-ext" "WixUtilExtension" $wixObj
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "light.exe failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
@ -3,34 +3,34 @@ import {
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
writeFileSync
|
||||
} from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const electrobunDir = path.join(rootDir, "node_modules/electrobun");
|
||||
const sharedSrcDir = path.join(electrobunDir, "src/shared");
|
||||
const sharedDistDir = path.join(electrobunDir, "dist/api/shared");
|
||||
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
||||
const electrobunDir = path.join(rootDir, 'node_modules/electrobun')
|
||||
const sharedSrcDir = path.join(electrobunDir, 'src/shared')
|
||||
const sharedDistDir = path.join(electrobunDir, 'dist/api/shared')
|
||||
|
||||
if (!existsSync(sharedDistDir)) {
|
||||
console.error("patch-electrobun-src: electrobun dist/api/shared not found");
|
||||
process.exit(1);
|
||||
console.error('patch-electrobun-src: electrobun dist/api/shared not found')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
mkdirSync(sharedSrcDir, { recursive: true });
|
||||
mkdirSync(sharedSrcDir, { recursive: true })
|
||||
|
||||
for (const fileName of [
|
||||
"cef-version.ts",
|
||||
"bun-version.ts",
|
||||
"electrobun-version.ts",
|
||||
"naming.ts",
|
||||
"rpc.ts",
|
||||
'cef-version.ts',
|
||||
'bun-version.ts',
|
||||
'electrobun-version.ts',
|
||||
'naming.ts',
|
||||
'rpc.ts'
|
||||
]) {
|
||||
const source = path.join(sharedDistDir, fileName);
|
||||
const destination = path.join(sharedSrcDir, fileName);
|
||||
const source = path.join(sharedDistDir, fileName)
|
||||
const destination = path.join(sharedSrcDir, fileName)
|
||||
if (existsSync(source)) {
|
||||
cpSync(source, destination);
|
||||
cpSync(source, destination)
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,14 +109,14 @@ export function getPlatformOS(): SupportedOS {
|
||||
export function getPlatformArch(): SupportedArch {
|
||||
return ARCH;
|
||||
}
|
||||
`;
|
||||
`
|
||||
|
||||
writeFileSync(path.join(sharedSrcDir, "platform.ts"), platformPatch);
|
||||
writeFileSync(path.join(sharedSrcDir, 'platform.ts'), platformPatch)
|
||||
|
||||
const templatesDir = path.join(electrobunDir, "src/cli/templates");
|
||||
mkdirSync(templatesDir, { recursive: true });
|
||||
const templatesDir = path.join(electrobunDir, 'src/cli/templates')
|
||||
mkdirSync(templatesDir, { recursive: true })
|
||||
writeFileSync(
|
||||
path.join(templatesDir, "embedded.ts"),
|
||||
path.join(templatesDir, 'embedded.ts'),
|
||||
`export function getTemplateNames() {
|
||||
return [];
|
||||
}
|
||||
@ -124,8 +124,8 @@ writeFileSync(
|
||||
export function getTemplate(name: string) {
|
||||
throw new Error(\`Template not available in patched electrobun CLI: \${name}\`);
|
||||
}
|
||||
`,
|
||||
);
|
||||
`
|
||||
)
|
||||
|
||||
const RCEDIT_RESOLVER_FN = `function resolveProjectRceditPkgPath(projectRoot) {
|
||||
const candidates = [
|
||||
@ -140,35 +140,41 @@ const RCEDIT_RESOLVER_FN = `function resolveProjectRceditPkgPath(projectRoot) {
|
||||
throw new Error(
|
||||
"rcedit not found under " + projectRoot + ". Install rcedit in the project (bun add -d rcedit).",
|
||||
);
|
||||
}`;
|
||||
}`
|
||||
|
||||
const cliPath = path.join(electrobunDir, "src/cli/index.ts");
|
||||
let cliSource = readFileSync(cliPath, "utf8");
|
||||
if (!cliSource.includes("HOST_ARCH")) {
|
||||
const cliPath = path.join(electrobunDir, 'src/cli/index.ts')
|
||||
let cliSource = readFileSync(cliPath, 'utf8')
|
||||
if (!cliSource.includes('HOST_ARCH')) {
|
||||
cliSource = cliSource.replace(
|
||||
'import { OS, ARCH } from "../shared/platform";',
|
||||
'import { OS, ARCH, HOST_ARCH } from "../shared/platform";',
|
||||
);
|
||||
'import { OS, ARCH, HOST_ARCH } from "../shared/platform";'
|
||||
)
|
||||
cliSource = cliSource.replace(
|
||||
"const hostPaths = getPlatformPaths(OS, ARCH);",
|
||||
"const hostPaths = getPlatformPaths(OS, HOST_ARCH);",
|
||||
);
|
||||
'const hostPaths = getPlatformPaths(OS, ARCH);',
|
||||
'const hostPaths = getPlatformPaths(OS, HOST_ARCH);'
|
||||
)
|
||||
}
|
||||
if (!cliSource.includes("toolPaths")) {
|
||||
if (!cliSource.includes('toolPaths')) {
|
||||
cliSource = cliSource.replace(
|
||||
"const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);",
|
||||
"const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);\n\t\tconst toolPaths = getPlatformPaths(currentTarget.os, ARCH !== HOST_ARCH ? HOST_ARCH : ARCH);",
|
||||
);
|
||||
cliSource = cliSource.replaceAll("const zstdPath = targetPaths.ZSTD;", "const zstdPath = toolPaths.ZSTD;");
|
||||
cliSource = cliSource.replaceAll("const bsdiffpath = targetPaths.BSDIFF;", "const bsdiffpath = toolPaths.BSDIFF;");
|
||||
'const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);',
|
||||
'const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);\n\t\tconst toolPaths = getPlatformPaths(currentTarget.os, ARCH !== HOST_ARCH ? HOST_ARCH : ARCH);'
|
||||
)
|
||||
cliSource = cliSource.replaceAll(
|
||||
'const zstdPath = targetPaths.ZSTD;',
|
||||
'const zstdPath = toolPaths.ZSTD;'
|
||||
)
|
||||
cliSource = cliSource.replaceAll(
|
||||
'const bsdiffpath = targetPaths.BSDIFF;',
|
||||
'const bsdiffpath = toolPaths.BSDIFF;'
|
||||
)
|
||||
cliSource = cliSource.replace(
|
||||
"zigAsarCli = join(targetPaths.BSPATCH).replace(\"bspatch\", \"zig-asar\");",
|
||||
"zigAsarCli = join(toolPaths.BSPATCH).replace(\"bspatch\", \"zig-asar\");",
|
||||
);
|
||||
writeFileSync(cliPath, cliSource);
|
||||
cliSource = readFileSync(cliPath, "utf8");
|
||||
'zigAsarCli = join(targetPaths.BSPATCH).replace("bspatch", "zig-asar");',
|
||||
'zigAsarCli = join(toolPaths.BSPATCH).replace("bspatch", "zig-asar");'
|
||||
)
|
||||
writeFileSync(cliPath, cliSource)
|
||||
cliSource = readFileSync(cliPath, 'utf8')
|
||||
}
|
||||
if (!cliSource.includes("hookBunBinary")) {
|
||||
if (!cliSource.includes('hookBunBinary')) {
|
||||
cliSource = cliSource.replace(
|
||||
`const hostPaths = getPlatformPaths(OS, HOST_ARCH);
|
||||
|
||||
@ -178,41 +184,41 @@ if (!cliSource.includes("hookBunBinary")) {
|
||||
? hostPaths.BUN_BINARY
|
||||
: process.execPath;
|
||||
|
||||
const result = Bun.spawnSync([hookBunBinary, hookScript],`,
|
||||
);
|
||||
const result = Bun.spawnSync([hookBunBinary, hookScript],`
|
||||
)
|
||||
cliSource = cliSource.replace(
|
||||
"console.error(\"Tried to run with bun at:\", hostPaths.BUN_BINARY);",
|
||||
"console.error(\"Tried to run with bun at:\", hookBunBinary);",
|
||||
);
|
||||
writeFileSync(cliPath, cliSource);
|
||||
cliSource = readFileSync(cliPath, "utf8");
|
||||
'console.error("Tried to run with bun at:", hostPaths.BUN_BINARY);',
|
||||
'console.error("Tried to run with bun at:", hookBunBinary);'
|
||||
)
|
||||
writeFileSync(cliPath, cliSource)
|
||||
cliSource = readFileSync(cliPath, 'utf8')
|
||||
}
|
||||
|
||||
if (!cliSource.includes("resolveProjectRceditPkgPath")) {
|
||||
if (!cliSource.includes('resolveProjectRceditPkgPath')) {
|
||||
cliSource = cliSource.replaceAll(
|
||||
"const rceditPkgPath = require.resolve(\"rcedit/package.json\");",
|
||||
"const rceditPkgPath = resolveProjectRceditPkgPath(projectRoot);",
|
||||
);
|
||||
'const rceditPkgPath = require.resolve("rcedit/package.json");',
|
||||
'const rceditPkgPath = resolveProjectRceditPkgPath(projectRoot);'
|
||||
)
|
||||
cliSource = cliSource.replace(
|
||||
"function getPlatformPaths(",
|
||||
'function getPlatformPaths(',
|
||||
`${RCEDIT_RESOLVER_FN}
|
||||
|
||||
function getPlatformPaths(`,
|
||||
);
|
||||
writeFileSync(cliPath, cliSource);
|
||||
cliSource = readFileSync(cliPath, "utf8");
|
||||
function getPlatformPaths(`
|
||||
)
|
||||
writeFileSync(cliPath, cliSource)
|
||||
cliSource = readFileSync(cliPath, 'utf8')
|
||||
} else {
|
||||
cliSource = cliSource.replace(
|
||||
/function resolveProjectRceditPkgPath\(projectRoot\) \{[\s\S]*?\n\}/m,
|
||||
RCEDIT_RESOLVER_FN,
|
||||
);
|
||||
writeFileSync(cliPath, cliSource);
|
||||
RCEDIT_RESOLVER_FN
|
||||
)
|
||||
writeFileSync(cliPath, cliSource)
|
||||
}
|
||||
|
||||
const electrobunCjsPath = path.join(electrobunDir, "bin/electrobun.cjs");
|
||||
let electrobunCjs = readFileSync(electrobunCjsPath, "utf8");
|
||||
const electrobunCjsPath = path.join(electrobunDir, 'bin/electrobun.cjs')
|
||||
let electrobunCjs = readFileSync(electrobunCjsPath, 'utf8')
|
||||
|
||||
if (!electrobunCjs.includes("farmcontrol-use-patched-cli")) {
|
||||
if (!electrobunCjs.includes('farmcontrol-use-patched-cli')) {
|
||||
electrobunCjs = electrobunCjs.replace(
|
||||
`async function main() {
|
||||
try {
|
||||
@ -259,19 +265,21 @@ if (!electrobunCjs.includes("farmcontrol-use-patched-cli")) {
|
||||
const child = spawn(cliPath, args, {
|
||||
stdio: 'inherit',
|
||||
cwd: process.cwd()
|
||||
});`,
|
||||
);
|
||||
writeFileSync(electrobunCjsPath, electrobunCjs);
|
||||
});`
|
||||
)
|
||||
writeFileSync(electrobunCjsPath, electrobunCjs)
|
||||
}
|
||||
|
||||
const rceditSrc = path.join(rootDir, "node_modules/rcedit");
|
||||
const rceditDest = path.join(electrobunDir, "node_modules/rcedit");
|
||||
const rceditSrc = path.join(rootDir, 'node_modules/rcedit')
|
||||
const rceditDest = path.join(electrobunDir, 'node_modules/rcedit')
|
||||
if (existsSync(rceditSrc)) {
|
||||
mkdirSync(path.join(electrobunDir, "node_modules"), { recursive: true });
|
||||
cpSync(rceditSrc, rceditDest, { recursive: true, force: true });
|
||||
mkdirSync(path.join(electrobunDir, 'node_modules'), { recursive: true })
|
||||
cpSync(rceditSrc, rceditDest, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
const markerPath = path.join(electrobunDir, ".farmcontrol-electrobun-patched");
|
||||
writeFileSync(markerPath, `patched-at=${new Date().toISOString()}\n`);
|
||||
const markerPath = path.join(electrobunDir, '.farmcontrol-electrobun-patched')
|
||||
writeFileSync(markerPath, `patched-at=${new Date().toISOString()}\n`)
|
||||
|
||||
console.log("patch-electrobun-src: electrobun src/shared ready for cross-arch builds");
|
||||
console.log(
|
||||
'patch-electrobun-src: electrobun src/shared ready for cross-arch builds'
|
||||
)
|
||||
|
||||
@ -199,134 +199,138 @@ const DashboardNavigation = () => {
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
<Menu
|
||||
mode='horizontal'
|
||||
className={isElectron ? 'electron-navigation' : null}
|
||||
items={mainMenuItems}
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
flexGrow: isMobile ? 0 : 1,
|
||||
border: 0,
|
||||
width: isMobile ? '64px' : 'unset'
|
||||
}}
|
||||
onClick={handleMainMenuClick}
|
||||
selectedKeys={[selectedKey]}
|
||||
overflowedIndicator={
|
||||
<Button
|
||||
type='text'
|
||||
icon={<MenuIcon />}
|
||||
style={{ marginBottom: '4px' }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{isMobile && <div style={{ flexGrow: 1 }} />}
|
||||
<Flex
|
||||
gap={'small'}
|
||||
align='center'
|
||||
style={{ marginTop: '-2px', marginRight: '6px' }}
|
||||
>
|
||||
<Space style={{ paddingTop: '2px', marginRight: '8px' }}>
|
||||
<WebAppSwitcher />
|
||||
<KeyboardShortcut
|
||||
shortcut='alt+q'
|
||||
hint='ALT Q'
|
||||
onTrigger={() => showSpotlight()}
|
||||
>
|
||||
<div className='electrobun-webkit-app-region-no-drag'>
|
||||
<Menu
|
||||
mode='horizontal'
|
||||
className={isElectron ? 'electron-navigation' : null}
|
||||
items={mainMenuItems}
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
flexGrow: isMobile ? 0 : 1,
|
||||
border: 0,
|
||||
width: isMobile ? '64px' : 'unset'
|
||||
}}
|
||||
onClick={handleMainMenuClick}
|
||||
selectedKeys={[selectedKey]}
|
||||
overflowedIndicator={
|
||||
<Button
|
||||
icon={<SearchIcon />}
|
||||
type='text'
|
||||
style={{ marginTop: '4px' }}
|
||||
onClick={() => showSpotlight()}
|
||||
icon={<MenuIcon />}
|
||||
style={{ marginBottom: '4px' }}
|
||||
/>
|
||||
</KeyboardShortcut>
|
||||
<Badge
|
||||
count={unreadCount}
|
||||
size='small'
|
||||
offset={[-5, 8]}
|
||||
style={{ padding: 0, fontWeight: 600 }}
|
||||
>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{isMobile && <div style={{ flexGrow: 1 }} />}
|
||||
<div className='electrobun-webkit-app-region-no-drag'>
|
||||
<Flex
|
||||
gap={'small'}
|
||||
align='center'
|
||||
style={{ marginTop: '-2px', marginRight: '6px' }}
|
||||
>
|
||||
<Space style={{ paddingTop: '2px', marginRight: '8px' }}>
|
||||
<WebAppSwitcher />
|
||||
<KeyboardShortcut
|
||||
shortcut='alt+n'
|
||||
hint='ALT N'
|
||||
onTrigger={() => toggleNotificationCenter()}
|
||||
shortcut='alt+q'
|
||||
hint='ALT Q'
|
||||
onTrigger={() => showSpotlight()}
|
||||
>
|
||||
<Button
|
||||
icon={<BellIcon />}
|
||||
icon={<SearchIcon />}
|
||||
type='text'
|
||||
style={{ marginTop: '2px' }}
|
||||
onClick={() => toggleNotificationCenter()}
|
||||
style={{ marginTop: '4px' }}
|
||||
onClick={() => showSpotlight()}
|
||||
/>
|
||||
</KeyboardShortcut>
|
||||
</Badge>
|
||||
</Space>
|
||||
{import.meta.env.MODE === 'development' && (
|
||||
<Space>
|
||||
{apiServerState === 'connected' ? (
|
||||
<Tooltip title='Connected to api server' arrow={false}>
|
||||
<Tag
|
||||
color='success'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<CloudIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{apiServerState === 'connecting' ? (
|
||||
<Tooltip title='Connecting to api erver...' arrow={false}>
|
||||
<Tag
|
||||
color='warning'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<LoadingOutlined />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{apiServerState === 'disconnected' ? (
|
||||
<Tooltip title='Disconnected from api server' arrow={false}>
|
||||
<Tag
|
||||
color='error'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<CloudIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
<Tooltip title='Developer' arrow={false}>
|
||||
<Tag
|
||||
color='yellow'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<DeveloperIcon />}
|
||||
onClick={() => {
|
||||
navigate('/dashboard/developer/sessionstorage')
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
)}
|
||||
{userProfile ? (
|
||||
<Space>
|
||||
<Popover
|
||||
content={userPopoverContent}
|
||||
placement='bottomRight'
|
||||
trigger='hover'
|
||||
open={userPopoverOpen}
|
||||
onOpenChange={setUserPopoverOpen}
|
||||
arrow={false}
|
||||
<Badge
|
||||
count={unreadCount}
|
||||
size='small'
|
||||
offset={[-5, 8]}
|
||||
style={{ padding: 0, fontWeight: 600 }}
|
||||
>
|
||||
<Tag style={{ marginRight: 0 }} icon={<PersonIcon />}>
|
||||
{!isMobile && (userProfile?.name || userProfile.username)}
|
||||
</Tag>
|
||||
</Popover>
|
||||
<KeyboardShortcut
|
||||
shortcut='alt+n'
|
||||
hint='ALT N'
|
||||
onTrigger={() => toggleNotificationCenter()}
|
||||
>
|
||||
<Button
|
||||
icon={<BellIcon />}
|
||||
type='text'
|
||||
style={{ marginTop: '2px' }}
|
||||
onClick={() => toggleNotificationCenter()}
|
||||
/>
|
||||
</KeyboardShortcut>
|
||||
</Badge>
|
||||
</Space>
|
||||
) : null}
|
||||
{isElectron && availableUpdate ? (
|
||||
<Tag
|
||||
icon={<CloudIcon />}
|
||||
style={{ cursor: 'pointer', margin: '2px 0 0 0' }}
|
||||
color='cyan'
|
||||
onClick={() => checkForUpdates()}
|
||||
>
|
||||
Update Available
|
||||
</Tag>
|
||||
) : null}
|
||||
</Flex>
|
||||
{import.meta.env.MODE === 'development' && (
|
||||
<Space>
|
||||
{apiServerState === 'connected' ? (
|
||||
<Tooltip title='Connected to api server' arrow={false}>
|
||||
<Tag
|
||||
color='success'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<CloudIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{apiServerState === 'connecting' ? (
|
||||
<Tooltip title='Connecting to api erver...' arrow={false}>
|
||||
<Tag
|
||||
color='warning'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<LoadingOutlined />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{apiServerState === 'disconnected' ? (
|
||||
<Tooltip title='Disconnected from api server' arrow={false}>
|
||||
<Tag
|
||||
color='error'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<CloudIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
<Tooltip title='Developer' arrow={false}>
|
||||
<Tag
|
||||
color='yellow'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<DeveloperIcon />}
|
||||
onClick={() => {
|
||||
navigate('/dashboard/developer/sessionstorage')
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
)}
|
||||
{userProfile ? (
|
||||
<Space>
|
||||
<Popover
|
||||
content={userPopoverContent}
|
||||
placement='bottomRight'
|
||||
trigger='hover'
|
||||
open={userPopoverOpen}
|
||||
onOpenChange={setUserPopoverOpen}
|
||||
arrow={false}
|
||||
>
|
||||
<Tag style={{ marginRight: 0 }} icon={<PersonIcon />}>
|
||||
{!isMobile && (userProfile?.name || userProfile.username)}
|
||||
</Tag>
|
||||
</Popover>
|
||||
</Space>
|
||||
) : null}
|
||||
{isElectron && availableUpdate ? (
|
||||
<Tag
|
||||
icon={<CloudIcon />}
|
||||
style={{ cursor: 'pointer', margin: '2px 0 0 0' }}
|
||||
color='cyan'
|
||||
onClick={() => checkForUpdates()}
|
||||
>
|
||||
Update Available
|
||||
</Tag>
|
||||
) : null}
|
||||
</Flex>
|
||||
</div>
|
||||
{isOtherApp ? <DashboardWindowButtons /> : null}
|
||||
</Flex>
|
||||
)
|
||||
@ -335,7 +339,7 @@ const DashboardNavigation = () => {
|
||||
<>
|
||||
{isElectron ? (
|
||||
<Flex
|
||||
className={`ant-menu-horizontal ant-menu-light${!notificationCenterVisible ? ' electron-navigation-wrapper' : ''}`}
|
||||
className={`ant-menu-horizontal ant-menu-light${!notificationCenterVisible ? ' electron-navigation-wrapper electrobun-webkit-app-region-drag' : ''}`}
|
||||
style={{ lineHeight: '40px', padding: '0 2px 0 2px' }}
|
||||
>
|
||||
{navigationContents}
|
||||
|
||||
@ -39,7 +39,10 @@ const DashboardWindowButtons = () => {
|
||||
<div style={{ width: '80px' }} />
|
||||
) : null
|
||||
) : (
|
||||
<div style={{ width: '95px', marginRight: '2.5px' }}>
|
||||
<div
|
||||
className='electrobun-webkit-app-region-no-drag'
|
||||
style={{ width: '95px', marginRight: '2.5px' }}
|
||||
>
|
||||
<Flex style={{ position: 'relative', zIndex: 9999 }}>
|
||||
{maximizeButton}
|
||||
{minimizeButton}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user