Fix: Detect downloaded scripts from all directories (ct, tools, vm, vw) (#120)
* Fix: Detect downloaded scripts from all directories (ct, tools, vm, vw) - Add getAllDownloadedScripts() method to scan all script directories - Update DownloadedScriptsTab to use new API endpoint - Update ScriptsGrid to use new API endpoint for download status detection - Update main page script counts to use new API endpoint - Add recursive directory scanning to handle subdirectories - Maintain backward compatibility with existing getCtScripts endpoint Fixes issue where scripts downloaded to tools/, vm/, or vw/ directories were not showing in Downloaded Scripts tab or showing correct download status in Available Scripts tab. * Fix: Remove redundant type annotation and method call arguments - Remove redundant string type annotation from relativePath parameter - Fix getScriptsFromDirectory method call to match updated signature
This commit is contained in:
committed by
GitHub
parent
c12c96cfb9
commit
9d83697d45
@@ -37,7 +37,7 @@ export function DownloadedScriptsTab({ onInstallScript }: DownloadedScriptsTabPr
|
|||||||
const gridRef = useRef<HTMLDivElement>(null);
|
const gridRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { data: scriptCardsData, isLoading: githubLoading, error: githubError, refetch } = api.scripts.getScriptCardsWithCategories.useQuery();
|
const { data: scriptCardsData, isLoading: githubLoading, error: githubError, refetch } = api.scripts.getScriptCardsWithCategories.useQuery();
|
||||||
const { data: localScriptsData, isLoading: localLoading, error: localError } = api.scripts.getCtScripts.useQuery();
|
const { data: localScriptsData, isLoading: localLoading, error: localError } = api.scripts.getAllDownloadedScripts.useQuery();
|
||||||
const { data: scriptData } = api.scripts.getScriptBySlug.useQuery(
|
const { data: scriptData } = api.scripts.getScriptBySlug.useQuery(
|
||||||
{ slug: selectedSlug ?? '' },
|
{ slug: selectedSlug ?? '' },
|
||||||
{ enabled: !!selectedSlug }
|
{ enabled: !!selectedSlug }
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
|
|||||||
const gridRef = useRef<HTMLDivElement>(null);
|
const gridRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { data: scriptCardsData, isLoading: githubLoading, error: githubError, refetch } = api.scripts.getScriptCardsWithCategories.useQuery();
|
const { data: scriptCardsData, isLoading: githubLoading, error: githubError, refetch } = api.scripts.getScriptCardsWithCategories.useQuery();
|
||||||
const { data: localScriptsData, isLoading: localLoading, error: localError } = api.scripts.getCtScripts.useQuery();
|
const { data: localScriptsData, isLoading: localLoading, error: localError } = api.scripts.getAllDownloadedScripts.useQuery();
|
||||||
const { data: scriptData } = api.scripts.getScriptBySlug.useQuery(
|
const { data: scriptData } = api.scripts.getScriptBySlug.useQuery(
|
||||||
{ slug: selectedSlug ?? '' },
|
{ slug: selectedSlug ?? '' },
|
||||||
{ enabled: !!selectedSlug }
|
{ enabled: !!selectedSlug }
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default function Home() {
|
|||||||
|
|
||||||
// Fetch data for script counts
|
// Fetch data for script counts
|
||||||
const { data: scriptCardsData } = api.scripts.getScriptCardsWithCategories.useQuery();
|
const { data: scriptCardsData } = api.scripts.getScriptCardsWithCategories.useQuery();
|
||||||
const { data: localScriptsData } = api.scripts.getCtScripts.useQuery();
|
const { data: localScriptsData } = api.scripts.getAllDownloadedScripts.useQuery();
|
||||||
const { data: installedScriptsData } = api.installedScripts.getAllInstalledScripts.useQuery();
|
const { data: installedScriptsData } = api.installedScripts.getAllInstalledScripts.useQuery();
|
||||||
|
|
||||||
// Calculate script counts
|
// Calculate script counts
|
||||||
|
|||||||
@@ -27,6 +27,16 @@ export const scriptsRouter = createTRPCRouter({
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// Get all downloaded scripts from all directories
|
||||||
|
getAllDownloadedScripts: publicProcedure
|
||||||
|
.query(async () => {
|
||||||
|
const scripts = await scriptManager.getAllDownloadedScripts();
|
||||||
|
return {
|
||||||
|
scripts,
|
||||||
|
directoryInfo: scriptManager.getScriptsDirectoryInfo()
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
// Get script content for viewing
|
// Get script content for viewing
|
||||||
getScriptContent: publicProcedure
|
getScriptContent: publicProcedure
|
||||||
|
|||||||
@@ -141,6 +141,95 @@ export class ScriptManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all downloaded scripts from all directories (ct, tools, vm, vw)
|
||||||
|
*/
|
||||||
|
async getAllDownloadedScripts(): Promise<ScriptInfo[]> {
|
||||||
|
this.initializeConfig();
|
||||||
|
const allScripts: ScriptInfo[] = [];
|
||||||
|
|
||||||
|
// Define all script directories to scan
|
||||||
|
const scriptDirs = ['ct', 'tools', 'vm', 'vw'];
|
||||||
|
|
||||||
|
for (const dirName of scriptDirs) {
|
||||||
|
try {
|
||||||
|
const dirPath = join(this.scriptsDir!, dirName);
|
||||||
|
|
||||||
|
// Check if directory exists
|
||||||
|
try {
|
||||||
|
await stat(dirPath);
|
||||||
|
} catch {
|
||||||
|
// Directory doesn't exist, skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scripts = await this.getScriptsFromDirectory(dirPath);
|
||||||
|
allScripts.push(...scripts);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error reading ${dirName} scripts directory:`, error);
|
||||||
|
// Continue with other directories even if one fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allScripts.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get scripts from a specific directory (recursively)
|
||||||
|
*/
|
||||||
|
private async getScriptsFromDirectory(dirPath: string): Promise<ScriptInfo[]> {
|
||||||
|
const scripts: ScriptInfo[] = [];
|
||||||
|
|
||||||
|
const scanDirectory = async (currentPath: string, relativePath = ''): Promise<void> => {
|
||||||
|
const files = await readdir(currentPath);
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = join(currentPath, file);
|
||||||
|
const stats = await stat(filePath);
|
||||||
|
|
||||||
|
if (stats.isFile()) {
|
||||||
|
const extension = extname(file);
|
||||||
|
|
||||||
|
// Check if file extension is allowed
|
||||||
|
if (this.allowedExtensions!.includes(extension)) {
|
||||||
|
// 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 {
|
||||||
|
// JSON file might not exist, that's okay
|
||||||
|
}
|
||||||
|
|
||||||
|
scripts.push({
|
||||||
|
name: file,
|
||||||
|
path: filePath,
|
||||||
|
extension,
|
||||||
|
size: stats.size,
|
||||||
|
lastModified: stats.mtime,
|
||||||
|
executable,
|
||||||
|
logo,
|
||||||
|
slug
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (stats.isDirectory()) {
|
||||||
|
// Recursively scan subdirectories
|
||||||
|
const subRelativePath = relativePath ? join(relativePath, file) : file;
|
||||||
|
await scanDirectory(filePath, subRelativePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await scanDirectory(dirPath);
|
||||||
|
return scripts;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a file is executable
|
* Check if a file is executable
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user