From 05dfb2869ce1135d16cf67878ec8f63274079a2c Mon Sep 17 00:00:00 2001 From: Hazel Bohon Date: Wed, 30 Sep 2026 11:29:00 -0400 Subject: [PATCH 1/4] Remove ValidWithExpiredUpgradeProtection and ValidWithExpiringUpgradeProtection --- .../src/components/LicenseNotificationPopup.vue | 4 ---- .../src/components/LicenseNotifications.spec.ts | 12 ------------ src/Frontend/src/components/LicenseNotifications.vue | 2 -- .../src/components/configuration/PlatformLicense.vue | 3 --- src/Frontend/src/resources/LicenseInfo.ts | 2 -- src/Frontend/src/stores/LicenseStore.ts | 6 ------ src/Frontend/test/preconditions/licensing.ts | 2 +- 7 files changed, 1 insertion(+), 30 deletions(-) diff --git a/src/Frontend/src/components/LicenseNotificationPopup.vue b/src/Frontend/src/components/LicenseNotificationPopup.vue index ee67de468f..63b68470a6 100644 --- a/src/Frontend/src/components/LicenseNotificationPopup.vue +++ b/src/Frontend/src/components/LicenseNotificationPopup.vue @@ -13,14 +13,10 @@ const props = defineProps<{ const heading = computed(() => { switch (props.licenseStatus) { - case LicenseStatus.ValidWithExpiredUpgradeProtection: - return "Upgrade protection expired"; case LicenseStatus.ValidWithExpiringTrial: return props.isMassTransitConnector ? "Early Access license expiring" : "Non-production development license expiring"; case LicenseStatus.ValidWithExpiringSubscription: return "Platform license expires soon"; - case LicenseStatus.ValidWithExpiringUpgradeProtection: - return "Upgrade protection expires soon"; default: return ""; } diff --git a/src/Frontend/src/components/LicenseNotifications.spec.ts b/src/Frontend/src/components/LicenseNotifications.spec.ts index 91f4fb394f..6301cd222d 100644 --- a/src/Frontend/src/components/LicenseNotifications.spec.ts +++ b/src/Frontend/src/components/LicenseNotifications.spec.ts @@ -35,18 +35,6 @@ describe("LicenseNotifications", () => { heading: "Early Access license expiring", body: "Your Early Access license will expire soon. To continue using the Particular Service Platform you'll need to extend your license.", }, - { - status: LicenseStatus.ValidWithExpiredUpgradeProtection, - isMassTransitConnector: false, - heading: "Upgrade protection expired", - body: "Once upgrade protection expires, you'll no longer have access to support or new product versions", - }, - { - status: LicenseStatus.ValidWithExpiringUpgradeProtection, - isMassTransitConnector: false, - heading: "Upgrade protection expires soon", - body: "Once upgrade protection expires, you'll no longer have access to support or new product versions", - }, { status: LicenseStatus.ValidWithExpiringSubscription, isMassTransitConnector: false, diff --git a/src/Frontend/src/components/LicenseNotifications.vue b/src/Frontend/src/components/LicenseNotifications.vue index 0ab98ee0a9..b37f27a65f 100644 --- a/src/Frontend/src/components/LicenseNotifications.vue +++ b/src/Frontend/src/components/LicenseNotifications.vue @@ -21,10 +21,8 @@ function displayWarningMessage(licenseStatus: LicenseStatus) { const configurationRootLink = router.resolve(routeLinks.configuration.root).href; let type: TYPE.WARNING | TYPE.ERROR; switch (licenseStatus) { - case LicenseStatus.ValidWithExpiredUpgradeProtection: case LicenseStatus.ValidWithExpiringTrial: case LicenseStatus.ValidWithExpiringSubscription: - case LicenseStatus.ValidWithExpiringUpgradeProtection: type = TYPE.WARNING; break; case LicenseStatus.InvalidDueToExpiredTrial: diff --git a/src/Frontend/src/components/configuration/PlatformLicense.vue b/src/Frontend/src/components/configuration/PlatformLicense.vue index 45f322bbc6..0db202124b 100644 --- a/src/Frontend/src/components/configuration/PlatformLicense.vue +++ b/src/Frontend/src/components/configuration/PlatformLicense.vue @@ -79,9 +79,6 @@ const { licenseStatus, license } = licenseStore; -
- Warning: Once upgrade protection expires, you'll no longer have access to support or new product versions. -
Your license upgrade protection expired before this version of ServicePulse was released.
diff --git a/src/Frontend/src/resources/LicenseInfo.ts b/src/Frontend/src/resources/LicenseInfo.ts index 89bf42c61f..934559ba99 100644 --- a/src/Frontend/src/resources/LicenseInfo.ts +++ b/src/Frontend/src/resources/LicenseInfo.ts @@ -33,8 +33,6 @@ export enum LicenseStatus { ValidWithExpiringTrial = "ValidWithExpiringTrial", InvalidDueToExpiredTrial = "InvalidDueToExpiredTrial", InvalidDueToExpiredUpgradeProtection = "InvalidDueToExpiredUpgradeProtection", - ValidWithExpiredUpgradeProtection = "ValidWithExpiredUpgradeProtection", - ValidWithExpiringUpgradeProtection = "ValidWithExpiringUpgradeProtection", ValidWithExpiringSubscription = "ValidWithExpiringSubscription", } export enum LicenseType { diff --git a/src/Frontend/src/stores/LicenseStore.ts b/src/Frontend/src/stores/LicenseStore.ts index 9eef2b3052..2733a9543f 100644 --- a/src/Frontend/src/stores/LicenseStore.ts +++ b/src/Frontend/src/stores/LicenseStore.ts @@ -32,8 +32,6 @@ export const useLicenseStore = defineStore("LicenseStore", () => { isPlatformTrialExpired: false, isPlatformTrialExpiring: false, isInvalidDueToUpgradeProtectionExpired: false, - isValidWithExpiredUpgradeProtection: false, - isValidWithExpiringUpgradeProtection: false, isExpired: false, upgradeDaysLeft: "", subscriptionDaysLeft: "", @@ -94,8 +92,6 @@ export const useLicenseStore = defineStore("LicenseStore", () => { licenseStatus.isPlatformTrialExpiring = license.license_status === LicenseStatus.ValidWithExpiringTrial; licenseStatus.isPlatformTrialExpired = license.license_status === LicenseStatus.InvalidDueToExpiredTrial; licenseStatus.isInvalidDueToUpgradeProtectionExpired = license.license_status === LicenseStatus.InvalidDueToExpiredUpgradeProtection; - licenseStatus.isValidWithExpiredUpgradeProtection = license.license_status === LicenseStatus.ValidWithExpiredUpgradeProtection; - licenseStatus.isValidWithExpiringUpgradeProtection = license.license_status === LicenseStatus.ValidWithExpiringUpgradeProtection; licenseStatus.upgradeDaysLeft = getUpgradeDaysLeft(); licenseStatus.subscriptionDaysLeft = getSubscriptionDaysLeft(); licenseStatus.trialDaysLeft = getTrialDaysLeft(); @@ -123,9 +119,7 @@ export const useLicenseStore = defineStore("LicenseStore", () => { case LicenseStatus.InvalidDueToExpiredSubscription: case LicenseStatus.InvalidDueToExpiredUpgradeProtection: return LicenseWarningLevel.Danger; - case LicenseStatus.ValidWithExpiringUpgradeProtection: case LicenseStatus.ValidWithExpiringTrial: - case LicenseStatus.ValidWithExpiredUpgradeProtection: case LicenseStatus.ValidWithExpiringSubscription: return LicenseWarningLevel.Warning; default: diff --git a/src/Frontend/test/preconditions/licensing.ts b/src/Frontend/test/preconditions/licensing.ts index 1598b8f7c0..409b1f575e 100644 --- a/src/Frontend/test/preconditions/licensing.ts +++ b/src/Frontend/test/preconditions/licensing.ts @@ -48,7 +48,7 @@ const getLicenseMockedResponse = licenseExtensionUrl = extensionUrl ? extensionUrl : "https://particular.net/extend-your-trial?p=servicepulse"; break; case LicenseType.UpgradeProtection: - status = isExpired ? LicenseStatus.InvalidDueToExpiredUpgradeProtection : LicenseStatus.ValidWithExpiringUpgradeProtection; + status = LicenseStatus.InvalidDueToExpiredUpgradeProtection; upgradeProtectionExpiration = customISOString; licenseExtensionUrl = extensionUrl ? extensionUrl : "https://particular.net/extend-your-trial?p=servicepulse"; break; From 1fbe1ce5a3f044f76f7e71d611deaca89ac2c5db Mon Sep 17 00:00:00 2001 From: Hazel Bohon Date: Wed, 30 Sep 2026 11:34:09 -0400 Subject: [PATCH 2/4] Change InvalidDueToExpiredUpgradeProtection to match the current InvalidDueToUpgradeProtectionNoLongerBeingSupported value. --- src/Frontend/src/components/LicenseNotifications.spec.ts | 2 +- src/Frontend/src/components/LicenseNotifications.vue | 2 +- src/Frontend/src/resources/LicenseInfo.ts | 2 +- src/Frontend/src/stores/LicenseStore.ts | 6 +++--- src/Frontend/test/preconditions/licensing.ts | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Frontend/src/components/LicenseNotifications.spec.ts b/src/Frontend/src/components/LicenseNotifications.spec.ts index 6301cd222d..a47d73f8af 100644 --- a/src/Frontend/src/components/LicenseNotifications.spec.ts +++ b/src/Frontend/src/components/LicenseNotifications.spec.ts @@ -66,7 +66,7 @@ describe("LicenseNotifications", () => { } }); - test.each([LicenseStatus.InvalidDueToExpiredTrial, LicenseStatus.InvalidDueToExpiredSubscription, LicenseStatus.InvalidDueToExpiredUpgradeProtection])("renders a persistent error for %s", async (status) => { + test.each([LicenseStatus.InvalidDueToExpiredTrial, LicenseStatus.InvalidDueToExpiredSubscription, LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported])("renders a persistent error for %s", async (status) => { const { licenseStore } = renderNotifications(); licenseStore.license.license_status = status; await nextTick(); diff --git a/src/Frontend/src/components/LicenseNotifications.vue b/src/Frontend/src/components/LicenseNotifications.vue index b37f27a65f..4d3815a010 100644 --- a/src/Frontend/src/components/LicenseNotifications.vue +++ b/src/Frontend/src/components/LicenseNotifications.vue @@ -27,7 +27,7 @@ function displayWarningMessage(licenseStatus: LicenseStatus) { break; case LicenseStatus.InvalidDueToExpiredTrial: case LicenseStatus.InvalidDueToExpiredSubscription: - case LicenseStatus.InvalidDueToExpiredUpgradeProtection: + case LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported: type = TYPE.ERROR; break; default: diff --git a/src/Frontend/src/resources/LicenseInfo.ts b/src/Frontend/src/resources/LicenseInfo.ts index 934559ba99..59938b0154 100644 --- a/src/Frontend/src/resources/LicenseInfo.ts +++ b/src/Frontend/src/resources/LicenseInfo.ts @@ -32,7 +32,7 @@ export enum LicenseStatus { InvalidDueToExpiredSubscription = "InvalidDueToExpiredSubscription", ValidWithExpiringTrial = "ValidWithExpiringTrial", InvalidDueToExpiredTrial = "InvalidDueToExpiredTrial", - InvalidDueToExpiredUpgradeProtection = "InvalidDueToExpiredUpgradeProtection", + InvalidDueToUpgradeProtectionNoLongerBeingSupported = "InvalidDueToUpgradeProtectionNoLongerBeingSupported", ValidWithExpiringSubscription = "ValidWithExpiringSubscription", } export enum LicenseType { diff --git a/src/Frontend/src/stores/LicenseStore.ts b/src/Frontend/src/stores/LicenseStore.ts index 2733a9543f..9eba1e432f 100644 --- a/src/Frontend/src/stores/LicenseStore.ts +++ b/src/Frontend/src/stores/LicenseStore.ts @@ -91,7 +91,7 @@ export const useLicenseStore = defineStore("LicenseStore", () => { licenseStatus.isPlatformExpired = license.license_status === LicenseStatus.InvalidDueToExpiredSubscription; licenseStatus.isPlatformTrialExpiring = license.license_status === LicenseStatus.ValidWithExpiringTrial; licenseStatus.isPlatformTrialExpired = license.license_status === LicenseStatus.InvalidDueToExpiredTrial; - licenseStatus.isInvalidDueToUpgradeProtectionExpired = license.license_status === LicenseStatus.InvalidDueToExpiredUpgradeProtection; + licenseStatus.isInvalidDueToUpgradeProtectionExpired = license.license_status === LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported; licenseStatus.upgradeDaysLeft = getUpgradeDaysLeft(); licenseStatus.subscriptionDaysLeft = getSubscriptionDaysLeft(); licenseStatus.trialDaysLeft = getTrialDaysLeft(); @@ -117,7 +117,7 @@ export const useLicenseStore = defineStore("LicenseStore", () => { switch (license.license_status) { case LicenseStatus.InvalidDueToExpiredTrial: case LicenseStatus.InvalidDueToExpiredSubscription: - case LicenseStatus.InvalidDueToExpiredUpgradeProtection: + case LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported: return LicenseWarningLevel.Danger; case LicenseStatus.ValidWithExpiringTrial: case LicenseStatus.ValidWithExpiringSubscription: @@ -159,7 +159,7 @@ export const useLicenseStore = defineStore("LicenseStore", () => { } function getUpgradeDaysLeft() { - if (license.license_status === LicenseStatus.InvalidDueToExpiredUpgradeProtection) return " - expired"; + if (license.license_status === LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported) return " - expired"; const expiringIn = useGetDayDiffFromToday(license.upgrade_protection_expiration); //TODO: can this be unified with the function above? Text is currently similar but not identical. diff --git a/src/Frontend/test/preconditions/licensing.ts b/src/Frontend/test/preconditions/licensing.ts index 409b1f575e..b5589cd911 100644 --- a/src/Frontend/test/preconditions/licensing.ts +++ b/src/Frontend/test/preconditions/licensing.ts @@ -48,7 +48,7 @@ const getLicenseMockedResponse = licenseExtensionUrl = extensionUrl ? extensionUrl : "https://particular.net/extend-your-trial?p=servicepulse"; break; case LicenseType.UpgradeProtection: - status = LicenseStatus.InvalidDueToExpiredUpgradeProtection; + status = LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported; upgradeProtectionExpiration = customISOString; licenseExtensionUrl = extensionUrl ? extensionUrl : "https://particular.net/extend-your-trial?p=servicepulse"; break; From 06fdaf3b60e49ae4ec94e2537103f499b4c6c998 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Oct 2026 10:17:33 +0000 Subject: [PATCH 3/4] Show accurate unsupported license notification Co-authored-by: hazel-bohon <2416062+hazel-bohon@users.noreply.github.com> --- src/Frontend/src/components/LicenseNotificationPopup.vue | 5 ++++- src/Frontend/src/components/LicenseNotifications.spec.ts | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Frontend/src/components/LicenseNotificationPopup.vue b/src/Frontend/src/components/LicenseNotificationPopup.vue index 63b68470a6..aae3fa1244 100644 --- a/src/Frontend/src/components/LicenseNotificationPopup.vue +++ b/src/Frontend/src/components/LicenseNotificationPopup.vue @@ -29,7 +29,10 @@ const heading = computed(() => {

{{ props.type === TYPE.ERROR ? "Error" : "" }}

- Your license has expired. Please contact Particular Software support at: https://particular.net/support + + {{ props.licenseStatus === LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported ? "Your upgrade protection license is no longer supported." : "Your license has expired." }} + Please contact Particular Software support at: https://particular.net/support +
{{ heading }}
diff --git a/src/Frontend/src/components/LicenseNotifications.spec.ts b/src/Frontend/src/components/LicenseNotifications.spec.ts index a47d73f8af..796756d888 100644 --- a/src/Frontend/src/components/LicenseNotifications.spec.ts +++ b/src/Frontend/src/components/LicenseNotifications.spec.ts @@ -66,7 +66,11 @@ describe("LicenseNotifications", () => { } }); - test.each([LicenseStatus.InvalidDueToExpiredTrial, LicenseStatus.InvalidDueToExpiredSubscription, LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported])("renders a persistent error for %s", async (status) => { + test.each([ + { status: LicenseStatus.InvalidDueToExpiredTrial, message: "Your license has expired. Please contact Particular Software support at:" }, + { status: LicenseStatus.InvalidDueToExpiredSubscription, message: "Your license has expired. Please contact Particular Software support at:" }, + { status: LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported, message: "Your upgrade protection license is no longer supported. Please contact Particular Software support at:" }, + ])("renders a persistent error for $status", async ({ status, message }) => { const { licenseStore } = renderNotifications(); licenseStore.license.license_status = status; await nextTick(); @@ -74,7 +78,7 @@ describe("LicenseNotifications", () => { const { container } = renderNotification(TYPE.ERROR, status); expect(screen.getByText("Error")).toBeInTheDocument(); - expect(screen.getByText("Your license has expired. Please contact Particular Software support at:")).toBeInTheDocument(); + expect(screen.getByText(message)).toBeInTheDocument(); expect(container.querySelector(".toast-message.toast-error")).toBeInTheDocument(); const support = screen.getByRole("link", { name: "https://particular.net/support" }); expect(support).toHaveAttribute("href", "https://particular.net/support"); From cd246699c8450c91734c4ef8e4daa71ddbb396c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 1 Oct 2026 11:15:14 +0000 Subject: [PATCH 4/4] Model unsupported upgrade-protection licenses and update scenarios Co-authored-by: hazel-bohon <2416062+hazel-bohon@users.noreply.github.com> --- .../src/components/LicenseExpired.vue | 6 +-- .../src/components/LicenseNotExpired.vue | 2 +- .../configuration/PlatformLicense.vue | 4 +- src/Frontend/src/stores/LicenseStore.ts | 10 ++--- src/Frontend/src/views/ConfigurationView.vue | 2 +- src/Frontend/test/preconditions/licensing.ts | 5 ++- .../configuration/viewing-license.spec.ts | 43 +++++++------------ .../licensing/license-enforcement.spec.ts | 38 ++++++++-------- 8 files changed, 50 insertions(+), 60 deletions(-) diff --git a/src/Frontend/src/components/LicenseExpired.vue b/src/Frontend/src/components/LicenseExpired.vue index 8eeba3b227..a76b4f5265 100644 --- a/src/Frontend/src/components/LicenseExpired.vue +++ b/src/Frontend/src/components/LicenseExpired.vue @@ -27,10 +27,10 @@ const { licenseStatus, license } = licenseStore;
-