diff --git a/web/src/lib/core/Navbar/navGroups.spec.ts b/web/src/lib/core/Navbar/navGroups.spec.ts
index d92d0c2a4e..47ae946be3 100644
--- a/web/src/lib/core/Navbar/navGroups.spec.ts
+++ b/web/src/lib/core/Navbar/navGroups.spec.ts
@@ -868,10 +868,17 @@ describe("GATE_PREDICATES", () => {
expect(GATE_PREDICATES.downtimes(ctx({ isEnterprise: true }))).toBe(false);
});
- it("marks Downtimes and Alert Calibration as Beta in the Reliability flyout, and nothing else there", () => {
+ it("marks Downtimes, Alert Calibration and every On-Call entry as Beta in the Reliability flyout, and nothing else there", () => {
const reliability = NAV_GROUPS.find((g) => g.children.some((c) => c.name === "downtimes"))!;
const beta = reliability.children.filter((c) => c.beta).map((c) => c.name);
- expect(beta).toEqual(["downtimes", "alertCalibration"]);
+ expect(beta).toEqual([
+ "downtimes",
+ "alertCalibration",
+ "onCallResponses",
+ "onCallTeams",
+ "onCallRouting",
+ "onCallMine",
+ ]);
});
it("puts Downtimes after Incidents when the rail carries a downtimes item", () => {
diff --git a/web/src/lib/core/Navbar/navGroups.ts b/web/src/lib/core/Navbar/navGroups.ts
index 6da6dc0611..8ca4300055 100644
--- a/web/src/lib/core/Navbar/navGroups.ts
+++ b/web/src/lib/core/Navbar/navGroups.ts
@@ -237,6 +237,7 @@ export const NAV_GROUPS: NavGroupDef[] = [
name: "onCallResponses",
categoryKey: "menu.onCall",
gate: "oncall",
+ beta: true,
},
{
titleKey: "oncall.teams",
@@ -244,6 +245,7 @@ export const NAV_GROUPS: NavGroupDef[] = [
name: "onCallTeams",
categoryKey: "menu.onCall",
gate: "oncall",
+ beta: true,
},
{
titleKey: "oncall.routingNav",
@@ -251,6 +253,7 @@ export const NAV_GROUPS: NavGroupDef[] = [
name: "onCallRouting",
categoryKey: "menu.onCall",
gate: "oncall",
+ beta: true,
},
// Same icon as the page's own header, so the menu and the page read as one place.
{
@@ -259,6 +262,7 @@ export const NAV_GROUPS: NavGroupDef[] = [
name: "onCallMine",
categoryKey: "menu.onCall",
gate: "oncall",
+ beta: true,
},
// Where external alerts (Grafana, Alertmanager, etc.) feed Incidents.
// Gated on incidentList, not alertList: this only makes sense where
diff --git a/web/src/views/OnCall/OnCallMine.spec.ts b/web/src/views/OnCall/OnCallMine.spec.ts
index 993e60c189..544562d5fd 100644
--- a/web/src/views/OnCall/OnCallMine.spec.ts
+++ b/web/src/views/OnCall/OnCallMine.spec.ts
@@ -158,6 +158,17 @@ describe("OnCallMine", () => {
service.resolvedSchedule.mockResolvedValue({ data: [] } as any);
});
+ /// Mounts the real page layout so the tag is proven to reach the rendered header.
+ it("tags the page title as Beta", async () => {
+ const wrapper = mount(OnCallMine, {
+ global: { plugins: [i18n, store], stubs: { ...stubs, OPageLayout: false } },
+ });
+ await flushPromises();
+ const badge = wrapper.find('[data-test="beta-badge"]');
+ expect(badge.exists()).toBe(true);
+ expect(badge.text()).toBe(String(i18n.global.t("common.beta")));
+ });
+
it("serves a revisit from cache", async () => {
const first = render();
await flushPromises();
diff --git a/web/src/views/OnCall/OnCallMine.vue b/web/src/views/OnCall/OnCallMine.vue
index a5a2fdcd63..33ddb5e7e7 100644
--- a/web/src/views/OnCall/OnCallMine.vue
+++ b/web/src/views/OnCall/OnCallMine.vue
@@ -23,6 +23,9 @@ along with this program. If not, see .
icon="person"
scroll
>
+
+
+
@@ -464,6 +467,7 @@ import OnCallReachRow from "@/components/oncall/OnCallReachRow.vue";
import OnCallSetupBanner from "@/components/oncall/OnCallSetupBanner.vue";
import OnCallSlackCard from "@/components/oncall/OnCallSlackCard.vue";
import OTag from "@/lib/core/Badge/OTag.vue";
+import BetaBadge from "@/components/common/BetaBadge.vue";
import OButton from "@/lib/core/Button/OButton.vue";
import OContent from "@/lib/core/Content/OContent.vue";
import OEmptyState from "@/lib/core/EmptyState/OEmptyState.vue";
diff --git a/web/src/views/OnCall/OnCallResponses.spec.ts b/web/src/views/OnCall/OnCallResponses.spec.ts
index f81b1e12f6..b23fc8ae5b 100644
--- a/web/src/views/OnCall/OnCallResponses.spec.ts
+++ b/web/src/views/OnCall/OnCallResponses.spec.ts
@@ -313,6 +313,17 @@ describe("OnCallResponses", () => {
service.getResponse.mockResolvedValue({ data: { events: [] } } as any);
});
+ /// Mounts the real page layout so the tag is proven to reach the rendered header.
+ it("tags the page title as Beta", async () => {
+ const wrapper = mountTracked(OnCallResponses, {
+ global: { plugins: [i18n, store], stubs: { ...stubs, OPageLayout: false } },
+ });
+ await flushPromises();
+ const badge = wrapper.find('[data-test="beta-badge"]');
+ expect(badge.exists()).toBe(true);
+ expect(badge.text()).toBe(String(i18n.global.t("common.beta")));
+ });
+
function page(over: Record = {}, source = "al_ckt") {
return {
id: "resp_1",
diff --git a/web/src/views/OnCall/OnCallResponses.vue b/web/src/views/OnCall/OnCallResponses.vue
index eaebb899ec..92effa9fac 100644
--- a/web/src/views/OnCall/OnCallResponses.vue
+++ b/web/src/views/OnCall/OnCallResponses.vue
@@ -21,6 +21,9 @@ along with this program. If not, see .
:title="t('oncall.responsesTitle')"
icon="notifications-active"
>
+
+
+
@@ -821,6 +824,7 @@ import OnCallShiftBanner from "@/components/oncall/OnCallShiftBanner.vue";
import { useOnCallPermissions } from "@/composables/useOnCallPermissions";
import OText from "@/lib/core/Typography/OText.vue";
import OTruncatedText from "@/lib/core/Typography/OTruncatedText.vue";
+import BetaBadge from "@/components/common/BetaBadge.vue";
import OButton from "@/lib/core/Button/OButton.vue";
import useBreakpoint from "@/composables/useBreakpoint";
import { useListViewState } from "@/composables/useListViewState";
diff --git a/web/src/views/OnCall/OnCallRouting.spec.ts b/web/src/views/OnCall/OnCallRouting.spec.ts
index a7be58b339..31a18464f5 100644
--- a/web/src/views/OnCall/OnCallRouting.spec.ts
+++ b/web/src/views/OnCall/OnCallRouting.spec.ts
@@ -259,6 +259,17 @@ describe("OnCallRouting", () => {
correlation.getDimensionAnalytics.mockResolvedValue({ data: { dimensions: [] } } as any);
});
+ /// Mounts the real page layout so the tag is proven to reach the rendered header.
+ it("tags the page title as Beta", async () => {
+ const wrapper = mount(OnCallRouting, {
+ global: { plugins: [i18n, store], stubs: { ...stubs, OPageLayout: false } },
+ });
+ await flushPromises();
+ const badge = wrapper.find('[data-test="beta-badge"]');
+ expect(badge.exists()).toBe(true);
+ expect(badge.text()).toBe(String(i18n.global.t("common.beta")));
+ });
+
/// The whole point of the org screen: no team_id, so shadowing is computed
/// across every team's rules, not one team's slice.
it("asks for the org-wide rules, not one team's", async () => {
diff --git a/web/src/views/OnCall/OnCallRouting.vue b/web/src/views/OnCall/OnCallRouting.vue
index f895e5b945..8f3bfa2725 100644
--- a/web/src/views/OnCall/OnCallRouting.vue
+++ b/web/src/views/OnCall/OnCallRouting.vue
@@ -23,6 +23,7 @@ along with this program. If not, see .
icon="alt-route"
>
+
{
service.getRoutingConfig.mockResolvedValue({ data: { default_team_id: null } } as any);
});
+ /// Mounts the real page layout so the tag is proven to reach the rendered header.
+ it("tags the page title as Beta", async () => {
+ const wrapper = mount(OnCallTeams, {
+ global: { plugins: [i18n, store], stubs: { ...stubs, OPageLayout: false } },
+ });
+ await flushPromises();
+ const badge = wrapper.find('[data-test="beta-badge"]');
+ expect(badge.exists()).toBe(true);
+ expect(badge.text()).toBe(String(i18n.global.t("common.beta")));
+ });
+
/// The setup checklist's first step sends somebody here already meaning to
/// create a team. Landing them on the list to hunt for the button is the same
/// click asked twice.
diff --git a/web/src/views/OnCall/OnCallTeams.vue b/web/src/views/OnCall/OnCallTeams.vue
index 7a5d6b5762..070acccb29 100644
--- a/web/src/views/OnCall/OnCallTeams.vue
+++ b/web/src/views/OnCall/OnCallTeams.vue
@@ -21,6 +21,9 @@ along with this program. If not, see .
:title="t('oncall.teamsTitle')"
icon="group-work"
>
+
+
+