Compare commits

..

4 Commits

Author SHA1 Message Date
Eli Bosley
cb91dfb910 Merge 93db717749 into 862b54de8c 2025-07-08 16:24:58 -04:00
Eli Bosley
93db717749 chore: return callback 2025-07-08 16:22:06 -04:00
Eli Bosley
a8ddf50e83 fix: update tests 2025-07-08 16:15:29 -04:00
Eli Bosley
e57c0c086b fix: sign out doesn't work 2025-07-08 16:09:55 -04:00
15 changed files with 13 additions and 373 deletions

View File

@@ -32,9 +32,7 @@ jobs:
with:
node-version: '22.17.0'
- run: |
cat << 'EOF' > release-notes.txt
${{ steps.release-info.outputs.body }}
EOF
echo '${{ steps.release-info.outputs.body }}' >> release-notes.txt
- run: npm install html-escaper@2 xml2js
- name: Update Plugin Changelog
uses: actions/github-script@v7

View File

@@ -1 +1 @@
{".":"4.9.1"}
{".":"4.9.0"}

View File

@@ -1,13 +1,5 @@
# Changelog
## [4.9.1](https://github.com/unraid/api/compare/v4.9.0...v4.9.1) (2025-07-08)
### Bug Fixes
* **HeaderOsVersion:** adjust top margin for header component ([#1485](https://github.com/unraid/api/issues/1485)) ([862b54d](https://github.com/unraid/api/commit/862b54de8cd793606f1d29e76c19d4a0e1ae172f))
* sign out doesn't work ([#1486](https://github.com/unraid/api/issues/1486)) ([f3671c3](https://github.com/unraid/api/commit/f3671c3e0750b79be1f19655a07a0e9932289b3f))
## [4.9.0](https://github.com/unraid/api/compare/v4.8.0...v4.9.0) (2025-07-08)

View File

@@ -1,6 +1,6 @@
{
"name": "@unraid/api",
"version": "4.9.1",
"version": "4.9.0",
"main": "src/cli/index.ts",
"type": "module",
"corepack": {

View File

@@ -1,7 +1,7 @@
{
"name": "unraid-monorepo",
"private": true,
"version": "4.9.1",
"version": "4.9.0",
"scripts": {
"build": "pnpm -r build",
"build:watch": " pnpm -r --parallel build:watch",

View File

@@ -1,6 +1,6 @@
{
"name": "@unraid/connect-plugin",
"version": "4.9.1",
"version": "4.9.0",
"private": true,
"dependencies": {
"commander": "14.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@unraid/ui",
"version": "4.9.1",
"version": "4.9.0",
"private": true,
"license": "GPL-2.0-or-later",
"type": "module",

View File

@@ -764,323 +764,4 @@ describe('useServerStore', () => {
expect(store.cloudError).toBeDefined();
expect((store.cloudError as { message: string })?.message).toBe('Test error');
});
describe('trial extension features', () => {
it('should determine trial extension eligibility correctly', () => {
const store = getStore();
// Add trialExtensionEligible property to the store
Object.defineProperty(store, 'trialExtensionEligible', {
get: () => !store.regGen || store.regGen < 2,
});
// Eligible - no regGen
store.setServer({ regGen: 0 });
expect(store.trialExtensionEligible).toBe(true);
// Eligible - regGen = 1
store.setServer({ regGen: 1 });
expect(store.trialExtensionEligible).toBe(true);
// Not eligible - regGen = 2
store.setServer({ regGen: 2 });
expect(store.trialExtensionEligible).toBe(false);
// Not eligible - regGen > 2
store.setServer({ regGen: 3 });
expect(store.trialExtensionEligible).toBe(false);
});
it('should calculate trial within 5 days of expiration correctly', () => {
const store = getStore();
// Add properties to the store
Object.defineProperty(store, 'expireTime', { value: 0, writable: true });
Object.defineProperty(store, 'trialWithin5DaysOfExpiration', {
get: () => {
if (!store.expireTime || store.state !== 'TRIAL') {
return false;
}
const today = dayjs();
const expirationDate = dayjs(store.expireTime);
const daysUntilExpiration = expirationDate.diff(today, 'day');
return daysUntilExpiration <= 5 && daysUntilExpiration >= 0;
},
});
// Not a trial
store.setServer({ state: 'PRO' as ServerState, expireTime: dayjs().add(3, 'day').unix() * 1000 });
expect(store.trialWithin5DaysOfExpiration).toBe(false);
// Trial but no expireTime
store.setServer({ state: 'TRIAL' as ServerState, expireTime: 0 });
expect(store.trialWithin5DaysOfExpiration).toBe(false);
// Trial expiring in 3 days
store.setServer({ state: 'TRIAL' as ServerState, expireTime: dayjs().add(3, 'day').unix() * 1000 });
expect(store.trialWithin5DaysOfExpiration).toBe(true);
// Trial expiring in exactly 5 days
store.setServer({ state: 'TRIAL' as ServerState, expireTime: dayjs().add(5, 'day').unix() * 1000 });
expect(store.trialWithin5DaysOfExpiration).toBe(true);
// Trial expiring in 7 days (to ensure it's clearly outside the 5-day window)
store.setServer({ state: 'TRIAL' as ServerState, expireTime: dayjs().add(7, 'day').unix() * 1000 });
expect(store.trialWithin5DaysOfExpiration).toBe(false);
// Trial already expired
store.setServer({ state: 'TRIAL' as ServerState, expireTime: dayjs().subtract(1, 'day').unix() * 1000 });
expect(store.trialWithin5DaysOfExpiration).toBe(false);
});
it('should calculate trial extension renewal window conditions correctly', () => {
const store = getStore();
// Add all necessary properties
Object.defineProperty(store, 'expireTime', { value: 0, writable: true });
Object.defineProperty(store, 'trialExtensionEligible', {
get: () => !store.regGen || store.regGen < 2,
});
Object.defineProperty(store, 'trialWithin5DaysOfExpiration', {
get: () => {
if (!store.expireTime || store.state !== 'TRIAL') {
return false;
}
const today = dayjs();
const expirationDate = dayjs(store.expireTime);
const daysUntilExpiration = expirationDate.diff(today, 'day');
return daysUntilExpiration <= 5 && daysUntilExpiration >= 0;
},
});
Object.defineProperty(store, 'trialExtensionEligibleInsideRenewalWindow', {
get: () => store.trialExtensionEligible && store.trialWithin5DaysOfExpiration,
});
Object.defineProperty(store, 'trialExtensionEligibleOutsideRenewalWindow', {
get: () => store.trialExtensionEligible && !store.trialWithin5DaysOfExpiration,
});
Object.defineProperty(store, 'trialExtensionIneligibleInsideRenewalWindow', {
get: () => !store.trialExtensionEligible && store.trialWithin5DaysOfExpiration,
});
// Eligible inside renewal window
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 1,
expireTime: dayjs().add(3, 'day').unix() * 1000,
});
expect(store.trialExtensionEligibleInsideRenewalWindow).toBe(true);
expect(store.trialExtensionEligibleOutsideRenewalWindow).toBe(false);
expect(store.trialExtensionIneligibleInsideRenewalWindow).toBe(false);
// Eligible outside renewal window
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 1,
expireTime: dayjs().add(10, 'day').unix() * 1000,
});
expect(store.trialExtensionEligibleInsideRenewalWindow).toBe(false);
expect(store.trialExtensionEligibleOutsideRenewalWindow).toBe(true);
expect(store.trialExtensionIneligibleInsideRenewalWindow).toBe(false);
// Ineligible inside renewal window
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 2,
expireTime: dayjs().add(3, 'day').unix() * 1000,
});
expect(store.trialExtensionEligibleInsideRenewalWindow).toBe(false);
expect(store.trialExtensionEligibleOutsideRenewalWindow).toBe(false);
expect(store.trialExtensionIneligibleInsideRenewalWindow).toBe(true);
// Ineligible outside renewal window
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 2,
expireTime: dayjs().add(10, 'day').unix() * 1000,
});
expect(store.trialExtensionEligibleInsideRenewalWindow).toBe(false);
expect(store.trialExtensionEligibleOutsideRenewalWindow).toBe(false);
expect(store.trialExtensionIneligibleInsideRenewalWindow).toBe(false);
});
it('should display correct trial messages based on extension eligibility and renewal window', () => {
const store = getStore();
// Add all necessary properties
Object.defineProperty(store, 'expireTime', { value: 0, writable: true });
Object.defineProperty(store, 'trialExtensionEligible', {
get: () => !store.regGen || store.regGen < 2,
});
Object.defineProperty(store, 'trialWithin5DaysOfExpiration', {
get: () => {
if (!store.expireTime || store.state !== 'TRIAL') {
return false;
}
const today = dayjs();
const expirationDate = dayjs(store.expireTime);
const daysUntilExpiration = expirationDate.diff(today, 'day');
return daysUntilExpiration <= 5 && daysUntilExpiration >= 0;
},
});
Object.defineProperty(store, 'trialExtensionEligibleInsideRenewalWindow', {
get: () => store.trialExtensionEligible && store.trialWithin5DaysOfExpiration,
});
Object.defineProperty(store, 'trialExtensionEligibleOutsideRenewalWindow', {
get: () => store.trialExtensionEligible && !store.trialWithin5DaysOfExpiration,
});
Object.defineProperty(store, 'trialExtensionIneligibleInsideRenewalWindow', {
get: () => !store.trialExtensionEligible && store.trialWithin5DaysOfExpiration,
});
// Mock stateData getter to include trial message logic
Object.defineProperty(store, 'stateData', {
get: () => {
if (store.state !== 'TRIAL') {
return {
humanReadable: '',
heading: '',
message: '',
actions: [],
};
}
let trialMessage = '';
if (store.trialExtensionEligibleInsideRenewalWindow) {
trialMessage = '<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>Your trial is expiring soon. When it expires, <strong>the array will stop</strong>. You may extend your trial now, purchase a license key, or wait until expiration to take action.</p>';
} else if (store.trialExtensionIneligibleInsideRenewalWindow) {
trialMessage = '<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>Your trial is expiring soon and you have used all available extensions. When it expires, <strong>the array will stop</strong>. To continue using Unraid OS, you must purchase a license key.</p>';
} else if (store.trialExtensionEligibleOutsideRenewalWindow) {
trialMessage = '<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>When your <em>Trial</em> expires, <strong>the array will stop</strong>. At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>';
} else {
trialMessage = '<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>You have used all available trial extensions. When your <em>Trial</em> expires, <strong>the array will stop</strong>. To continue using Unraid OS after expiration, you must purchase a license key.</p>';
}
return {
humanReadable: 'Trial',
heading: 'Thank you for choosing Unraid OS!',
message: trialMessage,
actions: [],
};
},
});
// Test case 1: Eligible inside renewal window
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 1,
expireTime: dayjs().add(3, 'day').unix() * 1000,
});
expect(store.stateData.message).toContain('Your trial is expiring soon');
expect(store.stateData.message).toContain('You may extend your trial now');
// Test case 2: Ineligible inside renewal window
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 2,
expireTime: dayjs().add(3, 'day').unix() * 1000,
});
expect(store.stateData.message).toContain('Your trial is expiring soon and you have used all available extensions');
expect(store.stateData.message).toContain('To continue using Unraid OS, you must purchase a license key');
// Test case 3: Eligible outside renewal window
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 0,
expireTime: dayjs().add(10, 'day').unix() * 1000,
});
expect(store.stateData.message).toContain('At that point you may either purchase a license key or request a <em>Trial</em> extension');
// Test case 4: Ineligible outside renewal window
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 2,
expireTime: dayjs().add(10, 'day').unix() * 1000,
});
expect(store.stateData.message).toContain('You have used all available trial extensions');
expect(store.stateData.message).toContain('To continue using Unraid OS after expiration, you must purchase a license key');
});
it('should include trial extend action only when eligible inside renewal window', () => {
const store = getStore();
// Add necessary properties
Object.defineProperty(store, 'expireTime', { value: 0, writable: true });
Object.defineProperty(store, 'trialExtensionEligible', {
get: () => !store.regGen || store.regGen < 2,
});
Object.defineProperty(store, 'trialWithin5DaysOfExpiration', {
get: () => {
if (!store.expireTime || store.state !== 'TRIAL') {
return false;
}
const today = dayjs();
const expirationDate = dayjs(store.expireTime);
const daysUntilExpiration = expirationDate.diff(today, 'day');
return daysUntilExpiration <= 5 && daysUntilExpiration >= 0;
},
});
Object.defineProperty(store, 'trialExtensionEligibleInsideRenewalWindow', {
get: () => store.trialExtensionEligible && store.trialWithin5DaysOfExpiration,
});
// Mock the trialExtendAction
const trialExtendAction = { name: 'trialExtend', text: 'Extend Trial' };
// Mock stateData getter to include actions logic
Object.defineProperty(store, 'stateData', {
get: () => {
if (store.state !== 'TRIAL') {
return {
humanReadable: '',
heading: '',
message: '',
actions: [],
};
}
const actions = [];
if (store.trialExtensionEligibleInsideRenewalWindow) {
actions.push(trialExtendAction);
}
return {
humanReadable: 'Trial',
heading: 'Thank you for choosing Unraid OS!',
message: '',
actions,
};
},
});
// Test case 1: Eligible inside renewal window - should include trialExtend action
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 1,
expireTime: dayjs().add(3, 'day').unix() * 1000,
registered: true,
connectPluginInstalled: 'true' as ServerconnectPluginInstalled,
});
expect(store.stateData.actions?.some((action: { name: string }) => action.name === 'trialExtend')).toBe(true);
// Test case 2: Not eligible inside renewal window - should NOT include trialExtend action
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 2,
expireTime: dayjs().add(3, 'day').unix() * 1000,
registered: true,
connectPluginInstalled: 'true' as ServerconnectPluginInstalled,
});
expect(store.stateData.actions?.some((action: { name: string }) => action.name === 'trialExtend')).toBe(false);
// Test case 3: Eligible outside renewal window - should NOT include trialExtend action
store.setServer({
state: 'TRIAL' as ServerState,
regGen: 1,
expireTime: dayjs().add(10, 'day').unix() * 1000,
registered: true,
connectPluginInstalled: 'true' as ServerconnectPluginInstalled,
});
expect(store.stateData.actions?.some((action: { name: string }) => action.name === 'trialExtend')).toBe(false);
});
});
});

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue';
import type { Component } from 'vue';
import { computed, type Component } from 'vue';
import { BellIcon, ExclamationTriangleIcon, ShieldExclamationIcon } from '@heroicons/vue/24/solid';
import { cn } from '@unraid/ui';

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import { computed, reactive } from 'vue';
import type { Component } from 'vue';
import { computed, reactive, type Component } from 'vue';
import { computedAsync } from '@vueuse/core';
import { Markdown } from '@/helpers/markdown';
import {

View File

@@ -1,5 +1,4 @@
import { InMemoryCache } from '@apollo/client/core';
import type { InMemoryCacheConfig } from '@apollo/client/core';
import { InMemoryCache, type InMemoryCacheConfig } from '@apollo/client/core';
import type { NotificationOverview } from '~/composables/gql/graphql';

View File

@@ -1,6 +1,5 @@
import DOMPurify from 'isomorphic-dompurify';
import { Marked } from 'marked';
import type { MarkedExtension } from 'marked';
import { Marked, type MarkedExtension } from 'marked';
const defaultMarkedExtension: MarkedExtension = {
hooks: {

View File

@@ -23,10 +23,6 @@
"<p>To support more storage devices as your server grows, click Upgrade Key.</p>": "<p>To support more storage devices as your server grows, click Upgrade Key.</p>",
"<p>You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.</p>": "<p>You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.</p>",
"<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>": "<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>",
"<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>When your <em>Trial</em> expires, <strong>the array will stop</strong>. At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>": "<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>When your <em>Trial</em> expires, <strong>the array will stop</strong>. At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>",
"<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>Your trial is expiring soon. When it expires, <strong>the array will stop</strong>. You may extend your trial now, purchase a license key, or wait until expiration to take action.</p>": "<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>Your trial is expiring soon. When it expires, <strong>the array will stop</strong>. You may extend your trial now, purchase a license key, or wait until expiration to take action.</p>",
"<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>Your trial is expiring soon and you have used all available extensions. When it expires, <strong>the array will stop</strong>. To continue using Unraid OS, you must purchase a license key.</p>": "<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>Your trial is expiring soon and you have used all available extensions. When it expires, <strong>the array will stop</strong>. To continue using Unraid OS, you must purchase a license key.</p>",
"<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>You have used all available trial extensions. When your <em>Trial</em> expires, <strong>the array will stop</strong>. To continue using Unraid OS after expiration, you must purchase a license key.</p>": "<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>You have used all available trial extensions. When your <em>Trial</em> expires, <strong>the array will stop</strong>. To continue using Unraid OS after expiration, you must purchase a license key.</p>",
"<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>If you do not have a backup copy of your license key file you may attempt to recover your key.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>": "<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>If you do not have a backup copy of your license key file you may attempt to recover your key.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>",
"<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>You may attempt to recover your key with your Unraid.net account.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>": "<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>You may attempt to recover your key with your Unraid.net account.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>",
"<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.</p><p>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.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class='list-disc pl-16px'><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>": "<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.</p><p>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.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class='list-disc pl-16px'><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>",

View File

@@ -1,6 +1,6 @@
{
"name": "@unraid/web",
"version": "4.9.1",
"version": "4.9.0",
"private": true,
"license": "GPL-2.0-or-later",
"scripts": {

View File

@@ -495,7 +495,6 @@ export const useServerStore = defineStore('server', () => {
});
let messageEGUID = '';
let trialMessage = '';
const stateData = computed((): ServerStateData => {
switch (state.value) {
case 'ENOKEYFILE':
@@ -511,26 +510,16 @@ export const useServerStore = defineStore('server', () => {
'<p>Choose an option below, then use our <a href="https://unraid.net/getting-started" target="_blank" rel="noreffer noopener">Getting Started Guide</a> to configure your array in less than 15 minutes.</p>',
};
case 'TRIAL':
if (trialExtensionEligibleInsideRenewalWindow.value) {
trialMessage = '<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>Your trial is expiring soon. When it expires, <strong>the array will stop</strong>. You may extend your trial now, purchase a license key, or wait until expiration to take action.</p>';
} else if (trialExtensionIneligibleInsideRenewalWindow.value) {
trialMessage = '<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>Your trial is expiring soon and you have used all available extensions. When it expires, <strong>the array will stop</strong>. To continue using Unraid OS, you must purchase a license key.</p>';
} else if (trialExtensionEligibleOutsideRenewalWindow.value) {
trialMessage = '<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>When your <em>Trial</em> expires, <strong>the array will stop</strong>. At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>';
} else { // would be trialExtensionIneligibleOutsideRenewalWindow if it wasn't an else conditionally
trialMessage = '<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>You have used all available trial extensions. When your <em>Trial</em> expires, <strong>the array will stop</strong>. To continue using Unraid OS after expiration, you must purchase a license key.</p>';
}
return {
actions: [
...(!registered.value && connectPluginInstalled.value ? [signInAction.value] : []),
...[purchaseAction.value, redeemAction.value],
...(trialExtensionEligibleInsideRenewalWindow.value ? [trialExtendAction.value] : []),
...(registered.value && connectPluginInstalled.value ? [signOutAction.value] : []),
],
humanReadable: 'Trial',
heading: 'Thank you for choosing Unraid OS!',
message: trialMessage,
message:
'<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>',
};
case 'EEXPIRED':
return {
@@ -784,18 +773,6 @@ 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;
});
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) {