Skip to content

Commit

Permalink
feat: add project to support multiple selections
Browse files Browse the repository at this point in the history
Signed-off-by: The1111mp <The1111mp@outlook.com>
  • Loading branch information
1111mp committed Feb 25, 2024
1 parent 4e13646 commit 2e3cf8b
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 96 deletions.
24 changes: 16 additions & 8 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { gt } from "semver";
import loadLocale from "./locale";
import { Closer, Themes } from "../types";

import type { MenuItemConstructorOptions } from "electron";
import type { MenuItemConstructorOptions, OpenDialogOptions } from "electron";

let mainWindow: BrowserWindow | null = null,
updater: AppUpdater | null = null,
Expand Down Expand Up @@ -105,7 +105,7 @@ const createWindow = async (code?: number) => {
? "#000000"
: "#ffffff",
webPreferences: {
preload: app.isPackaged
preload: app.isPackaged
? join(__dirname, "../preload/preload.js")
: join(__dirname, "../../out/preload/preload.js")
}
Expand Down Expand Up @@ -462,20 +462,28 @@ Promise.resolve().then(() => {

ipcMain.handle(
"open-folder-selecter",
async (_event, { title, project }: { title: string; project?: boolean }) => {
async (
_event,
{ title, multiple, project }: { title: string; multiple?: boolean; project?: boolean }
) => {
const properties: OpenDialogOptions["properties"] = [
"openDirectory",
"createDirectory",
"showHiddenFiles"
];
multiple && properties.push("multiSelections");
const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow!, {
title,
properties: ["openDirectory", "createDirectory", "showHiddenFiles"]
properties: properties
});

if (canceled) return { canceled, filePaths };

const [path] = filePaths;

if (!project) return { canceled, filePaths };

const version = await getVersion(path);
return { canceled, filePaths, version };
const versions = await Promise.all(filePaths.map((path) => getVersion(path)));

return { canceled, filePaths, versions };
}
);

Expand Down
152 changes: 80 additions & 72 deletions src/preload/index.ts
Original file line number Diff line number Diff line change
@@ -1,140 +1,148 @@
// Disable no-unused-vars, broken for spread args
/* eslint no-unused-vars: off */
import { contextBridge, ipcRenderer } from 'electron'
import { contextBridge, ipcRenderer } from "electron";

import type { OpenDialogReturnValue } from 'electron'
import type { ProgressInfo, UpdateInfo } from 'electron-updater'
import type { OpenDialogReturnValue } from "electron";
import type { ProgressInfo, UpdateInfo } from "electron-updater";

type OnCheckUpdateResultCallback = (info: UpdateInfo | 'update-not-available') => void
type OnUpdateProgressCallback = (progress: ProgressInfo) => void
type OnProgressCallback = (id: string, data: Nvmd.ProgressData) => void
type OnThemeChangedCallback = (theme: string) => void
type OnCurVersionChange = (version: string) => void
type OnProjectUpdate = (projects: Nvmd.Project[], version: string) => void
type OnMigrationError = () => void
type OnCheckUpdateResultCallback = (info: UpdateInfo | "update-not-available") => void;
type OnUpdateProgressCallback = (progress: ProgressInfo) => void;
type OnProgressCallback = (id: string, data: Nvmd.ProgressData) => void;
type OnThemeChangedCallback = (theme: string) => void;
type OnCurVersionChange = (version: string) => void;
type OnProjectUpdate = (projects: Nvmd.Project[], version: string) => void;
type OnMigrationError = () => void;

let onCheckUpdateResult: OnCheckUpdateResultCallback | null = null,
onUpdateProgress: OnUpdateProgressCallback | null = null,
onProgress: OnProgressCallback | null = null,
onThemeChanged: OnThemeChangedCallback | null = null,
onCurVersionChange: OnCurVersionChange | null = null,
onProjectUpdate: OnProjectUpdate | null = null,
onMigrationError: OnMigrationError | null = null
onMigrationError: OnMigrationError | null = null;

ipcRenderer.on('update-available', (_event, info: UpdateInfo) => {
onCheckUpdateResult?.(info)
})
ipcRenderer.on("update-available", (_event, info: UpdateInfo) => {
onCheckUpdateResult?.(info);
});

ipcRenderer.on('update-not-available', (_event, info: 'update-not-available') => {
onCheckUpdateResult?.(info)
})
ipcRenderer.on("update-not-available", (_event, info: "update-not-available") => {
onCheckUpdateResult?.(info);
});

ipcRenderer.on('download-progress', (_event, progress: ProgressInfo) => {
onUpdateProgress?.(progress)
})
ipcRenderer.on("download-progress", (_event, progress: ProgressInfo) => {
onUpdateProgress?.(progress);
});

ipcRenderer.on('update-error', (_event, err) => {
console.log(err)
})
ipcRenderer.on("update-error", (_event, err) => {
console.log(err);
});

ipcRenderer.on('get-node:progress', (_event, id: string, progress: Nvmd.ProgressData) => {
onProgress?.(id, progress)
})
ipcRenderer.on("get-node:progress", (_event, id: string, progress: Nvmd.ProgressData) => {
onProgress?.(id, progress);
});

ipcRenderer.on('native-theme:changed', (_event, theme: string) => {
onThemeChanged?.(theme)
})
ipcRenderer.on("native-theme:changed", (_event, theme: string) => {
onThemeChanged?.(theme);
});

ipcRenderer.on('current-version-update', (_evnet, version: string) => {
onCurVersionChange?.(version)
})
ipcRenderer.on("current-version-update", (_evnet, version: string) => {
onCurVersionChange?.(version);
});

ipcRenderer.on('call-projects-update', (_evnet, projects: Nvmd.Project[], version: string) => {
onProjectUpdate?.(projects, version)
})
ipcRenderer.on("call-projects-update", (_evnet, projects: Nvmd.Project[], version: string) => {
onProjectUpdate?.(projects, version);
});

ipcRenderer.on('migration-error', (_evnet) => {
onMigrationError?.()
})
ipcRenderer.on("migration-error", (_evnet) => {
onMigrationError?.();
});

const electronHandler = {
platform: process.platform,
arch: process.arch,
version: ipcRenderer.sendSync('get-app-version') as string,
version: ipcRenderer.sendSync("get-app-version") as string,

windowClose: () => {
ipcRenderer.send('window:close')
ipcRenderer.send("window:close");
},
windowMinimize: () => {
ipcRenderer.send('window:minimize')
ipcRenderer.send("window:minimize");
},

checkForUpdates: () => ipcRenderer.invoke('check-for-updates') as Promise<UpdateInfo | null>,
comfirmUpdate: () => ipcRenderer.invoke('confirm-update') as Promise<string[]>,
checkForUpdates: () => ipcRenderer.invoke("check-for-updates") as Promise<UpdateInfo | null>,
comfirmUpdate: () => ipcRenderer.invoke("confirm-update") as Promise<string[]>,
makeUpdateNow() {
ipcRenderer.send('make-update-now')
ipcRenderer.send("make-update-now");
},
onCheckUpdateResultCallback(callback: OnCheckUpdateResultCallback) {
onCheckUpdateResult = callback
onCheckUpdateResult = callback;
},
onRegistUpdateProgress(callback: OnUpdateProgressCallback) {
onUpdateProgress = callback
onUpdateProgress = callback;
},

getSettingData: () =>
ipcRenderer.sendSync('setting-data-get') as Nvmd.Setting & {
localeMessages: I18n.Message
ipcRenderer.sendSync("setting-data-get") as Nvmd.Setting & {
localeMessages: I18n.Message;
},
updateSettingData: (setting: Nvmd.Setting) =>
ipcRenderer.invoke('setting-data-set', setting) as Promise<void>,
getLocaleData: () => ipcRenderer.sendSync('locale-data') as I18n.Message,
ipcRenderer.invoke("setting-data-set", setting) as Promise<void>,
getLocaleData: () => ipcRenderer.sendSync("locale-data") as I18n.Message,

getAllNodeVersions: async (arg?: { id?: string; fetch?: boolean }) =>
ipcRenderer.invoke('all-node-versions', arg) as Promise<Nvmd.Versions>,
ipcRenderer.invoke("all-node-versions", arg) as Promise<Nvmd.Versions>,

getInstalledNodeVersions: async (refresh: boolean = false): Promise<string[]> =>
ipcRenderer.invoke('installed-node-versions', refresh),
ipcRenderer.invoke("installed-node-versions", refresh),

getNode: async (args: { id: string; version: string }) => ipcRenderer.invoke('get-node', args),
controllerAbort: (id: string) => ipcRenderer.invoke('controller:abort', id),
getNode: async (args: { id: string; version: string }) => ipcRenderer.invoke("get-node", args),
controllerAbort: (id: string) => ipcRenderer.invoke("controller:abort", id),

useNodeVersion: (version: string) => ipcRenderer.invoke('use-version', version),
getCurrentVersion: (fetch: boolean = false) => ipcRenderer.invoke('current-version', fetch),
useNodeVersion: (version: string) => ipcRenderer.invoke("use-version", version),
getCurrentVersion: (fetch: boolean = false) => ipcRenderer.invoke("current-version", fetch),
onRegistCurVersionChange: (callback: OnCurVersionChange) => {
onCurVersionChange = callback
onCurVersionChange = callback;
},

onRegistProgress: (onProgressSource: OnProgressCallback) => {
onProgress = onProgressSource
onProgress = onProgressSource;
},

uninstallVersion: (version: string, current: boolean = false) =>
ipcRenderer.invoke('uninstall-node-version', version, current),
ipcRenderer.invoke("uninstall-node-version", version, current),

getSystemTheme: () => ipcRenderer.sendSync('get-system-theme') as string,
getSystemTheme: () => ipcRenderer.sendSync("get-system-theme") as string,
onRegistThemeCallback: (callback: OnThemeChangedCallback) => {
onThemeChanged = callback
onThemeChanged = callback;
},

openFolderSelecter: ({ title, project = false }: { title: string; project?: boolean }) =>
ipcRenderer.invoke('open-folder-selecter', { title, project }) as Promise<
OpenDialogReturnValue & { version?: string }
openFolderSelecter: ({
title,
multiple = false,
project = false
}: {
title: string;
multiple?: boolean;
project?: boolean;
}) =>
ipcRenderer.invoke("open-folder-selecter", { title, multiple, project }) as Promise<
OpenDialogReturnValue & { versions?: string[] }
>,
getProjects: (load: boolean = false) =>
ipcRenderer.invoke('get-projects', load) as Promise<Nvmd.Project[]>,
ipcRenderer.invoke("get-projects", load) as Promise<Nvmd.Project[]>,
updateProjects: (projects: Nvmd.Project[], path?: string) =>
ipcRenderer.invoke('update-projects', projects, path) as Promise<void>,
ipcRenderer.invoke("update-projects", projects, path) as Promise<void>,
syncProjectVersion: (path: string, version: string) =>
ipcRenderer.invoke('sync-project-version', path, version) as Promise<404 | 200>,
ipcRenderer.invoke("sync-project-version", path, version) as Promise<404 | 200>,
onRegistProjectUpdate: (callback: OnProjectUpdate | null) => {
onProjectUpdate = callback
onProjectUpdate = callback;
},

onRegistMigrationError: (callback: OnMigrationError) => {
onMigrationError = callback
onMigrationError = callback;
}
}
};

contextBridge.exposeInMainWorld('Context', electronHandler)
contextBridge.exposeInMainWorld("Context", electronHandler);

export type ElectronHandler = typeof electronHandler
export type ElectronHandler = typeof electronHandler;
43 changes: 27 additions & 16 deletions src/renderer/src/pages/projects/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,28 +188,39 @@ export const Component: React.FC = () => {
);

const onAddProject = async () => {
const { canceled, filePaths, version } = await window.Context.openFolderSelecter({
const {
canceled,
filePaths,
versions = []
} = await window.Context.openFolderSelecter({
title: i18n("Project-Select"),
multiple: true,
project: true
});
if (canceled) return;
const [path] = filePaths;

if (projects.find(({ path: source }) => source === path)) {
return toast.error("The project already exists");
}
const addProjects: Nvmd.Project[] = [];

const pathArr = path.split(window.Context.platform === "win32" ? "\\" : "/");
const now = new Date().toISOString();
const project: Nvmd.Project = {
name: pathArr[pathArr.length - 1],
path,
version,
active: true,
createAt: now,
updateAt: now
};
const newProjects = [project, ...projects];
filePaths.forEach((path, index) => {
const pathArr = path.split(window.Context.platform === "win32" ? "\\" : "/"),
name = pathArr[pathArr.length - 1],
now = new Date().toISOString();

if (!projects.find(({ path: source }) => source === path)) {
addProjects.push({
name,
path,
version: versions[index],
active: true,
createAt: now,
updateAt: now
});
} else {
toast.error(`The project "${name}" already exists`);
}
});

const newProjects = [...addProjects, ...projects];
setProjects(newProjects);
window.Context.updateProjects(newProjects);
return;
Expand Down

0 comments on commit 2e3cf8b

Please sign in to comment.