import { ChannelType } from "../Common/Channels/ChannelType"; import { ITicketDateRange, ITicketMetricGroup, ITicketMetricPoint, TicketPriority, TicketPropertyValue } from "./Common"; import { ITicketFilter } from "./Api"; import type { SlaStatus } from "./Sla"; import type { AgentAvailabilityStatus } from "./Routing"; export declare enum TicketAnalyticsAudience { AGENT = "AGENT", SUPERVISOR = "SUPERVISOR", ADMIN = "ADMIN", CUSTOMER = "CUSTOMER" } export declare enum TicketDashboardVisibility { PRIVATE = "PRIVATE", SHARED = "SHARED", ROLE = "ROLE", GROUP = "GROUP" } export declare enum TicketWidgetType { KPI = "KPI", TREND = "TREND", BAR = "BAR", STACKED_BAR = "STACKED_BAR", LINE = "LINE", AREA = "AREA", PIE = "PIE", DONUT = "DONUT", FUNNEL = "FUNNEL", GAUGE = "GAUGE", HEATMAP = "HEATMAP", TABLE = "TABLE", LEADERBOARD = "LEADERBOARD", AGING_BUCKETS = "AGING_BUCKETS", SLA_CLOCK = "SLA_CLOCK", QUEUE = "QUEUE", TEXT = "TEXT" } export declare enum TicketMetricAggregation { COUNT = "COUNT", SUM = "SUM", AVERAGE = "AVERAGE", MIN = "MIN", MAX = "MAX", MEDIAN = "MEDIAN", PERCENTILE = "PERCENTILE", RATE = "RATE", RATIO = "RATIO", DISTINCT_COUNT = "DISTINCT_COUNT" } export declare enum TicketAnalyticsDimension { TIME = "TIME", STATUS = "STATUS", STAGE = "STAGE", PRIORITY = "PRIORITY", CATEGORY = "CATEGORY", ASSIGNEE = "ASSIGNEE", GROUP = "GROUP", QUEUE = "QUEUE", CHANNEL = "CHANNEL", ORIGIN = "ORIGIN", CONTACT = "CONTACT", ORGANIZATION = "ORGANIZATION", BRAND = "BRAND", REQUEST_TYPE = "REQUEST_TYPE", SLA_POLICY = "SLA_POLICY", RESOLUTION_TYPE = "RESOLUTION_TYPE", TAG = "TAG", SKILL = "SKILL", PUBLIC_STATUS = "PUBLIC_STATUS", CUSTOM_FIELD = "CUSTOM_FIELD" } export declare enum TicketTimeGranularity { MINUTE = "MINUTE", HOUR = "HOUR", DAY = "DAY", WEEK = "WEEK", MONTH = "MONTH", QUARTER = "QUARTER", YEAR = "YEAR" } export declare enum TicketComparisonMode { NONE = "NONE", PREVIOUS_PERIOD = "PREVIOUS_PERIOD", PREVIOUS_YEAR = "PREVIOUS_YEAR", CUSTOM = "CUSTOM", TARGET = "TARGET" } export declare enum TicketMetricFormat { NUMBER = "NUMBER", PERCENTAGE = "PERCENTAGE", DURATION = "DURATION", DECIMAL = "DECIMAL", CURRENCY = "CURRENCY", SCORE = "SCORE" } export declare enum TicketWidgetRefreshMode { MANUAL = "MANUAL", INTERVAL = "INTERVAL", REAL_TIME = "REAL_TIME" } export declare enum TicketDrilldownTarget { TICKETS = "TICKETS", AGENTS = "AGENTS", GROUPS = "GROUPS", CONVERSATIONS = "CONVERSATIONS", SLA_CYCLES = "SLA_CYCLES", TASKS = "TASKS", APPROVALS = "APPROVALS", DEFLECTION_EVENTS = "DEFLECTION_EVENTS" } /** Stable semantic metric identifiers. New visualizations should compose these instead of hard-coded endpoints. */ export declare enum TicketMetricCode { TICKETS_CREATED = "TICKETS_CREATED", TICKETS_RESOLVED = "TICKETS_RESOLVED", TICKETS_CLOSED = "TICKETS_CLOSED", TICKETS_CANCELLED = "TICKETS_CANCELLED", BACKLOG = "BACKLOG", BACKLOG_OVERDUE = "BACKLOG_OVERDUE", BACKLOG_UNASSIGNED = "BACKLOG_UNASSIGNED", BACKLOG_UNREPLIED = "BACKLOG_UNREPLIED", BACKLOG_AGING = "BACKLOG_AGING", NET_BACKLOG_CHANGE = "NET_BACKLOG_CHANGE", FIRST_RESPONSE_TIME = "FIRST_RESPONSE_TIME", NEXT_RESPONSE_TIME = "NEXT_RESPONSE_TIME", RESOLUTION_TIME = "RESOLUTION_TIME", ASSIGNMENT_TIME = "ASSIGNMENT_TIME", ACCEPTANCE_TIME = "ACCEPTANCE_TIME", HANDLE_TIME = "HANDLE_TIME", WAITING_CUSTOMER_TIME = "WAITING_CUSTOMER_TIME", WAITING_INTERNAL_TIME = "WAITING_INTERNAL_TIME", TIME_IN_STATUS = "TIME_IN_STATUS", FIRST_RESPONSE_SLA_RATE = "FIRST_RESPONSE_SLA_RATE", NEXT_RESPONSE_SLA_RATE = "NEXT_RESPONSE_SLA_RATE", RESOLUTION_SLA_RATE = "RESOLUTION_SLA_RATE", SLA_BREACH_COUNT = "SLA_BREACH_COUNT", SLA_AT_RISK_COUNT = "SLA_AT_RISK_COUNT", OLA_COMPLIANCE_RATE = "OLA_COMPLIANCE_RATE", UC_COMPLIANCE_RATE = "UC_COMPLIANCE_RATE", FIRST_CONTACT_RESOLUTION_RATE = "FIRST_CONTACT_RESOLUTION_RATE", REOPEN_COUNT = "REOPEN_COUNT", REOPEN_RATE = "REOPEN_RATE", TRANSFER_COUNT = "TRANSFER_COUNT", TRANSFER_RATE = "TRANSFER_RATE", ESCALATION_COUNT = "ESCALATION_COUNT", TOUCHES_PER_TICKET = "TOUCHES_PER_TICKET", COMMENTS_PER_TICKET = "COMMENTS_PER_TICKET", AGENT_ASSIGNED_COUNT = "AGENT_ASSIGNED_COUNT", AGENT_RESOLVED_COUNT = "AGENT_RESOLVED_COUNT", AGENT_ACTIVE_LOAD = "AGENT_ACTIVE_LOAD", AGENT_CAPACITY_UTILIZATION = "AGENT_CAPACITY_UTILIZATION", AGENT_AVAILABILITY_TIME = "AGENT_AVAILABILITY_TIME", AGENT_OCCUPANCY_RATE = "AGENT_OCCUPANCY_RATE", AGENT_ACCEPTANCE_RATE = "AGENT_ACCEPTANCE_RATE", AGENT_DECLINE_RATE = "AGENT_DECLINE_RATE", AGENT_PRODUCTIVITY = "AGENT_PRODUCTIVITY", QUEUE_SIZE = "QUEUE_SIZE", QUEUE_WAIT_TIME = "QUEUE_WAIT_TIME", QUEUE_ABANDONED_COUNT = "QUEUE_ABANDONED_COUNT", ROUTING_ATTEMPTS = "ROUTING_ATTEMPTS", AUTO_ASSIGNMENT_RATE = "AUTO_ASSIGNMENT_RATE", SKILL_MATCH_RATE = "SKILL_MATCH_RATE", FALLBACK_RATE = "FALLBACK_RATE", CSAT_SCORE = "CSAT_SCORE", CSAT_RESPONSE_RATE = "CSAT_RESPONSE_RATE", NPS_SCORE = "NPS_SCORE", NEGATIVE_SATISFACTION_COUNT = "NEGATIVE_SATISFACTION_COUNT", INBOUND_MESSAGES = "INBOUND_MESSAGES", OUTBOUND_MESSAGES = "OUTBOUND_MESSAGES", MESSAGES_PER_TICKET = "MESSAGES_PER_TICKET", CHANNEL_VOLUME = "CHANNEL_VOLUME", CHANNEL_RESPONSE_TIME = "CHANNEL_RESPONSE_TIME", CATEGORY_VOLUME = "CATEGORY_VOLUME", REQUEST_TYPE_VOLUME = "REQUEST_TYPE_VOLUME", RESOLUTION_TYPE_VOLUME = "RESOLUTION_TYPE_VOLUME", CONTACT_VOLUME = "CONTACT_VOLUME", ORGANIZATION_VOLUME = "ORGANIZATION_VOLUME", AUTOMATION_EXECUTION_COUNT = "AUTOMATION_EXECUTION_COUNT", AUTOMATION_SUCCESS_RATE = "AUTOMATION_SUCCESS_RATE", AUTOMATION_FAILURE_COUNT = "AUTOMATION_FAILURE_COUNT", AUTOMATED_RESOLUTION_RATE = "AUTOMATED_RESOLUTION_RATE", MACRO_USAGE_COUNT = "MACRO_USAGE_COUNT", DEFLECTION_RATE = "DEFLECTION_RATE", DEFLECTED_SESSIONS = "DEFLECTED_SESSIONS", ARTICLE_CLICK_RATE = "ARTICLE_CLICK_RATE", PORTAL_REQUEST_COUNT = "PORTAL_REQUEST_COUNT", SELF_SERVICE_RESOLUTION_RATE = "SELF_SERVICE_RESOLUTION_RATE", APPROVAL_PENDING_COUNT = "APPROVAL_PENDING_COUNT", APPROVAL_TIME = "APPROVAL_TIME", APPROVAL_REJECTION_RATE = "APPROVAL_REJECTION_RATE", APPROVAL_EXPIRED_COUNT = "APPROVAL_EXPIRED_COUNT", TASK_PENDING_COUNT = "TASK_PENDING_COUNT", TASK_COMPLETION_RATE = "TASK_COMPLETION_RATE", TASK_OVERDUE_COUNT = "TASK_OVERDUE_COUNT", TASK_BLOCKED_COUNT = "TASK_BLOCKED_COUNT", EXPORT_COUNT = "EXPORT_COUNT", SECURITY_DENIAL_COUNT = "SECURITY_DENIAL_COUNT", PII_ACCESS_COUNT = "PII_ACCESS_COUNT" } export declare enum DashboardIcon { DASHBOARD = "DASHBOARD", HOME = "HOME", SUPPORT = "SUPPORT", ANALYTICS = "ANALYTICS", REPORTS = "REPORTS", USERS = "USERS", SETTINGS = "SETTINGS", FAVORITES = "FAVORITES", QUICK_ACTIONS = "QUICK_ACTIONS" } export interface ITicketAnalyticsFilter extends ITicketFilter { range: ITicketDateRange; channelTypes?: ChannelType[]; queueIds?: string[]; organizationIds?: string[]; brandIds?: string[]; requestTypeIds?: string[]; slaPolicyIds?: string[]; resolutionTypeIds?: string[]; skillIds?: string[]; includeBots?: boolean; businessHoursOnly?: boolean; } export interface ITicketMetricDefinition { code: TicketMetricCode; name: string; description: string; format: TicketMetricFormat; defaultAggregation: TicketMetricAggregation; supportedAggregations: TicketMetricAggregation[]; supportedDimensions: TicketAnalyticsDimension[]; supportedAudiences: TicketAnalyticsAudience[]; supportsPercentile?: boolean; supportsRealTime?: boolean; higherIsBetter?: boolean; supportedFilters: (keyof Omit)[]; } export interface ITicketMetricQuery { metric: TicketMetricCode; aggregation?: TicketMetricAggregation; percentile?: number; filter: ITicketAnalyticsFilter; dimensions?: ITicketDimensionSpec[]; comparison?: ITicketComparison; target?: number; } export interface ITicketDimensionSpec { dimension: TicketAnalyticsDimension; fieldNameKey?: string; granularity?: TicketTimeGranularity; limit?: number; includeEmpty?: boolean; } export interface ITicketComparison { mode: TicketComparisonMode; range?: ITicketDateRange; } export interface ITicketMetricValue { value: number; formattedValue?: string; numerator?: number; denominator?: number; previousValue?: number; change?: number; changePercentage?: number; target?: number; targetMet?: boolean; } export interface ITicketMetricSeries { key: string; label: string; points: ITicketMetricPoint[]; } export interface ITicketMetricResult { query: ITicketMetricQuery; value?: ITicketMetricValue; groups?: ITicketMetricGroup[]; series?: ITicketMetricSeries[]; generatedAt: Date; dataFrom: Date; dataTo: Date; isPartial?: boolean; warnings?: string[]; } export interface ITicketWidgetPosition { x: number; y: number; width: number; height: number; minWidth?: number; minHeight?: number; } export interface ITicketWidgetThreshold { value: number; color: string; label?: string; operator?: "GT" | "GTE" | "LT" | "LTE"; } export interface ITicketWidgetDrilldown { enabled: boolean; target: TicketDrilldownTarget; inheritFilters: boolean; additionalFilter?: ITicketAnalyticsFilter; } export interface ITicketWidgetConfiguration { id: string; title: string; subtitle?: string; type: TicketWidgetType; queries: ITicketMetricQuery[]; position: ITicketWidgetPosition; thresholds?: ITicketWidgetThreshold[]; drilldown?: ITicketWidgetDrilldown; showLegend?: boolean; showComparison?: boolean; showTarget?: boolean; colorPalette?: string[]; customOptions?: { [key: string]: TicketPropertyValue; }; } export interface ITicketDashboard { id: string; spaceId: string; name: string; description?: string; ownerId: string; audience: TicketAnalyticsAudience; visibility: TicketDashboardVisibility; sharedRoleIds?: string[]; sharedGroupIds?: string[]; defaultFilter?: ITicketAnalyticsFilter; widgets: ITicketWidgetConfiguration[]; refreshMode: TicketWidgetRefreshMode; refreshIntervalSeconds?: number; isDefault?: boolean; order: number; icon?: DashboardIcon; createdAt: Date; createdBy: string; updatedAt?: Date; updatedBy?: string; } export interface ICreateTicketDashboardDto { name: string; description?: string; audience: TicketAnalyticsAudience; visibility: TicketDashboardVisibility; sharedRoleIds?: string[]; sharedGroupIds?: string[]; defaultFilter?: ITicketAnalyticsFilter; widgets?: ITicketWidgetConfiguration[]; refreshMode?: TicketWidgetRefreshMode; refreshIntervalSeconds?: number; order?: number; isDefault?: boolean; icon?: DashboardIcon; } export interface IUpdateTicketDashboardDto { name?: string; description?: string; audience?: TicketAnalyticsAudience; visibility?: TicketDashboardVisibility; sharedRoleIds?: string[]; sharedGroupIds?: string[]; defaultFilter?: ITicketAnalyticsFilter; widgets?: ITicketWidgetConfiguration[]; refreshMode?: TicketWidgetRefreshMode; refreshIntervalSeconds?: number; order?: number; isDefault?: boolean; icon?: DashboardIcon; } export interface ITicketDashboardTemplate { id: string; spaceId: string; name: string; description?: string; audience: TicketAnalyticsAudience; widgets: ITicketWidgetConfiguration[]; enabled: boolean; } export interface ICreateTicketDashboardTemplateDto { name: string; description?: string; audience: TicketAnalyticsAudience; widgets?: ITicketWidgetConfiguration[]; enabled?: boolean; } export interface IUpdateTicketDashboardTemplateDto { name?: string; description?: string; audience?: TicketAnalyticsAudience; widgets?: ITicketWidgetConfiguration[]; enabled?: boolean; } export interface ITicketDashboardSnapshot { id: string; dashboardId: string; generatedAt: Date; filter: ITicketAnalyticsFilter; widgetResults: { widgetId: string; results: ITicketMetricResult[]; }[]; expiresAt?: Date; } /** Used when clicking a widget to retrieve the exact underlying records behind a value. */ export interface ITicketDrilldownQuery { metricQuery: ITicketMetricQuery; target: TicketDrilldownTarget; groupKey?: string; cursor?: string; limit?: number; } export interface ITicketDrilldownResult { items: T[]; nextCursor?: string; hasMore: boolean; total?: number; } /** Allows supervisors to define operational goals independently from widget presentation. */ export interface ITicketAnalyticsGoal { id: string; spaceId: string; name: string; metric: TicketMetricCode; target: number; filter: ITicketAnalyticsFilter; validFrom: Date; validUntil?: Date; ownerGroupId?: string; ownerUserId?: string; createdAt: Date; } export interface ICreateTicketAnalyticsGoalDto { name: string; metric: TicketMetricCode; target: number; filter: ITicketAnalyticsFilter; validFrom: Date; validUntil?: Date; ownerGroupId?: string; ownerUserId?: string; } export interface IUpdateTicketAnalyticsGoalDto { name?: string; metric?: TicketMetricCode; target?: number; filter?: ITicketAnalyticsFilter; validFrom?: Date; validUntil?: Date; ownerGroupId?: string; ownerUserId?: string; } /** Reports freshness so users know whether a card is real-time, delayed or partial. */ export interface ITicketAnalyticsFreshness { metric: TicketMetricCode; lastEventAt?: Date; lastProcessedAt: Date; lagSeconds: number; realTime: boolean; healthy: boolean; } /** Compatibility aggregate for the original fixed dashboard endpoint. Prefer metric queries for configurable widgets. */ export interface ITicketDashboardFilter { range: ITicketDateRange; statusIds?: string[]; assigneeIds?: string[]; assignedGroupIds?: string[]; categoryIds?: string[]; channelTypes?: string[]; } export interface ITicketDashboardMetrics { range: ITicketDateRange; backlog: number; created: number; resolved: number; reopened: number; firstResponseSlaMetPercentage: number; resolutionSlaMetPercentage: number; averageFirstResponseMinutes: number; averageResolutionMinutes: number; averageSatisfactionScore?: number; createdSeries: ITicketMetricPoint[]; resolvedSeries: ITicketMetricPoint[]; byStatus: ITicketMetricGroup[]; byCategory: ITicketMetricGroup[]; byAssignee: ITicketMetricGroup[]; } export interface IAgentDashboardQueueItem { ticketId: string; number: number; title: string; priority: TicketPriority; statusId: string; statusLabel: string; dueAt?: Date; /** * PENDING / BREACHED / NOT_APPLICABLE are the only values this backend can * derive from dueAt — MET and PAUSED need real SLA cycles, which are not * persisted yet. "At risk" is NOT a SlaStatus value: the domain models it as a * separate warning threshold, which is why it is a boolean of its own. */ slaStatus: SlaStatus; slaAtRisk: boolean; createdAt: Date; updatedAt?: Date; } export interface IAgentDashboardCapacity { maximum: number; occupied: number; freePercentage: number; inProgress: number; waitingCustomer: number; new: number; } export interface IAgentDashboardQualityGoal { actual: number; target: number; } /** * The agent's PERSONAL dashboard. Not to be confused with * ITicketDashboardMetrics, which is the space-wide aggregate: everything here is * filtered by the acting agent. */ export interface IAgentDashboardMetrics { range: { from: Date; to: Date; }; activeLoad: number; resolvedCount: number; resolvedChangePercentage?: number; receivedCount: number; awaitingResponseCount: number; averageFirstResponseMinutes: number; averageResolutionMinutes: number; slaAttentionCount: number; slaBreachedCount: number; slaAtRiskCount: number; priorityQueue: IAgentDashboardQueueItem[]; capacity: IAgentDashboardCapacity; loadByPriority: { priority: TicketPriority; count: number; }[]; availabilityStatus: AgentAvailabilityStatus; resolutionRhythm: { series: ITicketMetricPoint[]; changePercentage?: number; }; qualityGoals: { firstResponseSla: IAgentDashboardQualityGoal; resolutionSla: IAgentDashboardQualityGoal; assignmentAcceptanceRate: IAgentDashboardQualityGoal; }; csatScore: IAgentDashboardQualityGoal; warnings: string[]; } /** A metric of the catalog, plus the dimensions a query MUST supply for it. */ export interface IMetricCatalogEntry extends ITicketMetricDefinition { requiredDimensions?: TicketAnalyticsDimension[]; } export type IWidgetPresetQuery = Omit; export type WidgetPresetCategory = 'kpi' | 'trend' | 'breakdown' | 'sla'; /** * A ready-made widget the user can drop on a dashboard. `queries` drops `filter` * on purpose: the preset defines WHAT is measured, the dashboard defines over * which slice. */ export interface IWidgetPreset { key: string; label: string; description: string; category: WidgetPresetCategory; audiences: TicketAnalyticsAudience[]; defaultSize: { width: number; height: number; }; widget: Omit & { queries: IWidgetPresetQuery[]; }; }