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
8 changes: 3 additions & 5 deletions web/components/Notifications/List.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useQuery } from '@vue/apollo-composable';
import { vInfiniteScroll } from '@vueuse/components';
import { useFragment } from '~/composables/gql/fragment-masking';
import type { Importance, NotificationType } from '~/composables/gql/graphql';
import { useUnraidApiStore } from '~/store/unraidApi';
import { getNotifications, NOTIFICATION_FRAGMENT } from './graphql/notification.query';

/**
Expand All @@ -28,6 +29,7 @@ watch(props, () => {
canLoadMore.value = true;
});

const { offlineError } = useUnraidApiStore();
const { result, error, loading, fetchMore, refetch } = useQuery(getNotifications, () => ({
filter: {
offset: 0,
Expand All @@ -37,10 +39,6 @@ const { result, error, loading, fetchMore, refetch } = useQuery(getNotifications
},
}));

watch(error, (newVal) => {
console.log('[getNotifications] error:', newVal);
});

const notifications = computed(() => {
if (!result.value?.notifications.list) return [];
const list = useFragment(NOTIFICATION_FRAGMENT, result.value?.notifications.list);
Expand Down Expand Up @@ -85,7 +83,7 @@ async function onLoadMore() {
</div>
</div>

<LoadingError v-else :loading="loading" :error="error" @retry="refetch">
<LoadingError v-else :loading="loading" :error="offlineError ?? error" @retry="refetch">
<div v-if="notifications?.length === 0" class="contents">
<CheckIcon class="h-10 text-green-600 translate-y-3" />
{{ `No ${props.importance?.toLowerCase() ?? ''} notifications to see here!` }}
Expand Down
2 changes: 1 addition & 1 deletion web/helpers/create-apollo-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const errorLink = onError(({ graphQLErrors, networkError }: any) => {
console.error('[GraphQL error]', error);
const errorMsg = error.error?.message ?? error.message;
if (errorMsg?.includes('offline')) {
// @todo restart the api
// @todo restart the api, but make sure not to trigger infinite loop
}
return error.message;
});
Expand Down
83 changes: 48 additions & 35 deletions web/store/unraidApi.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,63 @@
import {
type ApolloClient as ApolloClientType,
type NormalizedCacheObject,
} from "@apollo/client";
import { ArrowPathIcon } from "@heroicons/vue/24/solid";
import { type ApolloClient as ApolloClientType, type NormalizedCacheObject } from '@apollo/client';
import { ArrowPathIcon } from '@heroicons/vue/24/solid';
import { WebguiUnraidApiCommand } from '~/composables/services/webgui';
import { client } from '~/helpers/create-apollo-client';
import { useErrorsStore } from '~/store/errors';
import { useServerStore } from '~/store/server';
import type { UserProfileLink } from '~/types/userProfile';
// import { logErrorMessages } from '@vue/apollo-util';
import { defineStore, createPinia, setActivePinia } from "pinia";
import type { UserProfileLink } from "~/types/userProfile";

import { WebguiUnraidApiCommand } from "~/composables/services/webgui";
import { useErrorsStore } from "~/store/errors";
import { useServerStore } from "~/store/server";

import { client } from "~/helpers/create-apollo-client";
import { createPinia, defineStore, setActivePinia } from 'pinia';

/**
* @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 useUnraidApiStore = defineStore("unraidApi", () => {
export const useUnraidApiStore = defineStore('unraidApi', () => {
const errorsStore = useErrorsStore();
const serverStore = useServerStore();
const unraidApiClient = ref<ApolloClientType<NormalizedCacheObject> | null>(
client
);
const unraidApiClient = ref<ApolloClientType<NormalizedCacheObject> | null>(client);

// const unraidApiErrors = ref<any[]>([]);
const unraidApiStatus = ref<
"connecting" | "offline" | "online" | "restarting"
>("offline");
const unraidApiStatus = ref<'connecting' | 'offline' | 'online' | 'restarting'>('offline');
const prioritizeCorsError = ref(false); // Ensures we don't overwrite this specific error message with a non-descriptive network error message

const offlineError = computed(() => {
if (unraidApiStatus.value === 'offline') {
return new Error('The Unraid API is currently offline.');
}
});
// maintains an error in global store while api is offline
watch(
offlineError,
(error) => {
const errorId = 'unraidApiOffline';
if (error) {
errorsStore.setError({
heading: 'Warning: API is offline!',
message: error.message,
ref: errorId,
level: 'warning',
type: 'unraidApiState',
});
} else {
errorsStore.removeErrorByRef(errorId);
}
},
{ immediate: true }
);

const unraidApiRestartAction = computed((): UserProfileLink | undefined => {
const { connectPluginInstalled, stateDataError } = serverStore;
if (
unraidApiStatus.value !== "offline" ||
!connectPluginInstalled ||
stateDataError
) {
if (unraidApiStatus.value !== 'offline' || !connectPluginInstalled || stateDataError) {
return undefined;
}
return {
click: () => restartUnraidApiClient(),
emphasize: true,
icon: ArrowPathIcon,
text: "Restart unraid-api",
text: 'Restart unraid-api',
};
});

Expand All @@ -62,39 +74,40 @@ export const useUnraidApiStore = defineStore("unraidApi", () => {
// (wsLink.value as any).subscriptionClient.close(); // needed if we start using subscriptions
}
unraidApiClient.value = null;
unraidApiStatus.value = "offline";
unraidApiStatus.value = 'offline';
};
/**
* Can both start and restart the unraid-api depending on it's current status
*/
const restartUnraidApiClient = async () => {
const command = unraidApiStatus.value === "offline" ? "start" : "restart";
unraidApiStatus.value = "restarting";
const command = unraidApiStatus.value === 'offline' ? 'start' : 'restart';
unraidApiStatus.value = 'restarting';
try {
await WebguiUnraidApiCommand({
csrf_token: serverStore.csrf,
command,
});
} catch (error) {
let errorMessage = "Unknown error";
if (typeof error === "string") {
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",
heading: 'Error: unraid-api restart',
message: errorMessage,
level: "error",
ref: "restartUnraidApiClient",
type: "request",
level: 'error',
ref: 'restartUnraidApiClient',
type: 'request',
});
}
};

return {
unraidApiClient,
unraidApiStatus,
offlineError,
prioritizeCorsError,
unraidApiRestartAction,
closeUnraidApiClient,
Expand Down
Loading