feature/IO-3702-ESPD-UI-AND-FIXES - Stage 5 (Lint)

This commit is contained in:
Dave
2026-05-27 13:47:21 -04:00
parent 1e7e13ff32
commit 527a5ef16d
16 changed files with 188 additions and 196 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,29 +1,29 @@
#!/usr/bin/env node
// Cross-platform script to set artifact naming based on version
const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const fs = require("fs");
const path = require("path");
const { spawn } = require("child_process");
// Read the package.json to get the version
const packageJsonPath = path.join(__dirname, '..', 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const packageJsonPath = path.join(__dirname, "..", "package.json");
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
const version = packageJson.version;
console.log(`Current version: ${version}`);
// Determine the artifact suffix based on the version
let artifactSuffix = '';
let artifactSuffix = "";
if (version.includes('alpha')) {
artifactSuffix = `alpha-${version}-`;
console.log(`Detected alpha version, setting suffix to: ${artifactSuffix}`);
} else if (version.includes('beta')) {
artifactSuffix = `beta-${version}-`;
console.log(`Detected beta version, setting suffix to: ${artifactSuffix}`);
if (version.includes("alpha")) {
artifactSuffix = `alpha-${version}-`;
console.log(`Detected alpha version, setting suffix to: ${artifactSuffix}`);
} else if (version.includes("beta")) {
artifactSuffix = `beta-${version}-`;
console.log(`Detected beta version, setting suffix to: ${artifactSuffix}`);
} else {
artifactSuffix = '';
console.log('Detected release version, no suffix will be added');
artifactSuffix = "";
console.log("Detected release version, no suffix will be added");
}
// Set the environment variable for the current process
@@ -33,21 +33,23 @@ console.log(`ARTIFACT_SUFFIX set to: '${artifactSuffix}'`);
// If arguments are passed, execute the remaining command with the environment variable set
if (process.argv.length > 2) {
const command = process.argv[2];
const args = process.argv.slice(3);
const command = process.argv[2];
const args = process.argv.slice(3);
console.log(`Executing: ${command} ${args.join(' ')}`);
console.log(`Executing: ${command} ${args.join(" ")}`);
const child = spawn(command, args, {
stdio: 'inherit',
env: { ...process.env, ARTIFACT_SUFFIX: artifactSuffix },
shell: true
});
const child = spawn(command, args, {
stdio: "inherit",
env: { ...process.env, ARTIFACT_SUFFIX: artifactSuffix },
shell: true,
});
child.on('close', (code) => {
process.exit(code);
});
child.on("close", (code) => {
process.exit(code);
});
} else {
// Just setting the environment variable
console.log('Environment variable set. Use this script with additional arguments to run commands with the variable set.');
// Just setting the environment variable
console.log(
"Environment variable set. Use this script with additional arguments to run commands with the variable set.",
);
}

View File

@@ -1,64 +1,64 @@
#!/usr/bin/env node
// Cross-platform test script to demonstrate artifact naming for different versions
const fs = require('fs');
const path = require('path');
const fs = require("fs");
const path = require("path");
console.log('=== Artifact Naming Test (Cross-Platform) ===');
console.log('');
console.log("=== Artifact Naming Test (Cross-Platform) ===");
console.log("");
// Get current version
const packageJsonPath = path.join(__dirname, '..', 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const packageJsonPath = path.join(__dirname, "..", "package.json");
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
const currentVersion = packageJson.version;
console.log(`Current version: ${currentVersion}`);
// Function to get artifact suffix
function getArtifactSuffix(version) {
if (version.includes('alpha')) {
return `alpha-${version}-`;
} else if (version.includes('beta')) {
return `beta-${version}-`;
} else {
return '';
}
if (version.includes("alpha")) {
return `alpha-${version}-`;
} else if (version.includes("beta")) {
return `beta-${version}-`;
} else {
return "";
}
}
// Test scenarios
const testVersions = [
'1.0.5', // Release version
'1.0.5-alpha.2', // Alpha version
'1.0.5-beta.1', // Beta version
'2.0.0-alpha.1', // Another alpha
'1.5.0-beta.3' // Another beta
"1.0.5", // Release version
"1.0.5-alpha.2", // Alpha version
"1.0.5-beta.1", // Beta version
"2.0.0-alpha.1", // Another alpha
"1.5.0-beta.3", // Another beta
];
console.log('Test scenarios:');
console.log('==================');
console.log("Test scenarios:");
console.log("==================");
testVersions.forEach(version => {
const suffix = getArtifactSuffix(version);
// Different artifact names for different platforms
const windowsArtifact = `imex-partner-${suffix}x64.exe`;
const macArtifact = `imex-partner-${suffix}x64.dmg`;
const linuxArtifact = `imex-partner-${suffix}x64.AppImage`;
console.log(`Version: ${version}`);
console.log(` Suffix: '${suffix}'`);
console.log(` Windows: ${windowsArtifact}`);
console.log(` Mac: ${macArtifact}`);
console.log(` Linux: ${linuxArtifact}`);
console.log('');
testVersions.forEach((version) => {
const suffix = getArtifactSuffix(version);
// Different artifact names for different platforms
const windowsArtifact = `imex-partner-${suffix}x64.exe`;
const macArtifact = `imex-partner-${suffix}x64.dmg`;
const linuxArtifact = `imex-partner-${suffix}x64.AppImage`;
console.log(`Version: ${version}`);
console.log(` Suffix: '${suffix}'`);
console.log(` Windows: ${windowsArtifact}`);
console.log(` Mac: ${macArtifact}`);
console.log(` Linux: ${linuxArtifact}`);
console.log("");
});
console.log('Current configuration will produce:');
console.log("Current configuration will produce:");
const currentSuffix = getArtifactSuffix(currentVersion);
console.log(` Windows: imex-partner-${currentSuffix}x64.exe`);
console.log(` Mac: imex-partner-${currentSuffix}x64.dmg`);
console.log(` Linux: imex-partner-${currentSuffix}x64.AppImage`);
console.log('');
console.log("");
console.log(`Platform detected: ${process.platform}`);
console.log(`Architecture: ${process.arch}`);

View File

@@ -5,44 +5,42 @@ import eslintPluginReactHooks from "eslint-plugin-react-hooks";
import eslintPluginReactRefresh from "eslint-plugin-react-refresh";
export default tseslint.config(
{ ignores: ["**/node_modules", "**/dist", "**/out", "**/.serverless"] },
{
files: ["**/*.{ts,tsx}"],
extends: [tseslint.configs.recommended],
{ ignores: ["**/node_modules", "**/dist", "**/out", "**/.serverless"] },
{
files: ["**/*.{ts,tsx}"],
extends: [tseslint.configs.recommended],
},
eslintPluginReact.configs.flat.recommended,
eslintPluginReact.configs.flat["jsx-runtime"],
{
settings: {
react: {
version: "detect",
},
},
eslintPluginReact.configs.flat.recommended,
eslintPluginReact.configs.flat["jsx-runtime"],
{
settings: {
react: {
version: "detect",
},
},
},
{
files: ["**/*.{ts,tsx}"],
plugins: {
"react-hooks": eslintPluginReactHooks,
"react-refresh": eslintPluginReactRefresh,
},
{
files: ["**/*.{ts,tsx}"],
plugins: {
"react-hooks": eslintPluginReactHooks,
"react-refresh": eslintPluginReactRefresh,
},
rules: {
...eslintPluginReactHooks.configs.recommended.rules,
...eslintPluginReactRefresh.configs.vite.rules,
},
rules: {
...eslintPluginReactHooks.configs.recommended.rules,
...eslintPluginReactRefresh.configs.vite.rules,
},
{
files: ["serverless/**/*.js"],
rules: {
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
},
},
{
files: ["serverless/**/*.js"],
rules: {
"no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
},
{
files: ["**/*.{js,mjs,ts,tsx,jsx,tsx}"],
rules: {
"prettier/prettier": ["error", { "endOfLine": "auto" }]
}
},
{
files: ["**/*.{js,mjs,ts,tsx,jsx,tsx}"],
rules: {
"prettier/prettier": ["error", { endOfLine: "auto" }],
},
eslintConfigPrettier,
)
},
eslintConfigPrettier,
);

View File

@@ -29,3 +29,5 @@ yarn-error.log*
.env
.env.local
.env.*.local
.
.eslintcache

View File

@@ -27,7 +27,7 @@ interface EmsUploadResponse {
* @param {string} esApiKey - The ES API Key to validate
* @returns {boolean} - Always returns true for now (placeholder)
*/
function validateEmsUploadId(_esApiKey: string): boolean {
function validateEmsUploadId(): boolean {
// Placeholder validation - always returns true
// TODO: Implement actual validation logic
return true;
@@ -54,7 +54,7 @@ export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPr
}
// Validate the EMS Upload ID
const isValid = validateEmsUploadId(esApiKey);
const isValid = validateEmsUploadId();
if (!isValid) {
return {
statusCode: 401,

View File

@@ -172,10 +172,9 @@ async function ImportJob(filepath: string): Promise<void> {
mainWindow.show();
mainWindow.focus();
if (scrubHistoryJobId) {
mainWindow.webContents.send(
ipcTypes.toRenderer.scrub.openHistoryItem,
{ jobId: scrubHistoryJobId },
);
mainWindow.webContents.send(ipcTypes.toRenderer.scrub.openHistoryItem, {
jobId: scrubHistoryJobId,
});
}
};
@@ -362,6 +361,13 @@ export function ReplaceOwnerInfoWithClaimant<
>
>,
>(jobObject: T): T {
const mutableJob = jobObject as T &
Record<string, unknown> & {
owner?: {
data?: Record<string, unknown>;
};
};
// Promote claimant data first if owner identity is entirely missing; otherwise fallback to insured data.
const identityKeys = ["ln", "fn", "co_nm"] as const; // keys used to determine presence
const copyKeys = [
@@ -381,27 +387,23 @@ export function ReplaceOwnerInfoWithClaimant<
] as const; // full set of fields to copy/delete
const ownerMissing = identityKeys.every((k) =>
_.isEmpty((jobObject as any)[`ownr_${k}`]),
_.isEmpty(mutableJob[`ownr_${k}`]),
);
const claimantHasSome = identityKeys.some(
(k) => !_.isEmpty((jobObject as any)[`clmt_${k}`]),
(k) => !_.isEmpty(mutableJob[`clmt_${k}`]),
);
const claimantMissing = identityKeys.every((k) =>
_.isEmpty((jobObject as any)[`clmt_${k}`]),
_.isEmpty(mutableJob[`clmt_${k}`]),
);
const { owner } = jobObject as any; // destructure for optional nested updates
const { owner } = mutableJob; // destructure for optional nested updates
// Copy helper inline (no extra function as requested)
const promote = (sourcePrefix: "clmt" | "insd"): void => {
copyKeys.forEach((suffix) => {
(jobObject as any)[`ownr_${suffix}`] = (jobObject as any)[
`${sourcePrefix}_${suffix}`
];
mutableJob[`ownr_${suffix}`] = mutableJob[`${sourcePrefix}_${suffix}`];
if (owner?.data) {
owner.data[`ownr_${suffix}`] = (jobObject as any)[
`${sourcePrefix}_${suffix}`
];
owner.data[`ownr_${suffix}`] = mutableJob[`${sourcePrefix}_${suffix}`];
}
});
};
@@ -413,9 +415,9 @@ export function ReplaceOwnerInfoWithClaimant<
}
// Delete the claimant info as it's not needed.
copyKeys.forEach((suffix) => delete (jobObject as any)[`clmt_${suffix}`]);
copyKeys.forEach((suffix) => delete mutableJob[`clmt_${suffix}`]);
// Delete the insured info as it's not needed.
copyKeys.forEach((suffix) => delete (jobObject as any)[`insd_${suffix}`]);
copyKeys.forEach((suffix) => delete mutableJob[`insd_${suffix}`]);
return jobObject;
}

View File

@@ -107,7 +107,7 @@ function createWindow(): void {
const template = [
// { role: 'appMenu' }
// @ts-ignore
// @ts-ignore -- Electron menu role unions are narrower than this conditional template.
...(isMac
? [
{
@@ -128,7 +128,7 @@ function createWindow(): void {
{
label: "File",
submenu: [
// @ts-ignore
// @ts-ignore -- Electron menu role unions are narrower than this conditional template.
isMac ? { role: "close" } : { role: "quit" },
],
},
@@ -142,7 +142,7 @@ function createWindow(): void {
{ role: "cut" },
{ role: "copy" },
{ role: "paste" },
// @ts-ignore
// @ts-ignore -- Electron menu role unions are narrower than this conditional template.
...(isMac
? [
{ role: "pasteAndMatchStyle" },
@@ -160,7 +160,7 @@ function createWindow(): void {
// { role: 'viewMenu' }
{
label: "View",
// @ts-ignore
// @ts-ignore -- Electron menu role unions are narrower than this conditional template.
submenu: [
{ role: "reload" },
{ role: "forceReload" },
@@ -175,7 +175,7 @@ function createWindow(): void {
},
{
label: "Application",
// @ts-ignore
// @ts-ignore -- Electron menu role unions are narrower than this conditional template.
submenu: [
{
label: "Open on Startup",
@@ -376,7 +376,7 @@ function createWindow(): void {
submenu: [
{ role: "minimize" },
{ role: "zoom" },
// @ts-ignore
// @ts-ignore -- Electron menu role unions are narrower than this conditional template.
...(isMac
? [
{ type: "separator" },
@@ -399,7 +399,7 @@ function createWindow(): void {
// Update the menu to make the hidden item visible
// Find the menu item dynamically by its id
const fileMenu = template.find((item) => item.label === "Application");
// @ts-ignore
// @ts-ignore -- Electron menu submenu typing does not expose array helpers after casting.
const hiddenItem = fileMenu?.submenu?.find(
(item: { id: string }) => item.id === "development",
);

View File

@@ -15,8 +15,8 @@ export interface GraphQLResponse {
shopname: string;
};
jobs?: Array<{
labhrs: any;
larhrs: any;
labhrs: unknown;
larhrs: unknown;
ro_number: string;
ownr_ln: string;
ownr_fn: string;

View File

@@ -14,15 +14,15 @@ import {
const getSetting = async (
_event: IpcMainInvokeEvent,
key: string,
): Promise<any> => {
): Promise<unknown> => {
return Store.get(`settings.${key}`);
};
const setSetting = async (
_event: IpcMainInvokeEvent,
key: string,
value: any,
): Promise<any> => {
value: unknown,
): Promise<unknown> => {
Store.set(`settings.${key}`, value);
return Store.get(`settings.${key}`);
};

View File

@@ -1,11 +1,11 @@
import {BrowserWindow} from "electron";
import { BrowserWindow } from "electron";
import log from "electron-log/main";
const getMainWindow = (): Electron.BrowserWindow => {
return BrowserWindow.getAllWindows()[0];
};
const sendIpcToRenderer = (ipcMessage: string, ...args: any[]): void => {
const sendIpcToRenderer = (ipcMessage: string, ...args: unknown[]): void => {
const window = getMainWindow();
if (window) {
window.webContents.send(ipcMessage, ...args);

View File

@@ -1,4 +1,5 @@
import { nativeImage, type NativeImage, type Tray } from "electron";
import { PNG } from "pngjs";
let trayInstance: Tray | undefined;
let trayBaseImage: NativeImage | undefined;
@@ -29,29 +30,8 @@ function buildStatusTrayImage(
started: boolean,
): NativeImage {
try {
const pngjs = (() => {
try {
return require("pngjs") as {
PNG?: {
sync?: {
read?: (b: Buffer) => unknown;
write?: (p: unknown) => Buffer;
};
};
};
} catch {
return null;
}
})();
if (!pngjs?.PNG?.sync?.read || !pngjs.PNG.sync.write) return base;
const basePng = base.toPNG();
const png = pngjs.PNG.sync.read(basePng) as {
width: number;
height: number;
data: Uint8Array;
};
const png = PNG.sync.read(basePng);
const width = png.width;
const height = png.height;
@@ -86,7 +66,7 @@ function buildStatusTrayImage(
}
}
return nativeImage.createFromBuffer(pngjs.PNG.sync.write(png));
return nativeImage.createFromBuffer(PNG.sync.write(png));
} catch {
return base;
}

View File

@@ -3,22 +3,22 @@
* @param obj The object whose keys need to be converted to uppercase
* @returns A new object with all keys converted to uppercase
*/
function uppercaseObjectKeys<T extends Record<string, any>>(
obj: T,
): Record<string, any> {
if (typeof obj !== "object" || obj === null) {
return obj;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}
function uppercaseObjectKeys(
obj: Record<string, unknown>,
): Record<string, unknown> {
return Object.entries(obj).reduce(
(result, [key, value]) => {
const uppercaseKey = key.toUpperCase();
result[uppercaseKey] = typeof value === "object" && value !== null
? uppercaseObjectKeys(value)
: value;
result[uppercaseKey] = isRecord(value)
? uppercaseObjectKeys(value)
: value;
return result;
},
{} as Record<string, any>,
{} as Record<string, unknown>,
);
}
export default uppercaseObjectKeys;

View File

@@ -1,5 +1,6 @@
import { Card, Form, Input, Space } from "antd";
import { FC, useEffect } from "react";
import type { FormProps } from "antd";
import { FC, useEffect, useMemo } from "react";
import { useTranslation } from "react-i18next";
import ipcTypes from "../../../../util/ipcTypes.json";
@@ -7,31 +8,36 @@ const SettingsConfig: FC = () => {
const { t } = useTranslation();
const [form] = Form.useForm();
const settingFields = [
{
name: "esApiKey",
label: t("settings.labels.esApiKey"),
component: Input.Password,
hasFeedback: true,
componentProps: {
placeholder: "Enter your API key",
const settingFields = useMemo(
() => [
{
name: "esApiKey",
label: t("settings.labels.esApiKey"),
component: Input.Password,
hasFeedback: true,
componentProps: {
placeholder: "Enter your API key",
},
},
},
];
],
[t],
);
useEffect(() => {
settingFields.forEach((field) => {
window.electron.ipcRenderer
.invoke(ipcTypes.toMain.settings.get, field.name)
.then((value: any) => {
.then((value: unknown) => {
form.setFieldsValue({ [field.name]: value });
});
});
}, []);
}, [form, settingFields]);
const handleFieldChange = (changedFields: any): void => {
const handleFieldChange: FormProps["onFieldsChange"] = (changedFields) => {
changedFields.forEach((field) => {
const fieldName = field.name[0];
const fieldName = Array.isArray(field.name)
? String(field.name[0])
: String(field.name);
const { value } = field;
// Placeholder for validation
@@ -46,7 +52,7 @@ const SettingsConfig: FC = () => {
});
};
const validateField = (fieldName: string, value: any): boolean => {
const validateField = (fieldName: string, value: unknown): boolean => {
// Placeholder for actual validation logic
console.log(`Validating ${fieldName}:`, value);
return true;

View File

@@ -1,17 +1,19 @@
import {createContext, FC, ReactNode, useContext} from "react";
import { createContext, FC, ReactNode, useContext } from "react";
import { notification } from "antd";
/**
* Create our NotificationContext to store the `api` object
* returned by notification.useNotification().
*/
const NotificationContext = createContext(null);
type NotificationApi = ReturnType<typeof notification.useNotification>[0];
const NotificationContext = createContext<NotificationApi | null>(null);
/**
* A custom hook to make usage easier in child components.
*/
// eslint-disable-next-line react-refresh/only-export-components, @typescript-eslint/explicit-function-return-type
export const useNotification = () => {
// eslint-disable-next-line react-refresh/only-export-components
export const useNotification = (): NotificationApi | null => {
return useContext(NotificationContext);
};
@@ -26,8 +28,7 @@ interface NotificationProviderProps {
}
export const NotificationProvider: FC<NotificationProviderProps> = ({
// eslint-disable-next-line react/prop-types
children, //TODO: Unable to resolve this. Adding an eslint disable.
children,
}) => {
const [api, contextHolder] = notification.useNotification({
placement: "bottomRight",
@@ -36,7 +37,6 @@ export const NotificationProvider: FC<NotificationProviderProps> = ({
});
return (
// @ts-ignore
<NotificationContext.Provider value={api}>
{/* contextHolder must be rendered in the DOM so notifications can appear */}
{contextHolder}

View File

@@ -3,6 +3,7 @@ import log from "electron-log/main";
import fs from "fs";
import os from "os";
import path from "path";
import * as v8 from "v8";
import Store from "../main/store/store";
/**
* Human-readable memory/cpu/resource snapshot.
@@ -39,6 +40,10 @@ export type MemoryUsageStats = {
};
// (merged into top import)
type GlobalWithGc = typeof globalThis & {
gc?: () => void;
};
/**
* Options for dumpMemoryStats.
*/
@@ -89,9 +94,11 @@ export async function dumpMemoryStats(
} = options;
// Allow GC if requested and available to get a cleaner snapshot
if (runGc && typeof (global as any).gc === "function") {
const runtimeGlobal = globalThis as GlobalWithGc;
if (runGc && typeof runtimeGlobal.gc === "function") {
try {
(global as any).gc();
runtimeGlobal.gc();
} catch {
// ignore GC errors
}
@@ -143,8 +150,6 @@ export async function dumpMemoryStats(
if (includeHeapSpaces) {
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const v8: typeof import("v8") = require("v8");
if (typeof v8.getHeapSpaceStatistics === "function") {
stats.heapSpaces = v8.getHeapSpaceStatistics();
}
@@ -155,15 +160,13 @@ export async function dumpMemoryStats(
if (writeHeapSnapshot) {
try {
if (!runGc && typeof (global as any).gc === "function") {
if (!runGc && typeof runtimeGlobal.gc === "function") {
try {
(global as any).gc();
runtimeGlobal.gc();
} catch {
/* ignore */
}
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const v8: typeof import("v8") = require("v8");
if (typeof v8.writeHeapSnapshot === "function") {
const baseDir =
heapSnapshotDir || path.dirname(log.transports.file.getFile().path);