From 01e9db5d512371b53c4f3e5214914146f4a57bcb Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 8 Jul 2025 16:33:07 -0700 Subject: [PATCH 1/4] feat: trial extension allowed within 5 days of expiration --- web/locales/en_US.json | 4 ++++ web/store/server.ts | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/web/locales/en_US.json b/web/locales/en_US.json index 807c7dfaec..0bd2ccf220 100644 --- a/web/locales/en_US.json +++ b/web/locales/en_US.json @@ -23,6 +23,10 @@ "

To support more storage devices as your server grows, click Upgrade Key.

": "

To support more storage devices as your server grows, click Upgrade Key.

", "

You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.

": "

You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.

", "

Your Trial key includes all the functionality and device support of an Unleashed key.

After your Trial has reached expiration, your server still functions normally until the next time you Stop the array or reboot your server.

At that point you may either purchase a license key or request a Trial extension.

": "

Your Trial key includes all the functionality and device support of an Unleashed key.

After your Trial has reached expiration, your server still functions normally until the next time you Stop the array or reboot your server.

At that point you may either purchase a license key or request a Trial extension.

", + "

Your Trial key includes all the functionality and device support of an Unleashed key.

When your Trial expires, the array will stop. At that point you may either purchase a license key or request a Trial extension.

": "

Your Trial key includes all the functionality and device support of an Unleashed key.

When your Trial expires, the array will stop. At that point you may either purchase a license key or request a Trial extension.

", + "

Your Trial key includes all the functionality and device support of an Unleashed key.

Your trial is expiring soon. When it expires, the array will stop. You may extend your trial now, purchase a license key, or wait until expiration to take action.

": "

Your Trial key includes all the functionality and device support of an Unleashed key.

Your trial is expiring soon. When it expires, the array will stop. You may extend your trial now, purchase a license key, or wait until expiration to take action.

", + "

Your Trial key includes all the functionality and device support of an Unleashed key.

Your trial is expiring soon and you have used all available extensions. When it expires, the array will stop. To continue using Unraid OS, you must purchase a license key.

": "

Your Trial key includes all the functionality and device support of an Unleashed key.

Your trial is expiring soon and you have used all available extensions. When it expires, the array will stop. To continue using Unraid OS, you must purchase a license key.

", + "

Your Trial key includes all the functionality and device support of an Unleashed key.

You have used all available trial extensions. When your Trial expires, the array will stop. To continue using Unraid OS after expiration, you must purchase a license key.

": "

Your Trial key includes all the functionality and device support of an Unleashed key.

You have used all available trial extensions. When your Trial expires, the array will stop. To continue using Unraid OS after expiration, you must purchase a license key.

", "

Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.

If you do not have a backup copy of your license key file you may attempt to recover your key.

If this was an expired Trial installation, you may purchase a license key.

": "

Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.

If you do not have a backup copy of your license key file you may attempt to recover your key.

If this was an expired Trial installation, you may purchase a license key.

", "

Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.

You may attempt to recover your key with your Unraid.net account.

If this was an expired Trial installation, you may purchase a license key.

": "

Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.

You may attempt to recover your key with your Unraid.net account.

If this was an expired Trial installation, you may purchase a license key.

", "

Your server will not be usable until you purchase a Registration key or install a free 30 day Trial key. A Trial key provides all the functionality of an Unleashed Registration key.

Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.

Note: USB memory card readers are generally not supported because most do not present unique serial numbers.

Important:

": "

Your server will not be usable until you purchase a Registration key or install a free 30 day Trial key. A Trial key provides all the functionality of an Unleashed Registration key.

Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.

Note: USB memory card readers are generally not supported because most do not present unique serial numbers.

Important:

", diff --git a/web/store/server.ts b/web/store/server.ts index 313be3061d..dd6f8be871 100644 --- a/web/store/server.ts +++ b/web/store/server.ts @@ -495,6 +495,7 @@ export const useServerStore = defineStore('server', () => { }); let messageEGUID = ''; + let trialMessage = ''; const stateData = computed((): ServerStateData => { switch (state.value) { case 'ENOKEYFILE': @@ -510,16 +511,32 @@ export const useServerStore = defineStore('server', () => { '

Choose an option below, then use our Getting Started Guide to configure your array in less than 15 minutes.

', }; case 'TRIAL': + trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

'; + + if (trialWithin5DaysOfExpiration.value) { + if (trialExtensionEligible.value) { + trialMessage += '

