fix(web): type errors

This commit is contained in:
Zack Spear
2023-10-31 15:53:39 -07:00
committed by Zack Spear
parent 220a64ebdc
commit 5cbccb06ad
18 changed files with 174 additions and 95 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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',
});

View File

@@ -148,7 +148,7 @@ export const useReplaceRenewStore = defineStore('replaceRenewCheck', () => {
const keyLatestResponse: KeyLatestResponse = await keyLatest({
keyfile: keyfile.value,
}).json();
});
if (keyLatestResponse?.license) {
callbackStore.send(

View File

@@ -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<string>('');
const avatar = ref<string>(''); // @todo potentially move to a user store
const cloud = ref<ServerStateCloudStatus>();
const config = ref<ServerStateConfigStatus>();
const cloud = ref<Cloud | undefined>();
const config = ref<Config | undefined>();
const connectPluginInstalled = ref<ServerconnectPluginInstalled>('');
const connectPluginVersion = ref<string>('');
const csrf = ref<string>(''); // required to make requests to Unraid webgui
@@ -89,7 +88,7 @@ export const useServerStore = defineStore('server', () => {
const locale = ref<string>('');
const name = ref<string>('');
const osVersion = ref<string>('');
const osVersionBranch = ref<'stable' | 'next' | 'preview' | 'test'>('stable');
const osVersionBranch = ref<ServerOsVersionBranch>('stable');
const registered = ref<boolean>();
const regDev = ref<number>(0);
const regGen = ref<number>(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);
});
};

View File

@@ -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);

View File

@@ -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',
});
}
};

View File

@@ -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<SemVer | string>(payload.currentOsVersion ?? '');
const paramCurrentOsVersionBranch = ref<SemVer | string>(payload.currentOsVersionBranch ?? '');
const paramCurrentRegExp = ref<number>(payload.currentRegExp ?? 0);
const paramCurrentRegUpdatesExpired = ref<boolean>(payload.currentRegUpdatesExpired ?? false);
const paramCurrentIsLoggedIn = ref<boolean>(payload.currentIsLoggedIn ?? false);
const paramCurrentAuthUserAttributes = ref<UserInfo>(payload.currentAuthUserAttributes ?? {});
const paramCurrentOsVersion = ref<SemVer | string>(payload?.currentOsVersion ?? '');
const paramCurrentOsVersionBranch = ref<SemVer | string>(payload?.currentOsVersionBranch ?? '');
const paramCurrentRegExp = ref<number>(payload?.currentRegExp ?? 0);
const paramCurrentRegUpdatesExpired = ref<boolean>(payload?.currentRegUpdatesExpired ?? false);
const paramCurrentIsLoggedIn = ref<boolean>(payload?.currentIsLoggedIn ?? false);
const paramCurrentAuthUserAttributes = ref<UserInfo>(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 ?? '');

View File

@@ -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<ExternalUpdateOsAction | undefined>();
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,
};