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
48 changes: 45 additions & 3 deletions web/__test__/components/Registration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ vi.mock('@unraid/ui', async (importOriginal) => {

return {
...actual,
BrandButton: { template: '<button><slot /></button>', props: ['text', 'title', 'icon', 'disabled'] },
BrandButton: {
template:
'<button :disabled="disabled" @click="!disabled && $emit(\'click\')">{{ text }}<slot /></button>',
props: ['text', 'title', 'icon', 'disabled'],
},
CardWrapper: { template: '<div><slot /></div>' },
PageContainer: { template: '<div><slot /></div>' },
SettingsGrid: { template: '<div class="settings-grid"><slot /></div>' },
Expand Down Expand Up @@ -321,6 +325,8 @@ describe('Registration.standalone.vue', () => {
const moveButton = wrapper.find('[data-testid="move-license-to-tpm"]');

expect(moveButton.exists()).toBe(true);
expect(moveButton.attributes('disabled')).toBeUndefined();
expect(findItemByLabel(t('TPM GUID'))?.props('text')).toBe('03-V35H8S0L1QHK1SBG1XHXJNH7');
});

it('shows Move License to TPM when flashGuid is missing but the active GUID is still a flash GUID', async () => {
Expand Down Expand Up @@ -349,7 +355,7 @@ describe('Registration.standalone.vue', () => {
expect(accountStore.replaceTpm).toHaveBeenCalled();
});

it('does not show Move License to TPM for trial states', async () => {
it('shows a disabled Move License to TPM button for trial states', async () => {
serverStore.state = 'TRIAL';
serverStore.guid = '058F-6387-0000-0000F1F1E1C6';
serverStore.flashGuid = '058F-6387-0000-0000F1F1E1C6';
Expand All @@ -358,7 +364,43 @@ describe('Registration.standalone.vue', () => {

await wrapper.vm.$nextTick();

expect(wrapper.find('[data-testid="move-license-to-tpm"]').exists()).toBe(false);
const moveButton = wrapper.find('[data-testid="move-license-to-tpm"]');

expect(moveButton.exists()).toBe(true);
expect(moveButton.attributes('disabled')).toBeDefined();
expect(findItemByLabel(t('TPM GUID'))?.props('text')).toBe('03-V35H8S0L1QHK1SBG1XHXJNH7');
expect(wrapper.text()).toContain(
'Trials are locked to the registered GUID. You can move to TPM by purchasing a license.'
);
});

it('shows a disabled Move License to TPM button for expired trial states', async () => {
serverStore.state = 'EEXPIRED';
serverStore.guid = '058F-6387-0000-0000F1F1E1C6';
serverStore.flashGuid = '058F-6387-0000-0000F1F1E1C6';
serverStore.tpmGuid = '03-V35H8S0L1QHK1SBG1XHXJNH7';
serverStore.keyfile = 'keyfile-present';

await wrapper.vm.$nextTick();

const moveButton = wrapper.find('[data-testid="move-license-to-tpm"]');

expect(moveButton.exists()).toBe(true);
expect(moveButton.attributes('disabled')).toBeDefined();
});

it('does not trigger the TPM replacement action when the trial TPM button is clicked', async () => {
serverStore.state = 'TRIAL';
serverStore.guid = '058F-6387-0000-0000F1F1E1C6';
serverStore.flashGuid = '058F-6387-0000-0000F1F1E1C6';
serverStore.tpmGuid = '03-V35H8S0L1QHK1SBG1XHXJNH7';
serverStore.keyfile = 'keyfile-present';

await wrapper.vm.$nextTick();

await wrapper.find('[data-testid="move-license-to-tpm"]').trigger('click');

expect(accountStore.replaceTpm).not.toHaveBeenCalled();
});

it('does not show Move License to TPM after switching to TPM boot', async () => {
Expand Down
23 changes: 19 additions & 4 deletions web/src/components/Registration.standalone.vue
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,9 @@ const showPartnerActivationCode = computed(() => {
(currentState === 'ENOKEYFILE' || currentState === 'TRIAL' || currentState === 'EEXPIRED')
);
});
const showTpmTransferInfo = computed((): boolean =>
const showTpmTransferButton = computed((): boolean =>
Boolean(
keyInstalled.value &&
!showTrialExpiration.value &&
(keyInstalled.value || showTrialExpiration.value) &&
bootDeviceType.value === 'flash' &&
// The active GUID tells us whether we're still booted from flash, even if
// flashGuid is missing or has already fallen back to the TPM value.
Expand All @@ -146,6 +145,7 @@ const showTpmTransferInfo = computed((): boolean =>
guid.value !== tpmGuid.value
)
);
const disableTpmTransferButton = computed((): boolean => showTrialExpiration.value);

// Organize items into three sections
const bootDeviceItems = computed((): RegistrationItemProps[] => {
Expand All @@ -158,6 +158,14 @@ const bootDeviceItems = computed((): RegistrationItemProps[] => {
},
]
: []),
...(showTpmTransferButton.value && tpmGuid.value
? [
{
label: t('registration.tpmGuid'),
text: tpmGuid.value,
},
]
: []),
...(bootDeviceType.value
? [
{
Expand Down Expand Up @@ -390,12 +398,19 @@ const actionItems = computed((): RegistrationItemProps[] => {
>
<h4 class="mb-3 text-lg font-semibold">{{ t('registration.actions') }}</h4>
<BrandButton
v-if="showTpmTransferInfo"
v-if="showTpmTransferButton"
data-testid="move-license-to-tpm"
:disabled="disableTpmTransferButton"
:text="t('registration.moveLicenseToTpm')"
class="mb-4 w-full sm:max-w-[300px]"
@click="accountStore.replaceTpm()"
/>
<p
v-if="showTpmTransferButton && disableTpmTransferButton"
class="mb-4 text-sm leading-relaxed opacity-75"
>
{{ t('registration.moveLicenseToTpmTrialDisabled') }}
</p>
<blockquote
v-if="showPartnerActivationCode"
class="border-primary bg-primary/10 mb-4 border-l-4 p-4"
Expand Down
2 changes: 2 additions & 0 deletions web/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,9 @@
"registration.activationCode": "Activation Code",
"registration.partnerActivationDetected": "It appears you already have a license associated with this server. You can activate it now for free to unlock all features.",
"registration.moveLicenseToTpm": "Move License to TPM",
"registration.moveLicenseToTpmTrialDisabled": "Trials are locked to the registered GUID. You can move to TPM by purchasing a license.",
"registration.replaceCheck.checkEligibility": "Check Eligibility",
"registration.tpmGuid": "TPM GUID",
"registration.transferLicenseToNewDevice": "Transfer License to New Device",
"registration.trialExpiration": "Trial expiration",
"registration.unlimited": "unlimited",
Expand Down
Loading