feature/IO-3205-Paint-Scale-Integrations: init

This commit is contained in:
Dave Richer
2025-04-23 13:17:10 -04:00
parent d4bde2db40
commit 7d881fc9e6
7 changed files with 580 additions and 73 deletions

View File

@@ -1,3 +1,4 @@
// main/ipcMainConfig.ts
import { app, ipcMain } from "electron";
import log from "electron-log/main";
import { autoUpdater } from "electron-updater";
@@ -16,6 +17,12 @@ import {
SettingsWatcherPollingSet,
SettingEmsOutFilePathSet,
SettingEmsOutFilePathGet,
SettingsPaintScaleInputConfigsGet,
SettingsPaintScaleInputConfigsSet,
SettingsPaintScaleInputPathSet,
SettingsPaintScaleOutputConfigsGet,
SettingsPaintScaleOutputConfigsSet,
SettingsPaintScaleOutputPathSet,
} from "./ipcMainHandler.settings";
import {
ipcMainHandleAuthStateChanged,
@@ -24,23 +31,19 @@ import {
// Log all IPC messages and their payloads
const logIpcMessages = (): void => {
// Get all message types from ipcTypes.toMain
Object.keys(ipcTypes.toMain).forEach((key) => {
const messageType = ipcTypes.toMain[key];
// Wrap the original handler with our logging
const originalHandler = ipcMain.listeners(messageType)[0];
const originalHandler = ipcMain.listeners(messageType)?.[0];
if (originalHandler) {
ipcMain.removeAllListeners(messageType);
}
ipcMain.on(messageType, (event, payload) => {
log.info(
`%c[IPC Main]%c${messageType}`,
"color: red",
"color: green",
payload,
`%c[IPC Main]%c${messageType}`,
"color: red",
"color: green",
payload,
);
// Call original handler if it existed
if (originalHandler) {
originalHandler(event, payload);
}
@@ -49,20 +52,19 @@ const logIpcMessages = (): void => {
};
ipcMain.on(ipcTypes.toMain.test, () =>
console.log("** Verify that ipcMain is loaded and working."),
console.log("** Verify that ipcMain is loaded and working."),
);
//Auth handler
// Auth handler
ipcMain.on(ipcTypes.toMain.authStateChanged, ipcMainHandleAuthStateChanged);
ipcMain.on(ipcTypes.toMain.user.resetPassword, ipMainHandleResetPassword);
//Add debug handlers if in development
// Add debug handlers if in development
if (import.meta.env.DEV) {
log.debug("[IPC Debug Functions] Adding Debug Handlers");
ipcMain.on(ipcTypes.toMain.debug.decodeEstimate, async (): Promise<void> => {
const relativeEmsFilepath = `_reference/ems/MPI_1/3698420.ENV`;
// Get the app's root directory and create an absolute path
const rootDir = app.getAppPath();
const absoluteFilepath = path.join(rootDir, relativeEmsFilepath);
@@ -76,44 +78,72 @@ if (import.meta.env.DEV) {
});
}
//Settings Handlers
// Settings Handlers
ipcMain.handle(
ipcTypes.toMain.settings.filepaths.get,
SettingsWatchedFilePathsGet,
ipcTypes.toMain.settings.filepaths.get,
SettingsWatchedFilePathsGet,
);
ipcMain.handle(
ipcTypes.toMain.settings.filepaths.add,
SettingsWatchedFilePathsAdd,
ipcTypes.toMain.settings.filepaths.add,
SettingsWatchedFilePathsAdd,
);
ipcMain.handle(
ipcTypes.toMain.settings.filepaths.remove,
SettingsWatchedFilePathsRemove,
ipcTypes.toMain.settings.filepaths.remove,
SettingsWatchedFilePathsRemove,
);
ipcMain.handle(
ipcTypes.toMain.settings.watcher.getpolling,
SettingsWatcherPollingGet,
ipcTypes.toMain.settings.watcher.getpolling,
SettingsWatcherPollingGet,
);
ipcMain.handle(
ipcTypes.toMain.settings.watcher.setpolling,
SettingsWatcherPollingSet,
ipcTypes.toMain.settings.watcher.setpolling,
SettingsWatcherPollingSet,
);
ipcMain.handle(ipcTypes.toMain.settings.getPpcFilePath, SettingsPpcFilePathGet);
ipcMain.handle(ipcTypes.toMain.settings.setPpcFilePath, SettingsPpcFilePathSet);
ipcMain.handle(
ipcTypes.toMain.settings.getEmsOutFilePath,
SettingEmsOutFilePathGet,
ipcTypes.toMain.settings.getEmsOutFilePath,
SettingEmsOutFilePathGet,
);
ipcMain.handle(
ipcTypes.toMain.settings.setEmsOutFilePath,
SettingEmsOutFilePathSet,
ipcTypes.toMain.settings.setEmsOutFilePath,
SettingEmsOutFilePathSet,
);
// Paint Scale Input Settings Handlers
ipcMain.handle(
ipcTypes.toMain.settings.paintScale.getInputConfigs,
SettingsPaintScaleInputConfigsGet,
);
ipcMain.handle(
ipcTypes.toMain.settings.paintScale.setInputConfigs,
SettingsPaintScaleInputConfigsSet,
);
ipcMain.handle(
ipcTypes.toMain.settings.paintScale.setInputPath,
SettingsPaintScaleInputPathSet,
);
// Paint Scale Output Settings Handlers
ipcMain.handle(
ipcTypes.toMain.settings.paintScale.getOutputConfigs,
SettingsPaintScaleOutputConfigsGet,
);
ipcMain.handle(
ipcTypes.toMain.settings.paintScale.setOutputConfigs,
SettingsPaintScaleOutputConfigsSet,
);
ipcMain.handle(
ipcTypes.toMain.settings.paintScale.setOutputPath,
SettingsPaintScaleOutputPathSet,
);
ipcMain.handle(ipcTypes.toMain.user.getActiveShop, () => {
return store.get("app.bodyshop.shopname");
});
//Watcher Handlers
// Watcher Handlers
ipcMain.on(ipcTypes.toMain.watcher.start, () => {
StartWatcher();
});
@@ -127,4 +157,4 @@ ipcMain.on(ipcTypes.toMain.updates.download, () => {
autoUpdater.downloadUpdate();
});
logIpcMessages();
logIpcMessages();

View File

@@ -1,9 +1,31 @@
import {dialog, IpcMainInvokeEvent} from "electron";
// main/ipcMainHandler.settings.ts
import { dialog, IpcMainInvokeEvent } from "electron";
import log from "electron-log/main";
import _ from "lodash";
import Store from "../store/store";
import {getMainWindow} from "../util/toRenderer";
import {addWatcherPath, removeWatcherPath, StartWatcher, StopWatcher,} from "../watcher/watcher";
import { getMainWindow } from "../util/toRenderer";
import {
addWatcherPath,
removeWatcherPath,
StartWatcher,
StopWatcher,
} from "../watcher/watcher";
interface PaintScaleConfig {
id: string;
path: string | null;
type: string;
}
// Initialize paint scale input configs in store if not set
if (!Store.get("settings.paintScaleInputConfigs")) {
Store.set("settings.paintScaleInputConfigs", []);
}
// Initialize paint scale output configs in store if not set
if (!Store.get("settings.paintScaleOutputConfigs")) {
Store.set("settings.paintScaleOutputConfigs", []);
}
const SettingsWatchedFilePathsAdd = async (): Promise<string[]> => {
const mainWindow = getMainWindow();
@@ -17,21 +39,22 @@ const SettingsWatchedFilePathsAdd = async (): Promise<string[]> => {
if (!result.canceled) {
Store.set(
"settings.filepaths",
_.union(result.filePaths, Store.get("settings.filepaths")),
"settings.filepaths",
_.union(result.filePaths, Store.get("settings.filepaths")),
);
addWatcherPath(result.filePaths);
}
return Store.get("settings.filepaths");
};
const SettingsWatchedFilePathsRemove = async (
_event: IpcMainInvokeEvent,
path: string,
_event: IpcMainInvokeEvent,
path: string,
): Promise<string[]> => {
Store.set(
"settings.filepaths",
_.without(Store.get("settings.filepaths"), path),
"settings.filepaths",
_.without(Store.get("settings.filepaths"), path),
);
removeWatcherPath(path);
return Store.get("settings.filepaths");
@@ -46,15 +69,16 @@ const SettingsWatcherPollingGet = async (): Promise<{
interval: number;
}> => {
const pollingEnabled: { enabled: boolean; interval: number } =
Store.get("settings.polling");
Store.get("settings.polling");
return { enabled: pollingEnabled.enabled, interval: pollingEnabled.interval };
};
const SettingsWatcherPollingSet = async (
_event: IpcMainInvokeEvent,
pollingSettings: {
enabled: boolean;
interval: number;
},
_event: IpcMainInvokeEvent,
pollingSettings: {
enabled: boolean;
interval: number;
},
): Promise<{
enabled: boolean;
interval: number;
@@ -63,15 +87,16 @@ const SettingsWatcherPollingSet = async (
const { enabled, interval } = pollingSettings;
Store.set("settings.polling", { enabled, interval });
//Restart the watcher with these new settings.
await StopWatcher();
await StartWatcher();
return { enabled, interval };
};
const SettingsPpcFilePathGet = async (): Promise<string> => {
return Store.get("settings.ppcFilePath");
};
const SettingsPpcFilePathSet = async (): Promise<string> => {
const mainWindow = getMainWindow();
if (!mainWindow) {
@@ -83,14 +108,16 @@ const SettingsPpcFilePathSet = async (): Promise<string> => {
});
if (!result.canceled) {
Store.set("settings.ppcFilePath", result.filePaths[0]); //There should only ever be on directory that was selected.
Store.set("settings.ppcFilePath", result.filePaths[0]);
}
return (Store.get("settings.ppcFilePath") as string) || "";
};
const SettingEmsOutFilePathGet = async (): Promise<string> => {
return Store.get("settings.emsOutFilePath");
};
const SettingEmsOutFilePathSet = async (): Promise<string> => {
const mainWindow = getMainWindow();
if (!mainWindow) {
@@ -102,12 +129,116 @@ const SettingEmsOutFilePathSet = async (): Promise<string> => {
});
if (!result.canceled) {
Store.set("settings.emsOutFilePath", result.filePaths[0]); //There should only ever be on directory that was selected.
Store.set("settings.emsOutFilePath", result.filePaths[0]);
}
return (Store.get("settings.emsOutFilePath") as string) || "";
};
const SettingsPaintScaleInputConfigsGet = async (
_event: IpcMainInvokeEvent,
): Promise<PaintScaleConfig[]> => {
try {
const configs = Store.get("settings.paintScaleInputConfigs") as PaintScaleConfig[];
log.debug("Retrieved paint scale input configs:", configs);
return configs || [];
} catch (error) {
log.error("Error getting paint scale input configs:", error);
throw error;
}
};
const SettingsPaintScaleInputConfigsSet = async (
_event: IpcMainInvokeEvent,
configs: PaintScaleConfig[],
): Promise<boolean> => {
try {
Store.set("settings.paintScaleInputConfigs", configs);
log.debug("Saved paint scale input configs:", configs);
return true;
} catch (error) {
log.error("Error setting paint scale input configs:", error);
throw error;
}
};
const SettingsPaintScaleInputPathSet = async (
_event: IpcMainInvokeEvent,
): Promise<string | null> => {
try {
const mainWindow = getMainWindow();
if (!mainWindow) {
log.error("No main window found when trying to open dialog");
return null;
}
const result = await dialog.showOpenDialog(mainWindow, {
properties: ["openDirectory"],
});
if (result.canceled) {
log.debug("Paint scale input path selection canceled");
return null;
}
const path = result.filePaths[0];
log.debug("Selected paint scale input path:", path);
return path;
} catch (error) {
log.error("Error setting paint scale input path:", error);
throw error;
}
};
const SettingsPaintScaleOutputConfigsGet = async (
_event: IpcMainInvokeEvent,
): Promise<PaintScaleConfig[]> => {
try {
const configs = Store.get("settings.paintScaleOutputConfigs") as PaintScaleConfig[];
log.debug("Retrieved paint scale output configs:", configs);
return configs || [];
} catch (error) {
log.error("Error getting paint scale output configs:", error);
throw error;
}
};
const SettingsPaintScaleOutputConfigsSet = async (
_event: IpcMainInvokeEvent,
configs: PaintScaleConfig[],
): Promise<boolean> => {
try {
Store.set("settings.paintScaleOutputConfigs", configs);
log.debug("Saved paint scale output configs:", configs);
return true;
} catch (error) {
log.error("Error setting paint scale output configs:", error);
throw error;
}
};
const SettingsPaintScaleOutputPathSet = async (
_event: IpcMainInvokeEvent,
): Promise<string | null> => {
try {
const mainWindow = getMainWindow();
if (!mainWindow) {
log.error("No main window found when trying to open dialog");
return null;
}
const result = await dialog.showOpenDialog(mainWindow, {
properties: ["openDirectory"],
});
if (result.canceled) {
log.debug("Paint scale output path selection canceled");
return null;
}
const path = result.filePaths[0];
log.debug("Selected paint scale output path:", path);
return path;
} catch (error) {
log.error("Error setting paint scale output path:", error);
throw error;
}
};
export {
SettingsPpcFilePathGet,
SettingsPpcFilePathSet,
@@ -118,4 +249,10 @@ export {
SettingsWatcherPollingSet,
SettingEmsOutFilePathGet,
SettingEmsOutFilePathSet,
};
SettingsPaintScaleInputConfigsGet,
SettingsPaintScaleInputConfigsSet,
SettingsPaintScaleInputPathSet,
SettingsPaintScaleOutputConfigsGet,
SettingsPaintScaleOutputConfigsSet,
SettingsPaintScaleOutputPathSet,
};

View File

@@ -0,0 +1,157 @@
// renderer/Settings.PaintScaleInputPaths.tsx
import { FolderOpenFilled } from "@ant-design/icons";
import { Button, Card, Input, Select, Space, Table } from "antd";
import { FC, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import ipcTypes from "../../../../util/ipcTypes.json";
interface PaintScaleConfig {
id: string;
path: string | null;
type: PaintScaleType;
}
enum PaintScaleType {
PPG = "PPG",
SHERWIN = "SHERWIN",
AKZO = "AKZO",
}
const paintScaleTypeOptions = Object.values(PaintScaleType).map((type) => ({
value: type,
label: type,
}));
const SettingsPaintScaleInputPaths: FC = () => {
const { t } = useTranslation();
const [paintScaleConfigs, setPaintScaleConfigs] = useState<PaintScaleConfig[]>([]);
// Load paint scale input configs from store on mount
useEffect(() => {
window.electron.ipcRenderer
.invoke(ipcTypes.toMain.settings.paintScale.getInputConfigs)
.then((configs: PaintScaleConfig[]) => {
setPaintScaleConfigs(configs || []);
})
.catch((error) => {
console.error("Failed to load paint scale input configs:", error);
});
}, []);
// Handle adding a new paint scale config
const handleAddConfig = () => {
const newConfig: PaintScaleConfig = {
id: Date.now().toString(),
path: null,
type: PaintScaleType.PPG,
};
const updatedConfigs = [...paintScaleConfigs, newConfig];
setPaintScaleConfigs(updatedConfigs);
saveConfigs(updatedConfigs);
};
// Handle removing a config
const handleRemoveConfig = (id: string) => {
const updatedConfigs = paintScaleConfigs.filter((config) => config.id !== id);
setPaintScaleConfigs(updatedConfigs);
saveConfigs(updatedConfigs);
};
// Handle path selection
const handlePathChange = (id: string) => {
window.electron.ipcRenderer
.invoke(ipcTypes.toMain.settings.paintScale.setInputPath, id)
.then((path: string | null) => {
if (path) {
const updatedConfigs = paintScaleConfigs.map((config) =>
config.id === id ? { ...config, path } : config,
);
setPaintScaleConfigs(updatedConfigs);
saveConfigs(updatedConfigs);
}
})
.catch((error) => {
console.error("Failed to set paint scale input path:", error);
});
};
// Handle type change
const handleTypeChange = (id: string, type: PaintScaleType) => {
const updatedConfigs = paintScaleConfigs.map((config) =>
config.id === id ? { ...config, type } : config,
);
setPaintScaleConfigs(updatedConfigs);
saveConfigs(updatedConfigs);
};
// Save configs to store
const saveConfigs = (configs: PaintScaleConfig[]) => {
window.electron.ipcRenderer
.invoke(ipcTypes.toMain.settings.paintScale.setInputConfigs, configs)
.catch((error) => {
console.error("Failed to save paint scale input configs:", error);
});
};
// Table columns for paint scale configs
const columns = [
{
title: t("settings.labels.paintScalePath"),
dataIndex: "path",
key: "path",
render: (path: string | null, record: PaintScaleConfig) => (
<Space>
<Input
value={path || ""}
placeholder={t("settings.labels.paintScalePath")}
disabled
/>
<Button
onClick={() => handlePathChange(record.id)}
icon={<FolderOpenFilled />}
/>
</Space>
),
},
{
title: t("settings.labels.paintScaleType"),
dataIndex: "type",
key: "type",
render: (type: PaintScaleType, record: PaintScaleConfig) => (
<Select
value={type}
options={paintScaleTypeOptions}
onChange={(value) => handleTypeChange(record.id, value)}
style={{ width: 120 }}
/>
),
},
{
title: t("settings.labels.actions"),
key: "actions",
render: (_: any, record: PaintScaleConfig) => (
<Button danger onClick={() => handleRemoveConfig(record.id)}>
{t("settings.labels.remove")}
</Button>
),
},
];
return (
<Card title={t("settings.labels.paintScaleSettingsInput")}>
<Space direction="vertical" style={{ width: "100%" }}>
<Button type="primary" onClick={handleAddConfig}>
{t("settings.labels.addPaintScalePath")}
</Button>
<Table
dataSource={paintScaleConfigs}
columns={columns}
rowKey="id"
pagination={false}
/>
</Space>
</Card>
);
};
export default SettingsPaintScaleInputPaths;

View File

@@ -0,0 +1,157 @@
// renderer/Settings.PaintScaleOutputPaths.tsx
import { FolderOpenFilled } from "@ant-design/icons";
import { Button, Card, Input, Select, Space, Table } from "antd";
import { FC, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import ipcTypes from "../../../../util/ipcTypes.json";
interface PaintScaleConfig {
id: string;
path: string | null;
type: PaintScaleType;
}
enum PaintScaleType {
PPG = "PPG",
SHERWIN = "SHERWIN",
AKZO = "AKZO",
}
const paintScaleTypeOptions = Object.values(PaintScaleType).map((type) => ({
value: type,
label: type,
}));
const SettingsPaintScaleOutputPaths: FC = () => {
const { t } = useTranslation();
const [paintScaleConfigs, setPaintScaleConfigs] = useState<PaintScaleConfig[]>([]);
// Load paint scale output configs from store on mount
useEffect(() => {
window.electron.ipcRenderer
.invoke(ipcTypes.toMain.settings.paintScale.getOutputConfigs)
.then((configs: PaintScaleConfig[]) => {
setPaintScaleConfigs(configs || []);
})
.catch((error) => {
console.error("Failed to load paint scale output configs:", error);
});
}, []);
// Handle adding a new paint scale config
const handleAddConfig = () => {
const newConfig: PaintScaleConfig = {
id: Date.now().toString(),
path: null,
type: PaintScaleType.PPG,
};
const updatedConfigs = [...paintScaleConfigs, newConfig];
setPaintScaleConfigs(updatedConfigs);
saveConfigs(updatedConfigs);
};
// Handle removing a config
const handleRemoveConfig = (id: string) => {
const updatedConfigs = paintScaleConfigs.filter((config) => config.id !== id);
setPaintScaleConfigs(updatedConfigs);
saveConfigs(updatedConfigs);
};
// Handle path selection
const handlePathChange = (id: string) => {
window.electron.ipcRenderer
.invoke(ipcTypes.toMain.settings.paintScale.setOutputPath, id)
.then((path: string | null) => {
if (path) {
const updatedConfigs = paintScaleConfigs.map((config) =>
config.id === id ? { ...config, path } : config,
);
setPaintScaleConfigs(updatedConfigs);
saveConfigs(updatedConfigs);
}
})
.catch((error) => {
console.error("Failed to set paint scale output path:", error);
});
};
// Handle type change
const handleTypeChange = (id: string, type: PaintScaleType) => {
const updatedConfigs = paintScaleConfigs.map((config) =>
config.id === id ? { ...config, type } : config,
);
setPaintScaleConfigs(updatedConfigs);
saveConfigs(updatedConfigs);
};
// Save configs to store
const saveConfigs = (configs: PaintScaleConfig[]) => {
window.electron.ipcRenderer
.invoke(ipcTypes.toMain.settings.paintScale.setOutputConfigs, configs)
.catch((error) => {
console.error("Failed to save paint scale output configs:", error);
});
};
// Table columns for paint scale configs
const columns = [
{
title: t("settings.labels.paintScalePath"),
dataIndex: "path",
key: "path",
render: (path: string | null, record: PaintScaleConfig) => (
<Space>
<Input
value={path || ""}
placeholder={t("settings.labels.paintScalePath")}
disabled
/>
<Button
onClick={() => handlePathChange(record.id)}
icon={<FolderOpenFilled />}
/>
</Space>
),
},
{
title: t("settings.labels.paintScaleType"),
dataIndex: "type",
key: "type",
render: (type: PaintScaleType, record: PaintScaleConfig) => (
<Select
value={type}
options={paintScaleTypeOptions}
onChange={(value) => handleTypeChange(record.id, value)}
style={{ width: 120 }}
/>
),
},
{
title: t("settings.labels.actions"),
key: "actions",
render: (_: any, record: PaintScaleConfig) => (
<Button danger onClick={() => handleRemoveConfig(record.id)}>
{t("settings.labels.remove")}
</Button>
),
},
];
return (
<Card title={t("settings.labels.paintScaleSettingsOutput")}>
<Space direction="vertical" style={{ width: "100%" }}>
<Button type="primary" onClick={handleAddConfig}>
{t("settings.labels.addPaintScalePath")}
</Button>
<Table
dataSource={paintScaleConfigs}
columns={columns}
rowKey="id"
pagination={false}
/>
</Space>
</Card>
);
};
export default SettingsPaintScaleOutputPaths;

View File

@@ -1,3 +1,4 @@
// renderer/Settings.tsx
import { Col, Row } from "antd";
import { FC } from "react";
import SettingsWatchedPaths from "./Settings.WatchedPaths";
@@ -5,30 +6,40 @@ import SettingsWatcher from "./Settings.Watcher";
import Welcome from "../Welcome/Welcome";
import SettingsPpcFilepath from "./Settings.PpcFilePath";
import SettingsEmsOutFilePath from "./Settings.EmsOutFilePath";
import SettingsPaintScaleInputPaths from "./Settings.PaintScaleInputPaths";
import SettingsPaintScaleOutputPaths from "./Settings.PaintScaleOutputPaths";
const colSpans = {
md: 12,
sm: 24,
md: 12, // Two columns on medium screens and above
sm: 24, // One column on small screens
};
const Settings: FC = () => {
return (
<Row gutter={[16, 16]}>
<Col span={24}>
<Welcome />
</Col>
<Col {...colSpans}>
<SettingsWatchedPaths />
</Col>
<Col {...colSpans}>
<SettingsWatcher />
</Col>
<Col {...colSpans}>
<SettingsPpcFilepath />
</Col>
<Col {...colSpans}>
<SettingsEmsOutFilePath />
</Col>
</Row>
);
return (
<Row gutter={[16, 16]}>
<Col span={24}>
<Welcome />
</Col>
<Col {...colSpans}>
<SettingsWatchedPaths />
</Col>
<Col {...colSpans}>
<SettingsWatcher />
</Col>
<Col {...colSpans}>
<SettingsPpcFilepath />
</Col>
<Col {...colSpans}>
<SettingsEmsOutFilePath />
</Col>
<Col {...colSpans}>
<SettingsPaintScaleInputPaths />
</Col>
<Col {...colSpans}>
<SettingsPaintScaleOutputPaths />
</Col>
</Row>
);
};
export default Settings;
export default Settings;

View File

@@ -27,6 +27,14 @@
"watcher": {
"getpolling": "toMain_settings_watcher_getpolling",
"setpolling": "toMain_settings_watcher_setpolling"
},
"paintScale": {
"getInputConfigs": "toMain_settings_paintScale_getInputConfigs",
"setInputConfigs": "toMain_settings_paintScale_setInputConfigs",
"setInputPath": "toMain_settings_paintScale_setInputPath",
"getOutputConfigs": "toMain_settings_paintScale_getOutputConfigs",
"setOutputConfigs": "toMain_settings_paintScale_setOutputConfigs",
"setOutputPath": "toMain_settings_paintScale_setOutputPath"
}
},
"user": {
@@ -58,4 +66,4 @@
"showErrorMessage": "toRenderer_general_showErrorMessage"
}
}
}
}

View File

@@ -34,7 +34,14 @@
"watchedpaths": "Watched Paths",
"watchermodepolling": "Polling",
"watchermoderealtime": "Real Time",
"watcherstatus": "Watcher Status"
"watcherstatus": "Watcher Status",
"paintScaleSettingsInput": "Paint Scale Settings Input",
"paintScaleSettingsOutput": "Paint Scale Settings Output",
"paintScalePath": "Paint Scale Path",
"paintScaleType": "Paint Scale Type",
"addPaintScalePath": "Add Paint Scale Path",
"remove": "Remove",
"actions": "Actions"
}
},
"title": {