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
16 changes: 16 additions & 0 deletions web/__test__/components/Registration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,22 @@ describe('Registration.standalone.vue', () => {
expect(wrapper.find('[data-testid="key-actions"]').exists()).toBe(false);
});

it('renders unlimited text for attached storage devices when the license has no device cap', async () => {
serverStore.state = 'UNLEASHED';
serverStore.regTy = 'Unleashed';
serverStore.regTo = 'Test User';
serverStore.guid = 'FLASH-GUID-123';
serverStore.keyfile = 'keyfile-present';
serverStore.deviceCount = 8;

await wrapper.vm.$nextTick();

const attachedStorageDevicesItem = findItemByLabel(t('Attached Storage Devices'));

expect(attachedStorageDevicesItem).toBeDefined();
expect(attachedStorageDevicesItem?.props('text')).toBe('8 out of unlimited devices');
});

it('adds Activate Trial fallback for ENOKEYFILE partner activation', async () => {
activationCodeStateHolder.current!.value = {
code: 'PARTNER-CODE-123',
Expand Down
21 changes: 21 additions & 0 deletions web/__test__/utils/registration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { describe, expect, it } from 'vitest';

import { getRegistrationDeviceLimit, normalizeRegistrationType } from '~/utils/registration';

describe('registration utils', () => {
it('normalizes GraphQL enum registration types for display', () => {
expect(normalizeRegistrationType('UNLEASHED')).toBe('Unleashed');
expect(normalizeRegistrationType('PRO')).toBe('Pro');
expect(normalizeRegistrationType('Plus')).toBe('Plus');
});

it('keeps unlimited license device counts when the registration type is uppercase', () => {
expect(getRegistrationDeviceLimit('UNLEASHED', 0)).toBe(-1);
expect(getRegistrationDeviceLimit('PRO', 0)).toBe(-1);
expect(getRegistrationDeviceLimit('TRIAL', 0)).toBe(-1);
});

it('prefers an explicit device limit when one is provided', () => {
expect(getRegistrationDeviceLimit('BASIC', 10)).toBe(10);
});
});
24 changes: 3 additions & 21 deletions web/src/store/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { usePurchaseStore } from '~/store/purchase';
import { CLOUD_STATE_QUERY, SERVER_CLOUD_FRAGMENT, SERVER_STATE_QUERY } from '~/store/server.fragment';
import { useThemeStore } from '~/store/theme';
import { useUnraidApiStore } from '~/store/unraidApi';
import { getRegistrationDeviceLimit, normalizeRegistrationType } from '~/utils/registration';

export const useServerStore = defineStore('server', () => {
const { t } = useI18n();
Expand Down Expand Up @@ -114,26 +115,7 @@ export const useServerStore = defineStore('server', () => {
const rebootVersion = ref<string | undefined>();
const registered = ref<boolean>();
const regDevs = ref<number>(0); // use computedRegDevs to ensure it includes Basic, Plus, and Pro
const computedRegDevs = computed(() => {
if (regDevs.value > 0) {
return regDevs.value;
}

switch (regTy.value) {
case 'Starter':
case 'Basic':
return 6;
case 'Plus':
return 12;
case 'Unleashed':
case 'Lifetime':
case 'Pro':
case 'Trial':
return -1; // unlimited
default:
return 0;
}
});
const computedRegDevs = computed(() => getRegistrationDeviceLimit(regTy.value, regDevs.value));
const regGen = ref<number>(0);
const regGuid = ref<string>('');
const regTm = ref<number>(0);
Expand Down Expand Up @@ -1091,7 +1073,7 @@ export const useServerStore = defineStore('server', () => {
regGuid.value = data.regGuid;
}
if (typeof data?.regTy !== 'undefined') {
regTy.value = data.regTy;
regTy.value = normalizeRegistrationType(data.regTy);
}
if (typeof data?.regExp !== 'undefined') {
regExp.value = data.regExp;
Expand Down
44 changes: 44 additions & 0 deletions web/src/utils/registration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const REGISTRATION_TYPE_LABELS = {
BASIC: 'Basic',
PLUS: 'Plus',
PRO: 'Pro',
STARTER: 'Starter',
UNLEASHED: 'Unleashed',
LIFETIME: 'Lifetime',
TRIAL: 'Trial',
INVALID: 'Invalid',
} as const;

const REGISTRATION_DEVICE_LIMITS = {
BASIC: 6,
PLUS: 12,
PRO: -1,
STARTER: 6,
UNLEASHED: -1,
LIFETIME: -1,
TRIAL: -1,
} as const;

const getRegistrationTypeKey = (registrationType?: string): string =>
registrationType?.trim().toUpperCase() ?? '';

export const normalizeRegistrationType = (registrationType?: string): string => {
const registrationTypeKey = getRegistrationTypeKey(registrationType);
return (
REGISTRATION_TYPE_LABELS[registrationTypeKey as keyof typeof REGISTRATION_TYPE_LABELS] ??
registrationType ??
''
);
};

export const getRegistrationDeviceLimit = (
registrationType?: string,
registeredDeviceLimit?: number
): number => {
if (typeof registeredDeviceLimit === 'number' && registeredDeviceLimit > 0) {
return registeredDeviceLimit;
}

const registrationTypeKey = getRegistrationTypeKey(registrationType);
return REGISTRATION_DEVICE_LIMITS[registrationTypeKey as keyof typeof REGISTRATION_DEVICE_LIMITS] ?? 0;
};
Loading