diff --git a/.platform/hooks/predeploy/01-install-dd.sh b/.platform-disabled/hooks/predeploy/01-install-dd.sh similarity index 100% rename from .platform/hooks/predeploy/01-install-dd.sh rename to .platform-disabled/hooks/predeploy/01-install-dd.sh diff --git a/client/src/components/chat-media-selector/chat-media-selector.component.jsx b/client/src/components/chat-media-selector/chat-media-selector.component.jsx index 85ea7aa93..ff2336f69 100644 --- a/client/src/components/chat-media-selector/chat-media-selector.component.jsx +++ b/client/src/components/chat-media-selector/chat-media-selector.component.jsx @@ -40,7 +40,11 @@ export function ChatMediaSelector({ bodyshop, selectedMedia, setSelectedMedia, c variables: { jobId: conversation.job_conversations[0]?.jobid }, - skip: !open || !conversation.job_conversations || conversation.job_conversations.length === 0 + skip: + !open || + !conversation.job_conversations || + conversation.job_conversations.length === 0 || + bodyshop.uselocalmediaserver }); const handleVisibleChange = (change) => { @@ -48,7 +52,8 @@ export function ChatMediaSelector({ bodyshop, selectedMedia, setSelectedMedia, c }; useEffect(() => { - setSelectedMedia([]); + // Instead of wiping the array (which holds media objects), just clear selection flags + setSelectedMedia((prev) => prev.map((m) => ({ ...m, isSelected: false }))); }, [setSelectedMedia, conversation]); //Knowingly taking on the technical debt of poor implementation below. Done this way to avoid an edge case where no component may be displayed. @@ -75,6 +80,7 @@ export function ChatMediaSelector({ bodyshop, selectedMedia, setSelectedMedia, c )} @@ -90,6 +96,7 @@ export function ChatMediaSelector({ bodyshop, selectedMedia, setSelectedMedia, c )} @@ -110,6 +117,7 @@ export function ChatMediaSelector({ bodyshop, selectedMedia, setSelectedMedia, c trigger="click" open={open} onOpenChange={handleVisibleChange} + destroyOnHidden classNames={{ root: "media-selector-popover" }} > s.isSelected).length}> diff --git a/client/src/components/email-documents/email-documents.component.jsx b/client/src/components/email-documents/email-documents.component.jsx index 8882bd2da..1a1dc5e11 100644 --- a/client/src/components/email-documents/email-documents.component.jsx +++ b/client/src/components/email-documents/email-documents.component.jsx @@ -67,6 +67,7 @@ export function EmailDocumentsComponent({ emailConfig, form, selectedMediaState, )} @@ -82,6 +83,7 @@ export function EmailDocumentsComponent({ emailConfig, form, selectedMediaState, )} diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx index f631bf8ab..5ba5ce89e 100644 --- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx +++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx @@ -77,6 +77,8 @@ export function JobsDetailHeader({ job, bodyshop, disabled, insertAuditTrail, is .reduce((acc, val) => acc + val.mod_lb_hrs, 0); const ownerTitle = OwnerNameDisplayFunction(job).trim(); + const employeeData = bodyshop.associations.find((a) => a.useremail === job.admin_clerk)?.user?.employee ?? null; + // Handle checkbox changes const handleCheckboxChange = async (field, checked) => { const value = checked ? dayjs().toISOString() : null; @@ -162,7 +164,7 @@ export function JobsDetailHeader({ job, bodyshop, disabled, insertAuditTrail, is {job.cccontracts.map((c, index) => ( - {`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model}`} + {`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model} ${c.courtesycar.plate} - ${t(c.status)}`} {index !== job.cccontracts.length - 1 ? "," : null} @@ -355,6 +357,14 @@ export function JobsDetailHeader({ job, bodyshop, disabled, insertAuditTrail, is >
+ {job.admin_clerk && ( + <> + + + {employeeData?.displayName ?? job.admin_clerk} + + + )} {bodyHrs.toFixed(1)} / {refinishHrs.toFixed(1)} / {(bodyHrs + refinishHrs).toFixed(1)} diff --git a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.external.component.jsx b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.external.component.jsx index 47f1ebaa5..88bfe0dab 100644 --- a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.external.component.jsx +++ b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.external.component.jsx @@ -1,11 +1,12 @@ -import { useEffect } from "react"; -import { Gallery } from "react-grid-gallery"; +import { useEffect, useMemo, useState, useCallback } from "react"; +import LocalMediaGrid from "./local-media-grid.component"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { getJobMedia } from "../../redux/media/media.actions"; import { selectAllMedia } from "../../redux/media/media.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; +import LoadingSpinner from "../loading-spinner/loading-spinner.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -18,41 +19,127 @@ const mapDispatchToProps = (dispatch) => ({ export default connect(mapStateToProps, mapDispatchToProps)(JobDocumentsLocalGalleryExternal); -function JobDocumentsLocalGalleryExternal({ jobId, externalMediaState, getJobMedia, allMedia }) { +/** + * JobDocumentsLocalGalleryExternal + * Fetches and displays job-related image media using the custom LocalMediaGrid. + * + * Props: + * - jobId: string | number (required to fetch media) + * - externalMediaState: [imagesArray, setImagesFn] (state lifted to parent for shared selection) + * - getJobMedia: dispatching function to retrieve media for a job + * - allMedia: redux slice keyed by jobId containing raw media records + * - context: "chat" | "email" | other string used to drive grid behavior + * + * Notes: + * - The previous third-party gallery required a remount key (openVersion); custom grid no longer does. + * - Selection flags are preserved when media refreshes. + * - Loading state ends after transformation regardless of whether any images were found. + */ +function JobDocumentsLocalGalleryExternal({ jobId, externalMediaState, getJobMedia, allMedia, context = "chat" }) { const [galleryImages, setgalleryImages] = externalMediaState; - const { t } = useTranslation(); + const [isLoading, setIsLoading] = useState(false); + const { t } = useTranslation(); // i18n hook retained if future translations are added + const DEBUG_LOCAL_GALLERY = false; // flip to true for verbose console logging + // Transform raw media record into a normalized image object consumed by the grid. + const transformMediaToImages = useCallback((raw) => { + return raw + .filter((m) => m.type?.mime?.startsWith("image")) + .map((m) => ({ + ...m, + src: m.thumbnail, + thumbnail: m.thumbnail, + fullsize: m.src, + width: 225, + height: 225, + thumbnailWidth: 225, + thumbnailHeight: 225, + caption: m.filename || m.key + })); + }, []); + + // Fetch media when jobId changes (network request triggers Redux update -> documents memo recalculates). useEffect(() => { - if (jobId) { - getJobMedia(jobId); - } + if (!jobId) return; + setIsLoading(true); + getJobMedia(jobId); }, [jobId, getJobMedia]); - useEffect(() => { - let documents = allMedia?.[jobId] - ? allMedia[jobId].reduce((acc, val) => { - if (val.type?.mime && val.type.mime.startsWith("image")) { - acc.push({ ...val, src: val.thumbnail, fullsize: val.src }); - } - return acc; - }, []) - : []; - console.log( - "🚀 ~ file: jobs-documents-local-gallery.external.component.jsx:48 ~ useEffect ~ documents:", - documents - ); + // Memo: transform raw redux media into gallery documents. + const documents = useMemo( + () => transformMediaToImages(allMedia?.[jobId] || []), + [allMedia, jobId, transformMediaToImages] + ); - setgalleryImages(documents); - }, [allMedia, jobId, setgalleryImages, t]); + // Sync transformed documents into external state while preserving selection flags. + useEffect(() => { + const prevSelection = new Map(galleryImages.map((p) => [p.filename, p.isSelected])); + const nextImages = documents.map((d) => ({ ...d, isSelected: prevSelection.get(d.filename) || false })); + // Micro-optimization: if array length and each filename + selection flag match, skip creating a new array. + if (galleryImages.length === nextImages.length) { + let identical = true; + for (let i = 0; i < nextImages.length; i++) { + if ( + galleryImages[i].filename !== nextImages[i].filename || + galleryImages[i].isSelected !== nextImages[i].isSelected + ) { + identical = false; + break; + } + } + if (identical) { + setIsLoading(false); // ensure loading stops even on no-change + if (DEBUG_LOCAL_GALLERY) { + console.log("[LocalGallery] documents unchanged", { jobId, count: documents.length }); + } + return; + } + } + setgalleryImages(nextImages); + setIsLoading(false); // stop loading after transform regardless of emptiness + if (DEBUG_LOCAL_GALLERY) { + console.log("[LocalGallery] documents transformed", { jobId, count: documents.length }); + } + }, [documents, setgalleryImages, galleryImages, jobId, DEBUG_LOCAL_GALLERY]); + + // Toggle handler (stable reference) + const handleToggle = useCallback( + (idx) => { + setgalleryImages((imgs) => imgs.map((g, gIdx) => (gIdx === idx ? { ...g, isSelected: !g.isSelected } : g))); + }, + [setgalleryImages] + ); + + const messageStyle = { textAlign: "center", padding: "1rem" }; // retained for potential future states + + if (!jobId) { + return ( +
+
No job selected.
+
+ ); + } return ( -
- { - setgalleryImages(galleryImages.map((g, idx) => (index === idx ? { ...g, isSelected: !g.isSelected } : g))); - }} - /> +
+ {isLoading && galleryImages.length === 0 && ( +
+ +
+ )} + {galleryImages.length > 0 && ( + + )} + {galleryImages.length > 0 && ( +
+ {`${t("general.labels.media")}: ${galleryImages.length}`} +
+ )}
); } diff --git a/client/src/components/jobs-documents-local-gallery/local-media-grid.component.jsx b/client/src/components/jobs-documents-local-gallery/local-media-grid.component.jsx new file mode 100644 index 000000000..277351296 --- /dev/null +++ b/client/src/components/jobs-documents-local-gallery/local-media-grid.component.jsx @@ -0,0 +1,207 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; + +/** + * LocalMediaGrid + * Lightweight replacement for react-grid-gallery inside the chat popover. + * Props: + * - images: Array<{ src, fullsize, filename?, isSelected? }> + * - onToggle(index) + */ +export function LocalMediaGrid({ + images, + onToggle, + thumbSize = 100, + gap = 8, + minColumns = 3, + maxColumns = 12, + context = "default" +}) { + const containerRef = useRef(null); + const [cols, setCols] = useState(() => { + // Pre-calc initial columns to stabilize layout before images render + const count = images.length; + if (count === 0) return minColumns; // reserve minimal structure + if (count === 1 && context === "chat") return 1; + return Math.min(maxColumns, Math.max(minColumns, count)); + }); + const [justifyMode, setJustifyMode] = useState("start"); + const [distributeExtra, setDistributeExtra] = useState(false); + const [loadedMap, setLoadedMap] = useState(() => new Map()); // filename -> boolean loaded + + const handleImageLoad = useCallback((key) => { + setLoadedMap((prev) => { + if (prev.get(key)) return prev; // already loaded + const next = new Map(prev); + next.set(key, true); + return next; + }); + }, []); + + // Dynamically compute columns for all contexts to avoid auto-fit stretching gaps in email overlay + useEffect(() => { + const el = containerRef.current; + if (!el) return; + const compute = () => { + // For non-chat (email / default) we rely on CSS auto-fill; only chat needs explicit column calc & distribution logic. + if (context !== "chat") { + setCols(images.length || 0); // retain count for ARIA semantics; not used for template when non-chat. + setDistributeExtra(false); + return; + } + const width = el.clientWidth; + if (!width) return; + const perCol = thumbSize + gap; // track + gap space + const fitCols = Math.max(1, Math.floor((width + gap) / perCol)); + // base desired columns: up to how many images we have and how many fit + let finalCols = Math.min(images.length || 1, fitCols, maxColumns); + // enforce minimum columns to reserve layout skeleton (except when fewer images) + if (finalCols < minColumns && images.length >= minColumns) { + finalCols = Math.min(fitCols, minColumns); + } + // chat-specific clamp + if (context === "chat") { + finalCols = Math.min(finalCols, 4); + } + if (finalCols < 1) finalCols = 1; + setCols(finalCols); + setJustifyMode("start"); + + // Determine if there is leftover horizontal space that can't fit another column. + // Only distribute when we're at the maximum allowed columns for the context and images exceed or meet that count. + const contextMax = context === "chat" ? 4 : maxColumns; + const baseWidthNeeded = finalCols * thumbSize + (finalCols - 1) * gap; + const leftover = width - baseWidthNeeded; + const atMaxColumns = finalCols === contextMax && images.length >= finalCols; + // leftover must be positive but less than space needed for an additional column (perCol) + if (atMaxColumns && leftover > 0 && leftover < perCol) { + setDistributeExtra(true); + } else { + setDistributeExtra(false); + } + }; + compute(); + const ro = new ResizeObserver(() => compute()); + ro.observe(el); + return () => ro.disconnect(); + }, [images.length, thumbSize, gap, minColumns, maxColumns, context]); + + const gridTemplateColumns = useMemo(() => { + if (context === "chat") { + if (distributeExtra) { + return `repeat(${cols}, minmax(${thumbSize}px, 1fr))`; + } + return `repeat(${cols}, ${thumbSize}px)`; + } + // Non-chat contexts: allow browser to auto-fill columns; fixed min (thumbSize) ensures squares; tracks expand to distribute remaining space. + return `repeat(auto-fill, minmax(${thumbSize}px, 1fr))`; + }, [cols, thumbSize, distributeExtra, context]); + const stableWidth = undefined; // no fixed width + + const handleKeyDown = useCallback( + (e, idx) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + onToggle(idx); + } + }, + [onToggle] + ); + + return ( +
+ {images.map((img, idx) => ( +
onToggle(idx)} + onKeyDown={(e) => handleKeyDown(e, idx)} + style={{ + position: "relative", + border: img.isSelected ? "2px solid #1890ff" : "1px solid #ccc", + outline: "none", + borderRadius: 4, + cursor: "pointer", + background: "#fafafa", + width: thumbSize, + height: thumbSize, + overflow: "hidden", + boxSizing: "border-box" + }} + > + {(() => { + const key = img.filename || idx; + const loaded = loadedMap.get(key) === true; + return ( + <> + {!loaded && ( + + )} + {img.filename handleImageLoad(key)} + style={{ + width: thumbSize, + height: thumbSize, + objectFit: "cover", + display: "block", + borderRadius: 4, + opacity: loaded ? 1 : 0, + transition: "opacity .25s ease" + }} + /> + + ); + })()} + {img.isSelected && ( + + ))} + {/* No placeholders needed; layout uses auto-fit for non-chat or fixed columns for chat */} +
+ ); +} + +export default LocalMediaGrid; diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index f9f1cd55f..35dde7016 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -424,6 +424,7 @@ export const GET_JOB_BY_PK = gql` actual_delivery actual_in acv_amount + admin_clerk adjustment_bottom_line alt_transport area_of_damage @@ -2347,12 +2348,13 @@ export const MARK_JOB_AS_UNINVOICED = gql` mutation MARK_JOB_AS_UNINVOICED($jobId: uuid!, $default_delivered: String!) { update_jobs_by_pk( pk_columns: { id: $jobId } - _set: { date_exported: null, date_invoiced: null, status: $default_delivered } + _set: { date_exported: null, date_invoiced: null, status: $default_delivered, admin_clerk: null } ) { id date_exported date_invoiced status + admin_clerk } } `; diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx index 2423e2e6b..1719ed38d 100644 --- a/client/src/pages/jobs-close/jobs-close.component.jsx +++ b/client/src/pages/jobs-close/jobs-close.component.jsx @@ -39,13 +39,14 @@ import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { setModalContext } from "../../redux/modals/modals.actions.js"; -import { selectBodyshop } from "../../redux/user/user.selectors"; +import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; import dayjs from "../../utils/day"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, - jobRO: selectJobReadOnly + jobRO: selectJobReadOnly, + currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ @@ -59,7 +60,7 @@ const mapDispatchToProps = (dispatch) => ({ ) }); -export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, setPrintCenterContext }) { +export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, setPrintCenterContext, currentUser }) { const { t } = useTranslation(); const [form] = Form.useForm(); const client = useApolloClient(); @@ -97,6 +98,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, set kmin: values.kmin, kmout: values.kmout, dms_allocation: values.dms_allocation, + admin_clerk: currentUser.email, ...(removefromproduction ? { inproduction: false } : {}), ...(values.qb_multiple_payers ? { qb_multiple_payers: values.qb_multiple_payers } : {}) } diff --git a/client/src/redux/media/media.reducer.js b/client/src/redux/media/media.reducer.js index ace8cac46..7199fdff2 100644 --- a/client/src/redux/media/media.reducer.js +++ b/client/src/redux/media/media.reducer.js @@ -19,29 +19,19 @@ const mediaReducer = (state = INITIAL_STATE, action) => { case MediaActionTypes.TOGGLE_MEDIA_SELECTED: return { ...state, - [action.payload.jobid]: state[action.payload.jobid].map((p) => { - if (p.filename === action.payload.filename) { - p.isSelected = !p.isSelected; - } - return p; - }) + [action.payload.jobid]: state[action.payload.jobid].map((p) => + p.filename === action.payload.filename ? { ...p, isSelected: !p.isSelected } : p + ) }; case MediaActionTypes.SELECT_ALL_MEDIA_FOR_JOB: return { ...state, - [action.payload.jobid]: state[action.payload.jobid].map((p) => { - p.isSelected = true; - - return p; - }) + [action.payload.jobid]: state[action.payload.jobid].map((p) => ({ ...p, isSelected: true })) }; case MediaActionTypes.DESELECT_ALL_MEDIA_FOR_JOB: return { ...state, - [action.payload.jobid]: state[action.payload.jobid].map((p) => { - p.isSelected = false; - return p; - }) + [action.payload.jobid]: state[action.payload.jobid].map((p) => ({ ...p, isSelected: false })) }; default: return state; diff --git a/client/src/redux/media/media.sagas.js b/client/src/redux/media/media.sagas.js index a85109776..7b88ea73e 100644 --- a/client/src/redux/media/media.sagas.js +++ b/client/src/redux/media/media.sagas.js @@ -17,9 +17,10 @@ export function* getJobMedia({ payload: jobid }) { const imagesFetch = yield cleanAxios.post( `${localmediaserverhttp}/jobs/list`, { - jobid + jobid, + }, - { headers: { ims_token: bodyshop.localmediatoken } } + { headers: { ims_token: bodyshop.localmediatoken, bodyshopid: bodyshop.id } } ); const documentsFetch = yield cleanAxios.post( `${localmediaserverhttp}/bills/list`, diff --git a/client/src/redux/media/media.selectors.js b/client/src/redux/media/media.selectors.js index e5c930e5c..8c1123bb1 100644 --- a/client/src/redux/media/media.selectors.js +++ b/client/src/redux/media/media.selectors.js @@ -2,4 +2,5 @@ import { createSelector } from "reselect"; const selectMedia = (state) => state.media; -export const selectAllMedia = createSelector([selectMedia], (media) => media); +// Return a shallow copy to avoid identity selector warning and allow memoization to detect actual changes. +export const selectAllMedia = createSelector([selectMedia], (media) => ({ ...media })); diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 05219fd5e..193aba22a 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1678,6 +1678,7 @@ "actual_delivery": "Actual Delivery", "actual_in": "Actual In", "acv_amount": "ACV Amount", + "admin_clerk": "Admin Clerk", "adjustment_bottom_line": "Adjustments", "adjustmenthours": "Adjustment Hours", "alt_transport": "Alt. Trans.", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 20610391c..41a01b191 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -1679,6 +1679,7 @@ "actual_in": "Real en", "acv_amount": "", "adjustment_bottom_line": "Ajustes", + "admin_clerk": "", "adjustmenthours": "", "alt_transport": "", "area_of_damage_impact": { diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 76d5bbd1d..e80baacbc 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1678,6 +1678,7 @@ "actual_delivery": "Livraison réelle", "actual_in": "En réel", "acv_amount": "", + "admin_clerk": "", "adjustment_bottom_line": "Ajustements", "adjustmenthours": "", "alt_transport": "", diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 74a00b23b..a52ea634f 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -3615,6 +3615,7 @@ - adj_strdis - adj_towdis - adjustment_bottom_line + - admin_clerk - agt_addr1 - agt_addr2 - agt_city @@ -3890,6 +3891,7 @@ - adj_strdis - adj_towdis - adjustment_bottom_line + - admin_clerk - agt_addr1 - agt_addr2 - agt_city @@ -4178,6 +4180,7 @@ - adj_strdis - adj_towdis - adjustment_bottom_line + - admin_clerk - agt_addr1 - agt_addr2 - agt_city @@ -4705,6 +4708,34 @@ - key - value filter: {} +- table: + name: media_analytics + schema: public + object_relationships: + - name: bodyshop + using: + foreign_key_constraint_on: bodyshopid + array_relationships: + - name: media_analytics_details + using: + foreign_key_constraint_on: + column: media_analytics_id + table: + name: media_analytics_detail + schema: public +- table: + name: media_analytics_detail + schema: public + object_relationships: + - name: bodyshop + using: + foreign_key_constraint_on: bodyshopid + - name: job + using: + foreign_key_constraint_on: jobid + - name: media_analytic + using: + foreign_key_constraint_on: media_analytics_id - table: name: messages schema: public diff --git a/hasura/migrations/1762378985244_create_table_public_media_analytics/down.sql b/hasura/migrations/1762378985244_create_table_public_media_analytics/down.sql new file mode 100644 index 000000000..4ad01fe88 --- /dev/null +++ b/hasura/migrations/1762378985244_create_table_public_media_analytics/down.sql @@ -0,0 +1 @@ +DROP TABLE "public"."media_analytics"; diff --git a/hasura/migrations/1762378985244_create_table_public_media_analytics/up.sql b/hasura/migrations/1762378985244_create_table_public_media_analytics/up.sql new file mode 100644 index 000000000..4737001d2 --- /dev/null +++ b/hasura/migrations/1762378985244_create_table_public_media_analytics/up.sql @@ -0,0 +1,18 @@ +CREATE TABLE "public"."media_analytics" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "bodyshopid" uuid NOT NULL, "total_jobs" integer NOT NULL DEFAULT 0, "total_documents" integer NOT NULL DEFAULT 0, "file_type_stats" jsonb NOT NULL DEFAULT jsonb_build_object(), PRIMARY KEY ("id") , FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE restrict ON DELETE restrict);COMMENT ON TABLE "public"."media_analytics" IS E'LMS Media Analytics'; +CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"() +RETURNS TRIGGER AS $$ +DECLARE + _new record; +BEGIN + _new := NEW; + _new."updated_at" = NOW(); + RETURN _new; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER "set_public_media_analytics_updated_at" +BEFORE UPDATE ON "public"."media_analytics" +FOR EACH ROW +EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"(); +COMMENT ON TRIGGER "set_public_media_analytics_updated_at" ON "public"."media_analytics" +IS 'trigger to set value of column "updated_at" to current timestamp on row update'; +CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/hasura/migrations/1762380389542_create_table_public_media_analytics_detail/down.sql b/hasura/migrations/1762380389542_create_table_public_media_analytics_detail/down.sql new file mode 100644 index 000000000..f24f86d54 --- /dev/null +++ b/hasura/migrations/1762380389542_create_table_public_media_analytics_detail/down.sql @@ -0,0 +1 @@ +DROP TABLE "public"."media_analytics_detail"; diff --git a/hasura/migrations/1762380389542_create_table_public_media_analytics_detail/up.sql b/hasura/migrations/1762380389542_create_table_public_media_analytics_detail/up.sql new file mode 100644 index 000000000..e98665d28 --- /dev/null +++ b/hasura/migrations/1762380389542_create_table_public_media_analytics_detail/up.sql @@ -0,0 +1,2 @@ +CREATE TABLE "public"."media_analytics_detail" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "media_analytics_id" uuid NOT NULL, "jobid" uuid NOT NULL, "bodyshopid" uuid NOT NULL, "document_count" integer NOT NULL, "total_size_bytes" integer NOT NULL, "file_type_stats" jsonb NOT NULL DEFAULT jsonb_build_object(), PRIMARY KEY ("id") , FOREIGN KEY ("media_analytics_id") REFERENCES "public"."media_analytics"("id") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE restrict ON DELETE restrict); +CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/hasura/migrations/1762393769918_alter_table_public_jobs_add_column_admin_clerk/down.sql b/hasura/migrations/1762393769918_alter_table_public_jobs_add_column_admin_clerk/down.sql new file mode 100644 index 000000000..43e3c403d --- /dev/null +++ b/hasura/migrations/1762393769918_alter_table_public_jobs_add_column_admin_clerk/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."jobs" add column "admin_clerk" text +-- null; diff --git a/hasura/migrations/1762393769918_alter_table_public_jobs_add_column_admin_clerk/up.sql b/hasura/migrations/1762393769918_alter_table_public_jobs_add_column_admin_clerk/up.sql new file mode 100644 index 000000000..ec6f510c5 --- /dev/null +++ b/hasura/migrations/1762393769918_alter_table_public_jobs_add_column_admin_clerk/up.sql @@ -0,0 +1,2 @@ +alter table "public"."jobs" add column "admin_clerk" text + null; diff --git a/hasura/migrations/1762461945311_alter_table_public_media_analytics_add_column_total_size_bytes/down.sql b/hasura/migrations/1762461945311_alter_table_public_media_analytics_add_column_total_size_bytes/down.sql new file mode 100644 index 000000000..3e4d98345 --- /dev/null +++ b/hasura/migrations/1762461945311_alter_table_public_media_analytics_add_column_total_size_bytes/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."media_analytics" add column "total_size_bytes" integer +-- null; diff --git a/hasura/migrations/1762461945311_alter_table_public_media_analytics_add_column_total_size_bytes/up.sql b/hasura/migrations/1762461945311_alter_table_public_media_analytics_add_column_total_size_bytes/up.sql new file mode 100644 index 000000000..4567ad705 --- /dev/null +++ b/hasura/migrations/1762461945311_alter_table_public_media_analytics_add_column_total_size_bytes/up.sql @@ -0,0 +1,2 @@ +alter table "public"."media_analytics" add column "total_size_bytes" integer + null; diff --git a/hasura/migrations/1762461962953_alter_table_public_media_analytics_add_column_total_size_mb/down.sql b/hasura/migrations/1762461962953_alter_table_public_media_analytics_add_column_total_size_mb/down.sql new file mode 100644 index 000000000..bc5749bba --- /dev/null +++ b/hasura/migrations/1762461962953_alter_table_public_media_analytics_add_column_total_size_mb/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."media_analytics" add column "total_size_mb" numeric +-- null; diff --git a/hasura/migrations/1762461962953_alter_table_public_media_analytics_add_column_total_size_mb/up.sql b/hasura/migrations/1762461962953_alter_table_public_media_analytics_add_column_total_size_mb/up.sql new file mode 100644 index 000000000..cf5636cf4 --- /dev/null +++ b/hasura/migrations/1762461962953_alter_table_public_media_analytics_add_column_total_size_mb/up.sql @@ -0,0 +1,2 @@ +alter table "public"."media_analytics" add column "total_size_mb" numeric + null; diff --git a/hasura/migrations/1762464155142_alter_table_public_media_analytics_detail_add_column_total_size_mb/down.sql b/hasura/migrations/1762464155142_alter_table_public_media_analytics_detail_add_column_total_size_mb/down.sql new file mode 100644 index 000000000..48efb4911 --- /dev/null +++ b/hasura/migrations/1762464155142_alter_table_public_media_analytics_detail_add_column_total_size_mb/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."media_analytics_detail" add column "total_size_mb" numeric +-- null; diff --git a/hasura/migrations/1762464155142_alter_table_public_media_analytics_detail_add_column_total_size_mb/up.sql b/hasura/migrations/1762464155142_alter_table_public_media_analytics_detail_add_column_total_size_mb/up.sql new file mode 100644 index 000000000..4a0fde33a --- /dev/null +++ b/hasura/migrations/1762464155142_alter_table_public_media_analytics_detail_add_column_total_size_mb/up.sql @@ -0,0 +1,2 @@ +alter table "public"."media_analytics_detail" add column "total_size_mb" numeric + null; diff --git a/hasura/migrations/1762464955745_alter_table_public_media_analytics_detail_alter_column_jobid/down.sql b/hasura/migrations/1762464955745_alter_table_public_media_analytics_detail_alter_column_jobid/down.sql new file mode 100644 index 000000000..baeb4aef5 --- /dev/null +++ b/hasura/migrations/1762464955745_alter_table_public_media_analytics_detail_alter_column_jobid/down.sql @@ -0,0 +1 @@ +alter table "public"."media_analytics_detail" alter column "jobid" set not null; diff --git a/hasura/migrations/1762464955745_alter_table_public_media_analytics_detail_alter_column_jobid/up.sql b/hasura/migrations/1762464955745_alter_table_public_media_analytics_detail_alter_column_jobid/up.sql new file mode 100644 index 000000000..641d87df7 --- /dev/null +++ b/hasura/migrations/1762464955745_alter_table_public_media_analytics_detail_alter_column_jobid/up.sql @@ -0,0 +1 @@ +alter table "public"."media_analytics_detail" alter column "jobid" drop not null; diff --git a/hasura/migrations/1762546299465_alter_table_public_media_analytics_alter_column_total_size_bytes/down.sql b/hasura/migrations/1762546299465_alter_table_public_media_analytics_alter_column_total_size_bytes/down.sql new file mode 100644 index 000000000..8a8d722db --- /dev/null +++ b/hasura/migrations/1762546299465_alter_table_public_media_analytics_alter_column_total_size_bytes/down.sql @@ -0,0 +1 @@ +ALTER TABLE "public"."media_analytics" ALTER COLUMN "total_size_bytes" TYPE integer; diff --git a/hasura/migrations/1762546299465_alter_table_public_media_analytics_alter_column_total_size_bytes/up.sql b/hasura/migrations/1762546299465_alter_table_public_media_analytics_alter_column_total_size_bytes/up.sql new file mode 100644 index 000000000..41be3af0d --- /dev/null +++ b/hasura/migrations/1762546299465_alter_table_public_media_analytics_alter_column_total_size_bytes/up.sql @@ -0,0 +1 @@ +ALTER TABLE "public"."media_analytics" ALTER COLUMN "total_size_bytes" TYPE numeric; diff --git a/hasura/migrations/1762546323722_alter_table_public_media_analytics_detail_alter_column_total_size_bytes/down.sql b/hasura/migrations/1762546323722_alter_table_public_media_analytics_detail_alter_column_total_size_bytes/down.sql new file mode 100644 index 000000000..8c75804d7 --- /dev/null +++ b/hasura/migrations/1762546323722_alter_table_public_media_analytics_detail_alter_column_total_size_bytes/down.sql @@ -0,0 +1 @@ +ALTER TABLE "public"."media_analytics_detail" ALTER COLUMN "total_size_bytes" TYPE integer; diff --git a/hasura/migrations/1762546323722_alter_table_public_media_analytics_detail_alter_column_total_size_bytes/up.sql b/hasura/migrations/1762546323722_alter_table_public_media_analytics_detail_alter_column_total_size_bytes/up.sql new file mode 100644 index 000000000..7320b541a --- /dev/null +++ b/hasura/migrations/1762546323722_alter_table_public_media_analytics_detail_alter_column_total_size_bytes/up.sql @@ -0,0 +1 @@ +ALTER TABLE "public"."media_analytics_detail" ALTER COLUMN "total_size_bytes" TYPE numeric; diff --git a/package-lock.json b/package-lock.json index f32c42f22..673507a20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,6 @@ "cookie-parser": "^1.4.7", "cors": "^2.8.5", "crisp-status-reporter": "^1.2.2", - "dd-trace": "^5.70.0", "dinero.js": "^1.9.1", "dotenv": "^17.2.3", "express": "^4.21.1", @@ -1261,98 +1260,6 @@ "kuler": "^2.0.0" } }, - "node_modules/@datadog/libdatadog": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@datadog/libdatadog/-/libdatadog-0.7.0.tgz", - "integrity": "sha512-VVZLspzQcfEU47gmGCVoRkngn7RgFRR4CHjw4YaX8eWT+xz4Q4l6PvA45b7CMk9nlt3MNN5MtGdYttYMIpo6Sg==", - "license": "Apache-2.0" - }, - "node_modules/@datadog/native-appsec": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/@datadog/native-appsec/-/native-appsec-10.2.1.tgz", - "integrity": "sha512-FwRVo+otgNaz6vN74XVrBT8GdLwxPwAqOjH4Y9VQJaC1RiHmzRCMr77AhHFme1xi7zPG2LQqQN/cmOzG+sbrtQ==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "node-gyp-build": "^3.9.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@datadog/native-iast-taint-tracking": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@datadog/native-iast-taint-tracking/-/native-iast-taint-tracking-4.0.0.tgz", - "integrity": "sha512-2uF8RnQkJO5bmLi26Zkhxg+RFJn/uEsesYTflScI/Cz/BWv+792bxI+OaCKvhgmpLkm8EElenlpidcJyZm7GYw==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "node-gyp-build": "^3.9.0" - } - }, - "node_modules/@datadog/native-metrics": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@datadog/native-metrics/-/native-metrics-3.1.1.tgz", - "integrity": "sha512-MU1gHrolwryrU4X9g+fylA1KPH3S46oqJPEtVyrO+3Kh29z80fegmtyrU22bNt8LigPUK/EdPCnSbMe88QbnxQ==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "node-addon-api": "^6.1.0", - "node-gyp-build": "^3.9.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@datadog/pprof": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@datadog/pprof/-/pprof-5.10.0.tgz", - "integrity": "sha512-tEMhLeOM78FHC/rTltDd7pQN8WPAUZ1b0BPadYsKWqo/v6jWTbF6xeIMojdJa5yIW2vHjDU4LFJpkFFNacHpQw==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "delay": "^5.0.0", - "node-gyp-build": "<4.0", - "p-limit": "^3.1.0", - "pprof-format": "^2.2.1", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@datadog/sketches-js": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@datadog/sketches-js/-/sketches-js-2.1.1.tgz", - "integrity": "sha512-d5RjycE+MObE/hU+8OM5Zp4VjTwiPLRa8299fj7muOmR16fb942z8byoMbCErnGh0lBevvgkGrLclQDvINbIyg==", - "license": "Apache-2.0" - }, - "node_modules/@datadog/wasm-js-rewriter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@datadog/wasm-js-rewriter/-/wasm-js-rewriter-4.0.1.tgz", - "integrity": "sha512-JRa05Je6gw+9+3yZnm/BroQZrEfNwRYCxms56WCCHzOBnoPihQLB0fWy5coVJS29kneCUueUvBvxGp6NVXgdqw==", - "license": "Apache-2.0", - "dependencies": { - "js-yaml": "^4.1.0", - "lru-cache": "^7.14.0", - "module-details-from-path": "^1.0.3", - "node-gyp-build": "^4.5.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@datadog/wasm-js-rewriter/node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, "node_modules/@esbuild/win32-x64": { "version": "0.25.6", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", @@ -1853,15 +1760,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/ttlcache": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", - "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", @@ -1880,30 +1778,6 @@ "url": "https://opencollective.com/js-sdsl" } }, - "node_modules/@jsep-plugin/assignment": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", - "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" - } - }, - "node_modules/@jsep-plugin/regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", - "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" - } - }, "node_modules/@kurkle/color": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", @@ -2006,34 +1880,11 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", "license": "Apache-2.0", + "optional": true, "engines": { "node": ">=8.0.0" } }, - "node_modules/@opentelemetry/core": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", - "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", - "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, "node_modules/@paralleldrive/cuid2": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", @@ -2057,31 +1908,36 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "license": "BSD-3-Clause", + "optional": true, "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -2091,31 +1947,36 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.45.0", @@ -3341,6 +3202,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3349,15 +3211,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "license": "MIT", - "peerDependencies": { - "acorn": "^8" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -3476,6 +3329,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, "license": "Python-2.0" }, "node_modules/array-buffer-byte-length": { @@ -4109,12 +3963,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "license": "MIT" - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -4596,12 +4444,6 @@ "node": ">= 8" } }, - "node_modules/crypto-randomuuid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-randomuuid/-/crypto-randomuuid-1.0.0.tgz", - "integrity": "sha512-/RC5F4l1SCqD/jazwUF6+t34Cd8zTSAGZ7rvvZu1whZUhD2a5MOGKjSGowoGcpj/cbVZk1ZODIooJEQQq3nNAA==", - "license": "MIT" - }, "node_modules/csrf": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", @@ -4704,75 +4546,6 @@ "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", "license": "MIT" }, - "node_modules/dc-polyfill": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/dc-polyfill/-/dc-polyfill-0.1.10.tgz", - "integrity": "sha512-9iSbB8XZ7aIrhUtWI5ulEOJ+IyUN+axquodHK+bZO4r7HfY/xwmo6I4fYYf+aiDom+WMcN/wnzCz+pKvHDDCug==", - "license": "MIT", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/dd-trace": { - "version": "5.70.0", - "resolved": "https://registry.npmjs.org/dd-trace/-/dd-trace-5.70.0.tgz", - "integrity": "sha512-A757IJ3OIrRvFQXqa7bZ8KvwwtnjTEhj/2mNG88mNAbaildJI+FKQHDQWMM02YvQeJHwneeS6dmTj2V1mVnGrg==", - "hasInstallScript": true, - "license": "(Apache-2.0 OR BSD-3-Clause)", - "dependencies": { - "@datadog/libdatadog": "0.7.0", - "@datadog/native-appsec": "10.2.1", - "@datadog/native-iast-taint-tracking": "4.0.0", - "@datadog/native-metrics": "3.1.1", - "@datadog/pprof": "5.10.0", - "@datadog/sketches-js": "2.1.1", - "@datadog/wasm-js-rewriter": "4.0.1", - "@isaacs/ttlcache": "^1.4.1", - "@opentelemetry/api": ">=1.0.0 <1.10.0", - "@opentelemetry/core": ">=1.14.0 <1.31.0", - "crypto-randomuuid": "^1.0.0", - "dc-polyfill": "^0.1.10", - "ignore": "^7.0.5", - "import-in-the-middle": "^1.14.2", - "istanbul-lib-coverage": "^3.2.2", - "jest-docblock": "^29.7.0", - "jsonpath-plus": "^10.3.0", - "limiter": "^1.1.5", - "lodash.sortby": "^4.7.0", - "lru-cache": "^10.4.3", - "module-details-from-path": "^1.0.4", - "mutexify": "^1.4.0", - "opentracing": ">=0.14.7", - "path-to-regexp": "^0.1.12", - "pprof-format": "^2.1.1", - "protobufjs": "^7.5.3", - "retry": "^0.13.1", - "rfdc": "^1.4.1", - "semifies": "^1.0.0", - "shell-quote": "^1.8.2", - "source-map": "^0.7.4", - "tlhunter-sorted-set": "^0.1.0", - "ttl-set": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/dd-trace/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/dd-trace/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -4861,18 +4634,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/delay": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", - "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4929,15 +4690,6 @@ "node": ">=8" } }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/dev-null": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", @@ -6818,18 +6570,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-in-the-middle": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.14.2.tgz", - "integrity": "sha512-5tCuY9BV8ujfOpwtAGgsTx9CGUapcFMEEyByLv1B+v2+6DhAcw+Zr0nhQT7uwaZ7DiourxFEscghOR8e1aPLQw==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.14.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^1.2.2", - "module-details-from-path": "^1.0.3" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -7332,15 +7072,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, "node_modules/iterator.prototype": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", @@ -7374,18 +7105,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/jose": { "version": "4.15.9", "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", @@ -7412,6 +7131,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -7420,15 +7140,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsep": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", - "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - } - }, "node_modules/json-2-csv": { "version": "5.5.9", "resolved": "https://registry.npmjs.org/json-2-csv/-/json-2-csv-5.5.9.tgz", @@ -7481,24 +7192,6 @@ "json11": "dist/cli.mjs" } }, - "node_modules/jsonpath-plus": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", - "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", - "license": "MIT", - "dependencies": { - "@jsep-plugin/assignment": "^1.3.0", - "@jsep-plugin/regex": "^1.0.4", - "jsep": "^1.4.0" - }, - "bin": { - "jsonpath": "bin/jsonpath-cli.js", - "jsonpath-plus": "bin/jsonpath-cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -7831,12 +7524,6 @@ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "license": "MIT" - }, "node_modules/logform": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", @@ -7858,7 +7545,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "optional": true }, "node_modules/loose-envify": { "version": "1.4.0", @@ -7880,15 +7568,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/lru-memoizer": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz", @@ -8091,12 +7770,6 @@ "node": ">=0.10.0" } }, - "node_modules/module-details-from-path": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", - "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", - "license": "MIT" - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -8173,15 +7846,6 @@ "node": ">= 6.0.0" } }, - "node_modules/mutexify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.4.0.tgz", - "integrity": "sha512-pbYSsOrSB/AKN5h/WzzLRMFgZhClWccf2XIB4RSMC8JbquiB0e0/SH5AIfdQMdyHmYtv4seU7yV/TvAwPLJ1Yg==", - "license": "MIT", - "dependencies": { - "queue-tick": "^1.0.0" - } - }, "node_modules/nan": { "version": "2.22.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", @@ -8230,12 +7894,6 @@ "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", "license": "MIT" }, - "node_modules/node-addon-api": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", - "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "license": "MIT" - }, "node_modules/node-eta": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/node-eta/-/node-eta-0.9.0.tgz", @@ -8271,17 +7929,6 @@ "node": ">= 6.13.0" } }, - "node_modules/node-gyp-build": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", - "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, "node_modules/node-gyp-build-optional-packages": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", @@ -8500,15 +8147,6 @@ "fn.name": "1.x.x" } }, - "node_modules/opentracing": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", - "integrity": "sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.10" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -8798,12 +8436,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/pprof-format": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/pprof-format/-/pprof-format-2.2.1.tgz", - "integrity": "sha512-p4tVN7iK19ccDqQv8heyobzUmbHyds4N2FI6aBMcXz6y99MglTWDxIyhFkNaLeEXs6IFUEzT0zya0icbSLLY0g==", - "license": "MIT" - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8898,6 +8530,7 @@ "integrity": "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==", "hasInstallScript": true, "license": "BSD-3-Clause", + "optional": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -8989,12 +8622,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "license": "MIT" - }, "node_modules/random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -9211,6 +8838,7 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", + "optional": true, "engines": { "node": ">= 4" } @@ -9230,12 +8858,6 @@ "node": ">=14" } }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "license": "MIT" - }, "node_modules/rimraf": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", @@ -9502,12 +9124,6 @@ "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", "license": "BSD-3-Clause" }, - "node_modules/semifies": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semifies/-/semifies-1.0.0.tgz", - "integrity": "sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw==", - "license": "Apache-2.0" - }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", @@ -9671,18 +9287,6 @@ "node": ">=8" } }, - "node_modules/shell-quote": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -9909,15 +9513,6 @@ } } }, - "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">= 12" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -10608,12 +10203,6 @@ "node": ">=14.0.0" } }, - "node_modules/tlhunter-sorted-set": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/tlhunter-sorted-set/-/tlhunter-sorted-set-0.1.0.tgz", - "integrity": "sha512-eGYW4bjf1DtrHzUYxYfAcSytpOkA44zsr7G2n3PV7yOUR23vmkGe3LL4R+1jL9OsXtbsFOwe8XtbCrabeaEFnw==", - "license": "MIT" - }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -10653,15 +10242,6 @@ "node": ">=0.6.x" } }, - "node_modules/ttl-set": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ttl-set/-/ttl-set-1.0.0.tgz", - "integrity": "sha512-2fuHn/UR+8Z9HK49r97+p2Ru1b5Eewg2QqPrU14BVCQ9QoyU3+vLLZk2WEiyZ9sgJh6W8G1cZr9I2NBLywAHrA==", - "license": "MIT", - "dependencies": { - "fast-fifo": "^1.3.2" - } - }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", diff --git a/package.json b/package.json index c1ad5c302..268cb67fb 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "cookie-parser": "^1.4.7", "cors": "^2.8.5", "crisp-status-reporter": "^1.2.2", - "dd-trace": "^5.70.0", "dinero.js": "^1.9.1", "dotenv": "^17.2.3", "express": "^4.21.1", diff --git a/server.js b/server.js index 2bb2bf5a8..4ae883717 100644 --- a/server.js +++ b/server.js @@ -4,14 +4,14 @@ require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) }); -// Commented out due to stability issues -if (process.env.NODE_ENV) { - require("dd-trace").init({ - profiling: true, - env: process.env.NODE_ENV, - service: "bodyshop-api" - }); -} +// DATADOG TRACE Implemention (Uncomment to enable tracing, requires dd-trace package) +// if (process.env.NODE_ENV) { +// require("dd-trace").init({ +// profiling: true, +// env: process.env.NODE_ENV, +// service: "bodyshop-api" +// }); +// } const cors = require("cors"); const http = require("http"); diff --git a/server/data/analytics/documents.js b/server/data/analytics/documents.js new file mode 100644 index 000000000..5c457e2ef --- /dev/null +++ b/server/data/analytics/documents.js @@ -0,0 +1,37 @@ +const logger = require("../../utils/logger"); +const { client } = require('../../graphql-client/graphql-client'); +const { INSERT_MEDIA_ANALYTICS, GET_BODYSHOP_BY_ID } = require("../../graphql-client/queries"); + +const documentAnalytics = async (req, res) => { + try { + const { data } = req.body; + + //Check if the bodyshopid is real as a "security" measure + if (!data.bodyshopid) { + throw new Error("No bodyshopid provided in data"); + } + + const { bodyshops_by_pk } = await client.request(GET_BODYSHOP_BY_ID, { + id: data.bodyshopid + }); + + if (!bodyshops_by_pk) { + throw new Error("Invalid bodyshopid provided in data"); + } + + await client.request(INSERT_MEDIA_ANALYTICS, { + mediaObject: data + }); + + res.json({ status: "success" }) + } catch (error) { + logger.log("document-analytics-error", "ERROR", req?.user?.email, null, { + error: error.message, + stack: error.stack + }); + res.status(500).json({ error: error.message, stack: error.stack }); + } +}; + + +exports.default = documentAnalytics; diff --git a/server/data/data.js b/server/data/data.js index 0aa7f6e34..1706d78af 100644 --- a/server/data/data.js +++ b/server/data/data.js @@ -8,4 +8,5 @@ exports.podium = require("./podium").default; exports.emsUpload = require("./emsUpload").default; exports.carfax = require("./carfax").default; exports.carfaxRps = require("./carfax-rps").default; -exports.vehicletype = require("./vehicletype/vehicletype").default; \ No newline at end of file +exports.vehicletype = require("./vehicletype/vehicletype").default; +exports.documentAnalytics = require("./analytics/documents").default; \ No newline at end of file diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index eb0a979d9..60a37eebd 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -3151,3 +3151,12 @@ exports.DELETE_PHONE_NUMBER_OPT_OUT = ` } } `; + + +exports.INSERT_MEDIA_ANALYTICS = ` +mutation INSERT_MEDIA_ANALYTICS($mediaObject: media_analytics_insert_input!) { + insert_media_analytics_one(object: $mediaObject) { + id + } +} +` \ No newline at end of file diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index f875c3551..d1ff5abe6 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -381,7 +381,7 @@ async function CalculateRatesTotals({ job, client }) { if (item.mod_lbr_ty) { //Check to see if it has 0 hours and a price instead. - if (item.lbr_op === "OP14" && item.act_price > 0 && (!item.part_type || item.mod_lb_hrs === 0)) { + if (item.lbr_op === "OP14" && item.act_price > 0 && (!item.part_type || item.mod_lb_hrs === 0) && !IsAdditionalCost(item)) { //Scenario where SGI may pay out hours using a part price. if (!ret[item.mod_lbr_ty.toLowerCase()].total) { ret[item.mod_lbr_ty.toLowerCase()].base = Dinero(); diff --git a/server/job/job-totals.js b/server/job/job-totals.js index b6617b18c..c11d8d7de 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -315,7 +315,7 @@ function CalculateRatesTotals(ratesList) { if (item.mod_lbr_ty) { //Check to see if it has 0 hours and a price instead. //Extend for when there are hours and a price. - if (item.lbr_op === "OP14" && item.act_price > 0 && (!item.part_type || item.mod_lb_hrs === 0)) { + if (item.lbr_op === "OP14" && item.act_price > 0 && (!item.part_type || item.mod_lb_hrs === 0) && !IsAdditionalCost(item)) { //Scenario where SGI may pay out hours using a part price. if (!ret[item.mod_lbr_ty.toLowerCase()].total) { ret[item.mod_lbr_ty.toLowerCase()].total = Dinero(); diff --git a/server/routes/miscellaneousRoutes.js b/server/routes/miscellaneousRoutes.js index 0f783146f..df6c3448a 100644 --- a/server/routes/miscellaneousRoutes.js +++ b/server/routes/miscellaneousRoutes.js @@ -146,7 +146,7 @@ router.post("/bodyshop-cache", eventAuthorizationMiddleware, updateBodyshopCache // Estimate Scrubber Vehicle Type router.post("/es/vehicletype", data.vehicletype); - +router.post("/analytics/documents", data.documentAnalytics); // Health Check for docker-compose-cluster load balancer, only available in development if (process.env.NODE_ENV === "development") { router.get("/health", (req, res) => {