Your trial is expiring soon. When it expires, the array will stop. You may extend your trial now, purchase a license key, or wait until expiration to take action.

'; + } else { + trialMessage += '

Your trial is expiring soon and you have used all available extensions. When it expires, the array will stop. To continue using Unraid OS, you must purchase a license key.

'; + } + } else { + if (trialExtensionEligible.value) { + trialMessage += '

When your Trial expires, the array will stop. At that point you may either purchase a license key or request a Trial extension.

'; + } else { + trialMessage += '

You have used all available trial extensions. When your Trial expires, the array will stop. To continue using Unraid OS after expiration, you must purchase a license key.

'; + } + } + return { actions: [ ...(!registered.value && connectPluginInstalled.value ? [signInAction.value] : []), ...[purchaseAction.value, redeemAction.value], + ...(trialExtensionEligible.value && trialWithin5DaysOfExpiration.value ? [trialExtendAction.value] : []), ...(registered.value && connectPluginInstalled.value ? [signOutAction.value] : []), ], humanReadable: 'Trial', heading: 'Thank you for choosing Unraid OS!', - message: - '

Your Trial key includes all the functionality and device support of an Unleashed key.

After your Trial has reached expiration, your server still functions normally until the next time you Stop the array or reboot your server.

At that point you may either purchase a license key or request a Trial extension.

', + message: trialMessage, }; case 'EEXPIRED': return { @@ -773,6 +790,22 @@ export const useServerStore = defineStore('server', () => { return stateData.value.actions.filter((action) => !authActionsNames.includes(action.name)); }); const trialExtensionEligible = computed(() => !regGen.value || regGen.value < 2); + const trialWithin5DaysOfExpiration = computed(() => { + if (!expireTime.value || state.value !== 'TRIAL') { + return false; + } + const today = dayjs(); + const expirationDate = dayjs(expireTime.value); + const daysUntilExpiration = expirationDate.diff(today, 'day'); + return daysUntilExpiration <= 5 && daysUntilExpiration >= 0; + }); + + watchEffect(() => { + console.log('expireTime', expireTime.value); + console.log('state', state.value); + console.log('trialExtensionEligible', trialExtensionEligible.value); + console.log('trialWithin5DaysOfExpiration', trialWithin5DaysOfExpiration.value); + }); const serverConfigError = computed((): Error | undefined => { if (!config.value?.valid && config.value?.error) { From 43cff73b84dddf7f53c01b1e507721eed6db4df3 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 8 Jul 2025 17:18:52 -0700 Subject: [PATCH 2/4] chore: remove console logs from server store --- web/store/server.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/web/store/server.ts b/web/store/server.ts index dd6f8be871..8dcb265a30 100644 --- a/web/store/server.ts +++ b/web/store/server.ts @@ -800,13 +800,6 @@ export const useServerStore = defineStore('server', () => { return daysUntilExpiration <= 5 && daysUntilExpiration >= 0; }); - watchEffect(() => { - console.log('expireTime', expireTime.value); - console.log('state', state.value); - console.log('trialExtensionEligible', trialExtensionEligible.value); - console.log('trialWithin5DaysOfExpiration', trialWithin5DaysOfExpiration.value); - }); - const serverConfigError = computed((): Error | undefined => { if (!config.value?.valid && config.value?.error) { switch (config.value?.error) { From 82eaca400ffe584b0fcd2f1f6f24f796d3d92a7e Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Wed, 9 Jul 2025 12:02:27 -0700 Subject: [PATCH 3/4] refactor: streamline trial message logic in server store Consolidated trial message handling to reduce redundancy and improve readability. The logic now checks conditions for trial expiration and extension eligibility more efficiently, ensuring users receive accurate information based on their trial status. --- web/store/server.ts | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/web/store/server.ts b/web/store/server.ts index 8dcb265a30..c490aa5e2e 100644 --- a/web/store/server.ts +++ b/web/store/server.ts @@ -511,20 +511,14 @@ export const useServerStore = defineStore('server', () => { '

Choose an option below, then use our Getting Started Guide to configure your array in less than 15 minutes.

', }; case 'TRIAL': - trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

'; - - if (trialWithin5DaysOfExpiration.value) { - if (trialExtensionEligible.value) { - trialMessage += '

Your trial is expiring soon. When it expires, the array will stop. You may extend your trial now, purchase a license key, or wait until expiration to take action.

'; - } else { - trialMessage += '

