- Create new @link-stack/logger package wrapping Pino for structured logging - Replace all console.log/error/warn statements across the monorepo - Configure environment-aware logging (pretty-print in dev, JSON in prod) - Add automatic redaction of sensitive fields (passwords, tokens, etc.) - Remove dead commented-out logger file from bridge-worker - Follow Pino's standard argument order (context object first, message second) - Support log levels via LOG_LEVEL environment variable - Export TypeScript types for better IDE support This provides consistent, structured logging across all applications and packages, making debugging easier and production logs more parseable.
100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
"use server";
|
|
|
|
import { executeGraphQL, executeREST } from "app/_lib/zammad";
|
|
import { getTicketOverviewCountsQuery } from "app/_graphql/getTicketOverviewCountsQuery";
|
|
import { getTicketsByOverviewQuery } from "app/_graphql/getTicketsByOverviewQuery";
|
|
import { createLogger } from "@link-stack/logger";
|
|
|
|
const logger = createLogger('link-overviews');
|
|
|
|
const overviewLookup = {
|
|
Assigned: "My Assigned Tickets",
|
|
Open: "Open Tickets",
|
|
Urgent: "Escalated Tickets",
|
|
Unassigned: "Unassigned & Open Tickets",
|
|
Recent: "Recent Tickets",
|
|
Pending: "Pending Reached Tickets",
|
|
MyPending: "My Pending Reached Tickets",
|
|
MySubscribed: "My Subscribed Tickets",
|
|
};
|
|
|
|
export const getOverviewTicketCountsAction = async () => {
|
|
try {
|
|
const recent = await executeREST({ path: "/api/v1/recent_view" });
|
|
const countResult = await executeGraphQL({
|
|
query: getTicketOverviewCountsQuery,
|
|
});
|
|
const overviews = countResult?.ticketOverviews?.edges ?? [];
|
|
const counts = overviews.reduce((acc: any, overview: any) => {
|
|
const name = overview.node.name;
|
|
const key = Object.keys(overviewLookup)
|
|
.find((k) => overviewLookup[k] === name)
|
|
?.toLowerCase();
|
|
if (key) {
|
|
acc[key] = overview.node.ticketCount ?? 0;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
counts.recent = recent.length;
|
|
|
|
return counts;
|
|
} catch (e) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return {};
|
|
}
|
|
};
|
|
|
|
export const getOverviewTicketsAction = async (name: string) => {
|
|
let tickets = [];
|
|
|
|
try {
|
|
if (name === "Recent") {
|
|
const recent = await executeREST({ path: "/api/v1/recent_view" });
|
|
const uniqueIDs = new Set(recent.map((rec: any) => rec.o_id));
|
|
for (const id of uniqueIDs) {
|
|
const tkt = await executeREST({
|
|
path: `/api/v1/tickets/${id}`,
|
|
});
|
|
tickets.push({
|
|
...tkt,
|
|
internalId: tkt.id,
|
|
createdAt: tkt.created_at,
|
|
updatedAt: tkt.updated_at,
|
|
});
|
|
}
|
|
} else {
|
|
const fullName = overviewLookup[name];
|
|
const countResult = await executeGraphQL({
|
|
query: getTicketOverviewCountsQuery,
|
|
});
|
|
const overviewID = countResult?.ticketOverviews?.edges?.find(
|
|
(overview: any) => overview.node.name === fullName,
|
|
)?.node?.id;
|
|
|
|
const ticketsResult = await executeGraphQL({
|
|
query: getTicketsByOverviewQuery,
|
|
variables: { overviewId: overviewID, pageSize: 250 },
|
|
});
|
|
|
|
const edges = ticketsResult?.ticketsByOverview?.edges;
|
|
if (edges) {
|
|
tickets = edges.map((edge: any) => edge.node);
|
|
}
|
|
}
|
|
|
|
const sortedTickets = tickets.sort((a: any, b: any) => {
|
|
if (a.internalId < b.internalId) {
|
|
return 1;
|
|
}
|
|
if (a.internalId > b.internalId) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
});
|
|
|
|
return { tickets: sortedTickets };
|
|
} catch (e) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return { tickets, message: e.message ?? "" };
|
|
}
|
|
};
|