Files
firefrost-services/services/modpack-version-checker/blueprint-extension/views/server/wrapper.tsx
Claude (Chronicler #63) c160647f0b fix(modpackchecker): Move card to right column, match StatBlock style
build.sh:
- Changed injection from ServerConsoleContainer to AfterInformation.tsx
- Card now appears in right column after Network stats

wrapper.tsx:
- Redesigned to match Pterodactyl StatBlock aesthetic
- Uses Tailwind classes (bg-gray-600, rounded, etc.)
- FontAwesome cube icon with status colors
- Compact layout: title + Check button on one line
- Fire (#FF6B35/orange-400) for updates, Frost (#4ECDC4/cyan-400) for current

Fixes layout issue identified in Wizard review.

Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
2026-04-06 12:21:19 +00:00

112 lines
4.3 KiB
TypeScript

import React, { useState } from 'react';
import { ServerContext } from '@/state/server';
import http from '@/api/http';
import { faCube } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
interface VersionData {
success: boolean;
platform?: string;
modpack_id?: string;
modpack_name?: string;
current_version?: string;
latest_version?: string;
status?: string;
message?: string;
error?: string;
}
const ModpackVersionCard: React.FC = () => {
const uuid = ServerContext.useStoreState((state) => state.server.data?.uuid);
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
const [data, setData] = useState<VersionData | null>(null);
const checkForUpdates = async () => {
if (!uuid) return;
setStatus('loading');
try {
const response = await http.post(`/api/client/extensions/modpackchecker/servers/${uuid}/check`);
setData(response.data);
setStatus(response.data.success ? 'success' : 'error');
} catch (error: any) {
if (error.response?.status === 429) {
setData({
success: false,
error: 'Rate limit reached. Please wait 60 seconds.',
});
} else {
setData({
success: false,
error: error.response?.data?.message || 'Failed to check for updates',
});
}
setStatus('error');
}
};
// Match StatBlock styling from Pterodactyl
return (
<div className={'bg-gray-600 rounded p-3 mt-2'}>
<div className={'flex items-center justify-between'}>
<div className={'flex items-center'}>
<FontAwesomeIcon
icon={faCube}
className={`w-4 h-4 mr-2 ${
status === 'success' && data?.status === 'update_available'
? 'text-orange-400'
: status === 'success'
? 'text-cyan-400'
: 'text-gray-400'
}`}
/>
<span className={'text-gray-200 text-sm font-medium'}>Modpack</span>
</div>
{status === 'idle' && (
<button
onClick={checkForUpdates}
className={'text-xs text-cyan-400 hover:text-cyan-300 transition-colors'}
>
Check
</button>
)}
{status === 'success' && (
<button
onClick={checkForUpdates}
className={'text-xs text-gray-400 hover:text-gray-300 transition-colors'}
>
Refresh
</button>
)}
</div>
<div className={'mt-1'}>
{status === 'idle' && (
<span className={'text-gray-400 text-sm'}>Click to check</span>
)}
{status === 'loading' && (
<span className={'text-gray-400 text-sm'}>Checking...</span>
)}
{status === 'success' && data?.success && (
<div>
<span className={'text-white text-sm font-semibold'}>
{data.modpack_name || data.modpack_id}
</span>
<span className={`ml-2 text-xs ${
data.status === 'update_available' ? 'text-orange-400' : 'text-cyan-400'
}`}>
{data.status === 'update_available' ? `${data.latest_version}` : 'Up to date'}
</span>
</div>
)}
{(status === 'error' || (status === 'success' && !data?.success)) && (
<span className={'text-red-400 text-xs'}>
{data?.error || data?.message || 'Error'}
</span>
)}
</div>
</div>
);
};
export default ModpackVersionCard;