Add watcher status and additional typing.
This commit is contained in:
17
.prettierrc.js
Normal file
17
.prettierrc.js
Normal file
@@ -0,0 +1,17 @@
|
||||
export default {
|
||||
printWidth: 120,
|
||||
useTabs: false,
|
||||
tabWidth: 2,
|
||||
trailingComma: "none",
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
bracketSpacing: true,
|
||||
arrowParens: "always",
|
||||
jsxSingleQuote: false,
|
||||
bracketSameLine: false,
|
||||
endOfLine: "lf"
|
||||
// importOrder: ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
|
||||
// importOrderSeparation: true,
|
||||
// importOrderSortSpecifiers: true
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import tseslint from "@electron-toolkit/eslint-config-ts";
|
||||
import eslintConfigPrettier from "@electron-toolkit/eslint-config-prettier";
|
||||
import tseslint from "@electron-toolkit/eslint-config-ts";
|
||||
import eslintPluginReact from "eslint-plugin-react";
|
||||
import eslintPluginReactHooks from "eslint-plugin-react-hooks";
|
||||
import eslintPluginReactRefresh from "eslint-plugin-react-refresh";
|
||||
@@ -27,5 +27,5 @@ export default tseslint.config(
|
||||
...eslintPluginReactRefresh.configs.vite.rules,
|
||||
},
|
||||
},
|
||||
eslintConfigPrettier
|
||||
eslintConfigPrettier,
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { DecodedStl, DecodedStlLine } from "./decode-stl.interface";
|
||||
|
||||
const DecodeStl = async (
|
||||
extensionlessFilePath: string
|
||||
extensionlessFilePath: string,
|
||||
): Promise<DecodedStl> => {
|
||||
let dbf: DBFFile | null = null;
|
||||
try {
|
||||
@@ -47,7 +47,7 @@ const DecodeStl = async (
|
||||
"TTL_TYPAMT",
|
||||
"TTL_HRS",
|
||||
"TTL_AMT",
|
||||
])
|
||||
]),
|
||||
);
|
||||
//Apply line by line adjustments.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface DecodedVeh {
|
||||
impact2?: string;
|
||||
};
|
||||
// Complete vehicle data object
|
||||
vehicle: { data: VehicleRecordInterface };
|
||||
vehicle?: { data: VehicleRecordInterface };
|
||||
}
|
||||
|
||||
export interface VehicleRecordInterface {
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
import { UUID } from "crypto";
|
||||
import log from "electron-log/main";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import client from "../graphql/graphql-client";
|
||||
import {
|
||||
QUERY_JOB_BY_CLM_NO_TYPED,
|
||||
QUERY_VEHICLE_BY_VIN_TYPED,
|
||||
QueryJobByClmNoResult,
|
||||
VehicleQueryResult,
|
||||
} from "../graphql/queries";
|
||||
import store from "../store/store";
|
||||
import DecodeAD1 from "./decode-ad1";
|
||||
import { DecodedAd1 } from "./decode-ad1.interface";
|
||||
import DecodeAD2 from "./decode-ad2";
|
||||
import { DecodedAD2 } from "./decode-ad2.interface";
|
||||
import DecodeEnv from "./decode-env";
|
||||
import { DecodedEnv } from "./decode-env.interface";
|
||||
import DecodeLin from "./decode-lin";
|
||||
import { DecodedLin } from "./decode-lin.interface";
|
||||
import DecodePfh from "./decode-pfh";
|
||||
@@ -25,17 +37,12 @@ import DecodeTtl from "./decode-ttl";
|
||||
import { DecodedTtl } from "./decode-ttl.interface";
|
||||
import DecodeVeh from "./decode-veh";
|
||||
import { DecodedVeh } from "./decode-veh.interface";
|
||||
import { DecodedEnv } from "./decode-env.interface";
|
||||
import DecodeEnv from "./decode-env";
|
||||
import fs from "fs";
|
||||
import store from "../store/store";
|
||||
import client from "../graphql/graphql-client";
|
||||
|
||||
async function ImportJob(filepath: string): Promise<void> {
|
||||
const parsedFilePath = path.parse(filepath);
|
||||
const extensionlessFilePath = path.join(
|
||||
parsedFilePath.dir,
|
||||
parsedFilePath.name
|
||||
parsedFilePath.name,
|
||||
);
|
||||
log.debug("Importing Job", extensionlessFilePath);
|
||||
|
||||
@@ -56,7 +63,7 @@ async function ImportJob(filepath: string): Promise<void> {
|
||||
const ttl: DecodedTtl = await DecodeTtl(extensionlessFilePath);
|
||||
const pfp: DecodedPfp = await DecodePfp(extensionlessFilePath);
|
||||
|
||||
const jobObject = {
|
||||
const jobObject: RawJobDataObject = {
|
||||
...env,
|
||||
...ad1,
|
||||
...ad2,
|
||||
@@ -96,17 +103,7 @@ async function ImportJob(filepath: string): Promise<void> {
|
||||
//Build the request object
|
||||
|
||||
//Insert it
|
||||
const newAvailableJob = {
|
||||
// newJob.uploaded_by = Auth.authlink.User.Email;
|
||||
// newJob.bodyshopid = AppMetaData.ActiveShopId;
|
||||
// newJob.cieca_id = item.Job.ciecaid;
|
||||
// newJob.est_data = item.Job;
|
||||
// newJob.ownr_name = item.Job.ownr_fn?.Value + " " + item.Job.ownr_ln?.Value + " " + item.Job.ownr_co_nm?.Value;
|
||||
// newJob.ins_co_nm = item.Job.ins_co_nm?.Value;
|
||||
// newJob.vehicle_info = item.Job.vehicle.data.v_model_yr?.Value + " " + item.Job.vehicle.data.v_make_desc?.Value + " " + item.Job.vehicle.data.v_model_desc?.Value;
|
||||
// newJob.clm_no = item.Job.clm_no?.Value;
|
||||
// newJob.clm_amt = item.Job.clm_total?.Value;
|
||||
// newJob.source_system = item.Job.source_system?.Value;
|
||||
const newAvailableJob: AvailableJobSchema = {
|
||||
uploaded_by: store.get("app.user.email"),
|
||||
bodyshopid: store.get("app.bodyshop.id"),
|
||||
cieca_id: jobObject.ciecaid,
|
||||
@@ -117,30 +114,68 @@ async function ImportJob(filepath: string): Promise<void> {
|
||||
clm_no: jobObject.clm_no,
|
||||
clm_amt: jobObject.clm_total,
|
||||
// source_system: jobObject.source_system, //TODO: Add back source system if needed.
|
||||
issupplement: false,
|
||||
jobid: null,
|
||||
};
|
||||
|
||||
const existingVehicleId: uuid = await client.query ()
|
||||
// var vehuuid = await Utils.Queries.VehicleQueries.GetVehicleUuidByVin(item?.Job?.vehicle?.data?.v_vin?.Value ?? "");
|
||||
// if (!string.IsNullOrEmpty(vehuuid))
|
||||
// {
|
||||
// newJob.est_data.vehicle = null;
|
||||
// newJob.est_data.vehicleid = vehuuid;
|
||||
// }
|
||||
const existingVehicleRecord: VehicleQueryResult = await client.request(
|
||||
QUERY_VEHICLE_BY_VIN_TYPED,
|
||||
{
|
||||
vin: jobObject.v_vin,
|
||||
},
|
||||
);
|
||||
|
||||
if (existingVehicleRecord.vehicles.length > 0) {
|
||||
delete newAvailableJob.est_data.vehicle;
|
||||
newAvailableJob.est_data.vehicleid = existingVehicleRecord.vehicles[0].id;
|
||||
}
|
||||
|
||||
// string jobId = await Utils.Queries.JobsQueries.CheckSupplementByClaimNo(item.Job.clm_no?.Value ?? "");
|
||||
console.log(newAvailableJob);
|
||||
|
||||
// if (!string.IsNullOrEmpty(jobId))
|
||||
// {
|
||||
// newJob.issupplement = true;
|
||||
// newJob.jobid = jobId;
|
||||
// };
|
||||
|
||||
//Check if the vehicle exists, if it does, use that UUID, if not, keep it to insert it.
|
||||
const existingJobRecord: QueryJobByClmNoResult = await client.request(
|
||||
QUERY_JOB_BY_CLM_NO_TYPED,
|
||||
{ clm_no: jobObject.clm_no },
|
||||
);
|
||||
|
||||
if (existingJobRecord.jobs.length > 0) {
|
||||
newAvailableJob.issupplement = true;
|
||||
newAvailableJob.jobid = existingJobRecord.jobs[0].id;
|
||||
}
|
||||
} catch (error) {
|
||||
log.error("Error encountered while decoding job. ", errorTypeCheck(error));
|
||||
}
|
||||
}
|
||||
|
||||
export default ImportJob;
|
||||
|
||||
export interface RawJobDataObject
|
||||
extends DecodedEnv,
|
||||
DecodedAd1,
|
||||
DecodedAD2,
|
||||
DecodedVeh,
|
||||
DecodedLin,
|
||||
DecodedPfh,
|
||||
DecodedPfl,
|
||||
DecodedPft,
|
||||
DecodedPfm,
|
||||
DecodedPfo,
|
||||
DecodedStl,
|
||||
DecodedTtl,
|
||||
DecodedPfp {
|
||||
vehicleid?: UUID;
|
||||
}
|
||||
|
||||
export interface AvailableJobSchema {
|
||||
uploaded_by: string;
|
||||
bodyshopid: UUID;
|
||||
cieca_id?: string;
|
||||
est_data: RawJobDataObject;
|
||||
ownr_name: string;
|
||||
ins_co_nm?: string;
|
||||
vehicle_info: string;
|
||||
clm_no?: string;
|
||||
clm_amt: number;
|
||||
source_system?: string | null;
|
||||
issupplement: boolean;
|
||||
jobid: UUID | null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { UUID } from "crypto";
|
||||
import { parse, TypedQueryDocumentNode } from "graphql";
|
||||
import { gql } from "graphql-request";
|
||||
|
||||
import { AvailableJobSchema } from "../decoder/decoder";
|
||||
// Define types for the query result and variables
|
||||
export interface ActiveBodyshopQueryResult {
|
||||
bodyshops: Array<{
|
||||
@@ -9,10 +10,8 @@ export interface ActiveBodyshopQueryResult {
|
||||
region_config: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
// No variables needed for this query
|
||||
interface ActiveBodyshopQueryVariables {}
|
||||
|
||||
// Transform the string query into a TypedQueryDocumentNode
|
||||
export const QUERY_ACTIVE_BODYSHOP_TYPED: TypedQueryDocumentNode<
|
||||
ActiveBodyshopQueryResult,
|
||||
@@ -25,7 +24,10 @@ export const QUERY_ACTIVE_BODYSHOP_TYPED: TypedQueryDocumentNode<
|
||||
region_config
|
||||
}
|
||||
}
|
||||
`);
|
||||
`) as TypedQueryDocumentNode<
|
||||
ActiveBodyshopQueryResult,
|
||||
ActiveBodyshopQueryVariables
|
||||
>;
|
||||
|
||||
export interface MasterdataQueryResult {
|
||||
masterdata: Array<{
|
||||
@@ -33,11 +35,9 @@ export interface MasterdataQueryResult {
|
||||
key: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface MasterdataQueryVariables {
|
||||
key: string;
|
||||
}
|
||||
|
||||
export const QUERY_MASTERDATA_TYPED: TypedQueryDocumentNode<
|
||||
MasterdataQueryResult,
|
||||
MasterdataQueryVariables
|
||||
@@ -48,19 +48,16 @@ export const QUERY_MASTERDATA_TYPED: TypedQueryDocumentNode<
|
||||
key
|
||||
}
|
||||
}
|
||||
`);
|
||||
`) as TypedQueryDocumentNode<MasterdataQueryResult, MasterdataQueryVariables>;
|
||||
|
||||
export interface VehicleQueryResult {
|
||||
masterdata: Array<{
|
||||
value: string;
|
||||
key: string;
|
||||
vehicles: Array<{
|
||||
id: UUID;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface VehicleQueryVariables {
|
||||
vin: string;
|
||||
}
|
||||
|
||||
export const QUERY_VEHICLE_BY_VIN_TYPED: TypedQueryDocumentNode<
|
||||
VehicleQueryResult,
|
||||
VehicleQueryVariables
|
||||
@@ -70,4 +67,62 @@ export const QUERY_VEHICLE_BY_VIN_TYPED: TypedQueryDocumentNode<
|
||||
id
|
||||
}
|
||||
}
|
||||
`);
|
||||
`) as TypedQueryDocumentNode<VehicleQueryResult, VehicleQueryVariables>;
|
||||
|
||||
export interface QueryJobByClmNoResult {
|
||||
jobs: Array<{
|
||||
id: UUID;
|
||||
}>;
|
||||
}
|
||||
export interface QueryJobByClmNoVariables {
|
||||
clm_no: string;
|
||||
}
|
||||
export const QUERY_JOB_BY_CLM_NO_TYPED: TypedQueryDocumentNode<
|
||||
QueryJobByClmNoResult,
|
||||
QueryJobByClmNoVariables
|
||||
> = parse(gql`
|
||||
query QUERY_JOB_BY_CLM_NO($clm_no: String!) {
|
||||
jobs(where: { clm_no: { _eq: $clm_no } }) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`) as TypedQueryDocumentNode<QueryJobByClmNoResult, QueryJobByClmNoVariables>;
|
||||
|
||||
export interface InsertAvailableJobResult {
|
||||
returning: Array<{
|
||||
id: UUID;
|
||||
}>;
|
||||
}
|
||||
export interface InsertAvailableJobVariables {
|
||||
jobInput: Array<AvailableJobSchema>;
|
||||
}
|
||||
export const INSERT_AVAILABLE_JOB_TYPED: TypedQueryDocumentNode<
|
||||
InsertAvailableJobResult,
|
||||
InsertAvailableJobVariables
|
||||
> = parse(gql`
|
||||
mutation INSERT_AVAILABLE_JOB($jobInput: [available_jobs_insert_input!]!) {
|
||||
insert_available_jobs(
|
||||
objects: $jobInput
|
||||
on_conflict: {
|
||||
constraint: available_jobs_clm_no_bodyshopid_key
|
||||
update_columns: [
|
||||
clm_amt
|
||||
cieca_id
|
||||
est_data
|
||||
issupplement
|
||||
ownr_name
|
||||
source_system
|
||||
supplement_number
|
||||
vehicle_info
|
||||
]
|
||||
}
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`) as TypedQueryDocumentNode<
|
||||
InsertAvailableJobResult,
|
||||
InsertAvailableJobVariables
|
||||
>;
|
||||
|
||||
@@ -3,7 +3,7 @@ import log from "electron-log/main";
|
||||
import path from "path";
|
||||
import ipcTypes from "../../util/ipcTypes.json";
|
||||
import ImportJob from "../decoder/decoder";
|
||||
import { StartWatcher } from "../watcher/watcher";
|
||||
import { StartWatcher, StopWatcher } from "../watcher/watcher";
|
||||
import {
|
||||
SettingsWatchedFilePathsAdd,
|
||||
SettingsWatchedFilePathsGet,
|
||||
@@ -83,4 +83,8 @@ ipcMain.on(ipcTypes.toMain.watcher.start, () => {
|
||||
StartWatcher();
|
||||
});
|
||||
|
||||
ipcMain.on(ipcTypes.toMain.watcher.stop, () => {
|
||||
StopWatcher();
|
||||
});
|
||||
|
||||
logIpcMessages();
|
||||
|
||||
@@ -2,6 +2,7 @@ import { BrowserWindow, dialog, IpcMainInvokeEvent } from "electron";
|
||||
import log from "electron-log/main";
|
||||
import _ from "lodash";
|
||||
import Store from "../store/store";
|
||||
import { addWatcherPath, removeWatcherPath, watcher } from "../watcher/watcher";
|
||||
|
||||
const SettingsWatchedFilePathsAdd = async (): Promise<string[]> => {
|
||||
const mainWindow = BrowserWindow.getAllWindows()[0]; //TODO: Filter to only main window once a proper key has been set.
|
||||
@@ -18,6 +19,7 @@ const SettingsWatchedFilePathsAdd = async (): Promise<string[]> => {
|
||||
"settings.filepaths",
|
||||
_.union(result.filePaths, Store.get("settings.filepaths"))
|
||||
);
|
||||
addWatcherPath(result.filePaths);
|
||||
}
|
||||
|
||||
return Store.get("settings.filepaths");
|
||||
@@ -30,7 +32,7 @@ const SettingsWatchedFilePathsRemove = async (
|
||||
"settings.filepaths",
|
||||
_.without(Store.get("settings.filepaths"), path)
|
||||
);
|
||||
|
||||
removeWatcherPath(path);
|
||||
return Store.get("settings.filepaths");
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import chokidar, { FSWatcher } from "chokidar";
|
||||
import { Notification } from "electron";
|
||||
import { BrowserWindow, Notification } from "electron";
|
||||
import log from "electron-log/main";
|
||||
import path from "path";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import store from "../store/store";
|
||||
import ipcTypes from "../../util/ipcTypes.json";
|
||||
import ImportJob from "../decoder/decoder";
|
||||
import store from "../store/store";
|
||||
|
||||
let watcher: FSWatcher;
|
||||
|
||||
@@ -67,6 +68,10 @@ async function StartWatcher(): Promise<boolean> {
|
||||
// })
|
||||
.on("error", function (error) {
|
||||
log.error("Error in Watcher", errorTypeCheck(error));
|
||||
// mainWindow.webContents.send(
|
||||
// ipcTypes.toRenderer.watcher.error,
|
||||
// errorTypeCheck(error)
|
||||
// );
|
||||
})
|
||||
.on("ready", onWatcherReady)
|
||||
.on("raw", function (event, path, details) {
|
||||
@@ -77,24 +82,37 @@ async function StartWatcher(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
function removeWatcherPath(path: string): void {
|
||||
watcher.unwatch(path);
|
||||
log.debug(`Stopped watching path: ${path}`);
|
||||
}
|
||||
|
||||
function addWatcherPath(path: string | string[]): void {
|
||||
watcher.add(path);
|
||||
log.debug(`Started watching path: ${path}`);
|
||||
}
|
||||
|
||||
function onWatcherReady(): void {
|
||||
log.info("Watcher ready!");
|
||||
// const b = BrowserWindow.getAllWindows()[0];
|
||||
// b.webContents.send(ipcTypes.default.fileWatcher.toRenderer.startSuccess);
|
||||
const mainWindow = BrowserWindow.getAllWindows()[0]; //TODO: Filter to only main window once a proper key has been set.
|
||||
|
||||
new Notification({
|
||||
title: "Watcher Started",
|
||||
body: "Newly exported estimates will be automatically uploaded.",
|
||||
}).show();
|
||||
log.info("Confirmed watched paths:", watcher.getWatched());
|
||||
mainWindow.webContents.send(ipcTypes.toRenderer.watcher.started);
|
||||
}
|
||||
|
||||
async function StopWatcher(): Promise<boolean> {
|
||||
const mainWindow = BrowserWindow.getAllWindows()[0]; //TODO: Filter to only main window once a proper key has been set.
|
||||
|
||||
if (watcher) {
|
||||
await watcher.close();
|
||||
log.info("Watcher stopped.");
|
||||
mainWindow.webContents.send(ipcTypes.toRenderer.watcher.stopped);
|
||||
|
||||
new Notification({
|
||||
title: "RPS Watcher Stopped",
|
||||
title: "Watcher Stopped",
|
||||
body: "Estimates will not be automatically uploaded.",
|
||||
}).show();
|
||||
return true;
|
||||
@@ -107,4 +125,10 @@ async function HandleNewFile(path): Promise<void> {
|
||||
log.log("Received a new file", path);
|
||||
}
|
||||
|
||||
export { StartWatcher, StopWatcher, watcher };
|
||||
export {
|
||||
StartWatcher,
|
||||
StopWatcher,
|
||||
watcher,
|
||||
removeWatcherPath,
|
||||
addWatcherPath,
|
||||
};
|
||||
|
||||
@@ -1,16 +1,50 @@
|
||||
import { Button } from "antd";
|
||||
import {
|
||||
CheckCircleOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import {
|
||||
selectWatcherError,
|
||||
selectWatcherStatus,
|
||||
} from "@renderer/redux/app.slice";
|
||||
import { useAppDispatch, useAppSelector } from "@renderer/redux/reduxHooks";
|
||||
import { Button, Space } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ipcTypes from "../../../../util/ipcTypes.json";
|
||||
|
||||
const SettingsWatcher: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const isWatcherStarted = useAppSelector(selectWatcherStatus);
|
||||
const watcherError = useAppSelector(selectWatcherError);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleStart = (): void => {
|
||||
window.electron.ipcRenderer.send(ipcTypes.toMain.watcher.start);
|
||||
};
|
||||
|
||||
const handleStop = (): void => {
|
||||
window.electron.ipcRenderer.send(ipcTypes.toMain.watcher.stop);
|
||||
};
|
||||
|
||||
return (
|
||||
<Button onClick={handleStart}>{t("settings.actions.startwatcher")}</Button>
|
||||
<>
|
||||
<Button onClick={handleStart}>
|
||||
{t("settings.actions.startwatcher")}
|
||||
</Button>
|
||||
<Button onClick={handleStop}>{t("settings.actions.stopwatcher")}</Button>
|
||||
{isWatcherStarted}
|
||||
{watcherError}
|
||||
{isWatcherStarted ? (
|
||||
<Space>
|
||||
<CheckCircleOutlined style={{ color: "green" }} />
|
||||
{t("settings.labels.started")}
|
||||
</Space>
|
||||
) : (
|
||||
<Space>
|
||||
<ExclamationCircleOutlined style={{ color: "tomato" }} />
|
||||
{t("settings.labels.stopped")}
|
||||
</Space>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default SettingsWatcher;
|
||||
|
||||
@@ -1,46 +1,58 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import log from "electron-log/renderer";
|
||||
import type { RootState } from "./redux-store";
|
||||
|
||||
// Define a type for the slice state
|
||||
interface AppState {
|
||||
value: number;
|
||||
watcher: {
|
||||
started: boolean;
|
||||
error: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
// Define the initial state using that type
|
||||
const initialState: AppState = {
|
||||
value: 0,
|
||||
watcher: {
|
||||
started: false,
|
||||
error: null,
|
||||
},
|
||||
};
|
||||
|
||||
export const appSlice = createSlice({
|
||||
name: "counter",
|
||||
name: "app",
|
||||
// `createSlice` will infer the state type from the `initialState` argument
|
||||
initialState,
|
||||
reducers: {
|
||||
increment: (state) => {
|
||||
state.value += 1;
|
||||
watcherStarted: (state) => {
|
||||
state.watcher.started = true;
|
||||
},
|
||||
decrement: (state) => {
|
||||
state.value -= 1;
|
||||
watcherStopped: (state) => {
|
||||
state.watcher.started = false;
|
||||
},
|
||||
// Use the PayloadAction type to declare the contents of `action.payload`
|
||||
incrementByAmount: (state, action: PayloadAction<number>) => {
|
||||
state.value += action.payload;
|
||||
watcherError: (state, action: PayloadAction<string>) => {
|
||||
state.watcher.error = action.payload;
|
||||
state.watcher.started = false;
|
||||
log.error("[Redux] AppSlice: Watcher Error", action.payload);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { increment, decrement, incrementByAmount } = appSlice.actions;
|
||||
export const { watcherError, watcherStarted, watcherStopped } =
|
||||
appSlice.actions;
|
||||
|
||||
// Other code such as selectors can use the imported `RootState` type
|
||||
export const selectCount = (state: RootState): number => state.app.value;
|
||||
export const selectWatcherStatus = (state: RootState): boolean =>
|
||||
state.app.watcher.started;
|
||||
|
||||
export const selectWatcherError = (state: RootState): string | null =>
|
||||
state.app.watcher.error;
|
||||
|
||||
//Async Functions - Thunks
|
||||
// Define a thunk that dispatches those action creators
|
||||
const fetchUsers = () => async (dispatch) => {
|
||||
dispatch(increment());
|
||||
//dispatch(watcherStarted());
|
||||
//Some sort of async action.
|
||||
|
||||
dispatch(incrementByAmount(100));
|
||||
// dispatch(incrementByAmount(100));
|
||||
};
|
||||
|
||||
export default appSlice.reducer;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import type { TypedUseSelectorHook } from "react-redux";
|
||||
import { useDispatch, useSelector, useStore } from "react-redux";
|
||||
import type { AppDispatch, AppStore, RootState } from "./redux-store";
|
||||
|
||||
import store from "./redux-store";
|
||||
|
||||
//Use these custom hooks to access the Redux store from your component with type safety.
|
||||
export const useAppDispatch: () => AppDispatch = useDispatch;
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
export const useAppDispatch = useDispatch.withTypes<AppDispatch>(); // Ex
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||
export const useAppStore: () => AppStore = useStore;
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
//Set up all of the IPC handlers.
|
||||
import {
|
||||
watcherError,
|
||||
watcherStarted,
|
||||
watcherStopped,
|
||||
} from "@renderer/redux/app.slice";
|
||||
import store from "@renderer/redux/redux-store";
|
||||
import ipcTypes from "../../../util/ipcTypes.json";
|
||||
import { auth } from "./firebase";
|
||||
|
||||
const ipcRenderer = window.electron.ipcRenderer;
|
||||
const dispatch = store.dispatch;
|
||||
|
||||
ipcRenderer.on(
|
||||
ipcTypes.toRenderer.test,
|
||||
@@ -19,3 +26,29 @@ ipcRenderer.on(
|
||||
ipcRenderer.send(ipcTypes.toMain.user.getTokenResponse, token);
|
||||
}
|
||||
);
|
||||
|
||||
ipcRenderer.on(
|
||||
ipcTypes.toRenderer.watcher.started,
|
||||
(event: Electron.IpcRendererEvent, arg) => {
|
||||
console.log("Watcher has started");
|
||||
console.log(arg);
|
||||
dispatch(watcherStarted());
|
||||
}
|
||||
);
|
||||
|
||||
ipcRenderer.on(
|
||||
ipcTypes.toRenderer.watcher.stopped,
|
||||
(event: Electron.IpcRendererEvent, arg) => {
|
||||
console.log("Watcher has stopped");
|
||||
console.log(arg);
|
||||
dispatch(watcherStopped());
|
||||
}
|
||||
);
|
||||
ipcRenderer.on(
|
||||
ipcTypes.toRenderer.watcher.error,
|
||||
(event: Electron.IpcRendererEvent, error: string) => {
|
||||
console.log("Watcher has encountered an error");
|
||||
console.log(error);
|
||||
dispatch(watcherError(error));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
},
|
||||
"toRenderer": {
|
||||
"test": "toRenderer_test",
|
||||
"watcher": {
|
||||
"started": "toRenderer_watcher_started",
|
||||
"stopped": "toRenderer_watcher_stopped",
|
||||
"error": "toRenderer_watcher_error"
|
||||
},
|
||||
"user": {
|
||||
"getToken": "toRenderer_user_getToken"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,14 @@
|
||||
},
|
||||
"settings": {
|
||||
"actions": {
|
||||
"addpath": "Add path"
|
||||
"addpath": "Add path",
|
||||
"startwatcher": "Start Watcher",
|
||||
"stopwatcher": "Stop Watcher\n"
|
||||
},
|
||||
"labels": {
|
||||
"started": "Started",
|
||||
"stopped": "Stopped",
|
||||
"watcherstatus": "Watcher Status"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,76 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>startwatcher</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>stopwatcher</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>labels</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>started</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>stopped</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>watcherstatus</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.web.json" }]
|
||||
"references": [
|
||||
{ "path": "./tsconfig.node.json" },
|
||||
{ "path": "./tsconfig.web.json" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"tests/index.spec.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"composite": true,
|
||||
"types": ["electron-vite/node"]
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"src/util/**/*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"composite": true,
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": ".",
|
||||
|
||||
Reference in New Issue
Block a user