@oneuptime/common 10.4.8 → 10.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/Server/API/TelemetryExceptionAPI.ts +62 -0
  2. package/Server/Services/TelemetryExceptionService.ts +225 -0
  3. package/Server/Types/Database/QueryHelper.ts +35 -0
  4. package/Server/Types/Database/QueryUtil.ts +74 -2
  5. package/Types/Dashboard/DashboardComponents/DashboardAlertListComponent.ts +1 -0
  6. package/Types/Dashboard/DashboardComponents/DashboardDockerContainerListComponent.ts +1 -0
  7. package/Types/Dashboard/DashboardComponents/DashboardDockerHostListComponent.ts +1 -0
  8. package/Types/Dashboard/DashboardComponents/DashboardDockerImageListComponent.ts +1 -0
  9. package/Types/Dashboard/DashboardComponents/DashboardDockerNetworkListComponent.ts +1 -0
  10. package/Types/Dashboard/DashboardComponents/DashboardDockerVolumeListComponent.ts +1 -0
  11. package/Types/Dashboard/DashboardComponents/DashboardHostListComponent.ts +1 -0
  12. package/Types/Dashboard/DashboardComponents/DashboardIncidentListComponent.ts +1 -0
  13. package/Types/Dashboard/DashboardComponents/DashboardKubernetesCronJobListComponent.ts +1 -0
  14. package/Types/Dashboard/DashboardComponents/DashboardKubernetesDaemonSetListComponent.ts +1 -0
  15. package/Types/Dashboard/DashboardComponents/DashboardKubernetesDeploymentListComponent.ts +1 -0
  16. package/Types/Dashboard/DashboardComponents/DashboardKubernetesJobListComponent.ts +1 -0
  17. package/Types/Dashboard/DashboardComponents/DashboardKubernetesNamespaceListComponent.ts +1 -0
  18. package/Types/Dashboard/DashboardComponents/DashboardKubernetesNodeListComponent.ts +1 -0
  19. package/Types/Dashboard/DashboardComponents/DashboardKubernetesPodListComponent.ts +1 -0
  20. package/Types/Dashboard/DashboardComponents/DashboardKubernetesStatefulSetListComponent.ts +1 -0
  21. package/Types/Dashboard/DashboardComponents/DashboardMonitorListComponent.ts +1 -0
  22. package/Types/Dashboard/DashboardComponents/DashboardTraceListComponent.ts +1 -0
  23. package/Types/Time/RangeStartAndEndDateTime.ts +16 -0
  24. package/Types/Time/TimeRange.ts +2 -0
  25. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +2 -0
  26. package/UI/Components/ModelTable/BaseModelTable.tsx +64 -17
  27. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +2 -0
  28. package/Utils/Dashboard/Components/DashboardAlertListComponent.ts +5 -0
  29. package/Utils/Dashboard/Components/DashboardDockerContainerListComponent.ts +7 -0
  30. package/Utils/Dashboard/Components/DashboardDockerHostListComponent.ts +5 -0
  31. package/Utils/Dashboard/Components/DashboardDockerImageListComponent.ts +5 -0
  32. package/Utils/Dashboard/Components/DashboardDockerNetworkListComponent.ts +5 -0
  33. package/Utils/Dashboard/Components/DashboardDockerVolumeListComponent.ts +5 -0
  34. package/Utils/Dashboard/Components/DashboardHostListComponent.ts +3 -0
  35. package/Utils/Dashboard/Components/DashboardIncidentListComponent.ts +5 -0
  36. package/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.ts +3 -0
  37. package/Utils/Dashboard/Components/DashboardListSharedArgs.ts +31 -0
  38. package/Utils/Dashboard/Components/DashboardMonitorListComponent.ts +5 -0
  39. package/Utils/Dashboard/Components/DashboardTraceListComponent.ts +5 -0
  40. package/build/dist/Server/API/TelemetryExceptionAPI.js +37 -1
  41. package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
  42. package/build/dist/Server/Services/TelemetryExceptionService.js +175 -0
  43. package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
  44. package/build/dist/Server/Types/Database/QueryHelper.js +35 -0
  45. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  46. package/build/dist/Server/Types/Database/QueryUtil.js +58 -2
  47. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  48. package/build/dist/Types/Time/RangeStartAndEndDateTime.js +8 -0
  49. package/build/dist/Types/Time/RangeStartAndEndDateTime.js.map +1 -1
  50. package/build/dist/Types/Time/TimeRange.js +2 -0
  51. package/build/dist/Types/Time/TimeRange.js.map +1 -1
  52. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +2 -0
  53. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  54. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +48 -13
  55. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  56. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +2 -0
  57. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  58. package/build/dist/Utils/Dashboard/Components/DashboardAlertListComponent.js +2 -0
  59. package/build/dist/Utils/Dashboard/Components/DashboardAlertListComponent.js.map +1 -1
  60. package/build/dist/Utils/Dashboard/Components/DashboardDockerContainerListComponent.js +2 -0
  61. package/build/dist/Utils/Dashboard/Components/DashboardDockerContainerListComponent.js.map +1 -1
  62. package/build/dist/Utils/Dashboard/Components/DashboardDockerHostListComponent.js +2 -0
  63. package/build/dist/Utils/Dashboard/Components/DashboardDockerHostListComponent.js.map +1 -1
  64. package/build/dist/Utils/Dashboard/Components/DashboardDockerImageListComponent.js +2 -0
  65. package/build/dist/Utils/Dashboard/Components/DashboardDockerImageListComponent.js.map +1 -1
  66. package/build/dist/Utils/Dashboard/Components/DashboardDockerNetworkListComponent.js +2 -0
  67. package/build/dist/Utils/Dashboard/Components/DashboardDockerNetworkListComponent.js.map +1 -1
  68. package/build/dist/Utils/Dashboard/Components/DashboardDockerVolumeListComponent.js +2 -0
  69. package/build/dist/Utils/Dashboard/Components/DashboardDockerVolumeListComponent.js.map +1 -1
  70. package/build/dist/Utils/Dashboard/Components/DashboardHostListComponent.js +2 -0
  71. package/build/dist/Utils/Dashboard/Components/DashboardHostListComponent.js.map +1 -1
  72. package/build/dist/Utils/Dashboard/Components/DashboardIncidentListComponent.js +2 -0
  73. package/build/dist/Utils/Dashboard/Components/DashboardIncidentListComponent.js.map +1 -1
  74. package/build/dist/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.js +2 -0
  75. package/build/dist/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.js.map +1 -1
  76. package/build/dist/Utils/Dashboard/Components/DashboardListSharedArgs.js +21 -0
  77. package/build/dist/Utils/Dashboard/Components/DashboardListSharedArgs.js.map +1 -0
  78. package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js +2 -0
  79. package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js.map +1 -1
  80. package/build/dist/Utils/Dashboard/Components/DashboardTraceListComponent.js +2 -0
  81. package/build/dist/Utils/Dashboard/Components/DashboardTraceListComponent.js.map +1 -1
  82. package/package.json +1 -1
