@@ -216,7 +216,9 @@ export function JobLinesComponent({
|
|||||||
{
|
{
|
||||||
title: t("joblines.fields.part_qty"),
|
title: t("joblines.fields.part_qty"),
|
||||||
dataIndex: "part_qty",
|
dataIndex: "part_qty",
|
||||||
key: "part_qty"
|
key: "part_qty",
|
||||||
|
sorter: (a, b) => a.part_qty - b.part_qty,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "part_qty" && state.sortedInfo.order
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// title: t('joblines.fields.tax_part'),
|
// title: t('joblines.fields.tax_part'),
|
||||||
|
|||||||
@@ -110,7 +110,13 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
|||||||
to: values.to,
|
to: values.to,
|
||||||
subject: Templates[values.key]?.subject
|
subject: Templates[values.key]?.subject
|
||||||
},
|
},
|
||||||
values.sendbytext === "text" ? values.sendbytext : values.sendbyexcel === "excel" ? "x" : values.sendby === "email" ? "e" : "p",
|
values.sendbytext === "text"
|
||||||
|
? values.sendbytext
|
||||||
|
: values.sendbyexcel === "excel"
|
||||||
|
? "x"
|
||||||
|
: values.sendby === "email"
|
||||||
|
? "e"
|
||||||
|
: "p",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -274,6 +280,17 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
|||||||
{
|
{
|
||||||
required: true
|
required: true
|
||||||
//message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: (_, value) => {
|
||||||
|
if (value && value[0] && value[1] && process.env.NODE_ENV === "production") {
|
||||||
|
const diffInDays = (value[1] - value[0]) / (1000 * 3600 * 24);
|
||||||
|
if (diffInDays > 92) {
|
||||||
|
return Promise.reject(t("general.validation.dateRangeExceeded"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { gql } from "@apollo/client";
|
|||||||
|
|
||||||
export const GET_ALL_JOBLINES_BY_PK = gql`
|
export const GET_ALL_JOBLINES_BY_PK = gql`
|
||||||
query GET_ALL_JOBLINES_BY_PK($id: uuid!) {
|
query GET_ALL_JOBLINES_BY_PK($id: uuid!) {
|
||||||
joblines(where: { jobid: { _eq: $id } }, order_by: { line_no: asc }) {
|
joblines(where: { jobid: { _eq: $id }, removed: { _eq: false } }, order_by: { line_no: asc }) {
|
||||||
id
|
id
|
||||||
line_no
|
line_no
|
||||||
unq_seq
|
unq_seq
|
||||||
|
|||||||
@@ -1289,6 +1289,7 @@
|
|||||||
"unsavedchangespopup": "You have unsaved changes. Are you sure you want to leave?"
|
"unsavedchangespopup": "You have unsaved changes. Are you sure you want to leave?"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
"dateRangeExceeded": "The date range has been exceeded.",
|
||||||
"invalidemail": "Please enter a valid email.",
|
"invalidemail": "Please enter a valid email.",
|
||||||
"invalidphone": "Please enter a valid phone number.",
|
"invalidphone": "Please enter a valid phone number.",
|
||||||
"required": "{{label}} is required."
|
"required": "{{label}} is required."
|
||||||
|
|||||||
@@ -1289,6 +1289,7 @@
|
|||||||
"unsavedchangespopup": ""
|
"unsavedchangespopup": ""
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
"dateRangeExceeded": "",
|
||||||
"invalidemail": "Por favor introduzca una dirección de correo electrónico válida.",
|
"invalidemail": "Por favor introduzca una dirección de correo electrónico válida.",
|
||||||
"invalidphone": "",
|
"invalidphone": "",
|
||||||
"required": "Este campo es requerido."
|
"required": "Este campo es requerido."
|
||||||
|
|||||||
@@ -1289,6 +1289,7 @@
|
|||||||
"unsavedchangespopup": ""
|
"unsavedchangespopup": ""
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
"dateRangeExceeded": "",
|
||||||
"invalidemail": "S'il vous plaît entrer un email valide.",
|
"invalidemail": "S'il vous plaît entrer un email valide.",
|
||||||
"invalidphone": "",
|
"invalidphone": "",
|
||||||
"required": "Ce champ est requis."
|
"required": "Ce champ est requis."
|
||||||
|
|||||||
41
server.js
41
server.js
@@ -24,6 +24,8 @@ const { ElastiCacheClient, DescribeCacheClustersCommand } = require("@aws-sdk/cl
|
|||||||
const { InstanceRegion } = require("./server/utils/instanceMgr");
|
const { InstanceRegion } = require("./server/utils/instanceMgr");
|
||||||
const StartStatusReporter = require("./server/utils/statusReporter");
|
const StartStatusReporter = require("./server/utils/statusReporter");
|
||||||
|
|
||||||
|
const cleanupTasks = [];
|
||||||
|
let isShuttingDown = false;
|
||||||
const CLUSTER_RETRY_BASE_DELAY = 100;
|
const CLUSTER_RETRY_BASE_DELAY = 100;
|
||||||
const CLUSTER_RETRY_MAX_DELAY = 5000;
|
const CLUSTER_RETRY_MAX_DELAY = 5000;
|
||||||
const CLUSTER_RETRY_JITTER = 100;
|
const CLUSTER_RETRY_JITTER = 100;
|
||||||
@@ -298,7 +300,14 @@ const main = async () => {
|
|||||||
applyRoutes({ app });
|
applyRoutes({ app });
|
||||||
redisSocketEvents({ io: ioRedis, redisHelpers, ioHelpers, logger });
|
redisSocketEvents({ io: ioRedis, redisHelpers, ioHelpers, logger });
|
||||||
|
|
||||||
StartStatusReporter();
|
const StatusReporter = StartStatusReporter();
|
||||||
|
registerCleanupTask(async () => {
|
||||||
|
StatusReporter.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add SIGTERM signal handler
|
||||||
|
process.on("SIGTERM", handleSigterm);
|
||||||
|
process.on("SIGINT", handleSigterm); // Optional: Handle Ctrl+C
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await server.listen(port);
|
await server.listen(port);
|
||||||
@@ -317,3 +326,33 @@ main().catch((error) => {
|
|||||||
// Note: If we want the app to crash on all uncaught async operations, we would
|
// Note: If we want the app to crash on all uncaught async operations, we would
|
||||||
// need to put a `process.exit(1);` here
|
// need to put a `process.exit(1);` here
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Register a cleanup task
|
||||||
|
function registerCleanupTask(task) {
|
||||||
|
cleanupTasks.push(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIGTERM handler
|
||||||
|
async function handleSigterm() {
|
||||||
|
if (isShuttingDown) {
|
||||||
|
logger.log("sigterm-api", "WARN", null, null, { message: "Shutdown already in progress, ignoring signal." });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isShuttingDown = true;
|
||||||
|
|
||||||
|
logger.log("sigterm-api", "WARN", null, null, { message: "SIGTERM Received. Starting graceful shutdown." });
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (const task of cleanupTasks) {
|
||||||
|
logger.log("sigterm-api", "WARN", null, null, { message: `Running cleanup task: ${task.name}` });
|
||||||
|
|
||||||
|
await task();
|
||||||
|
}
|
||||||
|
logger.log("sigterm-api", "WARN", null, null, { message: `All cleanup tasks completed.` });
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("sigterm-api-error", "ERROR", null, null, { message: error.message, stack: error.stack });
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const InstanceManager = require("../utils/instanceMgr").default;
|
|||||||
function StartStatusReporter() {
|
function StartStatusReporter() {
|
||||||
//For ImEX Online.
|
//For ImEX Online.
|
||||||
|
|
||||||
InstanceManager({
|
return InstanceManager({
|
||||||
executeFunction: true,
|
executeFunction: true,
|
||||||
args: [],
|
args: [],
|
||||||
imex: () => {
|
imex: () => {
|
||||||
@@ -31,14 +31,14 @@ function StartStatusReporter() {
|
|||||||
service_id: process.env.CRISP_SERVICE_IDENTIFIER, // Service ID containing the parent Node for Replica (given by Crisp)
|
service_id: process.env.CRISP_SERVICE_IDENTIFIER, // Service ID containing the parent Node for Replica (given by Crisp)
|
||||||
node_id: process.env.CRISP_NODE_IDENTIFIER, // Node ID containing Replica (given by Crisp)
|
node_id: process.env.CRISP_NODE_IDENTIFIER, // Node ID containing Replica (given by Crisp)
|
||||||
replica_id: getHostNameOrIP(), // Unique Replica ID for instance (ie. your IP on the LAN)
|
replica_id: getHostNameOrIP(), // Unique Replica ID for instance (ie. your IP on the LAN)
|
||||||
interval: 30, // Reporting interval (in seconds; defaults to 30 seconds if not set)
|
interval: 30 // Reporting interval (in seconds; defaults to 30 seconds if not set)
|
||||||
|
|
||||||
console: {
|
// console: {
|
||||||
debug: (log_message, data) => logger.log("crisp-status-update", "DEBUG", null, null, { log_message, data }),
|
// debug: (log_message, data) => logger.log("crisp-status-update", "DEBUG", null, null, { log_message, data }),
|
||||||
log: (log_message, data) => logger.log("crisp-status-update", "DEBUG", null, null, { log_message, data }),
|
// log: (log_message, data) => logger.log("crisp-status-update", "DEBUG", null, null, { log_message, data }),
|
||||||
warn: (log_message, data) => logger.log("crisp-status-update", "WARN", null, null, { log_message, data }),
|
// warn: (log_message, data) => logger.log("crisp-status-update", "WARN", null, null, { log_message, data }),
|
||||||
error: (log_message, data) => logger.log("crisp-status-update", "ERROR", null, null, { log_message, data })
|
// error: (log_message, data) => logger.log("crisp-status-update", "ERROR", null, null, { log_message, data })
|
||||||
} // Console instance if you need to debug issues,
|
// } // Console instance if you need to debug issues,
|
||||||
});
|
});
|
||||||
|
|
||||||
return crispStatusReporter;
|
return crispStatusReporter;
|
||||||
|
|||||||
Reference in New Issue
Block a user