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:
Eli Bosley
2025-09-16 13:04:01 -04:00
committed by GitHub
parent 9714b21c5c
commit 1d9ce0aa3d
9 changed files with 172 additions and 9 deletions

2
web/components.d.ts vendored
View File

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

View File

@@ -0,0 +1,5 @@
<script lang="ts">
import ApiStatus from '@/components/ApiStatus/ApiStatus.vue';
export default ApiStatus;
</script>

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

View File

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

View File

@@ -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) => {