@oneuptime/common 12.0.31 → 12.0.32

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 (188) hide show
  1. package/Models/DatabaseModels/AlertState.ts +0 -2
  2. package/Models/DatabaseModels/Domain.ts +1 -1
  3. package/Models/DatabaseModels/Incident.ts +1 -1
  4. package/Models/DatabaseModels/IncidentTemplate.ts +1 -1
  5. package/Models/DatabaseModels/Index.ts +2 -0
  6. package/Models/DatabaseModels/MetricType.ts +0 -2
  7. package/Models/DatabaseModels/MonitorStatusTimeline.ts +0 -2
  8. package/Models/DatabaseModels/MonitorTest.ts +0 -2
  9. package/Models/DatabaseModels/NetworkDevice.ts +121 -2
  10. package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +3 -1
  11. package/Models/DatabaseModels/NetworkDeviceRole.ts +648 -0
  12. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -1
  13. package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -1
  14. package/Models/DatabaseModels/StatusPageAnnouncement.ts +0 -2
  15. package/Models/DatabaseModels/StatusPageAnnouncementTemplate.ts +0 -2
  16. package/Models/DatabaseModels/StatusPagePrivateUser.ts +0 -2
  17. package/Models/DatabaseModels/StatusPageResource.ts +0 -2
  18. package/Models/DatabaseModels/StatusPageSubscriber.ts +0 -2
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.ts +72 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  21. package/Server/Services/DatabaseService.ts +39 -9
  22. package/Server/Services/Index.ts +2 -0
  23. package/Server/Services/NetworkDeviceRoleService.ts +90 -0
  24. package/Server/Services/ProjectService.ts +85 -0
  25. package/Server/Services/UserNotificationSettingService.ts +0 -6
  26. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +31 -1
  27. package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +35 -8
  28. package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +107 -3
  29. package/Tests/App/Dashboard/DashboardWideChartZoom.test.tsx +401 -0
  30. package/Tests/App/Dashboard/MonitorTemplateColumnAndFacet.test.tsx +318 -0
  31. package/Tests/App/Dashboard/NetworkDeviceBulkDelete.test.tsx +357 -0
  32. package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +590 -0
  33. package/Tests/App/Dashboard/SideMenuHarness.tsx +11 -3
  34. package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +115 -41
  35. package/Tests/Server/Infrastructure/Postgres/NetworkDeviceRoleTableMigration.test.ts +476 -0
  36. package/Tests/Server/Services/DatabaseServiceGenerateSlug.test.ts +215 -0
  37. package/Tests/Server/Services/NetworkDeviceRoleModel.test.ts +672 -0
  38. package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +1 -1
  39. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +67 -4
  40. package/Tests/Server/Services/ScheduledMaintenanceSubscriberEndTime.test.ts +369 -0
  41. package/Tests/Server/Services/UserNotificationSettingMonitorDefaults.test.ts +248 -0
  42. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +43 -2
  43. package/Tests/Server/Utils/BasicCron.test.ts +283 -0
  44. package/Tests/Server/Utils/IncomingCallPhoneNumber.test.ts +174 -0
  45. package/Tests/Types/NetworkDevice/DefaultNetworkDeviceRole.test.ts +417 -0
  46. package/Tests/UI/Components/Charts/ChartClickDoubleClickDisambiguation.test.tsx +221 -0
  47. package/Tests/UI/Components/Charts/ChartDoubleClickReset.test.tsx +220 -0
  48. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +751 -0
  49. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +475 -43
  50. package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +89 -0
  51. package/Tests/UI/Components/NavBarCommandKGating.test.tsx +103 -8
  52. package/Tests/UI/Components/SideMenuItem.test.tsx +30 -0
  53. package/Tests/UI/Utils/TableColumnsToCsv.test.ts +30 -0
  54. package/Tests/UI/Utils/UseDashboardTimeRangeZoom.test.tsx +187 -0
  55. package/Tests/Utils/Dashboard/DashboardResourceListSharedArgs.test.ts +302 -0
  56. package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +242 -0
  57. package/Tests/Utils/Monitor/NetworkDeviceRoleCatalog.test.ts +981 -0
  58. package/Tests/Utils/Monitor/NetworkTopologyRoleCatalog.test.ts +865 -0
  59. package/Tests/Utils/NetworkDevice/DeviceRoleKeyUtil.test.ts +538 -0
  60. package/Tests/Utils/Slo/SloEvaluation.test.ts +171 -0
  61. package/Tests/Utils/Slug.test.ts +61 -1
  62. package/Tests/jest.setup.ts +19 -0
  63. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +61 -0
  64. package/Types/NetworkDevice/DefaultNetworkDeviceRole.ts +145 -0
  65. package/Types/Permission.ts +45 -0
  66. package/UI/Components/Charts/Area/AreaChart.tsx +7 -0
  67. package/UI/Components/Charts/Bar/BarChart.tsx +6 -0
  68. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +9 -1
  69. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +97 -35
  70. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +14 -0
  71. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +97 -35
  72. package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +13 -0
  73. package/UI/Components/Charts/Line/LineChart.tsx +7 -0
  74. package/UI/Components/ModelTable/BaseModelTable.tsx +50 -15
  75. package/UI/Components/Navbar/NavBar.tsx +62 -13
  76. package/UI/Components/Navbar/NavBarMenuModal.tsx +7 -2
  77. package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +2 -0
  78. package/UI/Components/SideMenu/SideMenu.tsx +12 -2
  79. package/UI/Components/SideMenu/SideMenuItem.tsx +4 -1
  80. package/UI/Components/SideMenu/SideMenuSection.tsx +14 -2
  81. package/UI/Utils/UseDashboardTimeRangeZoom.ts +77 -0
  82. package/Utils/Dashboard/DashboardTimeRangeZoom.ts +118 -0
  83. package/Utils/Monitor/NetworkDeviceRoleCatalog.ts +232 -0
  84. package/Utils/Monitor/NetworkDeviceRoleUtil.ts +2 -1
  85. package/Utils/Monitor/NetworkTopologyUtil.ts +116 -33
  86. package/Utils/NetworkDevice/DeviceRoleKeyUtil.ts +137 -0
  87. package/Utils/Rules/RulePatternMatchUtil.ts +1 -1
  88. package/Utils/Slug.ts +34 -1
  89. package/build/dist/Models/DatabaseModels/AlertState.js +0 -2
  90. package/build/dist/Models/DatabaseModels/AlertState.js.map +1 -1
  91. package/build/dist/Models/DatabaseModels/Domain.js +1 -1
  92. package/build/dist/Models/DatabaseModels/Domain.js.map +1 -1
  93. package/build/dist/Models/DatabaseModels/Incident.js +1 -1
  94. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  95. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +1 -1
  96. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  97. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  98. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  99. package/build/dist/Models/DatabaseModels/MetricType.js +0 -2
  100. package/build/dist/Models/DatabaseModels/MetricType.js.map +1 -1
  101. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +0 -2
  102. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
  103. package/build/dist/Models/DatabaseModels/MonitorTest.js +0 -2
  104. package/build/dist/Models/DatabaseModels/MonitorTest.js.map +1 -1
  105. package/build/dist/Models/DatabaseModels/NetworkDevice.js +124 -3
  106. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  107. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +3 -1
  108. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -1
  109. package/build/dist/Models/DatabaseModels/NetworkDeviceRole.js +677 -0
  110. package/build/dist/Models/DatabaseModels/NetworkDeviceRole.js.map +1 -0
  111. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -1
  112. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  113. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -1
  114. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
  115. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +0 -2
  116. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  117. package/build/dist/Models/DatabaseModels/StatusPageAnnouncementTemplate.js +0 -2
  118. package/build/dist/Models/DatabaseModels/StatusPageAnnouncementTemplate.js.map +1 -1
  119. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +0 -2
  120. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
  121. package/build/dist/Models/DatabaseModels/StatusPageResource.js +0 -2
  122. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  123. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +0 -2
  124. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  125. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.js +39 -0
  126. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.js.map +1 -0
  127. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  128. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  129. package/build/dist/Server/Services/DatabaseService.js +31 -5
  130. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  131. package/build/dist/Server/Services/Index.js +2 -0
  132. package/build/dist/Server/Services/Index.js.map +1 -1
  133. package/build/dist/Server/Services/NetworkDeviceRoleService.js +70 -0
  134. package/build/dist/Server/Services/NetworkDeviceRoleService.js.map +1 -0
  135. package/build/dist/Server/Services/ProjectService.js +65 -0
  136. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  137. package/build/dist/Server/Services/UserNotificationSettingService.js +0 -1
  138. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  139. package/build/dist/Types/NetworkDevice/DefaultNetworkDeviceRole.js +105 -0
  140. package/build/dist/Types/NetworkDevice/DefaultNetworkDeviceRole.js.map +1 -0
  141. package/build/dist/Types/Permission.js +40 -0
  142. package/build/dist/Types/Permission.js.map +1 -1
  143. package/build/dist/UI/Components/Charts/Area/AreaChart.js +1 -1
  144. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  145. package/build/dist/UI/Components/Charts/Bar/BarChart.js +1 -1
  146. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  147. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +6 -1
  148. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  149. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +79 -31
  150. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  151. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +7 -1
  152. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  153. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +79 -31
  154. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  155. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +14 -0
  156. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -0
  157. package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
  158. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  159. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +39 -13
  160. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  161. package/build/dist/UI/Components/Navbar/NavBar.js +44 -9
  162. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  163. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
  164. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  165. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +1 -1
  166. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
  167. package/build/dist/UI/Components/SideMenu/SideMenu.js +9 -6
  168. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  169. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +1 -1
  170. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  171. package/build/dist/UI/Components/SideMenu/SideMenuSection.js +7 -2
  172. package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
  173. package/build/dist/UI/Utils/UseDashboardTimeRangeZoom.js +42 -0
  174. package/build/dist/UI/Utils/UseDashboardTimeRangeZoom.js.map +1 -0
  175. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +74 -0
  176. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -0
  177. package/build/dist/Utils/Monitor/NetworkDeviceRoleCatalog.js +126 -0
  178. package/build/dist/Utils/Monitor/NetworkDeviceRoleCatalog.js.map +1 -0
  179. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +2 -1
  180. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
  181. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +67 -32
  182. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  183. package/build/dist/Utils/NetworkDevice/DeviceRoleKeyUtil.js +114 -0
  184. package/build/dist/Utils/NetworkDevice/DeviceRoleKeyUtil.js.map +1 -0
  185. package/build/dist/Utils/Rules/RulePatternMatchUtil.js +1 -1
  186. package/build/dist/Utils/Slug.js +31 -1
  187. package/build/dist/Utils/Slug.js.map +1 -1
  188. package/package.json +1 -1
