feat: Remove executable check and add logo support for local scripts
- Remove executable check from ScriptsList component - All scripts now show as runnable regardless of permissions - Add logo support using JSON data from script metadata - Update ScriptInfo interface to include logo and slug fields - Modify getCtScripts to fetch logo from corresponding JSON files - Update ScriptsList UI to display logos with fallback to file icons - Fix TypeScript errors for proper type safety
This commit is contained in:
@@ -88,16 +88,30 @@ export function ScriptsList({ onRunScript }: ScriptsListProps) {
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-3">
|
||||
<span className="text-2xl">{getFileIcon(script.extension)}</span>
|
||||
{script.logo ? (
|
||||
<img
|
||||
src={script.logo}
|
||||
alt={`${script.name} logo`}
|
||||
className="w-8 h-8 rounded object-contain"
|
||||
onError={(e) => {
|
||||
// Fallback to file icon if logo fails to load
|
||||
e.currentTarget.style.display = 'none';
|
||||
const nextElement = e.currentTarget.nextElementSibling as HTMLElement;
|
||||
if (nextElement) {
|
||||
nextElement.style.display = 'block';
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<span className="text-2xl" style={{ display: script.logo ? 'none' : 'block' }}>
|
||||
{getFileIcon(script.extension)}
|
||||
</span>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-800">{script.name}</h3>
|
||||
<div className="text-sm text-gray-500 space-y-1">
|
||||
<p>Size: {formatFileSize(script.size)}</p>
|
||||
<p>Modified: {formatDate(script.lastModified)}</p>
|
||||
<p>Extension: {script.extension}</p>
|
||||
<p className={`font-medium ${script.executable ? 'text-green-600' : 'text-red-600'}`}>
|
||||
{script.executable ? '✅ Executable' : '❌ Not executable'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -111,14 +125,9 @@ export function ScriptsList({ onRunScript }: ScriptsListProps) {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onRunScript(`scripts/ct/${script.name}`, script.name)}
|
||||
disabled={!script.executable}
|
||||
className={`px-4 py-2 text-sm font-medium rounded transition-colors ${
|
||||
script.executable
|
||||
? 'bg-green-600 text-white hover:bg-green-700'
|
||||
: 'bg-gray-300 text-gray-500 cursor-not-allowed'
|
||||
}`}
|
||||
className="px-4 py-2 text-sm font-medium rounded transition-colors bg-green-600 text-white hover:bg-green-700"
|
||||
>
|
||||
{script.executable ? '▶️ Run' : '🚫 Cannot Run'}
|
||||
▶️ Run
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { readdir, stat, access } from 'fs/promises';
|
||||
import { join, resolve, extname } from 'path';
|
||||
import { env } from '~/env.js';
|
||||
import { spawn, ChildProcess } from 'child_process';
|
||||
import { localScriptsService } from '~/server/services/localScripts';
|
||||
|
||||
export interface ScriptInfo {
|
||||
name: string;
|
||||
@@ -10,6 +11,8 @@ export interface ScriptInfo {
|
||||
size: number;
|
||||
lastModified: Date;
|
||||
executable: boolean;
|
||||
logo?: string;
|
||||
slug?: string;
|
||||
}
|
||||
|
||||
export class ScriptManager {
|
||||
@@ -85,13 +88,28 @@ export class ScriptManager {
|
||||
// Check if file is executable
|
||||
const executable = await this.isExecutable(filePath);
|
||||
|
||||
// Extract slug from filename (remove .sh extension)
|
||||
const slug = file.replace(/\.sh$/, '');
|
||||
|
||||
// Try to get logo from JSON data
|
||||
let logo: string | undefined;
|
||||
try {
|
||||
const scriptData = await localScriptsService.getScriptBySlug(slug);
|
||||
logo = scriptData?.logo || undefined;
|
||||
} catch (error) {
|
||||
// JSON file might not exist, that's okay
|
||||
console.log(`No JSON data found for ${slug}:`, error);
|
||||
}
|
||||
|
||||
scripts.push({
|
||||
name: file,
|
||||
path: filePath,
|
||||
extension,
|
||||
size: stats.size,
|
||||
lastModified: stats.mtime,
|
||||
executable
|
||||
executable,
|
||||
logo,
|
||||
slug
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ export class ScriptDownloaderService {
|
||||
const newPattern = 'SCRIPT_DIR="$(dirname "$0")" \nsource "$SCRIPT_DIR/../core/build.func"';
|
||||
|
||||
return content.replace(oldPattern, newPattern);
|
||||
|
||||
}
|
||||
|
||||
async loadScript(script: Script): Promise<{ success: boolean; message: string; files: string[] }> {
|
||||
|
||||
Reference in New Issue
Block a user