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 eslintConfigPrettier from "@electron-toolkit/eslint-config-prettier";
|
||||||
|
import tseslint from "@electron-toolkit/eslint-config-ts";
|
||||||
import eslintPluginReact from "eslint-plugin-react";
|
import eslintPluginReact from "eslint-plugin-react";
|
||||||
import eslintPluginReactHooks from "eslint-plugin-react-hooks";
|
import eslintPluginReactHooks from "eslint-plugin-react-hooks";
|
||||||
import eslintPluginReactRefresh from "eslint-plugin-react-refresh";
|
import eslintPluginReactRefresh from "eslint-plugin-react-refresh";
|
||||||
@@ -27,5 +27,5 @@ export default tseslint.config(
|
|||||||
...eslintPluginReactRefresh.configs.vite.rules,
|
...eslintPluginReactRefresh.configs.vite.rules,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
eslintConfigPrettier
|
eslintConfigPrettier,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import errorTypeCheck from "../../util/errorTypeCheck";
|
|||||||
import { DecodedStl, DecodedStlLine } from "./decode-stl.interface";
|
import { DecodedStl, DecodedStlLine } from "./decode-stl.interface";
|
||||||
|
|
||||||
const DecodeStl = async (
|
const DecodeStl = async (
|
||||||
extensionlessFilePath: string
|
extensionlessFilePath: string,
|
||||||
): Promise<DecodedStl> => {
|
): Promise<DecodedStl> => {
|
||||||
let dbf: DBFFile | null = null;
|
let dbf: DBFFile | null = null;
|
||||||
try {
|
try {
|
||||||
@@ -47,7 +47,7 @@ const DecodeStl = async (
|
|||||||
"TTL_TYPAMT",
|
"TTL_TYPAMT",
|
||||||
"TTL_HRS",
|
"TTL_HRS",
|
||||||
"TTL_AMT",
|
"TTL_AMT",
|
||||||
])
|
]),
|
||||||
);
|
);
|
||||||
//Apply line by line adjustments.
|
//Apply line by line adjustments.
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export interface DecodedVeh {
|
|||||||
impact2?: string;
|
impact2?: string;
|
||||||
};
|
};
|
||||||
// Complete vehicle data object
|
// Complete vehicle data object
|
||||||
vehicle: { data: VehicleRecordInterface };
|
vehicle?: { data: VehicleRecordInterface };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VehicleRecordInterface {
|
export interface VehicleRecordInterface {
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
|
import { UUID } from "crypto";
|
||||||
import log from "electron-log/main";
|
import log from "electron-log/main";
|
||||||
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
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 DecodeAD1 from "./decode-ad1";
|
||||||
import { DecodedAd1 } from "./decode-ad1.interface";
|
import { DecodedAd1 } from "./decode-ad1.interface";
|
||||||
import DecodeAD2 from "./decode-ad2";
|
import DecodeAD2 from "./decode-ad2";
|
||||||
import { DecodedAD2 } from "./decode-ad2.interface";
|
import { DecodedAD2 } from "./decode-ad2.interface";
|
||||||
|
import DecodeEnv from "./decode-env";
|
||||||
|
import { DecodedEnv } from "./decode-env.interface";
|
||||||
import DecodeLin from "./decode-lin";
|
import DecodeLin from "./decode-lin";
|
||||||
import { DecodedLin } from "./decode-lin.interface";
|
import { DecodedLin } from "./decode-lin.interface";
|
||||||
import DecodePfh from "./decode-pfh";
|
import DecodePfh from "./decode-pfh";
|
||||||
@@ -25,17 +37,12 @@ import DecodeTtl from "./decode-ttl";
|
|||||||
import { DecodedTtl } from "./decode-ttl.interface";
|
import { DecodedTtl } from "./decode-ttl.interface";
|
||||||
import DecodeVeh from "./decode-veh";
|
import DecodeVeh from "./decode-veh";
|
||||||
import { DecodedVeh } from "./decode-veh.interface";
|
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> {
|
async function ImportJob(filepath: string): Promise<void> {
|
||||||
const parsedFilePath = path.parse(filepath);
|
const parsedFilePath = path.parse(filepath);
|
||||||
const extensionlessFilePath = path.join(
|
const extensionlessFilePath = path.join(
|
||||||
parsedFilePath.dir,
|
parsedFilePath.dir,
|
||||||
parsedFilePath.name
|
parsedFilePath.name,
|
||||||
);
|
);
|
||||||
log.debug("Importing Job", extensionlessFilePath);
|
log.debug("Importing Job", extensionlessFilePath);
|
||||||
|
|
||||||
@@ -56,7 +63,7 @@ async function ImportJob(filepath: string): Promise<void> {
|
|||||||
const ttl: DecodedTtl = await DecodeTtl(extensionlessFilePath);
|
const ttl: DecodedTtl = await DecodeTtl(extensionlessFilePath);
|
||||||
const pfp: DecodedPfp = await DecodePfp(extensionlessFilePath);
|
const pfp: DecodedPfp = await DecodePfp(extensionlessFilePath);
|
||||||
|
|
||||||
const jobObject = {
|
const jobObject: RawJobDataObject = {
|
||||||
...env,
|
...env,
|
||||||
...ad1,
|
...ad1,
|
||||||
...ad2,
|
...ad2,
|
||||||
@@ -96,17 +103,7 @@ async function ImportJob(filepath: string): Promise<void> {
|
|||||||
//Build the request object
|
//Build the request object
|
||||||
|
|
||||||
//Insert it
|
//Insert it
|
||||||
const newAvailableJob = {
|
const newAvailableJob: AvailableJobSchema = {
|
||||||
// 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;
|
|
||||||
uploaded_by: store.get("app.user.email"),
|
uploaded_by: store.get("app.user.email"),
|
||||||
bodyshopid: store.get("app.bodyshop.id"),
|
bodyshopid: store.get("app.bodyshop.id"),
|
||||||
cieca_id: jobObject.ciecaid,
|
cieca_id: jobObject.ciecaid,
|
||||||
@@ -117,30 +114,68 @@ async function ImportJob(filepath: string): Promise<void> {
|
|||||||
clm_no: jobObject.clm_no,
|
clm_no: jobObject.clm_no,
|
||||||
clm_amt: jobObject.clm_total,
|
clm_amt: jobObject.clm_total,
|
||||||
// source_system: jobObject.source_system, //TODO: Add back source system if needed.
|
// source_system: jobObject.source_system, //TODO: Add back source system if needed.
|
||||||
|
issupplement: false,
|
||||||
|
jobid: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const existingVehicleId: uuid = await client.query ()
|
const existingVehicleRecord: VehicleQueryResult = await client.request(
|
||||||
// var vehuuid = await Utils.Queries.VehicleQueries.GetVehicleUuidByVin(item?.Job?.vehicle?.data?.v_vin?.Value ?? "");
|
QUERY_VEHICLE_BY_VIN_TYPED,
|
||||||
// if (!string.IsNullOrEmpty(vehuuid))
|
{
|
||||||
// {
|
vin: jobObject.v_vin,
|
||||||
// newJob.est_data.vehicle = null;
|
},
|
||||||
// newJob.est_data.vehicleid = vehuuid;
|
);
|
||||||
// }
|
|
||||||
|
|
||||||
|
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))
|
const existingJobRecord: QueryJobByClmNoResult = await client.request(
|
||||||
// {
|
QUERY_JOB_BY_CLM_NO_TYPED,
|
||||||
// newJob.issupplement = true;
|
{ clm_no: jobObject.clm_no },
|
||||||
// newJob.jobid = jobId;
|
);
|
||||||
// };
|
|
||||||
|
|
||||||
//Check if the vehicle exists, if it does, use that UUID, if not, keep it to insert it.
|
|
||||||
|
|
||||||
|
if (existingJobRecord.jobs.length > 0) {
|
||||||
|
newAvailableJob.issupplement = true;
|
||||||
|
newAvailableJob.jobid = existingJobRecord.jobs[0].id;
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error("Error encountered while decoding job. ", errorTypeCheck(error));
|
log.error("Error encountered while decoding job. ", errorTypeCheck(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ImportJob;
|
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 { parse, TypedQueryDocumentNode } from "graphql";
|
||||||
import { gql } from "graphql-request";
|
import { gql } from "graphql-request";
|
||||||
|
import { AvailableJobSchema } from "../decoder/decoder";
|
||||||
// Define types for the query result and variables
|
// Define types for the query result and variables
|
||||||
export interface ActiveBodyshopQueryResult {
|
export interface ActiveBodyshopQueryResult {
|
||||||
bodyshops: Array<{
|
bodyshops: Array<{
|
||||||
@@ -9,10 +10,8 @@ export interface ActiveBodyshopQueryResult {
|
|||||||
region_config: string;
|
region_config: string;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No variables needed for this query
|
// No variables needed for this query
|
||||||
interface ActiveBodyshopQueryVariables {}
|
interface ActiveBodyshopQueryVariables {}
|
||||||
|
|
||||||
// Transform the string query into a TypedQueryDocumentNode
|
// Transform the string query into a TypedQueryDocumentNode
|
||||||
export const QUERY_ACTIVE_BODYSHOP_TYPED: TypedQueryDocumentNode<
|
export const QUERY_ACTIVE_BODYSHOP_TYPED: TypedQueryDocumentNode<
|
||||||
ActiveBodyshopQueryResult,
|
ActiveBodyshopQueryResult,
|
||||||
@@ -25,7 +24,10 @@ export const QUERY_ACTIVE_BODYSHOP_TYPED: TypedQueryDocumentNode<
|
|||||||
region_config
|
region_config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`);
|
`) as TypedQueryDocumentNode<
|
||||||
|
ActiveBodyshopQueryResult,
|
||||||
|
ActiveBodyshopQueryVariables
|
||||||
|
>;
|
||||||
|
|
||||||
export interface MasterdataQueryResult {
|
export interface MasterdataQueryResult {
|
||||||
masterdata: Array<{
|
masterdata: Array<{
|
||||||
@@ -33,11 +35,9 @@ export interface MasterdataQueryResult {
|
|||||||
key: string;
|
key: string;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MasterdataQueryVariables {
|
interface MasterdataQueryVariables {
|
||||||
key: string;
|
key: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const QUERY_MASTERDATA_TYPED: TypedQueryDocumentNode<
|
export const QUERY_MASTERDATA_TYPED: TypedQueryDocumentNode<
|
||||||
MasterdataQueryResult,
|
MasterdataQueryResult,
|
||||||
MasterdataQueryVariables
|
MasterdataQueryVariables
|
||||||
@@ -48,19 +48,16 @@ export const QUERY_MASTERDATA_TYPED: TypedQueryDocumentNode<
|
|||||||
key
|
key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`);
|
`) as TypedQueryDocumentNode<MasterdataQueryResult, MasterdataQueryVariables>;
|
||||||
|
|
||||||
export interface VehicleQueryResult {
|
export interface VehicleQueryResult {
|
||||||
masterdata: Array<{
|
vehicles: Array<{
|
||||||
value: string;
|
id: UUID;
|
||||||
key: string;
|
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VehicleQueryVariables {
|
interface VehicleQueryVariables {
|
||||||
vin: string;
|
vin: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const QUERY_VEHICLE_BY_VIN_TYPED: TypedQueryDocumentNode<
|
export const QUERY_VEHICLE_BY_VIN_TYPED: TypedQueryDocumentNode<
|
||||||
VehicleQueryResult,
|
VehicleQueryResult,
|
||||||
VehicleQueryVariables
|
VehicleQueryVariables
|
||||||
@@ -70,4 +67,62 @@ export const QUERY_VEHICLE_BY_VIN_TYPED: TypedQueryDocumentNode<
|
|||||||
id
|
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 path from "path";
|
||||||
import ipcTypes from "../../util/ipcTypes.json";
|
import ipcTypes from "../../util/ipcTypes.json";
|
||||||
import ImportJob from "../decoder/decoder";
|
import ImportJob from "../decoder/decoder";
|
||||||
import { StartWatcher } from "../watcher/watcher";
|
import { StartWatcher, StopWatcher } from "../watcher/watcher";
|
||||||
import {
|
import {
|
||||||
SettingsWatchedFilePathsAdd,
|
SettingsWatchedFilePathsAdd,
|
||||||
SettingsWatchedFilePathsGet,
|
SettingsWatchedFilePathsGet,
|
||||||
@@ -83,4 +83,8 @@ ipcMain.on(ipcTypes.toMain.watcher.start, () => {
|
|||||||
StartWatcher();
|
StartWatcher();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.on(ipcTypes.toMain.watcher.stop, () => {
|
||||||
|
StopWatcher();
|
||||||
|
});
|
||||||
|
|
||||||
logIpcMessages();
|
logIpcMessages();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { BrowserWindow, dialog, IpcMainInvokeEvent } from "electron";
|
|||||||
import log from "electron-log/main";
|
import log from "electron-log/main";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import Store from "../store/store";
|
import Store from "../store/store";
|
||||||
|
import { addWatcherPath, removeWatcherPath, watcher } from "../watcher/watcher";
|
||||||
|
|
||||||
const SettingsWatchedFilePathsAdd = async (): Promise<string[]> => {
|
const SettingsWatchedFilePathsAdd = async (): Promise<string[]> => {
|
||||||
const mainWindow = BrowserWindow.getAllWindows()[0]; //TODO: Filter to only main window once a proper key has been set.
|
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",
|
"settings.filepaths",
|
||||||
_.union(result.filePaths, Store.get("settings.filepaths"))
|
_.union(result.filePaths, Store.get("settings.filepaths"))
|
||||||
);
|
);
|
||||||
|
addWatcherPath(result.filePaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Store.get("settings.filepaths");
|
return Store.get("settings.filepaths");
|
||||||
@@ -30,7 +32,7 @@ const SettingsWatchedFilePathsRemove = async (
|
|||||||
"settings.filepaths",
|
"settings.filepaths",
|
||||||
_.without(Store.get("settings.filepaths"), path)
|
_.without(Store.get("settings.filepaths"), path)
|
||||||
);
|
);
|
||||||
|
removeWatcherPath(path);
|
||||||
return Store.get("settings.filepaths");
|
return Store.get("settings.filepaths");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import chokidar, { FSWatcher } from "chokidar";
|
import chokidar, { FSWatcher } from "chokidar";
|
||||||
import { Notification } from "electron";
|
import { BrowserWindow, Notification } from "electron";
|
||||||
import log from "electron-log/main";
|
import log from "electron-log/main";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||||
import store from "../store/store";
|
import ipcTypes from "../../util/ipcTypes.json";
|
||||||
import ImportJob from "../decoder/decoder";
|
import ImportJob from "../decoder/decoder";
|
||||||
|
import store from "../store/store";
|
||||||
|
|
||||||
let watcher: FSWatcher;
|
let watcher: FSWatcher;
|
||||||
|
|
||||||
@@ -67,6 +68,10 @@ async function StartWatcher(): Promise<boolean> {
|
|||||||
// })
|
// })
|
||||||
.on("error", function (error) {
|
.on("error", function (error) {
|
||||||
log.error("Error in Watcher", errorTypeCheck(error));
|
log.error("Error in Watcher", errorTypeCheck(error));
|
||||||
|
// mainWindow.webContents.send(
|
||||||
|
// ipcTypes.toRenderer.watcher.error,
|
||||||
|
// errorTypeCheck(error)
|
||||||
|
// );
|
||||||
})
|
})
|
||||||
.on("ready", onWatcherReady)
|
.on("ready", onWatcherReady)
|
||||||
.on("raw", function (event, path, details) {
|
.on("raw", function (event, path, details) {
|
||||||
@@ -77,24 +82,37 @@ async function StartWatcher(): Promise<boolean> {
|
|||||||
return true;
|
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 {
|
function onWatcherReady(): void {
|
||||||
log.info("Watcher ready!");
|
const mainWindow = BrowserWindow.getAllWindows()[0]; //TODO: Filter to only main window once a proper key has been set.
|
||||||
// const b = BrowserWindow.getAllWindows()[0];
|
|
||||||
// b.webContents.send(ipcTypes.default.fileWatcher.toRenderer.startSuccess);
|
|
||||||
new Notification({
|
new Notification({
|
||||||
title: "Watcher Started",
|
title: "Watcher Started",
|
||||||
body: "Newly exported estimates will be automatically uploaded.",
|
body: "Newly exported estimates will be automatically uploaded.",
|
||||||
}).show();
|
}).show();
|
||||||
log.info("Confirmed watched paths:", watcher.getWatched());
|
log.info("Confirmed watched paths:", watcher.getWatched());
|
||||||
|
mainWindow.webContents.send(ipcTypes.toRenderer.watcher.started);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function StopWatcher(): Promise<boolean> {
|
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) {
|
if (watcher) {
|
||||||
await watcher.close();
|
await watcher.close();
|
||||||
log.info("Watcher stopped.");
|
log.info("Watcher stopped.");
|
||||||
|
mainWindow.webContents.send(ipcTypes.toRenderer.watcher.stopped);
|
||||||
|
|
||||||
new Notification({
|
new Notification({
|
||||||
title: "RPS Watcher Stopped",
|
title: "Watcher Stopped",
|
||||||
body: "Estimates will not be automatically uploaded.",
|
body: "Estimates will not be automatically uploaded.",
|
||||||
}).show();
|
}).show();
|
||||||
return true;
|
return true;
|
||||||
@@ -107,4 +125,10 @@ async function HandleNewFile(path): Promise<void> {
|
|||||||
log.log("Received a new file", path);
|
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 { useTranslation } from "react-i18next";
|
||||||
import ipcTypes from "../../../../util/ipcTypes.json";
|
import ipcTypes from "../../../../util/ipcTypes.json";
|
||||||
|
|
||||||
const SettingsWatcher: React.FC = () => {
|
const SettingsWatcher: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const isWatcherStarted = useAppSelector(selectWatcherStatus);
|
||||||
|
const watcherError = useAppSelector(selectWatcherError);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const handleStart = (): void => {
|
const handleStart = (): void => {
|
||||||
window.electron.ipcRenderer.send(ipcTypes.toMain.watcher.start);
|
window.electron.ipcRenderer.send(ipcTypes.toMain.watcher.start);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleStop = (): void => {
|
||||||
|
window.electron.ipcRenderer.send(ipcTypes.toMain.watcher.stop);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
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;
|
export default SettingsWatcher;
|
||||||
|
|||||||
@@ -1,46 +1,58 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
|
import log from "electron-log/renderer";
|
||||||
import type { RootState } from "./redux-store";
|
import type { RootState } from "./redux-store";
|
||||||
|
|
||||||
// Define a type for the slice state
|
|
||||||
interface AppState {
|
interface AppState {
|
||||||
value: number;
|
value: number;
|
||||||
|
watcher: {
|
||||||
|
started: boolean;
|
||||||
|
error: string | null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define the initial state using that type
|
// Define the initial state using that type
|
||||||
const initialState: AppState = {
|
const initialState: AppState = {
|
||||||
value: 0,
|
value: 0,
|
||||||
|
watcher: {
|
||||||
|
started: false,
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appSlice = createSlice({
|
export const appSlice = createSlice({
|
||||||
name: "counter",
|
name: "app",
|
||||||
// `createSlice` will infer the state type from the `initialState` argument
|
// `createSlice` will infer the state type from the `initialState` argument
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
increment: (state) => {
|
watcherStarted: (state) => {
|
||||||
state.value += 1;
|
state.watcher.started = true;
|
||||||
},
|
},
|
||||||
decrement: (state) => {
|
watcherStopped: (state) => {
|
||||||
state.value -= 1;
|
state.watcher.started = false;
|
||||||
},
|
},
|
||||||
// Use the PayloadAction type to declare the contents of `action.payload`
|
watcherError: (state, action: PayloadAction<string>) => {
|
||||||
incrementByAmount: (state, action: PayloadAction<number>) => {
|
state.watcher.error = action.payload;
|
||||||
state.value += 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
|
// 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
|
//Async Functions - Thunks
|
||||||
// Define a thunk that dispatches those action creators
|
// Define a thunk that dispatches those action creators
|
||||||
const fetchUsers = () => async (dispatch) => {
|
const fetchUsers = () => async (dispatch) => {
|
||||||
dispatch(increment());
|
//dispatch(watcherStarted());
|
||||||
//Some sort of async action.
|
//Some sort of async action.
|
||||||
|
// dispatch(incrementByAmount(100));
|
||||||
dispatch(incrementByAmount(100));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default appSlice.reducer;
|
export default appSlice.reducer;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import type { TypedUseSelectorHook } from "react-redux";
|
import type { TypedUseSelectorHook } from "react-redux";
|
||||||
import { useDispatch, useSelector, useStore } from "react-redux";
|
import { useDispatch, useSelector, useStore } from "react-redux";
|
||||||
import type { AppDispatch, AppStore, RootState } from "./redux-store";
|
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.
|
//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 useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||||
export const useAppStore: () => AppStore = useStore;
|
export const useAppStore: () => AppStore = useStore;
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
//Set up all of the IPC handlers.
|
//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 ipcTypes from "../../../util/ipcTypes.json";
|
||||||
import { auth } from "./firebase";
|
import { auth } from "./firebase";
|
||||||
|
|
||||||
const ipcRenderer = window.electron.ipcRenderer;
|
const ipcRenderer = window.electron.ipcRenderer;
|
||||||
|
const dispatch = store.dispatch;
|
||||||
|
|
||||||
ipcRenderer.on(
|
ipcRenderer.on(
|
||||||
ipcTypes.toRenderer.test,
|
ipcTypes.toRenderer.test,
|
||||||
@@ -19,3 +26,29 @@ ipcRenderer.on(
|
|||||||
ipcRenderer.send(ipcTypes.toMain.user.getTokenResponse, token);
|
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": {
|
"toRenderer": {
|
||||||
"test": "toRenderer_test",
|
"test": "toRenderer_test",
|
||||||
|
"watcher": {
|
||||||
|
"started": "toRenderer_watcher_started",
|
||||||
|
"stopped": "toRenderer_watcher_stopped",
|
||||||
|
"error": "toRenderer_watcher_error"
|
||||||
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"getToken": "toRenderer_user_getToken"
|
"getToken": "toRenderer_user_getToken"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,14 @@
|
|||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"actions": {
|
"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>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</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>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
</children>
|
</children>
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"files": [],
|
"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"
|
"tests/index.spec.ts"
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"resolveJsonModule": true,
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"types": ["electron-vite/node"]
|
"types": ["electron-vite/node"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"src/util/**/*"
|
"src/util/**/*"
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"resolveJsonModule": true,
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
|||||||
Reference in New Issue
Block a user