@@ -22,6 +22,8 @@ export interface LogTimeRangePickerProps {
22
22
 
23
23
  // Preset options to show in the dropdown (ordered for log investigation use)
24
24
  const PRESET_OPTIONS: Array<{ range: TimeRange; label: string }> = [
25
+ { range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
26
+ { range: TimeRange.PAST_FIFTEEN_MINS, label: "Past 15 Minutes" },
25
27
  { range: TimeRange.PAST_THIRTY_MINS, label: "Past 30 Minutes" },
26
28
  { range: TimeRange.PAST_ONE_HOUR, label: "Past 1 Hour" },
27
29
  { range: TimeRange.PAST_TWO_HOURS, label: "Past 2 Hours" },
@@ -1807,17 +1807,21 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1807
1807
  (): BulkActionButtonSchema<TBaseModel> => {
1808
1808
  return {
1809
1809
  title: "Delete",
1810
- buttonStyleType: ButtonStyleType.NORMAL,
1810
+ buttonStyleType: ButtonStyleType.DANGER,
1811
1811
  icon: IconProp.Trash,
1812
1812
  confirmMessage: (items: Array<TBaseModel>) => {
1813
- return `Are you sure you want to delete ${items.length} ${
1814
- props.pluralName || model.pluralName || "items"
1815
- }?`;
1813
+ const itemLabel: string =
1814
+ items.length === 1
1815
+ ? props.singularName || model.singularName || "item"
1816
+ : props.pluralName || model.pluralName || "items";
1817
+ return `Are you sure you want to delete ${items.length} ${itemLabel}? This action cannot be undone.`;
1816
1818
  },
1817
1819
  confirmTitle: (items: Array<TBaseModel>) => {
1818
- return `Delete ${items.length} ${
1819
- props.pluralName || model.pluralName || "items"
1820
- }`;
1820
+ const itemLabel: string =
1821
+ items.length === 1
1822
+ ? props.singularName || model.singularName || "item"
1823
+ : props.pluralName || model.pluralName || "items";
1824
+ return `Delete ${items.length} ${itemLabel}`;
1821
1825
  },
1822
1826
  confirmButtonStyleType: ButtonStyleType.DANGER,
1823
1827
  onClick: async ({
@@ -1908,25 +1912,68 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1908
1912
  onFilterRefreshClick={async () => {
1909
1913
  await getFilterDropdownItems();
1910
1914
  }}
1911
- bulkActions={{
1912
- buttons: props.bulkActions?.buttons.map(
1915
+ bulkActions={(() => {
1916
+ const permissions: Array<Permission> =
1917
+ PermissionUtil.getAllPermissions();
1918
+ const userCanDelete: boolean =
1919
+ model.hasDeletePermissions(permissions);
1920
+
1921
+ const sourceButtons: Array<
1922
+ BulkActionButtonSchema<TBaseModel> | ModalTableBulkDefaultActions
1923
+ > = [...(props.bulkActions?.buttons ?? [])];
1924
+
1925
+ /*
1926
+ * Auto-include the default Delete bulk action whenever the user has
1927
+ * model-level delete permission, so every table that exposes row
1928
+ * selection also exposes a way to delete the selected rows. This is
1929
+ * intentionally decoupled from `isDeleteable` — that flag governs the
1930
+ * per-row Delete button in the Actions column, not bulk operations.
1931
+ * The confirmation modal is wired up via the schema's confirmMessage
1932
+ * / confirmTitle below. Skip if the table author already added it.
1933
+ */
1934
+ const alreadyHasDeleteAction: boolean = sourceButtons.some(
1913
1935
  (
1914
1936
  action:
1915
1937
  | BulkActionButtonSchema<TBaseModel>
1916
1938
  | ModalTableBulkDefaultActions,
1917
1939
  ) => {
1918
- const permissions: Array<Permission> =
1919
- PermissionUtil.getAllPermissions();
1940
+ if (action === ModalTableBulkDefaultActions.Delete) {
1941
+ return true;
1942
+ }
1920
1943
  if (
1921
- action === ModalTableBulkDefaultActions.Delete &&
1922
- model.hasDeletePermissions(permissions)
1944
+ typeof action === "object" &&
1945
+ action !== null &&
1946
+ "title" in action &&
1947
+ (action as BulkActionButtonSchema<TBaseModel>).title ===
1948
+ "Delete"
1923
1949
  ) {
1924
- return getDeleteBulkAction();
1950
+ return true;
1925
1951
  }
1926
- return action;
1952
+ return false;
1927
1953
  },
1928
- ) as Array<BulkActionButtonSchema<TBaseModel>>,
1929
- }}
1954
+ );
1955
+ if (userCanDelete && !alreadyHasDeleteAction) {
1956
+ sourceButtons.push(ModalTableBulkDefaultActions.Delete);
1957
+ }
1958
+
1959
+ return {
1960
+ buttons: sourceButtons.map(
1961
+ (
1962
+ action:
1963
+ | BulkActionButtonSchema<TBaseModel>
1964
+ | ModalTableBulkDefaultActions,
1965
+ ) => {
1966
+ if (
1967
+ action === ModalTableBulkDefaultActions.Delete &&
1968
+ userCanDelete
1969
+ ) {
1970
+ return getDeleteBulkAction();
1971
+ }
1972
+ return action;
1973
+ },
1974
+ ) as Array<BulkActionButtonSchema<TBaseModel>>,
1975
+ };
1976
+ })()}
1930
1977
  onBulkActionEnd={async () => {
1931
1978
  setBulkSelectedItems([]);
1932
1979
  await fetchItems();
@@ -21,6 +21,8 @@ export interface TelemetryTimeRangePickerProps {
21
21
  }
22
22
 
23
23
  const PRESET_OPTIONS: Array<{ range: TimeRange; label: string }> = [
24
+ { range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
25
+ { range: TimeRange.PAST_FIFTEEN_MINS, label: "Past 15 Minutes" },
24
26
  { range: TimeRange.PAST_THIRTY_MINS, label: "Past 30 Minutes" },
25
27
  { range: TimeRange.PAST_ONE_HOUR, label: "Past 1 Hour" },
26
28
  { range: TimeRange.PAST_TWO_HOURS, label: "Past 2 Hours" },
@@ -9,6 +9,7 @@ import {
9
9
  EntityFilterModelType,
10
10
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
11
11
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
12
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
12
13
 
13
14
  const DisplaySection: ComponentArgumentSection = {
14
15
  name: "Display Options",
@@ -67,6 +68,10 @@ export default class DashboardAlertListComponentUtil extends DashboardBaseCompon
67
68
  section: DisplaySection,
68
69
  });
69
70
 
71
+ componentArguments.push(
72
+ getViewModeArgument<DashboardAlertListComponent>(DisplaySection),
73
+ );
74
+
70
75
  componentArguments.push({
71
76
  name: "Lifecycle State",
72
77
  description: "Quick filter by lifecycle state",
@@ -9,6 +9,7 @@ import {
9
9
  EntityFilterModelType,
10
10
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
11
11
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
12
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
12
13
 
13
14
  const DisplaySection: ComponentArgumentSection = {
14
15
  name: "Display Options",
@@ -67,6 +68,12 @@ export default class DashboardDockerContainerListComponentUtil extends Dashboard
67
68
  section: DisplaySection,
68
69
  });
69
70
 
71
+ args.push(
72
+ getViewModeArgument<DashboardDockerContainerListComponent>(
73
+ DisplaySection,
74
+ ),
75
+ );
76
+
70
77
  args.push({
71
78
  name: "Hosts",
72
79
  description: "Show only containers from the selected hosts",
@@ -8,6 +8,7 @@ import {
8
8
  ComponentInputType,
9
9
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
10
10
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
11
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
11
12
 
12
13
  const DisplaySection: ComponentArgumentSection = {
13
14
  name: "Display Options",
@@ -64,6 +65,10 @@ export default class DashboardDockerHostListComponentUtil extends DashboardBaseC
64
65
  section: DisplaySection,
65
66
  });
66
67
 
68
+ args.push(
69
+ getViewModeArgument<DashboardDockerHostListComponent>(DisplaySection),
70
+ );
71
+
67
72
  args.push({
68
73
  name: "Connection Status",
69
74
  description: "Quick filter by OTel collector status",
@@ -9,6 +9,7 @@ import {
9
9
  EntityFilterModelType,
10
10
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
11
11
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
12
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
12
13
 
13
14
  const DisplaySection: ComponentArgumentSection = {
14
15
  name: "Display Options",
@@ -66,6 +67,10 @@ export default class DashboardDockerImageListComponentUtil extends DashboardBase
66
67
  section: DisplaySection,
67
68
  });
68
69
 
70
+ args.push(
71
+ getViewModeArgument<DashboardDockerImageListComponent>(DisplaySection),
72
+ );
73
+
69
74
  args.push({
70
75
  name: "Hosts",
71
76
  description: "Show only images from the selected hosts",
@@ -9,6 +9,7 @@ import {
9
9
  EntityFilterModelType,
10
10
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
11
11
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
12
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
12
13
 
13
14
  const DisplaySection: ComponentArgumentSection = {
14
15
  name: "Display Options",
@@ -66,6 +67,10 @@ export default class DashboardDockerNetworkListComponentUtil extends DashboardBa
66
67
  section: DisplaySection,
67
68
  });
68
69
 
70
+ args.push(
71
+ getViewModeArgument<DashboardDockerNetworkListComponent>(DisplaySection),
72
+ );
73
+
69
74
  args.push({
70
75
  name: "Hosts",
71
76
  description: "Show only networks from the selected hosts",
@@ -9,6 +9,7 @@ import {
9
9
  EntityFilterModelType,
10
10
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
11
11
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
12
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
12
13
 
13
14
  const DisplaySection: ComponentArgumentSection = {
14
15
  name: "Display Options",
@@ -66,6 +67,10 @@ export default class DashboardDockerVolumeListComponentUtil extends DashboardBas
66
67
  section: DisplaySection,
67
68
  });
68
69
 
70
+ args.push(
71
+ getViewModeArgument<DashboardDockerVolumeListComponent>(DisplaySection),
72
+ );
73
+
69
74
  args.push({
70
75
  name: "Hosts",
71
76
  description: "Show only volumes from the selected hosts",
@@ -8,6 +8,7 @@ import {
8
8
  ComponentInputType,
9
9
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
10
10
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
11
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
11
12
 
12
13
  const DisplaySection: ComponentArgumentSection = {
13
14
  name: "Display Options",
@@ -64,6 +65,8 @@ export default class DashboardHostListComponentUtil extends DashboardBaseCompone
64
65
  section: DisplaySection,
65
66
  });
66
67
 
68
+ args.push(getViewModeArgument<DashboardHostListComponent>(DisplaySection));
69
+
67
70
  args.push({
68
71
  name: "Connection Status",
69
72
  description: "Quick filter by OTel collector status",
@@ -9,6 +9,7 @@ import {
9
9
  EntityFilterModelType,
10
10
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
11
11
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
12
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
12
13
 
13
14
  const DisplaySection: ComponentArgumentSection = {
14
15
  name: "Display Options",
@@ -67,6 +68,10 @@ export default class DashboardIncidentListComponentUtil extends DashboardBaseCom
67
68
  section: DisplaySection,
68
69
  });
69
70
 
71
+ componentArguments.push(
72
+ getViewModeArgument<DashboardIncidentListComponent>(DisplaySection),
73
+ );
74
+
70
75
  componentArguments.push({
71
76
  name: "Lifecycle State",
72
77
  description: "Quick filter by lifecycle state",
@@ -5,6 +5,7 @@ import {
5
5
  EntityFilterModelType,
6
6
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
7
7
  import DashboardBaseComponent from "../../../Types/Dashboard/DashboardComponents/DashboardBaseComponent";
8
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
8
9
 
9
10
  export const KubernetesDisplaySection: ComponentArgumentSection = {
10
11
  name: "Display Options",
@@ -47,6 +48,8 @@ export function getKubernetesCommonArguments<T extends DashboardBaseComponent>(
47
48
  section: KubernetesDisplaySection,
48
49
  });
49
50
 
51
+ args.push(getViewModeArgument<T>(KubernetesDisplaySection));
52
+
50
53
  args.push({
51
54
  name: "Clusters",
52
55
  description: "Show only resources from the selected clusters",
@@ -0,0 +1,31 @@
1
+ import {
2
+ ComponentArgument,
3
+ ComponentArgumentSection,
4
+ ComponentInputType,
5
+ } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
6
+ import DashboardBaseComponent from "../../../Types/Dashboard/DashboardComponents/DashboardBaseComponent";
7
+
8
+ export type DashboardListViewMode = "list" | "honeycomb";
9
+
10
+ /**
11
+ * Returns the `viewMode` dropdown argument used by every dashboard list
12
+ * component to switch between the default table view and a status-colored
13
+ * honeycomb view.
14
+ */
15
+ export function getViewModeArgument<T extends DashboardBaseComponent>(
16
+ section: ComponentArgumentSection,
17
+ ): ComponentArgument<T> {
18
+ return {
19
+ name: "View Mode",
20
+ description:
21
+ "Show entries as a list (default) or as a honeycomb where each cell is colored by status.",
22
+ required: false,
23
+ type: ComponentInputType.Dropdown,
24
+ id: "viewMode" as keyof T["arguments"],
25
+ section: section,
26
+ dropdownOptions: [
27
+ { label: "List", value: "list" },
28
+ { label: "Honeycomb", value: "honeycomb" },
29
+ ],
30
+ };
31
+ }
@@ -14,6 +14,7 @@ import {
14
14
  MonitorTypeProps,
15
15
  } from "../../../Types/Monitor/MonitorType";
16
16
  import { DropdownOption } from "../../../UI/Components/Dropdown/Dropdown";
17
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
17
18
 
18
19
  const DisplaySection: ComponentArgumentSection = {
19
20
  name: "Display Options",
@@ -90,6 +91,10 @@ export default class DashboardMonitorListComponentUtil extends DashboardBaseComp
90
91
  section: DisplaySection,
91
92
  });
92
93
 
94
+ componentArguments.push(
95
+ getViewModeArgument<DashboardMonitorListComponent>(DisplaySection),
96
+ );
97
+
93
98
  componentArguments.push({
94
99
  name: "Operational Status",
95
100
  description: "Quick filter by operational state",
@@ -8,6 +8,7 @@ import {
8
8
  ComponentInputType,
9
9
  } from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
10
10
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
11
+ import { getViewModeArgument } from "./DashboardListSharedArgs";
11
12
 
12
13
  const DisplaySection: ComponentArgumentSection = {
13
14
  name: "Display Options",
@@ -66,6 +67,10 @@ export default class DashboardTraceListComponentUtil extends DashboardBaseCompon
66
67
  section: DisplaySection,
67
68
  });
68
69
 
70
+ componentArguments.push(
71
+ getViewModeArgument<DashboardTraceListComponent>(DisplaySection),
72
+ );
73
+
69
74
  componentArguments.push({
70
75
  name: "Status",
71
76
  description: "Show only traces with this status",
@@ -1,6 +1,8 @@
1
1
  import TelemetryException from "../../Models/DatabaseModels/TelemetryException";
2
+ import TelemetryServiceModel from "../../Models/DatabaseModels/Service";
2
3
  import BadDataException from "../../Types/Exception/BadDataException";
3
4
  import ObjectID from "../../Types/ObjectID";
5
+ import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
4
6
  import TelemetryExceptionService from "../Services/TelemetryExceptionService";
5
7
  import AIAgentTaskTelemetryExceptionService from "../Services/AIAgentTaskTelemetryExceptionService";
6
8
  import UserMiddleware from "../Middleware/UserAuthorization";
@@ -11,7 +13,7 @@ import AIAgentTaskStatus, { AIAgentTaskStatusHelper, } from "../../Types/AI/AIAg
11
13
  import QueryHelper from "../Types/Database/QueryHelper";
12
14
  export default class TelemetryExceptionAPI extends BaseAPI {
13
15
  constructor() {
14
- var _a, _b;
16
+ var _a, _b, _c;
15
17
  super(TelemetryException, TelemetryExceptionService);
16
18
  // Create AI Agent Task for an exception
17
19
  this.router.post(`${(_a = new this.entityType()
@@ -33,6 +35,19 @@ export default class TelemetryExceptionAPI extends BaseAPI {
33
35
  next(err);
34
36
  }
35
37
  });
38
+ /*
39
+ * Aggregated dashboard summary for the Exceptions overview page.
40
+ * Returns counts, top/recent exceptions, and per-service summaries
41
+ * in a single round-trip with one SQL GROUP BY for service aggregation.
42
+ */
43
+ this.router.post(`${(_c = new this.entityType().getCrudApiPath()) === null || _c === void 0 ? void 0 : _c.toString()}/dashboard-summary`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
44
+ try {
45
+ await this.getDashboardSummary(req, res);
46
+ }
47
+ catch (err) {
48
+ next(err);
49
+ }
50
+ });
36
51
  }
37
52
  async createAIAgentTask(req, res) {
38
53
  const telemetryExceptionIdParam = req.params["telemetryExceptionId"];
@@ -116,5 +131,26 @@ export default class TelemetryExceptionAPI extends BaseAPI {
116
131
  },
117
132
  });
118
133
  }
134
+ async getDashboardSummary(req, res) {
135
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
136
+ const summary = await this.service.getDashboardSummary(props);
137
+ const topExceptionsJson = BaseModel.toJSONArray(summary.topExceptions, TelemetryException);
138
+ const recentExceptionsJson = BaseModel.toJSONArray(summary.recentExceptions, TelemetryException);
139
+ const serviceSummariesJson = summary.serviceSummaries.map((entry) => {
140
+ return {
141
+ service: BaseModel.toJSON(entry.service, TelemetryServiceModel),
142
+ unresolvedCount: entry.unresolvedCount,
143
+ totalOccurrences: entry.totalOccurrences,
144
+ };
145
+ });
146
+ return Response.sendJsonObjectResponse(req, res, {
147
+ unresolvedCount: summary.unresolvedCount,
148
+ resolvedCount: summary.resolvedCount,
149
+ archivedCount: summary.archivedCount,
150
+ topExceptions: topExceptionsJson,
151
+ recentExceptions: recentExceptionsJson,
152
+ serviceSummaries: serviceSummariesJson,
153
+ });
154
+ }
119
155
  }
120
156
  //# sourceMappingURL=TelemetryExceptionAPI.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TelemetryExceptionAPI.js","sourceRoot":"","sources":["../../../../Server/API/TelemetryExceptionAPI.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TelemetryExceptionAPI.js","sourceRoot":"","sources":["../../../../Server/API/TelemetryExceptionAPI.ts"],"names":[],"mappings":"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"}
@@ -11,12 +11,16 @@ import DatabaseService from "./DatabaseService";
11
11
  import Model from "../../Models/DatabaseModels/TelemetryException";
12
12
  import AIAgentTask from "../../Models/DatabaseModels/AIAgentTask";
13
13
  import ObjectID from "../../Types/ObjectID";
14
+ import PositiveNumber from "../../Types/PositiveNumber";
15
+ import SortOrder from "../../Types/BaseDatabase/SortOrder";
14
16
  import BadDataException from "../../Types/Exception/BadDataException";
15
17
  import AIAgentTaskType from "../../Types/AI/AIAgentTaskType";
16
18
  import AIAgentTaskStatus from "../../Types/AI/AIAgentTaskStatus";
17
19
  import AIAgentTaskService from "./AIAgentTaskService";
18
20
  import AIAgentTaskTelemetryExceptionService from "./AIAgentTaskTelemetryExceptionService";
21
+ import ServiceService from "./ServiceService";
19
22
  import QueryHelper from "../Types/Database/QueryHelper";
23
+ import ModelPermission from "../Types/Database/Permissions/Index";
20
24
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
21
25
  export class Service extends DatabaseService {
22
26
  constructor() {
@@ -105,6 +109,165 @@ export class Service extends DatabaseService {
105
109
  }
106
110
  return createdTask;
107
111
  }
112
+ async getDashboardSummary(props) {
113
+ if (!props.tenantId) {
114
+ throw new BadDataException("Project ID is required");
115
+ }
116
+ const projectId = props.tenantId;
117
+ const exceptionSelect = {
118
+ _id: true,
119
+ message: true,
120
+ exceptionType: true,
121
+ fingerprint: true,
122
+ isResolved: true,
123
+ isArchived: true,
124
+ occuranceCount: true,
125
+ lastSeenAt: true,
126
+ firstSeenAt: true,
127
+ environment: true,
128
+ service: {
129
+ _id: true,
130
+ name: true,
131
+ serviceColor: true,
132
+ },
133
+ };
134
+ const [unresolvedCount, resolvedCount, archivedCount, topExceptions, recentExceptions, serviceSummaries,] = await Promise.all([
135
+ this.countBy({
136
+ query: {
137
+ projectId,
138
+ isResolved: false,
139
+ isArchived: false,
140
+ },
141
+ props,
142
+ }),
143
+ this.countBy({
144
+ query: {
145
+ projectId,
146
+ isResolved: true,
147
+ isArchived: false,
148
+ },
149
+ props,
150
+ }),
151
+ this.countBy({
152
+ query: {
153
+ projectId,
154
+ isArchived: true,
155
+ },
156
+ props,
157
+ }),
158
+ this.findBy({
159
+ query: {
160
+ projectId,
161
+ isResolved: false,
162
+ isArchived: false,
163
+ },
164
+ select: exceptionSelect,
165
+ limit: 10,
166
+ skip: 0,
167
+ sort: {
168
+ occuranceCount: SortOrder.Descending,
169
+ },
170
+ props,
171
+ }),
172
+ this.findBy({
173
+ query: {
174
+ projectId,
175
+ isResolved: false,
176
+ isArchived: false,
177
+ },
178
+ select: exceptionSelect,
179
+ limit: 5,
180
+ skip: 0,
181
+ sort: {
182
+ lastSeenAt: SortOrder.Descending,
183
+ },
184
+ props,
185
+ }),
186
+ this.aggregateUnresolvedByService(projectId, props),
187
+ ]);
188
+ return {
189
+ unresolvedCount: unresolvedCount.toNumber(),
190
+ resolvedCount: resolvedCount.toNumber(),
191
+ archivedCount: archivedCount.toNumber(),
192
+ topExceptions,
193
+ recentExceptions,
194
+ serviceSummaries,
195
+ };
196
+ }
197
+ async aggregateUnresolvedByService(projectId, props) {
198
+ /*
199
+ * Assert the caller has read permission on TelemetryException. We don't
200
+ * use the returned filtered query — we run a raw GROUP BY below for
201
+ * efficiency — but this throws if the user lacks read access.
202
+ */
203
+ await ModelPermission.checkReadQueryPermission(Model, {
204
+ projectId,
205
+ isResolved: false,
206
+ isArchived: false,
207
+ }, null, props);
208
+ const rows = (await this.getQueryBuilder("TelemetryException")
209
+ .select(`"TelemetryException"."serviceId"`, "serviceId")
210
+ .addSelect(`COUNT(*)`, "unresolvedCount")
211
+ .addSelect(`COALESCE(SUM("TelemetryException"."occuranceCount"), 0)`, "totalOccurrences")
212
+ .where(`"TelemetryException"."projectId" = :projectId`, {
213
+ projectId: projectId.toString(),
214
+ })
215
+ .andWhere(`"TelemetryException"."isResolved" = false`)
216
+ .andWhere(`"TelemetryException"."isArchived" = false`)
217
+ .andWhere(`"TelemetryException"."deletedAt" IS NULL`)
218
+ .andWhere(`"TelemetryException"."serviceId" IS NOT NULL`)
219
+ .groupBy(`"TelemetryException"."serviceId"`)
220
+ .orderBy(`"unresolvedCount"`, "DESC")
221
+ .getRawMany());
222
+ if (rows.length === 0) {
223
+ return [];
224
+ }
225
+ const serviceIds = [];
226
+ for (const row of rows) {
227
+ if (row.serviceId) {
228
+ serviceIds.push(row.serviceId);
229
+ }
230
+ }
231
+ if (serviceIds.length === 0) {
232
+ return [];
233
+ }
234
+ const services = await ServiceService.findBy({
235
+ query: {
236
+ projectId,
237
+ _id: QueryHelper.any(serviceIds),
238
+ },
239
+ select: {
240
+ _id: true,
241
+ name: true,
242
+ serviceColor: true,
243
+ },
244
+ limit: new PositiveNumber(serviceIds.length),
245
+ skip: new PositiveNumber(0),
246
+ props,
247
+ });
248
+ const serviceById = new Map();
249
+ for (const service of services) {
250
+ if (service._id) {
251
+ serviceById.set(service._id, service);
252
+ }
253
+ }
254
+ const summaries = [];
255
+ for (const row of rows) {
256
+ if (!row.serviceId) {
257
+ continue;
258
+ }
259
+ const service = serviceById.get(row.serviceId);
260
+ if (!service) {
261
+ continue;
262
+ }
263
+ summaries.push({
264
+ service,
265
+ unresolvedCount: parseInt(row.unresolvedCount, 10) || 0,
266
+ totalOccurrences: parseInt(row.totalOccurrences || "0", 10) || 0,
267
+ });
268
+ }
269
+ return summaries;
270
+ }
108
271
  buildFixExceptionMetadata(params) {
109
272
  const { telemetryException, telemetryExceptionId } = params;
110
273
  const metadata = {
@@ -141,5 +304,17 @@ __decorate([
141
304
  __metadata("design:paramtypes", [Object]),
142
305
  __metadata("design:returntype", Promise)
143
306
  ], Service.prototype, "createFixExceptionTask", null);
307
+ __decorate([
308
+ CaptureSpan(),
309
+ __metadata("design:type", Function),
310
+ __metadata("design:paramtypes", [Object]),
311
+ __metadata("design:returntype", Promise)
312
+ ], Service.prototype, "getDashboardSummary", null);
313
+ __decorate([
314
+ CaptureSpan(),
315
+ __metadata("design:type", Function),
316
+ __metadata("design:paramtypes", [ObjectID, Object]),
317
+ __metadata("design:returntype", Promise)
318
+ ], Service.prototype, "aggregateUnresolvedByService", null);
144
319
  export default new Service();
145
320
  //# sourceMappingURL=TelemetryExceptionService.js.map