Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/Frontend/src/components/LicenseExpired.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ const { licenseStatus, license } = licenseStore;
</div>
</div>
</template>
<template v-if="licenseStatus.isInvalidDueToUpgradeProtectionExpired">
<template v-if="licenseStatus.isUpgradeProtectionUnsupported">
<div class="text-center monitoring-no-data">
<h1>Platform license expired</h1>
<p>Your upgrade protection period has elapsed and your license is not valid for this version of ServicePulse.</p>
<h1>Platform license no longer supported</h1>
<p>Your upgrade protection license is no longer supported. Please update your license to continue using the Particular Service Platform.</p>
<div class="action-toolbar">
<RouterLink class="btn btn-default btn-primary" :to="routeLinks.configuration.license.link">View license details</RouterLink>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/Frontend/src/components/LicenseNotExpired.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { licenseStatus } = licenseStore;
</script>

<template>
<ConditionalRender :supported="!licenseStatus.isExpired">
<ConditionalRender :supported="!licenseStatus.isInvalid">
<template #unsupported>
<LicenseExpired />
</template>
Expand Down
9 changes: 4 additions & 5 deletions src/Frontend/src/components/LicenseNotificationPopup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 "";
}
Expand All @@ -33,7 +29,10 @@ const heading = computed(() => {
<p>
<strong>{{ props.type === TYPE.ERROR ? "Error" : "" }}</strong>
</p>
<span v-if="props.type === TYPE.ERROR">Your license has expired. Please contact Particular Software support at: <a href="https://particular.net/support">https://particular.net/support</a></span>
<span v-if="props.type === TYPE.ERROR">
{{ props.licenseStatus === LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported ? "Your upgrade protection license is no longer supported." : "Your license has expired." }}
Please contact Particular Software support at: <a href="https://particular.net/support">https://particular.net/support</a>
</span>
<div v-else>
<strong>{{ heading }}</strong>
<div v-if="props.licenseStatus === LicenseStatus.ValidWithExpiringTrial">
Expand Down
20 changes: 6 additions & 14 deletions src/Frontend/src/components/LicenseNotifications.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -78,15 +66,19 @@ describe("LicenseNotifications", () => {
}
});

test.each([LicenseStatus.InvalidDueToExpiredTrial, LicenseStatus.InvalidDueToExpiredSubscription, LicenseStatus.InvalidDueToExpiredUpgradeProtection])("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();

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");
Expand Down
4 changes: 1 addition & 3 deletions src/Frontend/src/components/LicenseNotifications.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,13 @@ 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:
case LicenseStatus.InvalidDueToExpiredSubscription:
case LicenseStatus.InvalidDueToExpiredUpgradeProtection:
case LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the notification to say upgrade-protection licenses are no longer supported, while preserving the expired-license copy for expired trial/subscription statuses. Added coverage; commit 06fdaf3b.

type = TYPE.ERROR;
break;
default:
Expand Down
7 changes: 2 additions & 5 deletions src/Frontend/src/components/configuration/PlatformLicense.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,15 @@ const { licenseStatus, license } = licenseStore;
role="note"
aria-label="license-expiry-date"
:class="{
'license-expired': licenseStatus.isInvalidDueToUpgradeProtectionExpired,
'license-expired': licenseStatus.isUpgradeProtectionUnsupported,
}"
>
{{ formattedUpgradeProtectionExpiration }}
<span role="note" aria-label="license-days-left">{{ licenseStatus.upgradeDaysLeft }}</span>
<exclamation-mark :type="convertToWarningLevel(licenseStatus.warningLevel)" />
</span>
</DetailsItem>
<div class="license-expired-text" role="note" aria-label="license-expired" v-if="licenseStatus.isValidWithExpiredUpgradeProtection || licenseStatus.isValidWithExpiringUpgradeProtection">
<b>Warning:</b> Once upgrade protection expires, you'll no longer have access to support or new product versions.
</div>
<div class="license-expired-text" v-if="licenseStatus.isInvalidDueToUpgradeProtectionExpired">Your license upgrade protection expired before this version of ServicePulse was released.</div>
<div class="license-expired-text" v-if="licenseStatus.isUpgradeProtectionUnsupported">Your upgrade protection license is no longer supported. Please update your license to continue using the Particular Service Platform.</div>
</template>
<DetailsItem label="ServiceControl Instance">
{{ formattedInstanceName }}
Expand Down
4 changes: 1 addition & 3 deletions src/Frontend/src/resources/LicenseInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ export enum LicenseStatus {
InvalidDueToExpiredSubscription = "InvalidDueToExpiredSubscription",
ValidWithExpiringTrial = "ValidWithExpiringTrial",
InvalidDueToExpiredTrial = "InvalidDueToExpiredTrial",
InvalidDueToExpiredUpgradeProtection = "InvalidDueToExpiredUpgradeProtection",
ValidWithExpiredUpgradeProtection = "ValidWithExpiredUpgradeProtection",
ValidWithExpiringUpgradeProtection = "ValidWithExpiringUpgradeProtection",
InvalidDueToUpgradeProtectionNoLongerBeingSupported = "InvalidDueToUpgradeProtectionNoLongerBeingSupported",
ValidWithExpiringSubscription = "ValidWithExpiringSubscription",
}
export enum LicenseType {
Expand Down
18 changes: 6 additions & 12 deletions src/Frontend/src/stores/LicenseStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ export const useLicenseStore = defineStore("LicenseStore", () => {
isPlatformExpired: false,
isPlatformTrialExpired: false,
isPlatformTrialExpiring: false,
isInvalidDueToUpgradeProtectionExpired: false,
isValidWithExpiredUpgradeProtection: false,
isValidWithExpiringUpgradeProtection: false,
isExpired: false,
isUpgradeProtectionUnsupported: false,
isInvalid: false,
upgradeDaysLeft: "",
subscriptionDaysLeft: "",
trialDaysLeft: "",
Expand Down Expand Up @@ -93,14 +91,12 @@ 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.isValidWithExpiredUpgradeProtection = license.license_status === LicenseStatus.ValidWithExpiredUpgradeProtection;
licenseStatus.isValidWithExpiringUpgradeProtection = license.license_status === LicenseStatus.ValidWithExpiringUpgradeProtection;
licenseStatus.isUpgradeProtectionUnsupported = license.license_status === LicenseStatus.InvalidDueToUpgradeProtectionNoLongerBeingSupported;
licenseStatus.upgradeDaysLeft = getUpgradeDaysLeft();
licenseStatus.subscriptionDaysLeft = getSubscriptionDaysLeft();
licenseStatus.trialDaysLeft = getTrialDaysLeft();
licenseStatus.warningLevel = getLicenseWarningLevel();
licenseStatus.isExpired = licenseStatus.isPlatformExpired || licenseStatus.isPlatformTrialExpired || licenseStatus.isInvalidDueToUpgradeProtectionExpired;
licenseStatus.isInvalid = licenseStatus.isPlatformExpired || licenseStatus.isPlatformTrialExpired || licenseStatus.isUpgradeProtectionUnsupported;
licenseStatus.licenseExtensionUrl = license.license_extension_url;
} finally {
loading.value = false;
Expand All @@ -121,11 +117,9 @@ 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.ValidWithExpiringUpgradeProtection:
case LicenseStatus.ValidWithExpiringTrial:
case LicenseStatus.ValidWithExpiredUpgradeProtection:
case LicenseStatus.ValidWithExpiringSubscription:
return LicenseWarningLevel.Warning;
default:
Expand Down Expand Up @@ -165,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 " - no longer supported";

const expiringIn = useGetDayDiffFromToday(license.upgrade_protection_expiration);
//TODO: can this be unified with the function above? Text is currently similar but not identical.
Expand Down
2 changes: 1 addition & 1 deletion src/Frontend/src/views/ConfigurationView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function preventIfDisabled(e: Event, disabled: boolean) {
<RouterLink :to="routeLinks.throughput.setup.root">Usage Setup</RouterLink>
<exclamation-mark :type="WarningLevel.Danger" v-if="hasErrors" />
</h5>
<template v-if="!licenseStatus.isExpired">
<template v-if="!licenseStatus.isInvalid">
<h5
:class="{
active: isRouteSelected(routeLinks.configuration.massTransitConnector.link),
Expand Down
7 changes: 4 additions & 3 deletions src/Frontend/test/preconditions/licensing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ export const hasActiveLicense = ({ driver }: SetupFactoryOptions) => {
});
return licenseResponseTemplate;
};
export const hasExpiredLicense = (licenseType: LicenseType, expiredDays: number = 10, extensionUrl: string = "") => getLicenseMockedResponse(licenseType, expiredDays, extensionUrl, true);
export const hasExpiringLicense = (licenseType: LicenseType, expiringInDays: number = 10, extensionUrl: string = "") => getLicenseMockedResponse(licenseType, expiringInDays, extensionUrl, false);
export const hasExpiredLicense = (licenseType: LicenseType.Subscription | LicenseType.Trial, expiredDays: number = 10, extensionUrl: string = "") => getLicenseMockedResponse(licenseType, expiredDays, extensionUrl, true);
export const hasExpiringLicense = (licenseType: LicenseType.Subscription | LicenseType.Trial, expiringInDays: number = 10, extensionUrl: string = "") => getLicenseMockedResponse(licenseType, expiringInDays, extensionUrl, false);
export const hasUnsupportedUpgradeProtectionLicense = (protectionDateOffset: number = 10) => getLicenseMockedResponse(LicenseType.UpgradeProtection, protectionDateOffset, "", false);

const getLicenseMockedResponse =
(licenseType: LicenseType, expiringInDays: number, extensionUrl: string, isExpired: boolean) =>
Expand All @@ -48,7 +49,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.InvalidDueToUpgradeProtectionNoLongerBeingSupported;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cd246699. Replaced obsolete expiring-upgrade-protection scenarios with unsupported-license coverage for past, present, and future protection dates. Added an explicit unsupported fixture and restricted expiring/expired fixtures to trials and subscriptions. All 71 licensing/configuration tests pass.

upgradeProtectionExpiration = customISOString;
licenseExtensionUrl = extensionUrl ? extensionUrl : "https://particular.net/extend-your-trial?p=servicepulse";
break;
Expand Down
43 changes: 15 additions & 28 deletions src/Frontend/test/specs/configuration/viewing-license.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { licenseTypeDetails } from "./questions/licenseTypeDetails";
import { licenseExpiryDate } from "./questions/licenseExpiryDate";
import { licenseExpiryDaysLeft } from "./questions/licenseExpiryDaysLeft";
import { licenseExpired } from "./questions/licenseExpired";
import { waitFor } from "@testing-library/vue";
import { screen, waitFor } from "@testing-library/vue";
import { LicenseType } from "@/resources/LicenseInfo";
import { licenseTabList, licenseTabNames } from "./questions/licenseTabs";

Expand Down Expand Up @@ -82,33 +82,20 @@ describe("FEATURE: License", () => {
});
});

describe("RULE: Upgrade Protection license expiring soon must be displayed with a reference to how much time is left and a warning:'Once upgrade protection expires, you'll no longer have access to support or new product versions. '", () => {
test("EXAMPLE: Upgrade Protection license expiring in 11 days", async ({ driver }) => {
await driver.setUp(precondition.serviceControlWithMonitoring);
await driver.setUp(precondition.hasExpiringLicense(LicenseType.UpgradeProtection, 11));
await driver.goTo("/configuration/license");
await waitFor(async () => {
expect(await licenseExpiryDaysLeft()).toBeVisible();
expect((await licenseExpiryDaysLeft()).textContent).toContain("11 days left");
});
});
test("EXAMPLE: Upgrade Protection license expiring tomorrow", async ({ driver }) => {
await driver.setUp(precondition.serviceControlWithMonitoring);
await driver.setUp(precondition.hasExpiringLicense(LicenseType.UpgradeProtection, 1));
await driver.goTo("/configuration/license");
await waitFor(async () => {
expect(await licenseExpiryDaysLeft()).toBeVisible();
expect((await licenseExpiryDaysLeft()).textContent).toContain("1 day left");
});
});
test("EXAMPLE: Upgrade Protection license expiring today", async ({ driver }) => {
await driver.setUp(precondition.serviceControlWithMonitoring);
await driver.setUp(precondition.hasExpiringLicense(LicenseType.UpgradeProtection, -1));
await driver.goTo("/configuration/license");
await waitFor(async () => {
const testable = await licenseExpiryDaysLeft();
expect(testable).toBeVisible();
expect(testable.textContent).toContain("expired");
describe("RULE: Upgrade Protection licenses are unsupported regardless of the protection date", () => {
[11, 1, 0, -1].forEach((protectionDateOffset) => {
test(`EXAMPLE: Unsupported upgrade protection with protection date offset ${protectionDateOffset}`, async ({ driver }) => {
await driver.setUp(precondition.serviceControlWithMonitoring);
await driver.setUp(precondition.hasUnsupportedUpgradeProtectionLicense(protectionDateOffset));
await driver.goTo("/configuration/license");
await waitFor(async () => {
expect(await licenseExpiryDate()).toBeVisible();
expect(await licenseExpiryDaysLeft()).toHaveTextContent("no longer supported");
expect(screen.getByText("Your upgrade protection license is no longer supported. Please update your license to continue using the Particular Service Platform.")).toBeVisible();
expect(screen.queryByText(/expired before this version of ServicePulse was released/)).not.toBeInTheDocument();
expect(await licenseTabList()).toHaveLength(3);
expect(await licenseTabNames()).toEqual(expect.arrayContaining(["License", "Usage Setup", "Connections"]));
});
});
});
});
Expand Down
Loading