From 5cbccb06ad4fdef5b83c4e7bfbea5cc3f3096126 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 31 Oct 2023 15:53:39 -0700 Subject: [PATCH] fix(web): type errors --- web/app.vue | 1 + web/composables/gql/graphql.ts | 8 ++-- web/composables/services/keyServer.ts | 12 +++--- web/composables/services/request.ts | 16 +++++++- web/nuxt.config.ts | 4 ++ web/pages/index.vue | 3 +- web/pages/webComponents.vue | 1 + web/store/account.ts | 12 +++--- web/store/callbackActions.ts | 55 +++++++++++++++++---------- web/store/errors.ts | 12 ++++-- web/store/installKey.ts | 9 ++++- web/store/replaceRenew.ts | 2 +- web/store/server.ts | 41 +++++++++++--------- web/store/trial.ts | 4 +- web/store/unraidApi.ts | 32 +++++++++++----- web/store/updateOs.ts | 16 ++++---- web/store/updateOsActions.ts | 20 ++++++++++ web/types/server.ts | 21 +++++----- 18 files changed, 174 insertions(+), 95 deletions(-) diff --git a/web/app.vue b/web/app.vue index 2ddbece3b..af48a55d2 100644 --- a/web/app.vue +++ b/web/app.vue @@ -1,6 +1,7 @@ diff --git a/web/composables/gql/graphql.ts b/web/composables/gql/graphql.ts index b9c36401c..0095f19f3 100644 --- a/web/composables/gql/graphql.ts +++ b/web/composables/gql/graphql.ts @@ -220,11 +220,11 @@ export type Case = { export type Cloud = { __typename?: 'Cloud'; - allowedOrigins: Array; - apiKey: ApiKeyResponse; - cloud: CloudResponse; + allowedOrigins?: Array; + apiKey?: ApiKeyResponse; + cloud?: CloudResponse; error?: Maybe; - minigraphql: MinigraphqlResponse; + minigraphql?: MinigraphqlResponse; relay?: Maybe; }; diff --git a/web/composables/services/keyServer.ts b/web/composables/services/keyServer.ts index a3d68ca10..724229330 100644 --- a/web/composables/services/keyServer.ts +++ b/web/composables/services/keyServer.ts @@ -12,10 +12,11 @@ export interface StartTrialResponse { license?: string; trial?: string } -export const startTrial = async (payload: StartTrialPayload) => await KeyServer +export const startTrial = async (payload: StartTrialPayload): Promise => await KeyServer .url('/account/trial') .formUrl(payload) - .post(); + .post() + .json(); export interface ValidateGuidResponse { hasNewerKeyfile : boolean; @@ -30,7 +31,7 @@ export interface ValidateGuidPayload { guid: string; keyfile?: string; } -export const validateGuid = async (payload: ValidateGuidPayload) => await KeyServer +export const validateGuid = async (payload: ValidateGuidPayload): Promise => await KeyServer .url('/validate/guid') .formUrl(payload) .post() @@ -42,10 +43,11 @@ export interface KeyLatestPayload { export interface KeyLatestResponse { license: string; } -export const keyLatest = async (payload: KeyLatestPayload) => await KeyServer +export const keyLatest = async (payload: KeyLatestPayload): Promise => await KeyServer .url('/key/latest') .formUrl(payload) - .post(); + .post() + .json(); export const getOsReleaseBySha256 = async (sha256: string): Promise => await KeyServer .url(`/versions/sha256/${sha256}`) diff --git a/web/composables/services/request.ts b/web/composables/services/request.ts index 4ddf5331f..cf4e4978b 100644 --- a/web/composables/services/request.ts +++ b/web/composables/services/request.ts @@ -16,10 +16,22 @@ export const request = wretch() return ( response .error('Error', (error) => { - errorsStore.setError(error); + errorsStore.setError({ + heading: `WretchError ${error.status}`, + message: `${error.text} • ${error.url}`, + level: 'error', + ref: 'wretchError', + type: 'request', + }); }) .error('TypeError', (error) => { - errorsStore.setError(error); + errorsStore.setError({ + heading: `WretchTypeError ${error.status}`, + message: `${error.text} • ${error.url}`, + level: 'error', + ref: 'wretchTypeError', + type: 'request', + }); }) ); }); diff --git a/web/nuxt.config.ts b/web/nuxt.config.ts index 3362bfbab..341adda6b 100644 --- a/web/nuxt.config.ts +++ b/web/nuxt.config.ts @@ -56,6 +56,9 @@ export default defineNuxtConfig({ { path: '~/components/UserProfile', prefix: 'Upc' }, '~/components', ], + // typescript: { + // typeCheck: true + // }, vite: { build: { minify: 'terser', @@ -71,6 +74,7 @@ export default defineNuxtConfig({ }, customElements: { entries: [ + // @ts-ignore { name: 'UnraidComponents', tags: [ diff --git a/web/pages/index.vue b/web/pages/index.vue index 55d4d7e77..7eb420360 100644 --- a/web/pages/index.vue +++ b/web/pages/index.vue @@ -6,10 +6,11 @@ import { serverState } from '~/_data/serverState'; const nuxtApp = useNuxtApp(); onBeforeMount(() => { + // @ts-ignore nuxtApp.$customElements.registerEntry('UnraidComponents'); }); -const valueToMakeCallback = ref(''); +const valueToMakeCallback = ref(); const callbackDestination = ref(''); const createCallbackUrl = (payload: SendPayloads, sendType: string) => { // params differs from callbackActions.send diff --git a/web/pages/webComponents.vue b/web/pages/webComponents.vue index a2c63c327..ce08eac3a 100644 --- a/web/pages/webComponents.vue +++ b/web/pages/webComponents.vue @@ -3,6 +3,7 @@ import { serverState } from '~/_data/serverState'; const nuxtApp = useNuxtApp(); onBeforeMount(() => { + // @ts-ignore nuxtApp.$customElements.registerEntry('UnraidComponents'); }); diff --git a/web/store/account.ts b/web/store/account.ts index 8e89e2d5e..3d3b0d9d5 100644 --- a/web/store/account.ts +++ b/web/store/account.ts @@ -147,7 +147,7 @@ export const useAccountStore = defineStore('account', () => { (connectSignInPayload.value && (!connectSignInPayload.value.apiKey || !connectSignInPayload.value.email || !connectSignInPayload.value.preferred_username)) ) { accountActionStatus.value = 'failed'; - return; + return console.error('[connectSignInMutation] incorrect payload', connectSignInPayload.value); } accountActionStatus.value = 'updating'; @@ -197,11 +197,11 @@ export const useAccountStore = defineStore('account', () => { const connectSignOutMutation = async () => { accountActionStatus.value = 'updating'; // @todo is this still needed here with the change to a mutation? - if (!serverStore.registered && accountAction.value && !accountAction.value.user) { - accountActionHide.value = true; - accountActionStatus.value = 'success'; - return; - } + // if (!serverStore.registered && accountAction.value && !accountAction.value?.user) { + // accountActionHide.value = true; + // accountActionStatus.value = 'success'; + // return; + // } const { mutate: signOutMutation, onDone, onError } = await useMutation(CONNECT_SIGN_OUT); diff --git a/web/store/callbackActions.ts b/web/store/callbackActions.ts index 611d1ced1..07d3a0462 100644 --- a/web/store/callbackActions.ts +++ b/web/store/callbackActions.ts @@ -5,7 +5,15 @@ import { useAccountStore } from '~/store/account'; import { useInstallKeyStore } from '~/store/installKey'; import { useServerStore } from '~/store/server'; import { useUpdateOsStore, useUpdateOsActionsStore } from '~/store/updateOsActions'; -import { useCallbackStoreGeneric, type CallbackActionsStore, type ExternalKeyActions, type QueryPayloads } from '~/store/callback'; +import { + useCallbackStoreGeneric, + type CallbackActionsStore, + type ExternalKeyActions, + type ExternalSignIn, + type ExternalSignOut, + type ExternalUpdateOsAction, + type QueryPayloads, +} from '~/store/callback'; export const useCallbackActionsStore = defineStore('callbackActions', () => { const accountStore = useAccountStore(); @@ -35,6 +43,16 @@ export const useCallbackActionsStore = defineStore('callbackActions', () => { redirectToCallbackType?.(); }; + const actionTypesWithKey = [ + 'recover', + 'replace', + 'trialExtend', + 'trialStart', + 'purchase', + 'redeem', + 'renew', + 'upgrade', + ]; const redirectToCallbackType = () => { console.debug('[redirectToCallbackType]'); if (!callbackData.value || !callbackData.value.type || callbackData.value.type !== 'forUpc' || !callbackData.value.actions?.length) { @@ -49,33 +67,28 @@ export const useCallbackActionsStore = defineStore('callbackActions', () => { callbackData.value.actions.forEach(async (action, index, array) => { console.debug('[redirectToCallbackType]', { action, index, array }); - if (action?.keyUrl) { + if (actionTypesWithKey.includes(action.type)) { await installKeyStore.install(action as ExternalKeyActions); } - if (action?.user || action.type === 'signIn') { - accountStore.setAccountAction(action); - accountStore.setConnectSignInPayload({ - apiKey: action.apiKey, - email: action.user.email, - preferred_username: action.user.preferred_username, + + if (action.type === 'signIn' && action?.user) { + accountStore.setAccountAction(action as ExternalSignIn); + await accountStore.setConnectSignInPayload({ + apiKey: action?.apiKey ?? '', + email: action.user?.email ?? '', + preferred_username: action.user?.preferred_username ?? '', }); } + if (action.type === 'signOut' || action.type === 'oemSignOut') { - accountStore.setAccountAction(action); - accountStore.setQueueConnectSignOut(true); + accountStore.setAccountAction(action as ExternalSignOut); + await accountStore.setQueueConnectSignOut(true); } - if (action.type === 'updateOs' && action?.sha256) { - console.debug('[redirectToCallbackType] updateOs', action); - const foundRelease = await updateOsActionsStore.getReleaseFromKeyServer(action.sha256); - console.debug('[redirectToCallbackType] updateOs foundRelease', foundRelease); - if (!foundRelease) { - throw new Error('Release not found'); - } - if (foundRelease.version === serverStore.osVersion) { - throw new Error('Release version is the same as the server\'s current version'); - } - updateOsActionsStore.confirmUpdateOs(foundRelease); + if (action.type === 'updateOs') { + updateOsActionsStore.setUpdateOsAction(action as ExternalUpdateOsAction); + await updateOsActionsStore.actOnUpdateOsAction(); + if (array.length === 1) { // only 1 action, skip refresh server state console.debug('[redirectToCallbackType] updateOs done'); // removing query string relase is set so users can't refresh the page and go through the same actions diff --git a/web/store/errors.ts b/web/store/errors.ts index 06d8f782f..38976f238 100644 --- a/web/store/errors.ts +++ b/web/store/errors.ts @@ -11,7 +11,7 @@ import type { Server } from '~/types/server'; */ setActivePinia(createPinia()); -export type ErrorType = 'account' | 'callback' | 'installKey' | 'server' | 'serverState' | 'unraidApiGQL' | 'unraidApiState'; +export type ErrorType = 'account' | 'callback' | 'installKey' | 'request' | 'server' | 'serverState' | 'unraidApiGQL' | 'unraidApiState'; export interface Error { actions?: ButtonProps[]; debugServer?: Server; @@ -107,8 +107,14 @@ export const useErrorsStore = defineStore('errors', () => { await new Promise(resolve => setTimeout(resolve, 100)); $panels = $modal.querySelectorAll('.allpanels'); } - $panels.forEach(($panel: HTMLDivElement) => { - if ($panel.id === 'troubleshoot_panel') { $panel.style.display = 'block'; } else { $panel.style.display = 'none'; } + $panels.forEach(($panel: Element) => { + if ($panel.id === 'troubleshoot_panel') { + // @ts-ignore + $panel.style.display = 'block'; + } else { + // @ts-ignore + $panel.style.display = 'none'; + } }); } catch (error) { console.error('[openTroubleshoot]', error); diff --git a/web/store/installKey.ts b/web/store/installKey.ts index 6d738e5af..8c2e16500 100644 --- a/web/store/installKey.ts +++ b/web/store/installKey.ts @@ -55,12 +55,17 @@ export const useInstallKeyStore = defineStore('installKey', () => { } } catch (error) { console.error('[install] WebguiInstallKey error', error); + let errorMessage = 'Unknown error'; + if (typeof error === "string") { + errorMessage = error.toUpperCase(); + } else if (error instanceof Error) { + errorMessage = error.message; + } keyInstallStatus.value = 'failed'; errorsStore.setError({ heading: 'Failed to install key', - message: error.message, + message: errorMessage, level: 'error', - ref: 'installKey', type: 'installKey', }); diff --git a/web/store/replaceRenew.ts b/web/store/replaceRenew.ts index 9b493099a..e104cd058 100644 --- a/web/store/replaceRenew.ts +++ b/web/store/replaceRenew.ts @@ -148,7 +148,7 @@ export const useReplaceRenewStore = defineStore('replaceRenewCheck', () => { const keyLatestResponse: KeyLatestResponse = await keyLatest({ keyfile: keyfile.value, - }).json(); + }); if (keyLatestResponse?.license) { callbackStore.send( diff --git a/web/store/server.ts b/web/store/server.ts index a926ffaea..6fae4ff99 100644 --- a/web/store/server.ts +++ b/web/store/server.ts @@ -15,7 +15,6 @@ import { import { useQuery } from '@vue/apollo-composable'; import { SERVER_STATE_QUERY } from './server.fragment'; -import type { serverStateQuery } from '~/composables/gql/graphql'; import { WebguiState } from '~/composables/services/webgui'; import { WEBGUI_SETTINGS_MANAGMENT_ACCESS } from '~/helpers/urls'; import { useAccountStore } from '~/store/account'; @@ -24,19 +23,19 @@ import { usePurchaseStore } from '~/store/purchase'; import { useThemeStore, type Theme } from '~/store/theme'; import { useUnraidApiStore } from '~/store/unraidApi'; +import type { Cloud, Config, serverStateQuery } from '~/composables/gql/graphql'; import type { Server, ServerAccountCallbackSendPayload, ServerKeyTypeForPurchase, ServerPurchaseCallbackSendPayload, ServerState, - ServerStateCloudStatus, - ServerStateConfigStatus, ServerStateData, ServerStateDataAction, ServerconnectPluginInstalled, ServerDateTimeFormat, ServerStateDataKeyActions, + ServerOsVersionBranch, } from '~/types/server'; /** @@ -65,8 +64,8 @@ export const useServerStore = defineStore('server', () => { }); const apiVersion = ref(''); const avatar = ref(''); // @todo potentially move to a user store - const cloud = ref(); - const config = ref(); + const cloud = ref(); + const config = ref(); const connectPluginInstalled = ref(''); const connectPluginVersion = ref(''); const csrf = ref(''); // required to make requests to Unraid webgui @@ -89,7 +88,7 @@ export const useServerStore = defineStore('server', () => { const locale = ref(''); const name = ref(''); const osVersion = ref(''); - const osVersionBranch = ref<'stable' | 'next' | 'preview' | 'test'>('stable'); + const osVersionBranch = ref('stable'); const registered = ref(); const regDev = ref(0); const regGen = ref(0); @@ -238,7 +237,7 @@ export const useServerStore = defineStore('server', () => { const serverDebugPayload = computed((): Server => { const payload = { - apiKey: apiKey.value ? `${apiKey.value.substring(0, 6)}__[REDACTED]` : '', // so we don't send full api key in email + apiKey: apiKey.value && typeof apiKey.value === 'string' ? `${apiKey.value.substring(0, 6)}__[REDACTED]` : '', // so we don't send full api key in email apiVersion: apiVersion.value, avatar: avatar.value, connectPluginInstalled: connectPluginInstalled.value, @@ -782,12 +781,13 @@ export const useServerStore = defineStore('server', () => { }; const mutateServerStateFromApi = (data: serverStateQuery): Server => { + console.debug('mutateServerStateFromApi', data); const mutatedData = { // if we get an owners obj back and the username is root we don't want to overwrite the values ...(data.owner && data.owner.username !== 'root' ? { // avatar: data.owner.avatar, - username: data.owner.username, + username: data.owner.username ?? '', registered: true, } : { // handles sign outs @@ -796,19 +796,22 @@ export const useServerStore = defineStore('server', () => { registered: false, } ), - name: (data.info && data.info.os) ? data.info.os.hostname : null, - keyfile: (data.registration && data.registration.keyFile) ? data.registration.keyFile.contents : null, - regGen: data.vars ? data.vars.regGen : null, - state: data.vars ? data.vars.regState : null, + name: (data.info && data.info.os && data.info.os.hostname) ? data.info.os.hostname : undefined, + keyfile: (data.registration && data.registration.keyFile && data.registration.keyFile.contents) ? data.registration.keyFile.contents : undefined, + regGen: data.vars && data.vars.regGen ? parseInt(data.vars.regGen) : undefined, + state: data.vars && data.vars.regState? data.vars.regState : undefined, config: data.config ? data.config : { - error: data.vars ? data.vars.configError : null, - valid: data.vars ? data.vars.configValid : true, + error: data.vars && data.vars.configError ? data.vars.configError : undefined, + valid: data.vars && data.vars.configValid ? data.vars.configValid : true, }, - expireTime: (data.registration && data.registration.expiration) ? data.registration.expiration : 0, - ...(data.cloud && { cloud: data.cloud }), + expireTime: (data.registration && data.registration.expiration) ? parseInt(data.registration.expiration) : 0, + cloud: { + ...(data.cloud ?? {}), + }, }; + console.debug('mutatedData', mutatedData); return mutatedData; }; @@ -883,13 +886,13 @@ export const useServerStore = defineStore('server', () => { }, refreshTimeout); }; - const filteredKeyActions = (filterType: 'by' | 'out', filters: ServerStateDataKeyActions[]): ServerStateDataAction[] | undefined => { + const filteredKeyActions = (filterType: 'by' | 'out', filters: string|ServerStateDataKeyActions[]): ServerStateDataAction[] | undefined => { if (!stateData.value.actions) { return; } return stateData.value.actions.filter((action) => { return filterType === 'out' - ? !filters.includes(action.name) - : filters.includes(action.name); + ? !filters.includes(action.name as ServerStateDataKeyActions) + : filters.includes(action.name as ServerStateDataKeyActions); }); }; diff --git a/web/store/trial.ts b/web/store/trial.ts index 8aa0e43c2..3d1186630 100644 --- a/web/store/trial.ts +++ b/web/store/trial.ts @@ -31,7 +31,7 @@ export const useTrialStore = defineStore('trial', () => { guid: serverStore.guid, timestamp: Math.floor(Date.now() / 1000), }; - const response: StartTrialResponse = await startTrial(payload).json(); + const response: StartTrialResponse = await startTrial(payload); if (!response.license) { trialStatus.value = 'failed'; return console.error('[requestTrial]', 'No license returned', response); @@ -48,7 +48,7 @@ export const useTrialStore = defineStore('trial', () => { type: 'forUpc', }; trialStatus.value = 'success'; - return callbackActionsStore.redirectToCallbackType(trialStartData); + return callbackActionsStore.saveCallbackData(trialStartData); } catch (error) { trialStatus.value = 'failed'; console.error('[requestTrial]', error); diff --git a/web/store/unraidApi.ts b/web/store/unraidApi.ts index 5dad258ec..6d949f409 100644 --- a/web/store/unraidApi.ts +++ b/web/store/unraidApi.ts @@ -1,3 +1,4 @@ +// @ts-ignore import { from, ApolloClient, createHttpLink, InMemoryCache, split } from '@apollo/client/core/core.cjs'; import { onError } from '@apollo/client/link/error'; import { RetryLink } from '@apollo/client/link/retry'; @@ -81,12 +82,9 @@ export const useUnraidApiStore = defineStore('unraidApi', () => { }), ); - /** - * @todo integrate errorsStore errorsStore.setError(error); - */ - const errorLink = onError(({ graphQLErrors, networkError }) => { + const errorLink = onError(({ graphQLErrors, networkError }: any) => { if (graphQLErrors) { - graphQLErrors.map((error) => { + graphQLErrors.map((error: any) => { console.error('[GraphQL error]', error); const errorMsg = error.error && error.error.message ? error.error.message : error.message; if (errorMsg && errorMsg.includes('offline')) { @@ -140,9 +138,13 @@ export const useUnraidApiStore = defineStore('unraidApi', () => { }, }); + interface Definintion { + kind: string; + operation?: string; + }; const splitLinks = split( - ({ query }) => { - const definition = getMainDefinition(query); + ({ query }: any) => { + const definition: Definintion = getMainDefinition(query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' @@ -189,21 +191,31 @@ export const useUnraidApiStore = defineStore('unraidApi', () => { */ const restartUnraidApiClient = async () => { const command = unraidApiStatus.value === 'offline' ? 'start' : 'restart'; - console.debug('[restartUnraidApiClient]', { command }); unraidApiStatus.value = 'restarting'; try { const response = await WebguiUnraidApiCommand({ csrf_token: serverStore.csrf, command, }); - console.debug('[restartUnraidApiClient] response', response); return setTimeout(() => { if (unraidApiClient.value) { createApolloClient(); } }, 5000); } catch (error) { - errorsStore.setError(error); + let errorMessage = 'Unknown error'; + if (typeof error === "string") { + errorMessage = error.toUpperCase(); + } else if (error instanceof Error) { + errorMessage = error.message; + } + errorsStore.setError({ + heading: 'Error: unraid-api restart', + message: errorMessage, + level: 'error', + ref: 'restartUnraidApiClient', + type: 'request', + }); } }; diff --git a/web/store/updateOs.ts b/web/store/updateOs.ts index c1a1e3d87..3a919a5bb 100644 --- a/web/store/updateOs.ts +++ b/web/store/updateOs.ts @@ -108,21 +108,21 @@ extend(relativeTime); export const RELEASES_LOCAL_STORAGE_KEY = 'unraidReleasesResponse'; -export const useUpdateOsStoreGeneric = (payload: UpdateOsStorePayload) => +export const useUpdateOsStoreGeneric = (payload?: UpdateOsStorePayload) => defineStore('updateOs', () => { console.debug('[updateOs] payload', payload); // Since this file is shared between account.unraid.net and the web components, we need to handle the state differently // If useUpdateOsActions is passed in, we're in the webgui web components - const updateOsActions = payload.useUpdateOsActions !== undefined ? payload.useUpdateOsActions() : undefined; + const updateOsActions = payload?.useUpdateOsActions !== undefined ? payload.useUpdateOsActions() : undefined; console.debug('[updateOs] updateOsActions', updateOsActions); // If useUpdateOsActions is not passed in, we're in account.unraid.net // creating refs from the passed in values so that we can use them in the computed properties - const paramCurrentOsVersion = ref(payload.currentOsVersion ?? ''); - const paramCurrentOsVersionBranch = ref(payload.currentOsVersionBranch ?? ''); - const paramCurrentRegExp = ref(payload.currentRegExp ?? 0); - const paramCurrentRegUpdatesExpired = ref(payload.currentRegUpdatesExpired ?? false); - const paramCurrentIsLoggedIn = ref(payload.currentIsLoggedIn ?? false); - const paramCurrentAuthUserAttributes = ref(payload.currentAuthUserAttributes ?? {}); + const paramCurrentOsVersion = ref(payload?.currentOsVersion ?? ''); + const paramCurrentOsVersionBranch = ref(payload?.currentOsVersionBranch ?? ''); + const paramCurrentRegExp = ref(payload?.currentRegExp ?? 0); + const paramCurrentRegUpdatesExpired = ref(payload?.currentRegUpdatesExpired ?? false); + const paramCurrentIsLoggedIn = ref(payload?.currentIsLoggedIn ?? false); + const paramCurrentAuthUserAttributes = ref(payload?.currentAuthUserAttributes ?? {}); // getters – when set from updateOsActions we're in the webgui web components otherwise we're in account.unraid.net const osVersion = computed(() => updateOsActions?.osVersion ?? paramCurrentOsVersion.value ?? ''); const osVersionBranch = computed(() => updateOsActions?.osVersionBranch ?? paramCurrentOsVersionBranch.value ?? ''); diff --git a/web/store/updateOsActions.ts b/web/store/updateOsActions.ts index 4bf7abaf6..dc76fa12f 100644 --- a/web/store/updateOsActions.ts +++ b/web/store/updateOsActions.ts @@ -15,6 +15,7 @@ import { type UpdateOsActionStore, } from '~/store/updateOs'; +import type { ExternalUpdateOsAction } from '~/store/callback'; import type { UserProfileLink } from '~/types/userProfile'; /** @@ -33,6 +34,7 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => { const { install: installPlugin } = useInstallPlugin(); // State + const updateAction = ref(); const osVersion = computed(() => serverStore.osVersion); const osVersionBranch = computed(() => serverStore.osVersionBranch); const regExp = computed(() => serverStore.regExp); @@ -121,11 +123,15 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => { ); }; + const setUpdateOsAction = (payload: ExternalUpdateOsAction | undefined) => (updateAction.value = payload); /** * @description When receiving the callback the Account update page we'll use the provided sha256 of the release to get the release from the keyserver */ const getReleaseFromKeyServer = async (sha256: string) => { console.debug('[getReleaseFromKeyServer]', sha256); + if (!sha256) { + throw new Error('No sha256 provided'); + } try { const response = await getOsReleaseBySha256(sha256); console.debug('[getReleaseFromKeyServer]', response); @@ -141,6 +147,18 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => { setStatus('confirming'); }; + const actOnUpdateOsAction = async () => { + const foundRelease = await getReleaseFromKeyServer(updateAction.value?.sha256 ?? ''); + console.debug('[redirectToCallbackType] updateOs foundRelease', foundRelease); + if (!foundRelease) { + throw new Error('Release not found'); + } + if (foundRelease.version === serverStore.osVersion) { + throw new Error('Release version is the same as the server\'s current version'); + } + confirmUpdateOs(foundRelease); + }; + const installOsUpdate = () => { if (!callbackUpdateRelease.value) { return console.error('[installOsUpdate] release not found'); @@ -195,6 +213,7 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => { ineligibleText, toolsRegistrationAction, // Actions + actOnUpdateOsAction, confirmUpdateOs, installOsUpdate, initUpdateOsCallback, @@ -202,6 +221,7 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => { rebootServer, setStatus, setRebootType, + setUpdateOsAction, viewCurrentReleaseNotes, getReleaseFromKeyServer, }; diff --git a/web/types/server.ts b/web/types/server.ts index 4a592fa31..ab3829a39 100644 --- a/web/types/server.ts +++ b/web/types/server.ts @@ -1,14 +1,7 @@ +import type { Cloud, Config } from '~/composables/gql/graphql'; import type { Theme } from '~/store/theme'; import type { UserProfileLink } from '~/types/userProfile'; -export interface ServerStateConfigStatus { - error?: 'INVALID' | 'NO_KEY_SERVER' | 'UNKNOWN_ERROR' | 'WITHDRAWN'; - valid: boolean; -} -export interface ServerStateCloudStatus { - error: string | undefined; -} - export type ServerState = 'BASIC' | 'PLUS' | 'PRO' @@ -37,13 +30,15 @@ export type ServerState = 'BASIC' | 'LIFETIME' | undefined; +export type ServerOsVersionBranch = 'stable' | 'next' | 'preview' | 'test'; + export type ServerconnectPluginInstalled = 'dynamix.unraid.net.plg' | 'dynamix.unraid.net.staging.plg' | 'dynamix.unraid.net.plg_installFailed' | 'dynamix.unraid.net.staging.plg_installFailed' | ''; export interface Server { apiKey?: string; apiVersion?: string; avatar?: string; - cloud?: ServerStateCloudStatus; - config?: ServerStateConfigStatus | undefined; + cloud?: Cloud | undefined; + config?: Config | undefined; connectPluginInstalled?: ServerconnectPluginInstalled; connectPluginVersion?: string; csrf?: string; @@ -62,6 +57,7 @@ export interface Server { locale?: string; name?: string; osVersion?: string; + osVersionBranch?: ServerOsVersionBranch; registered?: boolean; regDev?: number; regGen?: number; @@ -95,10 +91,12 @@ export interface ServerAccountCallbackSendPayload { locale?: string; name?: string; osVersion?: string; + osVersionBranch?: ServerOsVersionBranch; registered: boolean; + regExp?: number; regGen?: number; regGuid?: string; - regExp?: number; + regTy?: string; regUpdatesExpired?: boolean; site?: string; state: ServerState; @@ -117,6 +115,7 @@ export interface ServerPurchaseCallbackSendPayload { keyTypeForPurchase: ServerKeyTypeForPurchase; locale: string; osVersion?: string; + osVersionBranch?: ServerOsVersionBranch; registered: boolean; regExp?: number; regUpdatesExpired?: boolean;