Handle undefined better

This commit is contained in:
Manav Rathi 2024-05-01 08:15:43 +05:30
parent ebbd946fc2
commit 4e8f2e65f0
No known key found for this signature in database
7 changed files with 66 additions and 18 deletions

View file

@ -19,7 +19,7 @@ export const createApplicationMenu = async (mainWindow: BrowserWindow) => {
// Whenever the menu is redrawn the current value of these variables is used
// to set the checked state for the various settings checkboxes.
let isAutoLaunchEnabled = await autoLauncher.isEnabled();
let shouldHideDockIcon = userPreferences.get("hideDockIcon");
let shouldHideDockIcon = !!userPreferences.get("hideDockIcon");
const macOSOnly = (options: MenuItemConstructorOptions[]) =>
process.platform == "darwin" ? options : [];

View file

@ -36,18 +36,21 @@ const checkForUpdatesAndNotify = async (mainWindow: BrowserWindow) => {
log.debug(() => `Update check found version ${version}`);
if (!version)
throw new Error("Unexpected empty version obtained from auto-updater");
if (compareVersions(version, app.getVersion()) <= 0) {
log.debug(() => "Skipping update, already at latest version");
return;
}
if (version === userPreferences.get("skipAppVersion")) {
if (version == userPreferences.get("skipAppVersion")) {
log.info(`User chose to skip version ${version}`);
return;
}
const mutedVersion = userPreferences.get("muteUpdateNotificationVersion");
if (version === mutedVersion) {
if (version == mutedVersion) {
log.info(`User has muted update notifications for version ${version}`);
return;
}

View file

@ -9,8 +9,8 @@ import { watchStore } from "../stores/watch";
* This is useful to reset state when the user logs out.
*/
export const clearStores = () => {
uploadStatusStore.clear();
safeStorageStore.clear();
uploadStatusStore.clear();
watchStore.clear();
};

View file

@ -46,7 +46,7 @@ export const pathOrZipItemSize = async (
};
export const pendingUploads = async (): Promise<PendingUploads | undefined> => {
const collectionName = uploadStatusStore.get("collectionName");
const collectionName = uploadStatusStore.get("collectionName") ?? undefined;
const allFilePaths = uploadStatusStore.get("filePaths") ?? [];
const filePaths = allFilePaths.filter((f) => existsSync(f));
@ -62,7 +62,7 @@ export const pendingUploads = async (): Promise<PendingUploads | undefined> => {
//
// This potentially can be cause us to try reuploading an already uploaded
// file, but the dedup logic will kick in at that point so no harm will come
// off it.
// of it.
if (allZipItems === undefined) {
const allZipPaths = uploadStatusStore.get("filePaths") ?? [];
const zipPaths = allZipPaths.filter((f) => existsSync(f));
@ -82,20 +82,65 @@ export const pendingUploads = async (): Promise<PendingUploads | undefined> => {
};
};
export const setPendingUploads = (pendingUploads: PendingUploads) =>
uploadStatusStore.set(pendingUploads);
/**
* [Note: Missing values in electron-store]
*
* Suppose we were to create a store like this:
*
* const store = new Store({
* schema: {
* foo: { type: "string" },
* bars: { type: "array", items: { type: "string" } },
* },
* });
*
* If we fetch `store.get("foo")` or `store.get("bars")`, we get `undefined`.
* But if we try to set these back to `undefined`, say `store.set("foo",
* someUndefValue)`, we get asked to
*
* TypeError: Use `delete()` to clear values
*
* This happens even if we do bulk object updates, e.g. with a JS object that
* has undefined keys:
*
* > TypeError: Setting a value of type `undefined` for key `collectionName` is
* > not allowed as it's not supported by JSON
*
* So what should the TypeScript type for "foo" be?
*
* If it is were to not include the possibility of `undefined`, then the type
* would lie because `store.get("foo")` can indeed be `undefined. But if we were
* to include the possibility of `undefined`, then trying to `store.set("foo",
* someUndefValue)` will throw.
*
* The approach we take is to rely on false-y values (empty strings and empty
* arrays) to indicate missing values, and then converting those to `undefined`
* when reading from the store, and converting `undefined` to the corresponding
* false-y value when writing.
*/
export const setPendingUploads = ({
collectionName,
filePaths,
zipItems,
}: PendingUploads) => {
uploadStatusStore.set({
collectionName: collectionName ?? "",
filePaths: filePaths,
zipItems: zipItems,
});
};
export const markUploadedFiles = (paths: string[]) => {
const existing = uploadStatusStore.get("filePaths");
const updated = existing?.filter((p) => !paths.includes(p));
const existing = uploadStatusStore.get("filePaths") ?? [];
const updated = existing.filter((p) => !paths.includes(p));
uploadStatusStore.set("filePaths", updated);
};
export const markUploadedZipItems = (
items: [zipPath: string, entryName: string][],
) => {
const existing = uploadStatusStore.get("zipItems");
const updated = existing?.filter(
const existing = uploadStatusStore.get("zipItems") ?? [];
const updated = existing.filter(
(z) => !items.some((e) => z[0] == e[0] && z[1] == e[1]),
);
uploadStatusStore.set("zipItems", updated);

View file

@ -1,7 +1,7 @@
import Store, { Schema } from "electron-store";
interface SafeStorageStore {
encryptionKey: string;
encryptionKey?: string;
}
const safeStorageSchema: Schema<SafeStorageStore> = {

View file

@ -6,24 +6,24 @@ export interface UploadStatusStore {
*
* Not all pending uploads will have an associated collection.
*/
collectionName: string | undefined;
collectionName?: string;
/**
* Paths to regular files that are pending upload.
*
* This should generally be present, albeit empty, but it is marked optional
* in sympathy with its siblings.
*/
filePaths: string[] | undefined;
filePaths?: string[];
/**
* Each item is the path to a zip file and the name of an entry within it.
*
* This is marked optional since legacy stores will not have it.
*/
zipItems: [zipPath: string, entryName: string][] | undefined;
zipItems?: [zipPath: string, entryName: string][];
/**
* @deprecated Legacy paths to zip files, now subsumed into zipItems.
*/
zipPaths: string[] | undefined;
zipPaths?: string[];
}
const uploadStatusSchema: Schema<UploadStatusStore> = {

View file

@ -1,7 +1,7 @@
import Store, { Schema } from "electron-store";
interface UserPreferences {
hideDockIcon: boolean;
hideDockIcon?: boolean;
skipAppVersion?: string;
muteUpdateNotificationVersion?: string;
}