@@ -0,0 +1,215 @@
1
+ import DatabaseService from "../../../Server/Services/DatabaseService";
2
+ import CreateBy from "../../../Server/Types/Database/CreateBy";
3
+ import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
4
+ import Incident from "../../../Models/DatabaseModels/Incident";
5
+ import IncidentTemplate from "../../../Models/DatabaseModels/IncidentTemplate";
6
+ import ScheduledMaintenance from "../../../Models/DatabaseModels/ScheduledMaintenance";
7
+ import ScheduledMaintenanceTemplate from "../../../Models/DatabaseModels/ScheduledMaintenanceTemplate";
8
+ import Domain from "../../../Models/DatabaseModels/Domain";
9
+ import MonitorStatusTimeline from "../../../Models/DatabaseModels/MonitorStatusTimeline";
10
+ import StatusPageResource from "../../../Models/DatabaseModels/StatusPageResource";
11
+ import DomainType from "../../../Types/Domain";
12
+ import ColumnLength from "../../../Types/Database/ColumnLength";
13
+ import { SLUG_SUFFIX_LENGTH } from "../../../Utils/Slug";
14
+ import { describe, expect, test } from "@jest/globals";
15
+
16
+ /*
17
+ * Regression tests for the slug sources fixed alongside the baseline in
18
+ * Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts.
19
+ *
20
+ * generateSlug resolves both halves of @SlugifyColumn BY NAME off the object
21
+ * rather than through the schema, so a source naming no column reads
22
+ * `undefined` and Slug.getSlug(null) answers with a slug built from
23
+ * Faker.generateName(). Nothing throws and nothing is null -- the row simply
24
+ * carries two random words as its public identity. That is why the fix has to
25
+ * be pinned behaviourally here and not only as a declaration in the registry
26
+ * sweep: the sweep proves the column EXISTS, these prove the slug is actually
27
+ * derived from it.
28
+ *
29
+ * Every assertion is on the derivation, never on the whole string: getSlug
30
+ * appends ten random digits to keep slugs unique.
31
+ */
32
+
33
+ const TEN_DIGIT_TAIL: RegExp = /^[\d]{10}$/;
34
+
35
+ /*
36
+ * Runs the real private hook the create path calls, and answers with whatever
37
+ * landed on `slug`.
38
+ */
39
+ const slugFor: (
40
+ modelType: { new (): BaseModel },
41
+ data: BaseModel,
42
+ ) => string | undefined = (
43
+ modelType: { new (): BaseModel },
44
+ data: BaseModel,
45
+ ): string | undefined => {
46
+ const service: DatabaseService<BaseModel> = new DatabaseService<BaseModel>(
47
+ modelType,
48
+ );
49
+
50
+ const createBy: CreateBy<BaseModel> = {
51
+ data,
52
+ props: { isRoot: true },
53
+ };
54
+
55
+ const result: CreateBy<BaseModel> = service["generateSlug"](createBy);
56
+
57
+ return (result.data as unknown as Record<string, string | undefined>)["slug"];
58
+ };
59
+
60
+ /*
61
+ * Asserts the slug reads as `<expected>-<ten digits>` without pinning the
62
+ * digits.
63
+ */
64
+ const expectSlugDerivedFrom: (
65
+ slug: string | undefined,
66
+ expected: string,
67
+ ) => void = (slug: string | undefined, expected: string): void => {
68
+ expect(slug).toBeDefined();
69
+ expect(slug!.substring(0, expected.length + 1)).toBe(`${expected}-`);
70
+ expect(slug!.substring(expected.length + 1)).toMatch(TEN_DIGIT_TAIL);
71
+ };
72
+
73
+ describe("DatabaseService.generateSlug — the slug comes from the column the model means", () => {
74
+ /*
75
+ * Incident's slug column documents the example
76
+ * "database-connection-failure-in-production", which is exactly its title
77
+ * column's example slugified. It slugified `name` -- a column Incident does
78
+ * not have -- so every incident URL in the product was a random name.
79
+ */
80
+ test("Incident slugifies its title", () => {
81
+ const incident: Incident = new Incident();
82
+ incident.title = "Database connection failure in production";
83
+
84
+ expectSlugDerivedFrom(
85
+ slugFor(Incident, incident),
86
+ "database-connection-failure-in-production",
87
+ );
88
+ });
89
+
90
+ test("ScheduledMaintenance slugifies its title", () => {
91
+ const event: ScheduledMaintenance = new ScheduledMaintenance();
92
+ event.title = "Database Migration and Server Upgrade";
93
+
94
+ expectSlugDerivedFrom(
95
+ slugFor(ScheduledMaintenance, event),
96
+ "database-migration-and-server-upgrade",
97
+ );
98
+ });
99
+
100
+ /*
101
+ * The two template models carry BOTH a title and a templateName, so which
102
+ * one they mean is a real choice rather than the only column available.
103
+ * They mean templateName: each documents a slug example that is its
104
+ * TEMPLATE NAME example slugified ("Server Outage Template" ->
105
+ * "server-outage-template"), and StatusPageAnnouncementTemplate -- the one
106
+ * template model whose source column was never mis-copied -- names
107
+ * templateName too. The title is the incident or event the template
108
+ * produces, and is not unique to the template.
109
+ */
110
+ test("IncidentTemplate slugifies its template name, not the incident title it produces", () => {
111
+ const template: IncidentTemplate = new IncidentTemplate();
112
+ template.templateName = "Server Outage Template";
113
+ template.title = "Production Server Outage - Database Connection Issue";
114
+
115
+ expectSlugDerivedFrom(
116
+ slugFor(IncidentTemplate, template),
117
+ "server-outage-template",
118
+ );
119
+ });
120
+
121
+ test("ScheduledMaintenanceTemplate slugifies its template name, not the event title it produces", () => {
122
+ const template: ScheduledMaintenanceTemplate =
123
+ new ScheduledMaintenanceTemplate();
124
+ template.templateName = "Database Upgrade Template";
125
+ template.title = "Scheduled Database Maintenance - PostgreSQL Upgrade";
126
+
127
+ expectSlugDerivedFrom(
128
+ slugFor(ScheduledMaintenanceTemplate, template),
129
+ "database-upgrade-template",
130
+ );
131
+ });
132
+
133
+ /*
134
+ * Domain has neither a name nor a title column; the domain IS its identity.
135
+ * getSlug strips dots along with the rest of [&*+~.,\\/()|'"!:@].
136
+ */
137
+ test("Domain slugifies the domain itself", () => {
138
+ const domain: Domain = new Domain();
139
+ domain.domain = new DomainType("status.example.com");
140
+
141
+ expectSlugDerivedFrom(slugFor(Domain, domain), "statusexamplecom");
142
+ });
143
+
144
+ /*
145
+ * States the failure mode the five tests above are guarding against, rather
146
+ * than leaving it to be inferred from a prefix that happens to match.
147
+ */
148
+ test("an unset source column falls back to a random name rather than failing", () => {
149
+ const slug: string | undefined = slugFor(Incident, new Incident());
150
+
151
+ expect(slug).toBeDefined();
152
+ expect(slug).toMatch(/^[a-z0-9-]+-[\d]{10}$/);
153
+ expect(slug!.startsWith("database-connection-failure")).toBe(false);
154
+ });
155
+
156
+ /*
157
+ * Incident.title is varchar(500) against a varchar(100) slug, so pointing
158
+ * the decorator at it is only safe because generateSlug clamps to the
159
+ * DESTINATION column. checkMaxLengthOfFields runs later in the same create
160
+ * and THROWS on overflow rather than truncating, so without the clamp a
161
+ * long incident title would be a failed insert instead of a long slug.
162
+ */
163
+ test("clamps an over-wide source down to the slug column", () => {
164
+ const title: string = "Database connection failure in production ".repeat(
165
+ 12,
166
+ );
167
+
168
+ expect(title.length).toBeGreaterThan(ColumnLength.Slug);
169
+
170
+ const incident: Incident = new Incident();
171
+ incident.title = title;
172
+
173
+ const slug: string | undefined = slugFor(Incident, incident);
174
+
175
+ expect(slug).toBeDefined();
176
+ expect(slug!.length).toBeLessThanOrEqual(ColumnLength.Slug);
177
+
178
+ /* The readable half is what gets cut; the unique tail survives whole. */
179
+ expect(slug!.substring(slug!.length - SLUG_SUFFIX_LENGTH)).toMatch(
180
+ /^-[\d]{10}$/,
181
+ );
182
+ expect(slug!.startsWith("database-connection-failure-in-production")).toBe(
183
+ true,
184
+ );
185
+
186
+ /* And never a dash left dangling where the cut fell. */
187
+ expect(slug).not.toMatch(/--[\d]{10}$/);
188
+ });
189
+
190
+ /*
191
+ * The other half of the sweep's fourteen: models whose decorator named
192
+ * columns they do not have at all. Their slug was assigned to a property
193
+ * with no column and dropped by TypeORM on insert, so the decorator was
194
+ * dead configuration and was removed rather than backed by a new column and
195
+ * a migration for a value nothing in the product reads.
196
+ */
197
+ test("a model with no slug configuration is left untouched", () => {
198
+ for (const model of [
199
+ new StatusPageResource(),
200
+ new MonitorStatusTimeline(),
201
+ ]) {
202
+ expect(model.getSlugifyColumn()).toBeFalsy();
203
+ expect(model.getSaveSlugToColumn()).toBeFalsy();
204
+
205
+ const ownPropertiesBefore: Array<string> = Object.keys(model).sort();
206
+
207
+ slugFor(
208
+ model.constructor as { new (): BaseModel },
209
+ model as unknown as BaseModel,
210
+ );
211
+
212
+ expect(Object.keys(model).sort()).toEqual(ownPropertiesBefore);
213
+ }
214
+ });
215
+ });