General bug fixes from testing, refresh on shop change, update display
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bodyshop-desktop",
|
"name": "bodyshop-desktop",
|
||||||
"version": "0.0.1-alpha.4",
|
"version": "0.0.1-alpha.5",
|
||||||
"description": "Shop Management System Partner",
|
"description": "Shop Management System Partner",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "Convenient Brands, LLC",
|
"author": "Convenient Brands, LLC",
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import http from "http";
|
|||||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||||
import ImportJob from "../decoder/decoder";
|
import ImportJob from "../decoder/decoder";
|
||||||
import folderScan from "../decoder/folder-scan";
|
import folderScan from "../decoder/folder-scan";
|
||||||
|
import { handleEMSPartsOrder } from "../ems-parts-order/ems-parts-order-handler";
|
||||||
|
import { handleShopMetaDataFetch } from "../ipc/ipcMainHandler.user";
|
||||||
import { handlePartsPariceChangeRequest } from "../ppc/ppc-handler";
|
import { handlePartsPariceChangeRequest } from "../ppc/ppc-handler";
|
||||||
import { handleQuickBookRequest } from "../quickbooks-desktop/quickbooks-desktop";
|
import { handleQuickBookRequest } from "../quickbooks-desktop/quickbooks-desktop";
|
||||||
import { handleEMSPartsOrder } from "../ems-parts-order/ems-parts-order-handler";
|
import { c } from "vite/dist/node/moduleRunnerTransport.d-CXw_Ws6P";
|
||||||
|
|
||||||
export default class LocalServer {
|
export default class LocalServer {
|
||||||
private app: express.Application;
|
private app: express.Application;
|
||||||
@@ -146,6 +148,26 @@ export default class LocalServer {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
this.app.post(
|
||||||
|
"/refresh",
|
||||||
|
async (req: express.Request, res: express.Response) => {
|
||||||
|
log.debug("[HTTP Server] Refresh request received");
|
||||||
|
try {
|
||||||
|
await handleShopMetaDataFetch(true);
|
||||||
|
res.status(200).json({ success: true });
|
||||||
|
} catch (error) {
|
||||||
|
log.error(
|
||||||
|
"[HTTP Server] Error refreshing shop metadata",
|
||||||
|
errorTypeCheck(error),
|
||||||
|
);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: "Error importing file",
|
||||||
|
...errorTypeCheck(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Add more routes as needed
|
// Add more routes as needed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { is, optimizer } from "@electron-toolkit/utils";
|
import { is, optimizer, platform } from "@electron-toolkit/utils";
|
||||||
import Sentry from "@sentry/electron/main";
|
import Sentry from "@sentry/electron/main";
|
||||||
import {
|
import {
|
||||||
app,
|
app,
|
||||||
@@ -88,7 +88,10 @@ function createWindow(): void {
|
|||||||
// { role: 'fileMenu' }
|
// { role: 'fileMenu' }
|
||||||
{
|
{
|
||||||
label: "File",
|
label: "File",
|
||||||
submenu: [isMac ? { role: "close" } : { role: "quit" }],
|
submenu: [
|
||||||
|
...(!isMac ? [{ role: "about" }] : []),
|
||||||
|
isMac ? { role: "close" } : { role: "quit" },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
// { role: 'editMenu' }
|
// { role: 'editMenu' }
|
||||||
{
|
{
|
||||||
@@ -149,7 +152,7 @@ function createWindow(): void {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Check for Updates",
|
label: `Check for Updates (${app.getVersion()})`,
|
||||||
click: (): void => {
|
click: (): void => {
|
||||||
checkForAppUpdates();
|
checkForAppUpdates();
|
||||||
},
|
},
|
||||||
@@ -169,6 +172,7 @@ function createWindow(): void {
|
|||||||
store.set("app.isTest", !currentSetting);
|
store.set("app.isTest", !currentSetting);
|
||||||
log.info("Setting isTest to: ", !currentSetting);
|
log.info("Setting isTest to: ", !currentSetting);
|
||||||
app.relaunch(); // Relaunch the app
|
app.relaunch(); // Relaunch the app
|
||||||
|
preQuitMethods(); //Quitting handlers aren't called. Manually execute to clean up the app.
|
||||||
app.exit(0); // Exit the current instance
|
app.exit(0); // Exit the current instance
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -321,6 +325,10 @@ app.whenReady().then(async () => {
|
|||||||
// Default open or close DevTools by F12 in development
|
// Default open or close DevTools by F12 in development
|
||||||
// and ignore CommandOrControl + R in production.
|
// and ignore CommandOrControl + R in production.
|
||||||
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
|
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
|
||||||
|
if (platform.isWindows) {
|
||||||
|
app.setAppUserModelId(app.name);
|
||||||
|
}
|
||||||
|
|
||||||
app.on("browser-window-created", (_, window) => {
|
app.on("browser-window-created", (_, window) => {
|
||||||
optimizer.watchWindowShortcuts(window);
|
optimizer.watchWindowShortcuts(window);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
} from "../graphql/queries";
|
} from "../graphql/queries";
|
||||||
import { default as Store, default as store } from "../store/store";
|
import { default as Store, default as store } from "../store/store";
|
||||||
import { checkForAppUpdatesContinuously } from "../util/checkForAppUpdates";
|
import { checkForAppUpdatesContinuously } from "../util/checkForAppUpdates";
|
||||||
import { sendIpcToRenderer } from "../util/toRenderer";
|
import { getMainWindow, sendIpcToRenderer } from "../util/toRenderer";
|
||||||
|
|
||||||
const ipcMainHandleAuthStateChanged = async (
|
const ipcMainHandleAuthStateChanged = async (
|
||||||
_event: IpcMainEvent,
|
_event: IpcMainEvent,
|
||||||
@@ -23,27 +23,10 @@ const ipcMainHandleAuthStateChanged = async (
|
|||||||
try {
|
try {
|
||||||
//Need to query the currently active shop, and store the metadata as well.
|
//Need to query the currently active shop, and store the metadata as well.
|
||||||
//Also need to query the OP Codes for decoding reference.
|
//Also need to query the OP Codes for decoding reference.
|
||||||
const activeBodyshop: ActiveBodyshopQueryResult = await client.request(
|
|
||||||
QUERY_ACTIVE_BODYSHOP_TYPED,
|
|
||||||
);
|
|
||||||
|
|
||||||
Store.set("app.bodyshop", activeBodyshop.bodyshops[0]);
|
|
||||||
|
|
||||||
const OpCodes: MasterdataQueryResult = await client.request(
|
|
||||||
QUERY_MASTERDATA_TYPED,
|
|
||||||
{
|
|
||||||
key: `${activeBodyshop.bodyshops[0].region_config}_ciecaopcodes`,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
Store.set(
|
|
||||||
"app.masterdata.opcodes",
|
|
||||||
JSON.parse(OpCodes.masterdata[0]?.value),
|
|
||||||
);
|
|
||||||
log.debug("Received authentication state change from Renderer.", user);
|
log.debug("Received authentication state change from Renderer.", user);
|
||||||
log.debug("Requery shop information & master data.");
|
handleShopMetaDataFetch();
|
||||||
|
|
||||||
//Check for updates
|
//Check for updates
|
||||||
const convCo = activeBodyshop.bodyshops[0].convenient_company;
|
const convCo = Store.get("app.bodyshop");
|
||||||
if (convCo === "alpha") {
|
if (convCo === "alpha") {
|
||||||
autoUpdater.channel = "alpha";
|
autoUpdater.channel = "alpha";
|
||||||
log.debug("Setting update channel to ALPHA channel.");
|
log.debug("Setting update channel to ALPHA channel.");
|
||||||
@@ -64,6 +47,39 @@ const ipcMainHandleAuthStateChanged = async (
|
|||||||
checkForAppUpdatesContinuously();
|
checkForAppUpdatesContinuously();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleShopMetaDataFetch = async (
|
||||||
|
reloadWindow: boolean,
|
||||||
|
): Promise<void> => {
|
||||||
|
try {
|
||||||
|
log.debug("Requery shop information & master data.");
|
||||||
|
const activeBodyshop: ActiveBodyshopQueryResult = await client.request(
|
||||||
|
QUERY_ACTIVE_BODYSHOP_TYPED,
|
||||||
|
);
|
||||||
|
|
||||||
|
Store.set("app.bodyshop", activeBodyshop.bodyshops[0]);
|
||||||
|
|
||||||
|
const OpCodes: MasterdataQueryResult = await client.request(
|
||||||
|
QUERY_MASTERDATA_TYPED,
|
||||||
|
{
|
||||||
|
key: `${activeBodyshop.bodyshops[0].region_config}_ciecaopcodes`,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Store.set(
|
||||||
|
"app.masterdata.opcodes",
|
||||||
|
JSON.parse(OpCodes.masterdata[0]?.value),
|
||||||
|
);
|
||||||
|
if (reloadWindow) {
|
||||||
|
const mainWindow = getMainWindow();
|
||||||
|
if (mainWindow) {
|
||||||
|
mainWindow.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
log.error("Error while fetching shop metadata", errorTypeCheck(error));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const ipMainHandleResetPassword = async (): Promise<void> => {
|
const ipMainHandleResetPassword = async (): Promise<void> => {
|
||||||
shell.openExternal(
|
shell.openExternal(
|
||||||
store.get("app.isTest")
|
store.get("app.isTest")
|
||||||
@@ -72,4 +88,8 @@ const ipMainHandleResetPassword = async (): Promise<void> => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { ipcMainHandleAuthStateChanged, ipMainHandleResetPassword };
|
export {
|
||||||
|
ipcMainHandleAuthStateChanged,
|
||||||
|
ipMainHandleResetPassword,
|
||||||
|
handleShopMetaDataFetch,
|
||||||
|
};
|
||||||
|
|||||||
@@ -134,16 +134,18 @@ const SettingsWatcher: React.FC = () => {
|
|||||||
checkedChildren={t("settings.labels.watchermoderealtime")}
|
checkedChildren={t("settings.labels.watchermoderealtime")}
|
||||||
unCheckedChildren={t("settings.labels.watchermodepolling")}
|
unCheckedChildren={t("settings.labels.watchermodepolling")}
|
||||||
/>
|
/>
|
||||||
<Space size="small" wrap>
|
{pollingState.enabled && (
|
||||||
<span>{t("settings.labels.pollinginterval")}</span>
|
<Space size="small" direction="vertical" wrap>
|
||||||
<InputNumber
|
<span>{t("settings.labels.pollinginterval")}</span>
|
||||||
title={t("settings.labels.pollinginterval")}
|
<InputNumber
|
||||||
disabled={!pollingState.enabled}
|
title={t("settings.labels.pollinginterval")}
|
||||||
min={1000}
|
disabled={!pollingState.enabled}
|
||||||
value={pollingState.interval}
|
min={1000}
|
||||||
onChange={handlePollingIntervalChange}
|
value={pollingState.interval}
|
||||||
/>
|
onChange={handlePollingIntervalChange}
|
||||||
</Space>
|
/>
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
{watcherError && <Alert message={watcherError} />}
|
{watcherError && <Alert message={watcherError} />}
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useAppSelector } from "@renderer/redux/reduxHooks";
|
|||||||
import { Affix, Button, Card, Progress, Space, Statistic } from "antd";
|
import { Affix, Button, Card, Progress, Space, Statistic } from "antd";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import ipcTypes from "../../../../util/ipcTypes.json";
|
import ipcTypes from "../../../../util/ipcTypes.json";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
const UpdateAvailable: React.FC = () => {
|
const UpdateAvailable: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -16,12 +17,14 @@ const UpdateAvailable: React.FC = () => {
|
|||||||
const updateSpeed = useAppSelector(selectAppUpdateSpeed);
|
const updateSpeed = useAppSelector(selectAppUpdateSpeed);
|
||||||
const updateProgress = useAppSelector(selectAppUpdateProgress);
|
const updateProgress = useAppSelector(selectAppUpdateProgress);
|
||||||
const isUpdateComplete = useAppSelector(selectAppUpdateCompleted);
|
const isUpdateComplete = useAppSelector(selectAppUpdateCompleted);
|
||||||
|
const [applyingUpdate, setApplyingUpdate] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleDownload = (): void => {
|
const handleDownload = (): void => {
|
||||||
window.electron.ipcRenderer.send(ipcTypes.toMain.updates.download);
|
window.electron.ipcRenderer.send(ipcTypes.toMain.updates.download);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleApply = (): void => {
|
const handleApply = (): void => {
|
||||||
|
setApplyingUpdate(true);
|
||||||
window.electron.ipcRenderer.send(ipcTypes.toMain.updates.apply);
|
window.electron.ipcRenderer.send(ipcTypes.toMain.updates.apply);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,28 +33,45 @@ const UpdateAvailable: React.FC = () => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Affix offsetTop={40} style={{ position: "absolute", right: 20 }}>
|
<Affix offsetTop={40} style={{ position: "absolute", right: 20 }}>
|
||||||
<Card title={t("updates.available")} style={{ width: "40vw" }}>
|
<Card
|
||||||
{updateProgress === 0 && (
|
title={t("updates.available")}
|
||||||
<Button onClick={handleDownload}>{t("updates.download")}</Button>
|
style={{
|
||||||
)}
|
maxWidth: 600,
|
||||||
<Progress
|
margin: "auto auto",
|
||||||
percent={updateProgress}
|
borderRadius: 8,
|
||||||
percentPosition={{ align: "center", type: "outer" }}
|
|
||||||
/>
|
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
||||||
{!isUpdateComplete && formatSpeed(updateSpeed)}
|
}}
|
||||||
{isUpdateComplete && (
|
>
|
||||||
<Space wrap>
|
<Space direction="vertical" style={{ width: "100%" }}>
|
||||||
<Button onClick={handleApply}>{t("updates.apply")}</Button>
|
{updateProgress === 0 && (
|
||||||
<Statistic.Countdown
|
<Button onClick={handleDownload}>{t("updates.download")}</Button>
|
||||||
title="Auto update in:"
|
)}
|
||||||
format="mm:ss"
|
<Progress
|
||||||
value={Date.now() + 10 * 1000}
|
percent={updateProgress}
|
||||||
onFinish={(): void =>
|
percentPosition={{ align: "center", type: "outer" }}
|
||||||
window.electron.ipcRenderer.send(ipcTypes.toMain.updates.apply)
|
/>
|
||||||
}
|
{!isUpdateComplete && formatSpeed(updateSpeed)}
|
||||||
/>
|
{isUpdateComplete && (
|
||||||
</Space>
|
<>
|
||||||
)}
|
<Button
|
||||||
|
type="primary"
|
||||||
|
loading={applyingUpdate}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
onClick={handleApply}
|
||||||
|
>
|
||||||
|
{applyingUpdate ? t("updates.applying") : t("updates.apply")}
|
||||||
|
</Button>
|
||||||
|
<Statistic.Countdown
|
||||||
|
title="Auto update in:"
|
||||||
|
format="mm:ss"
|
||||||
|
style={{ width: "100%", textAlign: "center" }}
|
||||||
|
value={Date.now() + 10 * 1000}
|
||||||
|
onFinish={(): void => handleApply()}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
</Affix>
|
</Affix>
|
||||||
);
|
);
|
||||||
|
|||||||
1
vscode-profile-2025-04-14-15-12-44.heapprofile
Normal file
1
vscode-profile-2025-04-14-15-12-44.heapprofile
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user