Your trial is expiring soon and you have used all available extensions. When it expires, the array will stop. To continue using Unraid OS, you must purchase a license key.

'; - } + if (trialWithin5DaysOfExpiration.value && trialExtensionEligible.value) { + trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

Your trial is expiring soon. When it expires, the array will stop. You may extend your trial now, purchase a license key, or wait until expiration to take action.

'; + } else if (trialWithin5DaysOfExpiration.value && !trialExtensionEligible.value) { + trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

Your trial is expiring soon and you have used all available extensions. When it expires, the array will stop. To continue using Unraid OS, you must purchase a license key.

'; + } else if (!trialWithin5DaysOfExpiration.value && trialExtensionEligible.value) { + trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

When your Trial expires, the array will stop. At that point you may either purchase a license key or request a Trial extension.

'; } else { - if (trialExtensionEligible.value) { - trialMessage += '

When your Trial expires, the array will stop. At that point you may either purchase a license key or request a Trial extension.

'; - } else { - trialMessage += '

You have used all available trial extensions. When your Trial expires, the array will stop. To continue using Unraid OS after expiration, you must purchase a license key.

'; - } + trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

You have used all available trial extensions. When your Trial expires, the array will stop. To continue using Unraid OS after expiration, you must purchase a license key.

'; } return { From 287b3d25c3df990348e3ee5ed19d93fd9d9b6f9b Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Thu, 10 Jul 2025 11:31:45 -0700 Subject: [PATCH 4/4] refactor: trial message logic to utilize new computed properties for better clarity and maintainability --- web/store/server.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/web/store/server.ts b/web/store/server.ts index c490aa5e2e..17d834a981 100644 --- a/web/store/server.ts +++ b/web/store/server.ts @@ -511,13 +511,13 @@ export const useServerStore = defineStore('server', () => { '

Choose an option below, then use our Getting Started Guide to configure your array in less than 15 minutes.

', }; case 'TRIAL': - if (trialWithin5DaysOfExpiration.value && trialExtensionEligible.value) { + if (trialExtensionEligibleInsideRenewalWindow.value) { trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

Your trial is expiring soon. When it expires, the array will stop. You may extend your trial now, purchase a license key, or wait until expiration to take action.

'; - } else if (trialWithin5DaysOfExpiration.value && !trialExtensionEligible.value) { + } else if (trialExtensionIneligibleInsideRenewalWindow.value) { trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

Your trial is expiring soon and you have used all available extensions. When it expires, the array will stop. To continue using Unraid OS, you must purchase a license key.

'; - } else if (!trialWithin5DaysOfExpiration.value && trialExtensionEligible.value) { + } else if (trialExtensionEligibleOutsideRenewalWindow.value) { trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

When your Trial expires, the array will stop. At that point you may either purchase a license key or request a Trial extension.

'; - } else { + } else { // would be trialExtensionIneligibleOutsideRenewalWindow if it wasn't an else conditionally trialMessage = '

Your Trial key includes all the functionality and device support of an Unleashed key.

You have used all available trial extensions. When your Trial expires, the array will stop. To continue using Unraid OS after expiration, you must purchase a license key.

'; } @@ -525,7 +525,7 @@ export const useServerStore = defineStore('server', () => { actions: [ ...(!registered.value && connectPluginInstalled.value ? [signInAction.value] : []), ...[purchaseAction.value, redeemAction.value], - ...(trialExtensionEligible.value && trialWithin5DaysOfExpiration.value ? [trialExtendAction.value] : []), + ...(trialExtensionEligibleInsideRenewalWindow.value ? [trialExtendAction.value] : []), ...(registered.value && connectPluginInstalled.value ? [signOutAction.value] : []), ], humanReadable: 'Trial', @@ -793,6 +793,9 @@ export const useServerStore = defineStore('server', () => { const daysUntilExpiration = expirationDate.diff(today, 'day'); return daysUntilExpiration <= 5 && daysUntilExpiration >= 0; }); + const trialExtensionEligibleInsideRenewalWindow = computed(() => trialExtensionEligible.value && trialWithin5DaysOfExpiration.value); + const trialExtensionEligibleOutsideRenewalWindow = computed(() => trialExtensionEligible.value && !trialWithin5DaysOfExpiration.value); + const trialExtensionIneligibleInsideRenewalWindow = computed(() => !trialExtensionEligible.value && trialWithin5DaysOfExpiration.value); const serverConfigError = computed((): Error | undefined => { if (!config.value?.valid && config.value?.error) {