Handle undefined better
This commit is contained in:
parent
ebbd946fc2
commit
4e8f2e65f0
|
@ -19,7 +19,7 @@ export const createApplicationMenu = async (mainWindow: BrowserWindow) => {
|
||||||
// Whenever the menu is redrawn the current value of these variables is used
|
// Whenever the menu is redrawn the current value of these variables is used
|
||||||
// to set the checked state for the various settings checkboxes.
|
// to set the checked state for the various settings checkboxes.
|
||||||
let isAutoLaunchEnabled = await autoLauncher.isEnabled();
|
let isAutoLaunchEnabled = await autoLauncher.isEnabled();
|
||||||
let shouldHideDockIcon = userPreferences.get("hideDockIcon");
|
let shouldHideDockIcon = !!userPreferences.get("hideDockIcon");
|
||||||
|
|
||||||
const macOSOnly = (options: MenuItemConstructorOptions[]) =>
|
const macOSOnly = (options: MenuItemConstructorOptions[]) =>
|
||||||
process.platform == "darwin" ? options : [];
|
process.platform == "darwin" ? options : [];
|
||||||
|
|
|
@ -36,18 +36,21 @@ const checkForUpdatesAndNotify = async (mainWindow: BrowserWindow) => {
|
||||||
|
|
||||||
log.debug(() => `Update check found version ${version}`);
|
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) {
|
if (compareVersions(version, app.getVersion()) <= 0) {
|
||||||
log.debug(() => "Skipping update, already at latest version");
|
log.debug(() => "Skipping update, already at latest version");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version === userPreferences.get("skipAppVersion")) {
|
if (version == userPreferences.get("skipAppVersion")) {
|
||||||
log.info(`User chose to skip version ${version}`);
|
log.info(`User chose to skip version ${version}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mutedVersion = userPreferences.get("muteUpdateNotificationVersion");
|
const mutedVersion = userPreferences.get("muteUpdateNotificationVersion");
|
||||||
if (version === mutedVersion) {
|
if (version == mutedVersion) {
|
||||||
log.info(`User has muted update notifications for version ${version}`);
|
log.info(`User has muted update notifications for version ${version}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { watchStore } from "../stores/watch";
|
||||||
* This is useful to reset state when the user logs out.
|
* This is useful to reset state when the user logs out.
|
||||||
*/
|
*/
|
||||||
export const clearStores = () => {
|
export const clearStores = () => {
|
||||||
uploadStatusStore.clear();
|
|
||||||
safeStorageStore.clear();
|
safeStorageStore.clear();
|
||||||
|
uploadStatusStore.clear();
|
||||||
watchStore.clear();
|
watchStore.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ export const pathOrZipItemSize = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const pendingUploads = async (): Promise<PendingUploads | undefined> => {
|
export const pendingUploads = async (): Promise<PendingUploads | undefined> => {
|
||||||
const collectionName = uploadStatusStore.get("collectionName");
|
const collectionName = uploadStatusStore.get("collectionName") ?? undefined;
|
||||||
|
|
||||||
const allFilePaths = uploadStatusStore.get("filePaths") ?? [];
|
const allFilePaths = uploadStatusStore.get("filePaths") ?? [];
|
||||||
const filePaths = allFilePaths.filter((f) => existsSync(f));
|
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
|
// 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
|
// file, but the dedup logic will kick in at that point so no harm will come
|
||||||
// off it.
|
// of it.
|
||||||
if (allZipItems === undefined) {
|
if (allZipItems === undefined) {
|
||||||
const allZipPaths = uploadStatusStore.get("filePaths") ?? [];
|
const allZipPaths = uploadStatusStore.get("filePaths") ?? [];
|
||||||
const zipPaths = allZipPaths.filter((f) => existsSync(f));
|
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[]) => {
|
export const markUploadedFiles = (paths: string[]) => {
|
||||||
const existing = uploadStatusStore.get("filePaths");
|
const existing = uploadStatusStore.get("filePaths") ?? [];
|
||||||
const updated = existing?.filter((p) => !paths.includes(p));
|
const updated = existing.filter((p) => !paths.includes(p));
|
||||||
uploadStatusStore.set("filePaths", updated);
|
uploadStatusStore.set("filePaths", updated);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const markUploadedZipItems = (
|
export const markUploadedZipItems = (
|
||||||
items: [zipPath: string, entryName: string][],
|
items: [zipPath: string, entryName: string][],
|
||||||
) => {
|
) => {
|
||||||
const existing = uploadStatusStore.get("zipItems");
|
const existing = uploadStatusStore.get("zipItems") ?? [];
|
||||||
const updated = existing?.filter(
|
const updated = existing.filter(
|
||||||
(z) => !items.some((e) => z[0] == e[0] && z[1] == e[1]),
|
(z) => !items.some((e) => z[0] == e[0] && z[1] == e[1]),
|
||||||
);
|
);
|
||||||
uploadStatusStore.set("zipItems", updated);
|
uploadStatusStore.set("zipItems", updated);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Store, { Schema } from "electron-store";
|
import Store, { Schema } from "electron-store";
|
||||||
|
|
||||||
interface SafeStorageStore {
|
interface SafeStorageStore {
|
||||||
encryptionKey: string;
|
encryptionKey?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const safeStorageSchema: Schema<SafeStorageStore> = {
|
const safeStorageSchema: Schema<SafeStorageStore> = {
|
||||||
|
|
|
@ -6,24 +6,24 @@ export interface UploadStatusStore {
|
||||||
*
|
*
|
||||||
* Not all pending uploads will have an associated collection.
|
* Not all pending uploads will have an associated collection.
|
||||||
*/
|
*/
|
||||||
collectionName: string | undefined;
|
collectionName?: string;
|
||||||
/**
|
/**
|
||||||
* Paths to regular files that are pending upload.
|
* Paths to regular files that are pending upload.
|
||||||
*
|
*
|
||||||
* This should generally be present, albeit empty, but it is marked optional
|
* This should generally be present, albeit empty, but it is marked optional
|
||||||
* in sympathy with its siblings.
|
* 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.
|
* 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.
|
* 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.
|
* @deprecated Legacy paths to zip files, now subsumed into zipItems.
|
||||||
*/
|
*/
|
||||||
zipPaths: string[] | undefined;
|
zipPaths?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadStatusSchema: Schema<UploadStatusStore> = {
|
const uploadStatusSchema: Schema<UploadStatusStore> = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Store, { Schema } from "electron-store";
|
import Store, { Schema } from "electron-store";
|
||||||
|
|
||||||
interface UserPreferences {
|
interface UserPreferences {
|
||||||
hideDockIcon: boolean;
|
hideDockIcon?: boolean;
|
||||||
skipAppVersion?: string;
|
skipAppVersion?: string;
|
||||||
muteUpdateNotificationVersion?: string;
|
muteUpdateNotificationVersion?: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue