@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.
- package/Models/DatabaseModels/AlertState.ts +0 -2
- package/Models/DatabaseModels/Domain.ts +1 -1
- package/Models/DatabaseModels/Incident.ts +1 -1
- package/Models/DatabaseModels/IncidentTemplate.ts +1 -1
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/MetricType.ts +0 -2
- package/Models/DatabaseModels/MonitorStatusTimeline.ts +0 -2
- package/Models/DatabaseModels/MonitorTest.ts +0 -2
- package/Models/DatabaseModels/NetworkDevice.ts +121 -2
- package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +3 -1
- package/Models/DatabaseModels/NetworkDeviceRole.ts +648 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -1
- package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -1
- package/Models/DatabaseModels/StatusPageAnnouncement.ts +0 -2
- package/Models/DatabaseModels/StatusPageAnnouncementTemplate.ts +0 -2
- package/Models/DatabaseModels/StatusPagePrivateUser.ts +0 -2
- package/Models/DatabaseModels/StatusPageResource.ts +0 -2
- package/Models/DatabaseModels/StatusPageSubscriber.ts +0 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.ts +72 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/DatabaseService.ts +39 -9
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/NetworkDeviceRoleService.ts +90 -0
- package/Server/Services/ProjectService.ts +85 -0
- package/Server/Services/UserNotificationSettingService.ts +0 -6
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +31 -1
- package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +35 -8
- package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +107 -3
- package/Tests/App/Dashboard/DashboardWideChartZoom.test.tsx +401 -0
- package/Tests/App/Dashboard/MonitorTemplateColumnAndFacet.test.tsx +318 -0
- package/Tests/App/Dashboard/NetworkDeviceBulkDelete.test.tsx +357 -0
- package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +590 -0
- package/Tests/App/Dashboard/SideMenuHarness.tsx +11 -3
- package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +115 -41
- package/Tests/Server/Infrastructure/Postgres/NetworkDeviceRoleTableMigration.test.ts +476 -0
- package/Tests/Server/Services/DatabaseServiceGenerateSlug.test.ts +215 -0
- package/Tests/Server/Services/NetworkDeviceRoleModel.test.ts +672 -0
- package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +1 -1
- package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +67 -4
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberEndTime.test.ts +369 -0
- package/Tests/Server/Services/UserNotificationSettingMonitorDefaults.test.ts +248 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +43 -2
- package/Tests/Server/Utils/BasicCron.test.ts +283 -0
- package/Tests/Server/Utils/IncomingCallPhoneNumber.test.ts +174 -0
- package/Tests/Types/NetworkDevice/DefaultNetworkDeviceRole.test.ts +417 -0
- package/Tests/UI/Components/Charts/ChartClickDoubleClickDisambiguation.test.tsx +221 -0
- package/Tests/UI/Components/Charts/ChartDoubleClickReset.test.tsx +220 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +751 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +475 -43
- package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +89 -0
- package/Tests/UI/Components/NavBarCommandKGating.test.tsx +103 -8
- package/Tests/UI/Components/SideMenuItem.test.tsx +30 -0
- package/Tests/UI/Utils/TableColumnsToCsv.test.ts +30 -0
- package/Tests/UI/Utils/UseDashboardTimeRangeZoom.test.tsx +187 -0
- package/Tests/Utils/Dashboard/DashboardResourceListSharedArgs.test.ts +302 -0
- package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +242 -0
- package/Tests/Utils/Monitor/NetworkDeviceRoleCatalog.test.ts +981 -0
- package/Tests/Utils/Monitor/NetworkTopologyRoleCatalog.test.ts +865 -0
- package/Tests/Utils/NetworkDevice/DeviceRoleKeyUtil.test.ts +538 -0
- package/Tests/Utils/Slo/SloEvaluation.test.ts +171 -0
- package/Tests/Utils/Slug.test.ts +61 -1
- package/Tests/jest.setup.ts +19 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +61 -0
- package/Types/NetworkDevice/DefaultNetworkDeviceRole.ts +145 -0
- package/Types/Permission.ts +45 -0
- package/UI/Components/Charts/Area/AreaChart.tsx +7 -0
- package/UI/Components/Charts/Bar/BarChart.tsx +6 -0
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +9 -1
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +97 -35
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +14 -0
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +97 -35
- package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +7 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +50 -15
- package/UI/Components/Navbar/NavBar.tsx +62 -13
- package/UI/Components/Navbar/NavBarMenuModal.tsx +7 -2
- package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +2 -0
- package/UI/Components/SideMenu/SideMenu.tsx +12 -2
- package/UI/Components/SideMenu/SideMenuItem.tsx +4 -1
- package/UI/Components/SideMenu/SideMenuSection.tsx +14 -2
- package/UI/Utils/UseDashboardTimeRangeZoom.ts +77 -0
- package/Utils/Dashboard/DashboardTimeRangeZoom.ts +118 -0
- package/Utils/Monitor/NetworkDeviceRoleCatalog.ts +232 -0
- package/Utils/Monitor/NetworkDeviceRoleUtil.ts +2 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +116 -33
- package/Utils/NetworkDevice/DeviceRoleKeyUtil.ts +137 -0
- package/Utils/Rules/RulePatternMatchUtil.ts +1 -1
- package/Utils/Slug.ts +34 -1
- package/build/dist/Models/DatabaseModels/AlertState.js +0 -2
- package/build/dist/Models/DatabaseModels/AlertState.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Domain.js +1 -1
- package/build/dist/Models/DatabaseModels/Domain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MetricType.js +0 -2
- package/build/dist/Models/DatabaseModels/MetricType.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +0 -2
- package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTest.js +0 -2
- package/build/dist/Models/DatabaseModels/MonitorTest.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +124 -3
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +3 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceRole.js +677 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceRole.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncementTemplate.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncementTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageResource.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +0 -2
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.js +39 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +31 -5
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceRoleService.js +70 -0
- package/build/dist/Server/Services/NetworkDeviceRoleService.js.map +1 -0
- package/build/dist/Server/Services/ProjectService.js +65 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +0 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Types/NetworkDevice/DefaultNetworkDeviceRole.js +105 -0
- package/build/dist/Types/NetworkDevice/DefaultNetworkDeviceRole.js.map +1 -0
- package/build/dist/Types/Permission.js +40 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +6 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +79 -31
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +7 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +79 -31
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +14 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -0
- package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +39 -13
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +44 -9
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +1 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +9 -6
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js +7 -2
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
- package/build/dist/UI/Utils/UseDashboardTimeRangeZoom.js +42 -0
- package/build/dist/UI/Utils/UseDashboardTimeRangeZoom.js.map +1 -0
- package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +74 -0
- package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleCatalog.js +126 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleCatalog.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +2 -1
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +67 -32
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceRoleKeyUtil.js +114 -0
- package/build/dist/Utils/NetworkDevice/DeviceRoleKeyUtil.js.map +1 -0
- package/build/dist/Utils/Rules/RulePatternMatchUtil.js +1 -1
- package/build/dist/Utils/Slug.js +31 -1
- package/build/dist/Utils/Slug.js.map +1 -1
- package/package.json +1 -1
|
@@ -14,7 +14,6 @@ import ColumnType from "../../Types/Database/ColumnType";
|
|
|
14
14
|
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
|
|
15
15
|
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
|
|
16
16
|
import EnableWorkflow from "../../Types/Database/EnableWorkflow";
|
|
17
|
-
import SlugifyColumn from "../../Types/Database/SlugifyColumn";
|
|
18
17
|
import TableColumn from "../../Types/Database/TableColumn";
|
|
19
18
|
import TableColumnType from "../../Types/Database/TableColumnType";
|
|
20
19
|
import TableMetadata from "../../Types/Database/TableMetadata";
|
|
@@ -78,7 +77,6 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
78
77
|
read: true,
|
|
79
78
|
})
|
|
80
79
|
@CrudApiEndpoint(new Route("/status-page-private-user"))
|
|
81
|
-
@SlugifyColumn("name", "slug")
|
|
82
80
|
@TableMetadata({
|
|
83
81
|
tableName: "StatusPagePrivateUser",
|
|
84
82
|
singularName: "Status Page Private User",
|
|
@@ -15,7 +15,6 @@ import ColumnType from "../../Types/Database/ColumnType";
|
|
|
15
15
|
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
|
|
16
16
|
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
|
|
17
17
|
import EnableWorkflow from "../../Types/Database/EnableWorkflow";
|
|
18
|
-
import SlugifyColumn from "../../Types/Database/SlugifyColumn";
|
|
19
18
|
import TableColumn from "../../Types/Database/TableColumn";
|
|
20
19
|
import TableColumnType from "../../Types/Database/TableColumnType";
|
|
21
20
|
import TableMetadata from "../../Types/Database/TableMetadata";
|
|
@@ -72,7 +71,6 @@ import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
|
|
|
72
71
|
read: true,
|
|
73
72
|
})
|
|
74
73
|
@CrudApiEndpoint(new Route("/status-page-resource"))
|
|
75
|
-
@SlugifyColumn("name", "slug")
|
|
76
74
|
@TableMetadata({
|
|
77
75
|
tableName: "StatusPageResource",
|
|
78
76
|
singularName: "Status Page Resource",
|
|
@@ -14,7 +14,6 @@ import ColumnType from "../../Types/Database/ColumnType";
|
|
|
14
14
|
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
|
|
15
15
|
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
|
|
16
16
|
import EnableWorkflow from "../../Types/Database/EnableWorkflow";
|
|
17
|
-
import SlugifyColumn from "../../Types/Database/SlugifyColumn";
|
|
18
17
|
import TableColumn from "../../Types/Database/TableColumn";
|
|
19
18
|
import TableColumnType from "../../Types/Database/TableColumnType";
|
|
20
19
|
import TableMetadata from "../../Types/Database/TableMetadata";
|
|
@@ -82,7 +81,6 @@ import StatusPageEventType from "../../Types/StatusPage/StatusPageEventType";
|
|
|
82
81
|
],
|
|
83
82
|
})
|
|
84
83
|
@CrudApiEndpoint(new Route("/status-page-subscriber"))
|
|
85
|
-
@SlugifyColumn("name", "slug")
|
|
86
84
|
@TableMetadata({
|
|
87
85
|
tableName: "StatusPageSubscriber",
|
|
88
86
|
singularName: "Status Page Subscriber",
|
package/Server/Infrastructure/Postgres/SchemaMigrations/1790800000000-AddNetworkDeviceRoleTable.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Device roles become a per-project lookup instead of a fixed union.
|
|
5
|
+
*
|
|
6
|
+
* "deviceRole" (the inline string on NetworkDevice) is NOT touched here: the
|
|
7
|
+
* BackfillNetworkDeviceRoles data migration still reads it to point every
|
|
8
|
+
* device that has one at its new NetworkDeviceRole row. It is dropped in a
|
|
9
|
+
* follow-up once that backfill has run everywhere.
|
|
10
|
+
*
|
|
11
|
+
* networkDeviceRoleId is ON DELETE SET NULL on purpose. Deleting a role from
|
|
12
|
+
* the project's settings must not delete the devices using it - they simply go
|
|
13
|
+
* back to being classified from their own SNMP identity, which is exactly what
|
|
14
|
+
* a NULL role has always meant.
|
|
15
|
+
*/
|
|
16
|
+
export class AddNetworkDeviceRoleTable1790800000000
|
|
17
|
+
implements MigrationInterface
|
|
18
|
+
{
|
|
19
|
+
public name: string = "AddNetworkDeviceRoleTable1790800000000";
|
|
20
|
+
|
|
21
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`CREATE TABLE "NetworkDeviceRole" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(100) NOT NULL, "slug" character varying(100) NOT NULL, "key" character varying(100) NOT NULL, "description" character varying(500), "topologyShape" character varying(100), "isCoreLayer" boolean NOT NULL DEFAULT false, "isSnmpWalkable" boolean NOT NULL DEFAULT true, "order" integer, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_10fb79a5d66950e4a9c6d774d07" PRIMARY KEY ("_id"))`,
|
|
24
|
+
);
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`CREATE INDEX "IDX_188009b80d1281f1d7ccecdf74" ON "NetworkDeviceRole" ("projectId") `,
|
|
27
|
+
);
|
|
28
|
+
await queryRunner.query(
|
|
29
|
+
`ALTER TABLE "NetworkDevice" ADD "networkDeviceRoleId" uuid`,
|
|
30
|
+
);
|
|
31
|
+
await queryRunner.query(
|
|
32
|
+
`CREATE INDEX "IDX_41f59fed52c5ec4ff6a2725ad9" ON "NetworkDevice" ("networkDeviceRoleId") `,
|
|
33
|
+
);
|
|
34
|
+
await queryRunner.query(
|
|
35
|
+
`ALTER TABLE "NetworkDeviceRole" ADD CONSTRAINT "FK_188009b80d1281f1d7ccecdf74d" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
36
|
+
);
|
|
37
|
+
await queryRunner.query(
|
|
38
|
+
`ALTER TABLE "NetworkDeviceRole" ADD CONSTRAINT "FK_9860e7a5b4d23cf1c4192c468cd" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
39
|
+
);
|
|
40
|
+
await queryRunner.query(
|
|
41
|
+
`ALTER TABLE "NetworkDeviceRole" ADD CONSTRAINT "FK_9dc66fa19636ba160af1521f45d" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
42
|
+
);
|
|
43
|
+
await queryRunner.query(
|
|
44
|
+
`ALTER TABLE "NetworkDevice" ADD CONSTRAINT "FK_41f59fed52c5ec4ff6a2725ad9a" FOREIGN KEY ("networkDeviceRoleId") REFERENCES "NetworkDeviceRole"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
49
|
+
await queryRunner.query(
|
|
50
|
+
`ALTER TABLE "NetworkDevice" DROP CONSTRAINT "FK_41f59fed52c5ec4ff6a2725ad9a"`,
|
|
51
|
+
);
|
|
52
|
+
await queryRunner.query(
|
|
53
|
+
`ALTER TABLE "NetworkDeviceRole" DROP CONSTRAINT "FK_9dc66fa19636ba160af1521f45d"`,
|
|
54
|
+
);
|
|
55
|
+
await queryRunner.query(
|
|
56
|
+
`ALTER TABLE "NetworkDeviceRole" DROP CONSTRAINT "FK_9860e7a5b4d23cf1c4192c468cd"`,
|
|
57
|
+
);
|
|
58
|
+
await queryRunner.query(
|
|
59
|
+
`ALTER TABLE "NetworkDeviceRole" DROP CONSTRAINT "FK_188009b80d1281f1d7ccecdf74d"`,
|
|
60
|
+
);
|
|
61
|
+
await queryRunner.query(
|
|
62
|
+
`DROP INDEX "public"."IDX_41f59fed52c5ec4ff6a2725ad9"`,
|
|
63
|
+
);
|
|
64
|
+
await queryRunner.query(
|
|
65
|
+
`ALTER TABLE "NetworkDevice" DROP COLUMN "networkDeviceRoleId"`,
|
|
66
|
+
);
|
|
67
|
+
await queryRunner.query(
|
|
68
|
+
`DROP INDEX "public"."IDX_188009b80d1281f1d7ccecdf74"`,
|
|
69
|
+
);
|
|
70
|
+
await queryRunner.query(`DROP TABLE "NetworkDeviceRole"`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -566,6 +566,7 @@ import { AddCertificateReissueRequestedAtToDomains1790300000000 } from "./179030
|
|
|
566
566
|
import { AddOnCallCalendarFeeds1790400000000 } from "./1790400000000-AddOnCallCalendarFeeds";
|
|
567
567
|
import { AddNetworkDeviceOidTemplate1790500000000 } from "./1790500000000-AddNetworkDeviceOidTemplate";
|
|
568
568
|
import { AddAutoImportRuleOidTemplate1790600000000 } from "./1790600000000-AddAutoImportRuleOidTemplate";
|
|
569
|
+
import { AddNetworkDeviceRoleTable1790800000000 } from "./1790800000000-AddNetworkDeviceRoleTable";
|
|
569
570
|
|
|
570
571
|
export default [
|
|
571
572
|
InitialMigration,
|
|
@@ -1136,4 +1137,5 @@ export default [
|
|
|
1136
1137
|
AddOnCallCalendarFeeds1790400000000,
|
|
1137
1138
|
AddNetworkDeviceOidTemplate1790500000000,
|
|
1138
1139
|
AddAutoImportRuleOidTemplate1790600000000,
|
|
1140
|
+
AddNetworkDeviceRoleTable1790800000000,
|
|
1139
1141
|
];
|
|
@@ -616,21 +616,51 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
616
616
|
throw PostgresErrorTranslator.translateException(error);
|
|
617
617
|
}
|
|
618
618
|
|
|
619
|
+
/*
|
|
620
|
+
* Both halves of @SlugifyColumn are resolved BY NAME off the object rather
|
|
621
|
+
* than through the schema, so a name matching no declared column misfires
|
|
622
|
+
* silently: a missing source reads `undefined` and Slug.getSlug answers with
|
|
623
|
+
* a random Faker name, and a missing destination is assigned to a property
|
|
624
|
+
* TypeORM drops on insert. ModelRegistryInvariants sweeps every model for
|
|
625
|
+
* both, so the pairing is guaranteed by a test rather than by this code.
|
|
626
|
+
*
|
|
627
|
+
* The ceiling comes from the DESTINATION column, not from Slug: getSlug
|
|
628
|
+
* appends a dash and ten random digits, and checkMaxLengthOfFields -- which
|
|
629
|
+
* runs later in the same create -- THROWS on overflow rather than
|
|
630
|
+
* truncating. Sources are routinely wider than the slug they feed
|
|
631
|
+
* (Incident.title is varchar(500) against a varchar(100) slug), so without
|
|
632
|
+
* this a long title would be a failed insert rather than a long slug.
|
|
633
|
+
*/
|
|
619
634
|
private generateSlug(createBy: CreateBy<TBaseModel>): CreateBy<TBaseModel> {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
createBy.data.getSlugifyColumn() as string
|
|
626
|
-
] as string)
|
|
627
|
-
: null,
|
|
628
|
-
);
|
|
635
|
+
const slugifyColumn: string | null = createBy.data.getSlugifyColumn();
|
|
636
|
+
const saveSlugToColumn: string | null = createBy.data.getSaveSlugToColumn();
|
|
637
|
+
|
|
638
|
+
if (!slugifyColumn || !saveSlugToColumn) {
|
|
639
|
+
return createBy;
|
|
629
640
|
}
|
|
630
641
|
|
|
642
|
+
const source: JSONValue = (createBy.data as any)[slugifyColumn];
|
|
643
|
+
|
|
644
|
+
(createBy.data as any)[saveSlugToColumn] = Slug.getSlug(
|
|
645
|
+
source ? String(source) : null,
|
|
646
|
+
this.getMaxLengthOfColumn(saveSlugToColumn),
|
|
647
|
+
);
|
|
648
|
+
|
|
631
649
|
return createBy;
|
|
632
650
|
}
|
|
633
651
|
|
|
652
|
+
/*
|
|
653
|
+
* The declared width of a column, or undefined for a column that declares
|
|
654
|
+
* none -- including a name that is not a column at all, which is what
|
|
655
|
+
* getTableColumnMetadata answers for.
|
|
656
|
+
*/
|
|
657
|
+
private getMaxLengthOfColumn(columnName: string): number | undefined {
|
|
658
|
+
const columnType: TableColumnType | undefined =
|
|
659
|
+
this.model.getTableColumnMetadata(columnName)?.type;
|
|
660
|
+
|
|
661
|
+
return columnType ? getMaxLengthFromTableColumnType(columnType) : undefined;
|
|
662
|
+
}
|
|
663
|
+
|
|
634
664
|
private async sanitizeCreateOrUpdate(
|
|
635
665
|
data: TBaseModel | PartialEntity<TBaseModel>,
|
|
636
666
|
props: DatabaseCommonInteractionProps,
|
package/Server/Services/Index.ts
CHANGED
|
@@ -62,6 +62,7 @@ import NetworkDeviceOwnerRuleService from "./NetworkDeviceOwnerRuleService";
|
|
|
62
62
|
import NetworkDeviceLabelRuleService from "./NetworkDeviceLabelRuleService";
|
|
63
63
|
import NetworkDeviceAutoImportRuleService from "./NetworkDeviceAutoImportRuleService";
|
|
64
64
|
import NetworkDeviceOidTemplateService from "./NetworkDeviceOidTemplateService";
|
|
65
|
+
import NetworkDeviceRoleService from "./NetworkDeviceRoleService";
|
|
65
66
|
import NetworkDeviceDiscoveryScanService from "./NetworkDeviceDiscoveryScanService";
|
|
66
67
|
import NetworkInterfaceService from "./NetworkInterfaceService";
|
|
67
68
|
import NetworkSiteService from "./NetworkSiteService";
|
|
@@ -508,6 +509,7 @@ const services: Array<BaseService> = [
|
|
|
508
509
|
NetworkDeviceLabelRuleService,
|
|
509
510
|
NetworkDeviceAutoImportRuleService,
|
|
510
511
|
NetworkDeviceOidTemplateService,
|
|
512
|
+
NetworkDeviceRoleService,
|
|
511
513
|
NetworkDeviceDiscoveryScanService,
|
|
512
514
|
NetworkInterfaceService,
|
|
513
515
|
NetworkSiteService,
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import Model from "../../Models/DatabaseModels/NetworkDeviceRole";
|
|
3
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
4
|
+
import { OnCreate } from "../Types/Database/Hooks";
|
|
5
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
6
|
+
import ObjectID from "../../Types/ObjectID";
|
|
7
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
8
|
+
import { buildUniqueDeviceRoleKey } from "../../Utils/NetworkDevice/DeviceRoleKeyUtil";
|
|
9
|
+
|
|
10
|
+
export class Service extends DatabaseService<Model> {
|
|
11
|
+
public constructor() {
|
|
12
|
+
super(Model);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* Every role gets its stable key here, and only here.
|
|
17
|
+
*
|
|
18
|
+
* The key is not a form field - an operator names a role, they do not name
|
|
19
|
+
* its identifier - and it must never change afterwards, because it is what
|
|
20
|
+
* the SNMP classifier's answer and every stored topology payload match
|
|
21
|
+
* against. Deriving it at create time is therefore the whole of its
|
|
22
|
+
* lifecycle: the column's ColumnAccessControl grants create and update to
|
|
23
|
+
* nobody, so the API cannot set or move it either.
|
|
24
|
+
*
|
|
25
|
+
* The seeders pass an explicit key so the eleven built-in roles keep the
|
|
26
|
+
* exact identifiers the classifier emits ("wirelessAccessPoint" from
|
|
27
|
+
* "Wireless AP", which no derivation would produce). Anything else derives
|
|
28
|
+
* one from the name, de-duplicated against the keys the project already
|
|
29
|
+
* holds.
|
|
30
|
+
*/
|
|
31
|
+
protected override async onBeforeCreate(
|
|
32
|
+
createBy: CreateBy<Model>,
|
|
33
|
+
): Promise<OnCreate<Model>> {
|
|
34
|
+
if (!createBy.data.key) {
|
|
35
|
+
const projectId: ObjectID | undefined =
|
|
36
|
+
createBy.data.projectId || createBy.props.tenantId || undefined;
|
|
37
|
+
|
|
38
|
+
if (!projectId) {
|
|
39
|
+
throw new BadDataException(
|
|
40
|
+
"Project ID is required to create a network device role.",
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
createBy.data.key = buildUniqueDeviceRoleKey(
|
|
45
|
+
createBy.data.name || "",
|
|
46
|
+
await this.getKeysInProject(projectId),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
createBy: createBy,
|
|
52
|
+
carryForward: undefined,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Every role key already in use in this project, for uniqueness checks.
|
|
58
|
+
*
|
|
59
|
+
* Read as root: a member who may create a role must get a key that does not
|
|
60
|
+
* collide with one they are not allowed to see, and a partial view of the
|
|
61
|
+
* project's keys would hand them a duplicate the database then rejects.
|
|
62
|
+
*/
|
|
63
|
+
public async getKeysInProject(projectId: ObjectID): Promise<Set<string>> {
|
|
64
|
+
const existing: Array<Model> = await this.findBy({
|
|
65
|
+
query: {
|
|
66
|
+
projectId: projectId,
|
|
67
|
+
},
|
|
68
|
+
select: {
|
|
69
|
+
key: true,
|
|
70
|
+
},
|
|
71
|
+
skip: 0,
|
|
72
|
+
limit: LIMIT_MAX,
|
|
73
|
+
props: {
|
|
74
|
+
isRoot: true,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const keys: Set<string> = new Set<string>();
|
|
79
|
+
|
|
80
|
+
for (const role of existing) {
|
|
81
|
+
if (role.key) {
|
|
82
|
+
keys.add(role.key);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return keys;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default new Service();
|
|
@@ -34,6 +34,7 @@ import IncidentStateService from "./IncidentStateService";
|
|
|
34
34
|
import IncidentRoleService from "./IncidentRoleService";
|
|
35
35
|
import MailService from "./MailService";
|
|
36
36
|
import MonitorStatusService from "./MonitorStatusService";
|
|
37
|
+
import NetworkDeviceRoleService from "./NetworkDeviceRoleService";
|
|
37
38
|
import NetworkSiteTypeService from "./NetworkSiteTypeService";
|
|
38
39
|
import NotificationService from "./NotificationService";
|
|
39
40
|
import PromoCodeService from "./PromoCodeService";
|
|
@@ -79,6 +80,11 @@ import IncidentRole from "../../Models/DatabaseModels/IncidentRole";
|
|
|
79
80
|
import MonitorStatus from "../../Models/DatabaseModels/MonitorStatus";
|
|
80
81
|
import NetworkSiteType from "../../Models/DatabaseModels/NetworkSiteType";
|
|
81
82
|
import DefaultNetworkSiteType from "../../Types/NetworkSite/DefaultNetworkSiteType";
|
|
83
|
+
import NetworkDeviceRole from "../../Models/DatabaseModels/NetworkDeviceRole";
|
|
84
|
+
import {
|
|
85
|
+
DEFAULT_NETWORK_DEVICE_ROLES,
|
|
86
|
+
DefaultNetworkDeviceRole,
|
|
87
|
+
} from "../../Types/NetworkDevice/DefaultNetworkDeviceRole";
|
|
82
88
|
import Model from "../../Models/DatabaseModels/Project";
|
|
83
89
|
import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
84
90
|
import PromoCode from "../../Models/DatabaseModels/PromoCode";
|
|
@@ -1444,6 +1450,7 @@ These are no longer recorded against the project and have to be cancelled by han
|
|
|
1444
1450
|
this.addDefaultAlertState(createdItem),
|
|
1445
1451
|
this.addDefaultIncidentRoles(createdItem),
|
|
1446
1452
|
this.addDefaultNetworkSiteTypes(createdItem),
|
|
1453
|
+
this.addDefaultNetworkDeviceRoles(createdItem),
|
|
1447
1454
|
]);
|
|
1448
1455
|
|
|
1449
1456
|
if (createdItem.createdOwnerEmail) {
|
|
@@ -2007,6 +2014,84 @@ These are no longer recorded against the project and have to be cancelled by han
|
|
|
2007
2014
|
return createdItem;
|
|
2008
2015
|
}
|
|
2009
2016
|
|
|
2017
|
+
/**
|
|
2018
|
+
* Seeds the per-project network device role lookup table.
|
|
2019
|
+
*
|
|
2020
|
+
* Device roles used to be a fixed union with the label, the silhouette and
|
|
2021
|
+
* the "is this a core device?" flag hardcoded in three different modules.
|
|
2022
|
+
* They are now a configurable per-project table, so a project can rename
|
|
2023
|
+
* "Wireless AP" to "Access Point", draw firewalls as something else, or add
|
|
2024
|
+
* a role of its own - which means every project needs its own seeded copy of
|
|
2025
|
+
* the defaults.
|
|
2026
|
+
*
|
|
2027
|
+
* Public for the same reason addDefaultNetworkSiteTypes is: the
|
|
2028
|
+
* BackfillNetworkDeviceRoles data migration calls it to seed roles into
|
|
2029
|
+
* projects that existed before the table did, so the defaults are defined
|
|
2030
|
+
* once and cannot drift between project creation and the backfill.
|
|
2031
|
+
*
|
|
2032
|
+
* The key is passed explicitly rather than derived from the name. It has to
|
|
2033
|
+
* be exactly what the SNMP classifier emits - "wirelessAccessPoint", which
|
|
2034
|
+
* no derivation from "Wireless AP" would produce - or a classified access
|
|
2035
|
+
* point would match no row.
|
|
2036
|
+
*/
|
|
2037
|
+
@CaptureSpan()
|
|
2038
|
+
public async addDefaultNetworkDeviceRoles(
|
|
2039
|
+
createdItem: Model,
|
|
2040
|
+
): Promise<Model> {
|
|
2041
|
+
const projectId: ObjectID = createdItem.id!;
|
|
2042
|
+
|
|
2043
|
+
// Idempotent - see getExistingProjectScopedNames.
|
|
2044
|
+
const existingNames: Set<string | undefined> =
|
|
2045
|
+
await this.getExistingProjectScopedNames(
|
|
2046
|
+
NetworkDeviceRoleService,
|
|
2047
|
+
projectId,
|
|
2048
|
+
);
|
|
2049
|
+
|
|
2050
|
+
/*
|
|
2051
|
+
* Also guarded on the key, not just the name: a project that renamed the
|
|
2052
|
+
* seeded "Router" to "Edge Router" must not get a second row called
|
|
2053
|
+
* "Router" the next time this runs, and the key is the identity that
|
|
2054
|
+
* survives the rename.
|
|
2055
|
+
*/
|
|
2056
|
+
const existingKeys: Set<string> =
|
|
2057
|
+
await NetworkDeviceRoleService.getKeysInProject(projectId);
|
|
2058
|
+
|
|
2059
|
+
for (
|
|
2060
|
+
let index: number = 0;
|
|
2061
|
+
index < DEFAULT_NETWORK_DEVICE_ROLES.length;
|
|
2062
|
+
index++
|
|
2063
|
+
) {
|
|
2064
|
+
const defaultRole: DefaultNetworkDeviceRole =
|
|
2065
|
+
DEFAULT_NETWORK_DEVICE_ROLES[index]!;
|
|
2066
|
+
|
|
2067
|
+
if (
|
|
2068
|
+
existingNames.has(defaultRole.name) ||
|
|
2069
|
+
existingKeys.has(defaultRole.key)
|
|
2070
|
+
) {
|
|
2071
|
+
continue;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
const networkDeviceRole: NetworkDeviceRole = new NetworkDeviceRole();
|
|
2075
|
+
networkDeviceRole.name = defaultRole.name;
|
|
2076
|
+
networkDeviceRole.key = defaultRole.key;
|
|
2077
|
+
networkDeviceRole.description = defaultRole.description;
|
|
2078
|
+
networkDeviceRole.topologyShape = defaultRole.topologyShape;
|
|
2079
|
+
networkDeviceRole.isCoreLayer = defaultRole.isCoreLayer;
|
|
2080
|
+
networkDeviceRole.isSnmpWalkable = defaultRole.isSnmpWalkable;
|
|
2081
|
+
networkDeviceRole.projectId = projectId;
|
|
2082
|
+
networkDeviceRole.order = index + 1;
|
|
2083
|
+
|
|
2084
|
+
await NetworkDeviceRoleService.create({
|
|
2085
|
+
data: networkDeviceRole,
|
|
2086
|
+
props: {
|
|
2087
|
+
isRoot: true,
|
|
2088
|
+
},
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
return createdItem;
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2010
2095
|
private async addDefaultProjectTeams(createdItem: Model): Promise<Model> {
|
|
2011
2096
|
// add a team member.
|
|
2012
2097
|
|
|
@@ -800,12 +800,6 @@ export class Service extends DatabaseService<UserNotificationSetting> {
|
|
|
800
800
|
userId: ObjectID,
|
|
801
801
|
projectId: ObjectID,
|
|
802
802
|
): Promise<void> {
|
|
803
|
-
await this.addNotificationSettingIfNotExists(
|
|
804
|
-
userId,
|
|
805
|
-
projectId,
|
|
806
|
-
NotificationSettingEventType.SEND_MONITOR_STATUS_CHANGED_OWNER_NOTIFICATION,
|
|
807
|
-
);
|
|
808
|
-
|
|
809
803
|
await this.addNotificationSettingIfNotExists(
|
|
810
804
|
userId,
|
|
811
805
|
projectId,
|
|
@@ -128,12 +128,26 @@ const SECOND_SWITCH_NODE: NetworkTopologyNode = {
|
|
|
128
128
|
status: "up",
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
+
/*
|
|
132
|
+
* Carries the role stamp the topology builder puts on a node now that roles
|
|
133
|
+
* are per-project rows: `roleId` is the project's row for the classified role,
|
|
134
|
+
* and it is what the form can actually preselect - the role is a relation, and
|
|
135
|
+
* a form cannot resolve a key to a row.
|
|
136
|
+
*/
|
|
137
|
+
const PHONE_ROLE_ID: string = "b7a1a0f6-3a4b-4a0e-9c3f-4f1f7f2a91cd";
|
|
138
|
+
|
|
139
|
+
const SWITCH_ROLE_ID: string = "0c2d5b41-9f22-4a3e-8f61-2d7c6a4e8b03";
|
|
140
|
+
|
|
131
141
|
const PHONE_NODE: NetworkTopologyNode = {
|
|
132
142
|
id: "unmanaged:sep6026aaf2b46b",
|
|
133
143
|
name: "SEP6026AAF2B46B",
|
|
134
144
|
isManaged: false,
|
|
135
145
|
kind: "unmanaged",
|
|
136
146
|
role: "phone",
|
|
147
|
+
roleKey: "phone",
|
|
148
|
+
roleLabel: "IP phone",
|
|
149
|
+
roleId: PHONE_ROLE_ID,
|
|
150
|
+
isSnmpWalkableRole: false,
|
|
137
151
|
status: "unknown",
|
|
138
152
|
deviceModel: "Cisco IP Phone 8811",
|
|
139
153
|
ipAddress: "10.0.12.41",
|
|
@@ -227,7 +241,12 @@ describe("the Add to Monitoring dialog", () => {
|
|
|
227
241
|
test("opens on the role the map classified the device as", async () => {
|
|
228
242
|
const props: CapturedModalProps = await openDialog();
|
|
229
243
|
|
|
230
|
-
|
|
244
|
+
/*
|
|
245
|
+
* The row's id, not the classifier's key: the role is a relation to the
|
|
246
|
+
* project's own NetworkDeviceRole table, so this is what the picker binds
|
|
247
|
+
* to and what a rename or a custom role travels through.
|
|
248
|
+
*/
|
|
249
|
+
expect(props.initialValues["networkDeviceRole"]).toBe(PHONE_ROLE_ID);
|
|
231
250
|
});
|
|
232
251
|
|
|
233
252
|
/*
|
|
@@ -297,7 +316,18 @@ describe("the Add to Monitoring dialog", () => {
|
|
|
297
316
|
test("inherits a probe for a device that will be polled", async () => {
|
|
298
317
|
const props: CapturedModalProps = await openDialog({
|
|
299
318
|
...PHONE_NODE,
|
|
319
|
+
/*
|
|
320
|
+
* The whole role stamp, not just `role`: the configured
|
|
321
|
+
* isSnmpWalkableRole is what decides the monitoring method now, and the
|
|
322
|
+
* phone fixture carries the handset's (false). Overriding only the
|
|
323
|
+
* built-in role would leave the flag saying "nothing will poll this",
|
|
324
|
+
* which is the opposite of what this test is about.
|
|
325
|
+
*/
|
|
300
326
|
role: "switch",
|
|
327
|
+
roleKey: "switch",
|
|
328
|
+
roleLabel: "Switch",
|
|
329
|
+
roleId: SWITCH_ROLE_ID,
|
|
330
|
+
isSnmpWalkableRole: true,
|
|
301
331
|
});
|
|
302
332
|
|
|
303
333
|
expect(props.initialValues["monitoringMethod"]).toBe("SNMP");
|
|
@@ -20,13 +20,23 @@ import * as React from "react";
|
|
|
20
20
|
import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
21
21
|
|
|
22
22
|
/*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
23
|
+
* The chart widget's STANDALONE fallback: what drag-to-zoom does when the
|
|
24
|
+
* host hands down no onDashboardTimeRangeSelect — the edit-mode settings
|
|
25
|
+
* preview, and any future surface that mounts the widget without owning a
|
|
26
|
+
* time range. Selecting a window narrows THIS widget, refetches for the
|
|
27
|
+
* narrowed window, and offers a way back (Reset) and a way deeper (Open in
|
|
28
|
+
* Explorer, carrying the zoomed window).
|
|
29
|
+
*
|
|
30
|
+
* On a real dashboard the shell DOES take the drag and the whole board
|
|
31
|
+
* retimes (issue #3530) — that contract lives in
|
|
32
|
+
* DashboardWideChartZoom.test.tsx. Both paths are pinned because the
|
|
33
|
+
* widget picks between them purely on whether the callback prop is
|
|
34
|
+
* present, and a host that forgets to pass it should degrade to this
|
|
35
|
+
* rather than lose the gesture.
|
|
36
|
+
*
|
|
37
|
+
* Edit mode must not zoom either way — the drag gesture belongs to widget
|
|
38
|
+
* move/resize there, and series pivots would navigate away from unsaved
|
|
39
|
+
* dashboard changes.
|
|
30
40
|
*/
|
|
31
41
|
|
|
32
42
|
const fetchResultsMock: MockFunction = getJestMockFunction();
|
|
@@ -215,7 +225,24 @@ afterEach(() => {
|
|
|
215
225
|
cleanup();
|
|
216
226
|
});
|
|
217
227
|
|
|
218
|
-
describe("dashboard chart widget drag-to-zoom", () => {
|
|
228
|
+
describe("dashboard chart widget drag-to-zoom (standalone fallback)", () => {
|
|
229
|
+
test("the fallback is what runs when the host offers no dashboard-wide zoom", async () => {
|
|
230
|
+
renderWidget();
|
|
231
|
+
|
|
232
|
+
await waitFor(() => {
|
|
233
|
+
expect(screen.getByTestId("metric-charts")).toBeInTheDocument();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
/*
|
|
237
|
+
* Guards the branch this whole suite depends on: these props are the
|
|
238
|
+
* switch between narrowing this widget and retiming the board, and
|
|
239
|
+
* buildBaseProps deliberately leaves them off.
|
|
240
|
+
*/
|
|
241
|
+
const baseProps: DashboardBaseComponentProps = buildBaseProps();
|
|
242
|
+
expect(baseProps.onDashboardTimeRangeSelect).toBeUndefined();
|
|
243
|
+
expect(baseProps.onDashboardTimeRangeReset).toBeUndefined();
|
|
244
|
+
});
|
|
245
|
+
|
|
219
246
|
test("drag-selecting a window refetches THIS widget for that window and shows the zoom bar", async () => {
|
|
220
247
|
renderWidget();
|
|
221
248
|
|