mirror of
https://github.com/unraid/api.git
synced 2026-01-06 08:39:54 -06:00
feat: add unraid api status manager (#1708)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added “Unraid API Status” page under Management Access to view current API status, refresh it, and restart the API with confirmation. - Status view shows running state, detailed output, and in-app success/error messages after actions. - Style - Minor theme adjustments to border colors; no layout changes expected. - Chores - Updated UI text: “Unraid API” → “Unraid API Settings” in settings. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
2
web/components.d.ts
vendored
2
web/components.d.ts
vendored
@@ -16,6 +16,8 @@ declare module 'vue' {
|
||||
ApiKeyCreate: typeof import('./src/components/ApiKey/ApiKeyCreate.vue')['default']
|
||||
ApiKeyManager: typeof import('./src/components/ApiKey/ApiKeyManager.vue')['default']
|
||||
'ApiKeyPage.standalone': typeof import('./src/components/ApiKeyPage.standalone.vue')['default']
|
||||
ApiStatus: typeof import('./src/components/ApiStatus/ApiStatus.vue')['default']
|
||||
'ApiStatus.standalone': typeof import('./src/components/ApiStatus/ApiStatus.standalone.vue')['default']
|
||||
'Auth.standalone': typeof import('./src/components/Auth.standalone.vue')['default']
|
||||
Avatar: typeof import('./src/components/Brand/Avatar.vue')['default']
|
||||
Beta: typeof import('./src/components/UserProfile/Beta.vue')['default']
|
||||
|
||||
5
web/src/components/ApiStatus/ApiStatus.standalone.vue
Normal file
5
web/src/components/ApiStatus/ApiStatus.standalone.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<script lang="ts">
|
||||
import ApiStatus from '@/components/ApiStatus/ApiStatus.vue';
|
||||
|
||||
export default ApiStatus;
|
||||
</script>
|
||||
139
web/src/components/ApiStatus/ApiStatus.vue
Normal file
139
web/src/components/ApiStatus/ApiStatus.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
import { WebguiUnraidApiCommand } from '~/composables/services/webgui';
|
||||
import { useServerStore } from '~/store/server';
|
||||
|
||||
const serverStore = useServerStore();
|
||||
|
||||
const apiStatus = ref<string>('');
|
||||
const isRunning = ref<boolean>(false);
|
||||
const isLoading = ref<boolean>(false);
|
||||
const isRestarting = ref<boolean>(false);
|
||||
const statusMessage = ref<string>('');
|
||||
const messageType = ref<'success' | 'error' | 'info' | ''>('');
|
||||
|
||||
const checkStatus = async () => {
|
||||
isLoading.value = true;
|
||||
statusMessage.value = '';
|
||||
try {
|
||||
const response = await WebguiUnraidApiCommand({
|
||||
csrf_token: serverStore.csrf,
|
||||
command: 'status',
|
||||
});
|
||||
|
||||
if (response?.result) {
|
||||
apiStatus.value = response.result;
|
||||
isRunning.value =
|
||||
response.result.includes('running') ||
|
||||
response.result.includes('active') ||
|
||||
response.result.includes('status : online');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get API status:', error);
|
||||
apiStatus.value = 'Error fetching status';
|
||||
isRunning.value = false;
|
||||
statusMessage.value = 'Failed to fetch API status';
|
||||
messageType.value = 'error';
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const restartApi = async () => {
|
||||
const confirmed = window.confirm(
|
||||
'Are you sure you want to restart the Unraid API service? This will temporarily interrupt API connections.'
|
||||
);
|
||||
|
||||
if (!confirmed) return;
|
||||
|
||||
isRestarting.value = true;
|
||||
statusMessage.value = 'Restarting API service...';
|
||||
messageType.value = 'info';
|
||||
|
||||
try {
|
||||
const response = await WebguiUnraidApiCommand({
|
||||
csrf_token: serverStore.csrf,
|
||||
command: 'restart',
|
||||
});
|
||||
|
||||
if (response?.success) {
|
||||
statusMessage.value = 'API service restart initiated. Please wait a few seconds.';
|
||||
messageType.value = 'success';
|
||||
setTimeout(() => {
|
||||
checkStatus();
|
||||
}, 3000);
|
||||
} else {
|
||||
statusMessage.value = response?.error || 'Failed to restart API service';
|
||||
messageType.value = 'error';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to restart API:', error);
|
||||
statusMessage.value = 'Failed to restart API service';
|
||||
messageType.value = 'error';
|
||||
} finally {
|
||||
isRestarting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
checkStatus();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-muted border-muted my-4 rounded-lg border p-6">
|
||||
<div class="mb-4">
|
||||
<h3 class="mb-2 text-lg font-semibold">API Service Status</h3>
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="font-medium">Status:</span>
|
||||
<span :class="['font-semibold', isRunning ? 'text-green-500' : 'text-orange-500']">
|
||||
{{ isLoading ? 'Loading...' : isRunning ? 'Running' : 'Not Running' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<pre
|
||||
class="max-h-52 overflow-y-auto rounded bg-black p-4 font-mono text-xs break-words whitespace-pre-wrap text-white"
|
||||
>{{ apiStatus }}</pre
|
||||
>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="statusMessage"
|
||||
:class="[
|
||||
'my-4 rounded px-4 py-3 text-sm',
|
||||
messageType === 'success' && 'bg-green-500 text-white',
|
||||
messageType === 'error' && 'bg-red-500 text-white',
|
||||
messageType === 'info' && 'bg-blue-500 text-white',
|
||||
]"
|
||||
>
|
||||
{{ statusMessage }}
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex gap-4">
|
||||
<button
|
||||
@click="checkStatus"
|
||||
:disabled="isLoading"
|
||||
class="bg-secondary hover:bg-secondary/80 text-secondary-foreground rounded px-4 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
{{ isLoading ? 'Refreshing...' : 'Refresh Status' }}
|
||||
</button>
|
||||
<button
|
||||
@click="restartApi"
|
||||
:disabled="isRestarting"
|
||||
class="bg-destructive hover:bg-destructive/90 text-destructive-foreground rounded px-4 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
{{ isRestarting ? 'Restarting...' : 'Restart API' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="border-muted mt-6 border-t pt-4">
|
||||
<p class="text-muted-foreground text-sm">
|
||||
View the current status of the Unraid API service and restart if needed. Use this to debug API
|
||||
connection issues.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -141,4 +141,9 @@ export const componentMappings: ComponentMapping[] = [
|
||||
selector: 'unraid-test-theme-switcher',
|
||||
appId: 'test-theme-switcher',
|
||||
},
|
||||
{
|
||||
component: defineAsyncComponent(() => import('../ApiStatus/ApiStatus.standalone.vue')),
|
||||
selector: 'unraid-api-status-manager',
|
||||
appId: 'api-status-manager',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -35,7 +35,7 @@ export const WebguiState = request.url('/plugins/dynamix.my.servers/data/server-
|
||||
*/
|
||||
export interface WebguiUnraidApiCommandPayload {
|
||||
csrf_token: string;
|
||||
command: 'report' | 'restart' | 'start';
|
||||
command: 'report' | 'restart' | 'start' | 'status';
|
||||
param1?: '-v' | '-vv';
|
||||
}
|
||||
export const WebguiUnraidApiCommand = async (payload: WebguiUnraidApiCommandPayload) => {
|
||||
|
||||
Reference in New Issue
Block a user