Skip to content
Merged
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
7 changes: 4 additions & 3 deletions src/Frontend/src/components/LicenseExpired.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import routeLinks from "@/router/routeLinks";
import ExternalLink from "@/components/ExternalLink.vue";
import { useLicenseStore } from "@/stores/LicenseStore";
import { upgradeProtectionUnsupportedMessage } from "@/resources/LicenseInfo";

const licenseStore = useLicenseStore();
const { licenseStatus, license } = licenseStore;
Expand All @@ -27,10 +28,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>{{ upgradeProtectionUnsupportedMessage }} 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
12 changes: 5 additions & 7 deletions src/Frontend/src/components/LicenseNotificationPopup.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed } from "vue";
import { TYPE } from "vue-toastification";
import { LicenseStatus } from "@/resources/LicenseInfo";
import { LicenseStatus, upgradeProtectionUnsupportedMessage } from "@/resources/LicenseInfo";

const props = defineProps<{
type: TYPE.WARNING | TYPE.ERROR;
Expand All @@ -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,14 +29,16 @@ 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 ? upgradeProtectionUnsupportedMessage : "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">
Your {{ props.isMassTransitConnector ? "Early Access" : "non-production development" }} license will expire soon. To continue using the Particular Service Platform you'll need to extend your license.
</div>
<div v-else-if="props.licenseStatus === LicenseStatus.ValidWithExpiringSubscription">Once the license expires you'll no longer be able to continue using the Particular Service Platform.</div>
<div v-else>Once upgrade protection expires, you'll no longer have access to support or new product versions</div>
<a v-if="props.licenseStatus === LicenseStatus.ValidWithExpiringTrial" :href="props.licenseExtensionUrl" class="btn btn-warning">Extend your license</a>
<a :href="props.configurationRootLink" class="btn" :class="props.licenseStatus === LicenseStatus.ValidWithExpiringTrial ? 'btn-light' : 'btn-warning'">View license details</a>
</div>
Expand Down
22 changes: 7 additions & 15 deletions src/Frontend/src/components/LicenseNotifications.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { TYPE } from "vue-toastification";
import LicenseNotifications from "@/components/LicenseNotifications.vue";
import LicenseNotificationPopup from "@/components/LicenseNotificationPopup.vue";
import { useShowToast } from "@/composables/toast";
import { LicenseStatus } from "@/resources/LicenseInfo";
import { LicenseStatus, upgradeProtectionUnsupportedMessage } from "@/resources/LicenseInfo";
import routeLinks from "@/router/routeLinks";
import { useConfigurationStore } from "@/stores/ConfigurationStore";
import { useLicenseStore } from "@/stores/LicenseStore";
Expand Down 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: `${upgradeProtectionUnsupportedMessage} 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
9 changes: 4 additions & 5 deletions src/Frontend/src/components/configuration/PlatformLicense.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import ServiceControlAvailable from "../ServiceControlAvailable.vue";
import ExclamationMark from "./../../components/ExclamationMark.vue";
import convertToWarningLevel from "@/components/configuration/convertToWarningLevel";
import { typeText } from "@/resources/LicenseInfo";
import { typeText, upgradeProtectionUnsupportedMessage } from "@/resources/LicenseInfo";
import ExternalLink from "@/components/ExternalLink.vue";
import { useConfigurationStore } from "@/stores/ConfigurationStore";
import { storeToRefs } from "pinia";
Expand Down Expand Up @@ -71,18 +71,17 @@ 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 class="license-expired-text" role="note" aria-label="license-unsupported" v-if="licenseStatus.isUpgradeProtectionUnsupported">
{{ upgradeProtectionUnsupportedMessage }} Please update your license to continue using the Particular Service Platform.
</div>
<div class="license-expired-text" v-if="licenseStatus.isInvalidDueToUpgradeProtectionExpired">Your license upgrade protection expired before this version of ServicePulse was released.</div>
</template>
<DetailsItem label="ServiceControl Instance">
{{ formattedInstanceName }}
Expand Down
6 changes: 3 additions & 3 deletions src/Frontend/src/resources/LicenseInfo.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type Configuration from "./Configuration";

export const upgradeProtectionUnsupportedMessage = "Your upgrade protection license is no longer supported.";

export interface LicensedProduct {
name: string;
quantity: number;
Expand Down Expand Up @@ -32,9 +34,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
Loading
Loading