Disable in-app updater for repo builds (HELIXNOTES_INSTALL_TYPE), open tel:/sms: links in the system handler (#98), label AI button \"OpenAI Compatible\"

This commit is contained in:
Yuri Karamian
2026-06-11 21:24:42 +02:00
parent 2fea44bde6
commit db924f7352
4 changed files with 35 additions and 6 deletions
+11
View File
@@ -1740,8 +1740,12 @@ fn xdg_open(arg: &str) -> Result<(), String> {
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {
use std::os::windows::process::CommandExt;
// CREATE_NO_WINDOW: open the URL/path without flashing a console window.
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
std::process::Command::new("cmd") std::process::Command::new("cmd")
.args(["/C", "start", "", arg]) .args(["/C", "start", "", arg])
.creation_flags(CREATE_NO_WINDOW)
.spawn() .spawn()
.map_err(|e| format!("Failed to open {}: {}", arg, e))?; .map_err(|e| format!("Failed to open {}: {}", arg, e))?;
} }
@@ -2253,6 +2257,13 @@ fn save_app_config(config: &AppConfig) -> Result<(), String> {
#[tauri::command] #[tauri::command]
pub fn get_install_type() -> String { pub fn get_install_type() -> String {
// Build-time override for distro packagers (e.g. Solus): build with
// HELIXNOTES_INSTALL_TYPE=solus to report that type and suppress the in-app updater.
if let Some(forced) = option_env!("HELIXNOTES_INSTALL_TYPE") {
if !forced.is_empty() {
return forced.to_string();
}
}
if cfg!(target_os = "macos") { if cfg!(target_os = "macos") {
"macos".to_string() "macos".to_string()
} else if cfg!(target_os = "windows") { } else if cfg!(target_os = "windows") {
+9 -2
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { showSettings, theme, appConfig, updateAvailable as globalUpdateAvailable, updateObj as globalUpdateObj, installType, settingsTab, vaultReady, androidApkUrl, checkForUpdateMobile, notebookSortMode } from '$lib/stores/app'; import { showSettings, theme, appConfig, updateAvailable as globalUpdateAvailable, updateObj as globalUpdateObj, installType, settingsTab, vaultReady, androidApkUrl, checkForUpdateMobile, notebookSortMode, isManagedInstall } from '$lib/stores/app';
import { setTheme, setAccentColor, setFontSize, setFontFamily, setLineHeight, setUiScale, setGeneralSettings, importObsidian, createBackup, listBackups, restoreBackup, deleteBackup, setBackupSettings, setAiSettings, testAiConnection, setSyncSettings, testSyncConnection, syncNow } from '$lib/api'; import { setTheme, setAccentColor, setFontSize, setFontFamily, setLineHeight, setUiScale, setGeneralSettings, importObsidian, createBackup, listBackups, restoreBackup, deleteBackup, setBackupSettings, setAiSettings, testAiConnection, setSyncSettings, testSyncConnection, syncNow } from '$lib/api';
import { open as openDialog } from '@tauri-apps/plugin-dialog'; import { open as openDialog } from '@tauri-apps/plugin-dialog';
import { listen } from '@tauri-apps/api/event'; import { listen } from '@tauri-apps/api/event';
@@ -1258,7 +1258,7 @@
<button class="option-btn" class:active={aiProvider === 'ollama'} onclick={() => { if (aiProvider === 'ollama') return; aiProvider = 'ollama'; aiModel = 'gemma3:4b'; aiTestMessage = null; saveAiSettings(); }}>Ollama</button> <button class="option-btn" class:active={aiProvider === 'ollama'} onclick={() => { if (aiProvider === 'ollama') return; aiProvider = 'ollama'; aiModel = 'gemma3:4b'; aiTestMessage = null; saveAiSettings(); }}>Ollama</button>
<button class="option-btn" class:active={aiProvider === 'anthropic'} onclick={() => { if (aiProvider === 'anthropic') return; aiProvider = 'anthropic'; aiModel = 'claude-sonnet-4-6'; aiTestMessage = null; saveAiSettings(); }}>Anthropic</button> <button class="option-btn" class:active={aiProvider === 'anthropic'} onclick={() => { if (aiProvider === 'anthropic') return; aiProvider = 'anthropic'; aiModel = 'claude-sonnet-4-6'; aiTestMessage = null; saveAiSettings(); }}>Anthropic</button>
<button class="option-btn" class:active={aiProvider === 'openai'} onclick={() => { if (aiProvider === 'openai') return; aiProvider = 'openai'; aiModel = 'gpt-5.5'; aiTestMessage = null; saveAiSettings(); }}>OpenAI</button> <button class="option-btn" class:active={aiProvider === 'openai'} onclick={() => { if (aiProvider === 'openai') return; aiProvider = 'openai'; aiModel = 'gpt-5.5'; aiTestMessage = null; saveAiSettings(); }}>OpenAI</button>
<button class="option-btn" class:active={aiProvider === 'openai_compatible'} onclick={() => { if (aiProvider === 'openai_compatible') return; aiProvider = 'openai_compatible'; aiModel = ''; aiTestMessage = null; saveAiSettings(); }}>Compatible</button> <button class="option-btn" class:active={aiProvider === 'openai_compatible'} onclick={() => { if (aiProvider === 'openai_compatible') return; aiProvider = 'openai_compatible'; aiModel = ''; aiTestMessage = null; saveAiSettings(); }}>OpenAI Compatible</button>
</div> </div>
</div> </div>
@@ -1560,6 +1560,12 @@
<p class="update-version">HelixNotes <strong>v{appVersion}</strong></p> <p class="update-version">HelixNotes <strong>v{appVersion}</strong></p>
</div> </div>
{#if isManagedInstall($installType)}
<div class="settings-section">
<h3>Updates</h3>
<p class="setting-hint">HelixNotes was installed through your system package manager, which delivers updates. The app does not check for or install updates on its own.</p>
</div>
{:else}
<div class="settings-section"> <div class="settings-section">
<h3>Check for Updates</h3> <h3>Check for Updates</h3>
<button class="import-btn" onclick={handleCheckUpdate} disabled={updateChecking || updateDownloading}> <button class="import-btn" onclick={handleCheckUpdate} disabled={updateChecking || updateDownloading}>
@@ -1574,6 +1580,7 @@
{/if} {/if}
</button> </button>
</div> </div>
{/if}
{#if updateAvailable} {#if updateAvailable}
<div class="settings-section"> <div class="settings-section">
+9
View File
@@ -87,6 +87,15 @@ export const updateObj = writable<any>(null);
export const installType = writable<string>("native"); export const installType = writable<string>("native");
export const androidApkUrl = writable<string | null>(null); export const androidApkUrl = writable<string | null>(null);
// Install types that handle their own updates (in-app auto-updater, or a
// package-manager notice for deb/aur). Anything else - e.g. a distro repo build
// that sets the HELIXNOTES_INSTALL_TYPE build flag (Solus, etc.) - is "managed":
// the app does no update check and shows no update UI at all.
const SELF_UPDATING_INSTALL_TYPES = ["macos", "windows", "deb", "aur", "appimage", "native", "android"];
export function isManagedInstall(type: string): boolean {
return !SELF_UPDATING_INSTALL_TYPES.includes(type);
}
export async function checkForUpdate() { export async function checkForUpdate() {
try { try {
const { check } = await import("@tauri-apps/plugin-updater"); const { check } = await import("@tauri-apps/plugin-updater");
+6 -4
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import '../app.css'; import '../app.css';
import { theme, appConfig, activeNote, activeNotePath, installType, checkForUpdate, checkForUpdateMobile } from '$lib/stores/app'; import { theme, appConfig, activeNote, activeNotePath, installType, checkForUpdate, checkForUpdateMobile, isManagedInstall } from '$lib/stores/app';
import { openFile, openUrl, readNote, getInstallType } from '$lib/api'; import { openFile, openUrl, readNote, getInstallType } from '$lib/api';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import ResizeHandles from '$lib/components/ResizeHandles.svelte'; import ResizeHandles from '$lib/components/ResizeHandles.svelte';
@@ -53,7 +53,7 @@
} }
function resolveAndHandleLink(href: string) { function resolveAndHandleLink(href: string) {
if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('mailto:')) { if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('mailto:') || href.startsWith('tel:') || href.startsWith('sms:')) {
openUrl(href).catch((err) => console.error('Failed to open URL:', err)); openUrl(href).catch((err) => console.error('Failed to open URL:', err));
} else if (!href.startsWith('#')) { } else if (!href.startsWith('#')) {
const decoded = decodeURIComponent(href); const decoded = decodeURIComponent(href);
@@ -92,8 +92,10 @@
installType.set('android'); installType.set('android');
checkForUpdateMobile(); checkForUpdateMobile();
} else { } else {
getInstallType().then(t => installType.set(t)).catch(() => {}); getInstallType().then(t => {
checkForUpdate(); installType.set(t);
if (!isManagedInstall(t)) checkForUpdate();
}).catch(() => {});
} }
}); });