Skip to content

Commit

Permalink
change: handle incompatible configs
Browse files Browse the repository at this point in the history
  • Loading branch information
macjuul committed Aug 6, 2024
1 parent 87388f8 commit 33e2459
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 71 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@lezer/highlight": "^1.2.0",
"@mantine/core": "^7.6.2",
"@mantine/hooks": "^7.6.2",
"@mantine/modals": "^7.12.0",
"@mantine/notifications": "^7.6.2",
"@mdi/js": "^7.2.96",
"@replit/codemirror-indentation-markers": "^6.5.0",
Expand Down
28 changes: 23 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 41 additions & 14 deletions src-tauri/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
use std::{
fs::{self, File},
io::{Read, Write},
fs::{self, copy, File},
io::{Read, Write}, path::PathBuf,
};

use crate::paths::{get_config_path, get_legacy_config_backup_path, get_legacy_config_path};
use crate::paths::{get_config_backup_path, get_config_path, get_legacy_config_backup_path, get_legacy_config_path};

const DEFAULT_CONFIG: &str = "{}";

fn write_config(config: &str) {
let config_path = get_config_path();
let parent = config_path.parent().unwrap();
fn write_config(config: &str, path: PathBuf) {
let parent = path.parent().unwrap();

fs::create_dir_all(parent).expect("config directory should be writable");

let mut write_op = File::create(config_path).unwrap();
let mut write_op = File::create(path).unwrap();
let config_json_value: serde_json::Value = serde_json::from_str(config).unwrap();
let mut pretty_config = serde_json::to_string_pretty(&config_json_value).unwrap();

Expand All @@ -38,14 +37,45 @@ pub fn load_config() -> String {
.expect("config should be readable");
}
Err(_) => {
write_config(DEFAULT_CONFIG);
write_config(DEFAULT_CONFIG, get_config_path());
buffer = DEFAULT_CONFIG.to_string();
}
}

buffer
}

#[tauri::command]
pub fn save_config(config: &str) {
write_config(config, get_config_path())
}

#[tauri::command]
pub fn backup_config(config: &str, version: u32) {
write_config(config, get_config_backup_path(version));
}

#[tauri::command]
pub fn has_config_backup(version: u32) -> bool {
get_config_backup_path(version).exists()
}

#[tauri::command]
pub fn restore_config_backup(version: u32) -> Result<(), String> {
let backup_path = get_config_backup_path(version);
let config_path = get_config_path();

if !backup_path.exists() {
return Err("Backup does not exist".into());
}

match copy(backup_path, config_path) {
Ok(_) => Ok(()),
Err(_) => Err("Failed to restore config backup".into()),
}
}

#[deprecated]
#[tauri::command]
pub fn load_legacy_config() -> String {
let config_path = get_legacy_config_path();
Expand All @@ -60,24 +90,21 @@ pub fn load_legacy_config() -> String {
.expect("legacy config should be readable");
}
Err(_) => {
write_config(DEFAULT_CONFIG);
write_config(DEFAULT_CONFIG, get_config_path());
buffer = DEFAULT_CONFIG.to_string();
}
}

buffer
}

#[tauri::command]
pub fn save_config(config: &str) {
write_config(config)
}

#[deprecated]
#[tauri::command]
pub fn has_legacy_config() -> bool {
get_legacy_config_path().exists()
}

#[deprecated]
#[tauri::command]
pub fn complete_legacy_migrate() {
let legacy = get_legacy_config_path();
Expand Down
5 changes: 4 additions & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,12 @@ fn main() {
.manage(DatabaseState(Default::default()))
.invoke_handler(tauri::generate_handler![
config::load_config,
config::load_legacy_config,
config::save_config,
config::backup_config,
config::has_config_backup,
config::restore_config_backup,
config::has_legacy_config,
config::load_legacy_config,
config::complete_legacy_migrate,
database::start_database,
database::stop_database,
Expand Down
13 changes: 9 additions & 4 deletions src-tauri/src/open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,15 @@ pub fn get_opened_resources(state: State<OpenResourceState>) -> Vec<OpenedResour
query,
}))
}
"surrealist" => Some(OpenedResource::Link(LinkResource {
host: u.host_str().unwrap_or_default().to_owned(),
params: u.query().unwrap_or_default().to_owned(),
})),
"surrealist" => {
let host = u.host_str().unwrap_or_default().to_owned();
let params = u.query().unwrap_or_default().to_owned();

Some(OpenedResource::Link(LinkResource {
host,
params
}))
},
_ => Some(OpenedResource::Unknown),
})
.collect()
Expand Down
8 changes: 8 additions & 0 deletions src-tauri/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ pub fn get_config_path() -> PathBuf {
config_path
}

/// The path to a backup configuration file
pub fn get_config_backup_path(version: u32) -> PathBuf {
let mut config_path = get_data_directory();
config_path.push("backups");
config_path.push(format!("config-version-{}.json", version));
config_path
}

