mirror of
https://github.com/unraid/api.git
synced 2026-05-09 08:41:12 -05:00
refactor(web): replace key eligibility using store
This commit is contained in:
+2
-1
@@ -59,12 +59,13 @@ $serverState = [
|
||||
"name" => htmlspecialchars($var['NAME']),
|
||||
"osVersion" => $var['version'],
|
||||
"protocol" => $_SERVER['REQUEST_SCHEME'],
|
||||
"regDev" => (int)$var['regDev'] ?? 0,
|
||||
"regGen" => (int)$var['regGen'],
|
||||
"regGuid" => @$var['regGUID'] ?? '',
|
||||
"regTo" => @htmlspecialchars($var['regTo']) ?? '',
|
||||
"regTm" => $var['regTm'] ? @$var['regTm'] * 1000 : '', // JS expects milliseconds
|
||||
"regTy" => @$var['regTy'] ?? '',
|
||||
"regUpdExpAt" => $var['regUpdExpAt'] ? @$var['regUpdExpAt'] * 1000 : '', // JS expects milliseconds
|
||||
"regExp" => $var['regExp'] ? @$var['regExp'] * 1000 : '', // JS expects milliseconds
|
||||
"registered" => $registered,
|
||||
"registeredTime" => $myservers['remote']['regWizTime'] ?? '',
|
||||
"site" => $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'],
|
||||
|
||||
@@ -1,119 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ArrowTopRightOnSquareIcon,
|
||||
CheckCircleIcon,
|
||||
KeyIcon,
|
||||
XCircleIcon,
|
||||
ShieldExclamationIcon,
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import type { WretchError } from 'wretch';
|
||||
|
||||
import { validateGuid, type ValidateGuidPayload } from '~/composables/services/keyServer';
|
||||
import { useServerStore } from '~/store/server';
|
||||
|
||||
import BrandLoadingWhite from '~/components/Brand/LoadingWhite.vue';
|
||||
import { useReplaceCheckStore } from '~/store/replaceCheck';
|
||||
|
||||
const replaceCheckStore = useReplaceCheckStore();
|
||||
const { status, statusOutput } = storeToRefs(replaceCheckStore);
|
||||
|
||||
const props = defineProps<{
|
||||
t: any;
|
||||
}>();
|
||||
|
||||
const { guid, keyfile } = storeToRefs(useServerStore());
|
||||
|
||||
const error = ref<{
|
||||
name: string;
|
||||
message: string;
|
||||
stack?: string | undefined;
|
||||
cause?: unknown;
|
||||
} | null>(null);
|
||||
const status = ref<'checking' | 'eligible' | 'error' | 'ineligible' | 'ready'>(guid.value ? 'ready' : 'error');
|
||||
const statusOutput = computed(() => {
|
||||
switch (status.value) {
|
||||
case 'eligible':
|
||||
return {
|
||||
color: 'green',
|
||||
icon: CheckCircleIcon,
|
||||
text: props.t('Eligible'),
|
||||
};
|
||||
|
||||
case 'ineligible':
|
||||
return {
|
||||
color: 'red',
|
||||
icon: XCircleIcon,
|
||||
text: props.t('Ineligible'),
|
||||
};
|
||||
|
||||
case 'error':
|
||||
return {
|
||||
color: 'red',
|
||||
icon: ShieldExclamationIcon,
|
||||
text: error.value?.message || 'Unknown error',
|
||||
};
|
||||
|
||||
default: return null;
|
||||
}
|
||||
});
|
||||
const validationResponse = ref<ValidateGuidPayload | undefined>(sessionStorage.getItem('replaceCheck') ? JSON.parse(sessionStorage.getItem('replaceCheck') as string) : undefined);
|
||||
|
||||
const check = async () => {
|
||||
if (!guid.value) {
|
||||
status.value = 'error';
|
||||
error.value = { name: 'Error', message: props.t('Flash GUID required') };
|
||||
}
|
||||
|
||||
try {
|
||||
status.value = 'checking';
|
||||
error.value = null;
|
||||
/**
|
||||
* @todo will eventually take a keyfile and provide renewal details. If this says there's a reneal key available then we'll make a separate request to replace / swap the new key. We'll also use this to update the keyfile to the new key type for legacy users.
|
||||
* endpoint will be through key server
|
||||
* this should happen automatically when the web components are mounted…
|
||||
* account.unraid.net will do a similar thing`
|
||||
*/
|
||||
const response: ValidateGuidPayload = await validateGuid({
|
||||
guid: guid.value,
|
||||
keyfile: keyfile.value,
|
||||
}).json();
|
||||
sessionStorage.setItem('replaceCheck', JSON.stringify(response));
|
||||
status.value = response?.replaceable ? 'eligible' : 'ineligible';
|
||||
} catch (err) {
|
||||
const catchError = err as WretchError;
|
||||
status.value = 'error';
|
||||
error.value = catchError?.message ? catchError : { name: 'Error', message: 'Unknown error' };
|
||||
console.error('[ReplaceCheck.check]', catchError);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If we already have a validation response, set the status to eligible or ineligible
|
||||
*/
|
||||
onBeforeMount(() => {
|
||||
if (validationResponse.value) {
|
||||
status.value = validationResponse.value?.replaceable ? 'eligible' : 'ineligible';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<BrandButton
|
||||
v-if="status === 'checking' || status === 'ready'"
|
||||
@click="check"
|
||||
@click="replaceCheckStore.check"
|
||||
:disabled="status !== 'ready'"
|
||||
:icon="status === 'checking' ? BrandLoadingWhite : KeyIcon"
|
||||
:text="t('Check Eligibility')"
|
||||
class="w-full sm:max-w-300px"
|
||||
/>
|
||||
class="w-full sm:max-w-300px" />
|
||||
|
||||
<p
|
||||
v-else-if="statusOutput"
|
||||
class="flex flex-col sm:flex-row items-start justify-between gap-4px"
|
||||
>
|
||||
<UiBadge :color="statusOutput.color" :icon="statusOutput.icon" size="16px">
|
||||
{{ statusOutput.text }}
|
||||
{{ t(statusOutput.text) }}
|
||||
</UiBadge>
|
||||
<BrandButton
|
||||
v-if="status === 'eligible' || status === 'ineligible'"
|
||||
v-if="status !== 'checking' || status === 'ready'"
|
||||
btn-style="underline"
|
||||
:external="true"
|
||||
:href="'https://docs.unraid.net/unraid-os/manual/changing-the-flash-device/'"
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
XCircleIcon,
|
||||
ShieldExclamationIcon,
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import type { WretchError } from 'wretch';
|
||||
|
||||
import { validateGuid, type ValidateGuidPayload } from '~/composables/services/keyServer';
|
||||
import { useServerStore } from '~/store/server';
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
* @see https://github.com/vuejs/pinia/discussions/1085
|
||||
*/
|
||||
setActivePinia(createPinia());
|
||||
|
||||
export const useReplaceCheckStore = defineStore('replaceCheck', () => {
|
||||
const serverStore = useServerStore();
|
||||
|
||||
const guid = computed(() => serverStore.guid);
|
||||
const keyfile = computed(() => serverStore.keyfile);
|
||||
|
||||
const error = ref<{
|
||||
name: string;
|
||||
message: string;
|
||||
stack?: string | undefined;
|
||||
cause?: unknown;
|
||||
} | null>(null);
|
||||
const status = ref<'checking' | 'eligible' | 'error' | 'ineligible' | 'ready'>(guid.value ? 'ready' : 'error');
|
||||
const statusOutput = computed(() => {
|
||||
// text values are translated in the component
|
||||
switch (status.value) {
|
||||
case 'eligible':
|
||||
return {
|
||||
color: 'green',
|
||||
icon: CheckCircleIcon,
|
||||
text: 'Eligible',
|
||||
};
|
||||
case 'ineligible':
|
||||
return {
|
||||
color: 'red',
|
||||
icon: XCircleIcon,
|
||||
text: 'Ineligible',
|
||||
};
|
||||
case 'error':
|
||||
return {
|
||||
color: 'red',
|
||||
icon: ShieldExclamationIcon,
|
||||
text: error.value?.message || 'Unknown error',
|
||||
};
|
||||
default: return null;
|
||||
}
|
||||
});
|
||||
const validationResponse = ref<ValidateGuidPayload | undefined>(
|
||||
sessionStorage.getItem('replaceCheck')
|
||||
? JSON.parse(sessionStorage.getItem('replaceCheck') as string)
|
||||
: undefined
|
||||
);
|
||||
|
||||
const check = async () => {
|
||||
if (!guid.value) {
|
||||
status.value = 'error';
|
||||
error.value = { name: 'Error', message: 'Flash GUID required to check replacement status' };
|
||||
}
|
||||
if (!keyfile.value) {
|
||||
status.value = 'error';
|
||||
error.value = { name: 'Error', message: 'Keyfile required to check replacement status' };
|
||||
}
|
||||
|
||||
try {
|
||||
status.value = 'checking';
|
||||
error.value = null;
|
||||
/**
|
||||
* @todo will eventually take a keyfile and provide renewal details. If this says there's a reneal key available then we'll make a separate request to replace / swap the new key. We'll also use this to update the keyfile to the new key type for legacy users.
|
||||
* endpoint will be through key server
|
||||
* this should happen automatically when the web components are mounted…
|
||||
* account.unraid.net will do a similar thing`
|
||||
*/
|
||||
const response: ValidateGuidPayload = await validateGuid({
|
||||
guid: guid.value,
|
||||
keyfile: keyfile.value,
|
||||
}).json();
|
||||
sessionStorage.setItem('replaceCheck', JSON.stringify(response));
|
||||
status.value = response?.replaceable ? 'eligible' : 'ineligible';
|
||||
} catch (err) {
|
||||
const catchError = err as WretchError;
|
||||
status.value = 'error';
|
||||
error.value = catchError?.message ? catchError : { name: 'Error', message: 'Unknown error' };
|
||||
console.error('[ReplaceCheck.check]', catchError);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If we already have a validation response, set the status to eligible or ineligible
|
||||
*/
|
||||
onBeforeMount(() => {
|
||||
if (validationResponse.value) {
|
||||
status.value = validationResponse.value?.replaceable ? 'eligible' : 'ineligible';
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
status,
|
||||
statusOutput,
|
||||
check,
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user