mirror of
https://github.com/unraid/api.git
synced 2026-01-02 14:40:01 -06:00
feat: api offline restart button
This commit is contained in:
@@ -2,26 +2,36 @@
|
||||
import { ExclamationTriangleIcon, CheckCircleIcon } from '@heroicons/vue/24/solid';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import { useServerStore } from '~/store/server';
|
||||
// import { useServerStore } from '~/store/server';
|
||||
import { useUnraidApiStore } from '~/store/unraidApi';
|
||||
|
||||
const serverStore = useServerStore();
|
||||
const { cloud } = storeToRefs(serverStore);
|
||||
// const serverStore = useServerStore();
|
||||
// const { cloud } = storeToRefs(serverStore);
|
||||
const unraidApiStore = useUnraidApiStore();
|
||||
const { unraidApiStatus, unraidApiRestartAction } = storeToRefs(unraidApiStore);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<li class="px-8px flex flex-col items-center">
|
||||
<template v-if="!cloud">
|
||||
<template v-if="unraidApiStatus === 'connecting' || unraidApiStatus === 'restarting'">
|
||||
<BrandLoading class="w-36px mx-auto" />
|
||||
<span class="text-12px italic opacity-80">{{ 'Loading Connect status…' }}</span>
|
||||
<span class="text-12px italic opacity-80">{{ unraidApiStatus === 'connecting' ? 'Loading Connect…' : 'Restarting unraid-api…' }}</span>
|
||||
</template>
|
||||
<span
|
||||
v-else
|
||||
class="w-full flex flex-row justify-start items-center gap-x-8px"
|
||||
:title="!cloud.error ? 'Connect is connected to Unraid cloud services' : cloud.error"
|
||||
>
|
||||
<CheckCircleIcon v-if="!cloud.error" class="text-green-500 w-16px h-16px" />
|
||||
<ExclamationTriangleIcon v-else class="text-red-500 w-16px h-16px" />
|
||||
<span>{{ !cloud.error ? 'Connected' : 'Not connected' }}</span>
|
||||
<template v-if="unraidApiStatus === 'offline'">
|
||||
<ExclamationTriangleIcon class="text-red-500 w-16px h-16px" />
|
||||
{{ 'Not connected' }}
|
||||
</template>
|
||||
<template v-if="unraidApiStatus === 'online'">
|
||||
<CheckCircleIcon class="text-green-500 w-16px h-16px" />
|
||||
{{ 'Connected' }}
|
||||
</template>
|
||||
</span>
|
||||
<div v-if="unraidApiRestartAction" class="w-full -mx-32px">
|
||||
<UpcDropdownItem :item="unraidApiRestartAction" />
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/24/solid';
|
||||
import type { ServerStateDataAction } from '~/types/server';
|
||||
@@ -19,7 +18,6 @@ const showExternalIconOnHover = computed(() => props.item?.external && props.ite
|
||||
<template>
|
||||
<component
|
||||
:is="item?.click ? 'button' : 'a'"
|
||||
@click.stop="item?.click ? item?.click() : null"
|
||||
:href="item?.href ?? null"
|
||||
:title="item?.title ?? null"
|
||||
:target="item?.external ? '_blank' : null"
|
||||
@@ -31,6 +29,7 @@ const showExternalIconOnHover = computed(() => props.item?.external && props.ite
|
||||
'group': showExternalIconOnHover,
|
||||
'rounded-md': rounded,
|
||||
}"
|
||||
@click.stop="item?.click ? item?.click() : null"
|
||||
>
|
||||
<span class="leading-snug inline-flex flex-row items-center gap-x-8px">
|
||||
<component :is="item?.icon" class="flex-shrink-0 text-current w-16px h-16px" aria-hidden="true" />
|
||||
|
||||
@@ -59,10 +59,10 @@ export const WebguiUnraidApiCommand = async (payload: WebguiUnraidApiCommandPayl
|
||||
})
|
||||
.post()
|
||||
.json((json) => {
|
||||
log.debug('👼 [WebguiUnraidApiCommand] json %o', json);
|
||||
console.debug('👼 [WebguiUnraidApiCommand]', json);
|
||||
})
|
||||
.catch((error) => {
|
||||
log.error(`[WebguiUnraidApiCommand] catch failed to execute unraid-api ${command} 😢 %o`, error);
|
||||
console.error(`[WebguiUnraidApiCommand] catch failed to execute unraid-api ${command} 😢`, error);
|
||||
});
|
||||
return response;
|
||||
};
|
||||
|
||||
@@ -736,15 +736,12 @@ export const useServerStore = defineStore('server', () => {
|
||||
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,
|
||||
// avatar: data.owner.avatar,
|
||||
username: data.owner.username,
|
||||
registered: true,
|
||||
}),
|
||||
// if owners obj is empty we need to sign user out
|
||||
// ...(context.state.signOutTriggered && { username: '', avatar: '', registered: false }),
|
||||
name: (data.info && data.info.os) ? data.info.os.hostname : null,
|
||||
keyfile: (data.registration && data.registration.keyFile) ? data.registration.keyFile.contents : null,
|
||||
// sendCrashInfo: data.crashReportingEnabled,
|
||||
regGen: data.vars ? data.vars.regGen : null,
|
||||
state: data.vars ? data.vars.regState : null,
|
||||
config: data.config
|
||||
|
||||
@@ -2,12 +2,14 @@ import { from, ApolloClient, createHttpLink, InMemoryCache, split } from '@apoll
|
||||
import { onError } from '@apollo/client/link/error';
|
||||
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
||||
import { getMainDefinition } from '@apollo/client/utilities';
|
||||
import { ArrowPathIcon } from '@heroicons/vue/24/solid';
|
||||
import { provideApolloClient } from '@vue/apollo-composable';
|
||||
import { logErrorMessages } from '@vue/apollo-util';
|
||||
// import { logErrorMessages } from '@vue/apollo-util';
|
||||
import { createClient } from 'graphql-ws';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import { UserProfileLink } from 'types/userProfile';
|
||||
|
||||
// import { WebguiUnraidApiCommand } from '~/composables/services/webgui';
|
||||
import { WebguiUnraidApiCommand } from '~/composables/services/webgui';
|
||||
import { useAccountStore } from '~/store/account';
|
||||
// import { useErrorsStore } from '~/store/errors';
|
||||
import { useServerStore } from '~/store/server';
|
||||
@@ -41,10 +43,17 @@ export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
watch(unraidApiClient, (newVal, oldVal) => {
|
||||
console.debug('[watch:unraidApiStore.unraidApiClient]', { newVal, oldVal });
|
||||
if (newVal && !oldVal) { // first time
|
||||
unraidApiStatus.value = 'online';
|
||||
serverStore.fetchServerFromApi();
|
||||
}
|
||||
});
|
||||
|
||||
// const unraidApiErrors = ref<any[]>([]);
|
||||
const unraidApiStatus = ref<'connecting' | 'offline' | 'online' | 'restarting'>('offline');
|
||||
watch(unraidApiStatus, (newVal, oldVal) => {
|
||||
console.debug('[watch:unraidApiStore.unraidApiStatus]', { newVal, oldVal });
|
||||
});
|
||||
|
||||
/**
|
||||
* Automatically called when an apiKey is set in the serverStore
|
||||
*/
|
||||
@@ -53,6 +62,9 @@ export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
if (accountStore.accountActionType === 'signOut') {
|
||||
return console.debug('[useUnraidApiStore.createApolloClient] sign out imminent, skipping createApolloClient');
|
||||
}
|
||||
|
||||
unraidApiStatus.value = 'connecting';
|
||||
|
||||
const headers = { 'x-api-key': serverStore.apiKey };
|
||||
|
||||
const httpLink = createHttpLink({
|
||||
@@ -71,21 +83,23 @@ export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
|
||||
/**
|
||||
* @todo integrate errorsStore errorsStore.setError(error);
|
||||
* { graphQLErrors, networkError }
|
||||
*/
|
||||
const errorLink = onError((errors) => {
|
||||
logErrorMessages(errors);
|
||||
// clientErrors.value = errors;
|
||||
// if (graphQLErrors) {
|
||||
// logErrorMessages(graphQLErrors);
|
||||
// // graphQLErrors.map(({ message, locations, path }) => {
|
||||
// // // console.error(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`);
|
||||
// // })
|
||||
// }
|
||||
const errorLink = onError(({ graphQLErrors, networkError }) => {
|
||||
if (graphQLErrors) {
|
||||
console.debug('[GraphQL error]', graphQLErrors);
|
||||
graphQLErrors.map((error) => {
|
||||
console.error('[GraphQL error]', error, error.error.message);
|
||||
if (error.error.message.includes('offline')) {
|
||||
unraidApiStatus.value = 'offline';
|
||||
}
|
||||
return error.message;
|
||||
});
|
||||
console.debug('[GraphQL error]', graphQLErrors);
|
||||
}
|
||||
|
||||
// if (networkError) {
|
||||
// logErrorMessages(networkError);
|
||||
// }
|
||||
if (networkError) {
|
||||
console.error(`[Network error]: ${networkError}`);
|
||||
}
|
||||
});
|
||||
|
||||
const splitLinks = split(
|
||||
@@ -129,43 +143,58 @@ export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
// (wsLink.value as any).subscriptionClient.close(); // needed if we start using subscriptions
|
||||
}
|
||||
unraidApiClient.value = undefined;
|
||||
unraidApiStatus.value = 'offline';
|
||||
console.debug('[useUnraidApiStore.closeUnraidApiClient] DONE');
|
||||
};
|
||||
|
||||
// const clientErrors = ref<any>();
|
||||
// const offlineTimer = ref(false);
|
||||
// const enableRestartUnraidApiClient = computed(() => {
|
||||
// const { connectPluginInstalled, stateDataError } = serverStore;
|
||||
// return clientErrors.value && connectPluginInstalled && !stateDataError;
|
||||
// });
|
||||
|
||||
const unraidApiRestartAction = computed((): UserProfileLink | undefined => {
|
||||
const { connectPluginInstalled, stateDataError } = serverStore;
|
||||
if (unraidApiStatus.value !== 'offline' || !connectPluginInstalled || stateDataError) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
click: () => restartUnraidApiClient(),
|
||||
emphasize: true,
|
||||
icon: ArrowPathIcon,
|
||||
name: 'Restart unraid-api',
|
||||
text: 'Restart unraid-api',
|
||||
title: 'Restart unraid-api',
|
||||
};
|
||||
});
|
||||
// /**
|
||||
// * @name detectOfflineTimer
|
||||
// * @description if after 30secs the api isn't started we want to possibly enable apiEnableRestartButton
|
||||
// * @param {String} from
|
||||
// */
|
||||
// const detectOfflineTimer = () => {
|
||||
// console.debug('[detectOfflineTimer]');
|
||||
// setTimeout(() => {
|
||||
// if (!unraidApiClient.value && serverStore.registered) {
|
||||
// offlineTimer.value = true;
|
||||
// // offlineTimer.value = true;
|
||||
// sessionStorage.setItem('offlineTimer', Date.now());
|
||||
// }
|
||||
// }, 30000);
|
||||
// };
|
||||
// const restartUnraidApiClient = () => {
|
||||
// WebguiUnraidApiCommand({
|
||||
// csrf_token: serverStore.csrfToken,
|
||||
// command: 'start',
|
||||
// });
|
||||
// // reset so the detectOfflineTimer can be used again without a page refresh
|
||||
// offlineTimer.value = false;
|
||||
// this.restartTriggered = true;
|
||||
// sessionStorage.removeItem('offlineTimer');
|
||||
// };
|
||||
const restartUnraidApiClient = async () => {
|
||||
unraidApiStatus.value = 'restarting';
|
||||
const response = await WebguiUnraidApiCommand({
|
||||
csrf_token: serverStore.csrf,
|
||||
command: 'start',
|
||||
});
|
||||
console.debug('[restartUnraidApiClient]', response);
|
||||
// reset so the detectOfflineTimer can be used again without a page refresh
|
||||
// offlineTimer.value = false;
|
||||
// this.restartTriggered = true;
|
||||
// sessionStorage.removeItem('offlineTimer');
|
||||
};
|
||||
|
||||
return {
|
||||
unraidApiClient,
|
||||
unraidApiStatus,
|
||||
unraidApiRestartAction,
|
||||
createApolloClient,
|
||||
closeUnraidApiClient,
|
||||
restartUnraidApiClient,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface Server {
|
||||
flashProduct?: string;
|
||||
flashVendor?: string;
|
||||
guid?: string;
|
||||
inIframe: boolean;
|
||||
inIframe?: boolean;
|
||||
keyfile?: string;
|
||||
lanIp?: string;
|
||||
license?: string;
|
||||
@@ -63,7 +63,7 @@ export interface Server {
|
||||
regGuid?: string;
|
||||
site?: string;
|
||||
state?: ServerState;
|
||||
theme: Theme | undefined;
|
||||
theme?: Theme | undefined;
|
||||
uptime?: number;
|
||||
username?: string;
|
||||
wanFQDN?: string;
|
||||
|
||||
Reference in New Issue
Block a user