/// The path to the legacy configuration file (Surrealist 1.x)
pub fn get_legacy_config_path() -> PathBuf {
let mut config_path = config_dir().expect("config directory should be resolvable");
Expand Down
71 changes: 37 additions & 34 deletions src/components/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { KeymapModal } from "./modals/hotkeys";
import { UpdaterDialog } from "./modals/updater";
import { isDesktop } from "~/adapter";
import { HighlightToolModal } from "./modals/highlight-tool";
import { ModalsProvider } from "@mantine/modals";

const queryClient = new QueryClient();

Expand Down Expand Up @@ -58,43 +59,45 @@ export function App() {
>
<Notifications />

<ContextMenuProvider
borderRadius="md"
shadow={isLight ? "xs" : "0 6px 12px 2px rgba(0, 0, 0, 0.25)"}
submenuDelay={250}
>
<ConfirmationProvider>
<InspectorProvider>
<ErrorBoundary
FallbackComponent={AppErrorHandler}
onReset={handleReset}
>
{screen === "start"
? <StartScreen />
: <DatabaseScreen />
}
<ModalsProvider>
<ContextMenuProvider
borderRadius="md"
shadow={isLight ? "xs" : "0 6px 12px 2px rgba(0, 0, 0, 0.25)"}
submenuDelay={250}
>
<ConfirmationProvider>
<InspectorProvider>
<ErrorBoundary
FallbackComponent={AppErrorHandler}
onReset={handleReset}
>
{screen === "start"
? <StartScreen />
: <DatabaseScreen />
}

<Settings />
<Settings />

<CommandPaletteModal />
<ChangelogModal />
<ConnectionModal />
<DownloadModal />
<EmbedderModal />
<LegacyModal />
<SandboxModal />
<ScopeSignupModal />
<TableCreatorModal />
<KeymapModal />
<HighlightToolModal />
<CommandPaletteModal />
<ChangelogModal />
<ConnectionModal />
<DownloadModal />
<EmbedderModal />
<LegacyModal />
<SandboxModal />
<ScopeSignupModal />
<TableCreatorModal />
<KeymapModal />
<HighlightToolModal />

{isDesktop && (
<UpdaterDialog />
)}
</ErrorBoundary>
</InspectorProvider>
</ConfirmationProvider>
</ContextMenuProvider>
{isDesktop && (
<UpdaterDialog />
)}
</ErrorBoundary>
</InspectorProvider>
</ConfirmationProvider>
</ContextMenuProvider>
</ModalsProvider>
</MantineProvider>
</QueryClientProvider>
</FeatureFlagsProvider>
Expand Down
39 changes: 38 additions & 1 deletion src/components/App/modals/updater.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ import { Icon } from "~/components/Icon";
import { useStable } from "~/hooks/stable";
import { useInterfaceStore } from "~/stores/interface";
import { iconClose, iconDownload } from "~/util/icons";
import { useConfirmation } from "~/providers/Confirmation";
import { invoke } from "@tauri-apps/api/core";
import { useConfigStore } from "~/stores/config";

type Phase = 'idle' | 'downloading' | 'error';

function extractMajor(version: string) {
return Number.parseInt(version.split(".")[0] ?? 0);
}

export function UpdaterDialog() {
const { hideAvailableUpdate } = useInterfaceStore.getState();

Expand All @@ -18,6 +25,10 @@ export function UpdaterDialog() {
const [packageTotal, setPackageTotal] = useState(0);
const [packageProgress, setPackageProgress] = useState(0);

const currentMajor = extractMajor(import.meta.env.VERSION);
const latestMajor = extractMajor(update?.version || "0.0.0");
const isDangerous = latestMajor > currentMajor;

const hideUpdate = useStable((e: MouseEvent) => {
e.stopPropagation();
hideAvailableUpdate();
Expand All @@ -26,6 +37,15 @@ export function UpdaterDialog() {
const installUpdate = useStable(async () => {
if (!update || phase !== 'idle') return;

if (isDangerous) {
const config = useConfigStore.getState();

await invoke("backup_config", {
config: JSON.stringify(config),
version: config.configVersion
});
}

setPhase('downloading');
setPackageProgress(0);

Expand All @@ -45,6 +65,23 @@ export function UpdaterDialog() {
}
});

const promptUpdate = useConfirmation({
title: "New major release",
message: "The update you are about to install is a new major version of Surrealist. Are you sure you want to proceed?",
confirmText: "Install update",
confirmProps: { variant: "gradient" },
dismissText: "Don't update now",
onConfirm: () => installUpdate()
});

const handleClick = useStable(() => {
if (isDangerous) {
promptUpdate();
} else {
installUpdate();
}
});

const progress = packageTotal > 0
? (packageProgress / packageTotal * 100).toFixed(0)
: 0;
Expand All @@ -67,7 +104,7 @@ export function UpdaterDialog() {
classNames={{
root: classes.updateDialog
}}
onClick={installUpdate}
onClick={handleClick}
>
<ActionIcon
onClick={hideUpdate}
Expand Down
Loading

0 comments on commit 33e2459

Please sign in to comment.