Merge pull request #204 from community-scripts/fix/185
fix/185: normalize script matching to handle underscore vs hyphen differences
This commit is contained in:
@@ -169,6 +169,13 @@ export function DownloadedScriptsTab({ onInstallScript }: DownloadedScriptsTabPr
|
|||||||
|
|
||||||
// Update scripts with download status and filter to only downloaded scripts
|
// Update scripts with download status and filter to only downloaded scripts
|
||||||
const downloadedScripts = React.useMemo((): ScriptCardType[] => {
|
const downloadedScripts = React.useMemo((): ScriptCardType[] => {
|
||||||
|
// Helper to normalize identifiers so underscores vs hyphens don't break matches
|
||||||
|
const normalizeId = (s?: string): string => (s ?? '')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\.(sh|bash|py|js|ts)$/g, '')
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '');
|
||||||
|
|
||||||
return combinedScripts
|
return combinedScripts
|
||||||
.map(script => {
|
.map(script => {
|
||||||
if (!script?.name) {
|
if (!script?.name) {
|
||||||
@@ -178,9 +185,13 @@ export function DownloadedScriptsTab({ onInstallScript }: DownloadedScriptsTabPr
|
|||||||
// Check if there's a corresponding local script
|
// Check if there's a corresponding local script
|
||||||
const hasLocalVersion = localScriptsData?.scripts?.some(local => {
|
const hasLocalVersion = localScriptsData?.scripts?.some(local => {
|
||||||
if (!local?.name) return false;
|
if (!local?.name) return false;
|
||||||
const localName = local.name.replace(/\.sh$/, '');
|
const normalizedLocal = normalizeId(local.name);
|
||||||
return localName.toLowerCase() === script.name.toLowerCase() ||
|
const matchesNameOrSlug = (
|
||||||
localName.toLowerCase() === (script.slug ?? '').toLowerCase();
|
normalizedLocal === normalizeId(script.name) ||
|
||||||
|
normalizedLocal === normalizeId(script.slug)
|
||||||
|
);
|
||||||
|
const matchesInstallBasename = (script as any)?.install_basenames?.some((base: string) => normalizeId(base) === normalizedLocal) ?? false;
|
||||||
|
return matchesNameOrSlug || matchesInstallBasename;
|
||||||
}) ?? false;
|
}) ?? false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -200,6 +200,13 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
|
|||||||
|
|
||||||
// Update scripts with download status
|
// Update scripts with download status
|
||||||
const scriptsWithStatus = React.useMemo((): ScriptCardType[] => {
|
const scriptsWithStatus = React.useMemo((): ScriptCardType[] => {
|
||||||
|
// Helper to normalize identifiers for robust matching
|
||||||
|
const normalizeId = (s?: string): string => (s ?? '')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\.(sh|bash|py|js|ts)$/g, '')
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '');
|
||||||
|
|
||||||
return combinedScripts.map(script => {
|
return combinedScripts.map(script => {
|
||||||
if (!script?.name) {
|
if (!script?.name) {
|
||||||
return script; // Return as-is if invalid
|
return script; // Return as-is if invalid
|
||||||
@@ -208,9 +215,13 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
|
|||||||
// Check if there's a corresponding local script
|
// Check if there's a corresponding local script
|
||||||
const hasLocalVersion = localScriptsData?.scripts?.some(local => {
|
const hasLocalVersion = localScriptsData?.scripts?.some(local => {
|
||||||
if (!local?.name) return false;
|
if (!local?.name) return false;
|
||||||
const localName = local.name.replace(/\.sh$/, '');
|
const normalizedLocal = normalizeId(local.name);
|
||||||
return localName.toLowerCase() === script.name.toLowerCase() ||
|
const matchesNameOrSlug = (
|
||||||
localName.toLowerCase() === (script.slug ?? '').toLowerCase();
|
normalizedLocal === normalizeId(script.name) ||
|
||||||
|
normalizedLocal === normalizeId(script.slug)
|
||||||
|
);
|
||||||
|
const matchesInstallBasename = (script as any)?.install_basenames?.some((base: string) => normalizeId(base) === normalizedLocal) ?? false;
|
||||||
|
return matchesNameOrSlug || matchesInstallBasename;
|
||||||
}) ?? false;
|
}) ?? false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -177,6 +177,15 @@ export const scriptsRouter = createTRPCRouter({
|
|||||||
const firstInstallMethod = script?.install_methods?.[0];
|
const firstInstallMethod = script?.install_methods?.[0];
|
||||||
const os = firstInstallMethod?.resources?.os;
|
const os = firstInstallMethod?.resources?.os;
|
||||||
const version = firstInstallMethod?.resources?.version;
|
const version = firstInstallMethod?.resources?.version;
|
||||||
|
// Extract install basenames for robust local matching (e.g., execute.sh -> execute)
|
||||||
|
const install_basenames = (script?.install_methods ?? [])
|
||||||
|
.map(m => m?.script)
|
||||||
|
.filter((p): p is string => typeof p === 'string')
|
||||||
|
.map(p => {
|
||||||
|
const parts = p.split('/');
|
||||||
|
const file = parts[parts.length - 1] ?? '';
|
||||||
|
return file.replace(/\.(sh|bash|py|js|ts)$/i, '');
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...card,
|
...card,
|
||||||
@@ -189,6 +198,7 @@ export const scriptsRouter = createTRPCRouter({
|
|||||||
version: version,
|
version: version,
|
||||||
// Add interface port
|
// Add interface port
|
||||||
interface_port: script?.interface_port,
|
interface_port: script?.interface_port,
|
||||||
|
install_basenames,
|
||||||
} as ScriptCard;
|
} as ScriptCard;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ export interface ScriptCard {
|
|||||||
os?: string;
|
os?: string;
|
||||||
version?: string;
|
version?: string;
|
||||||
interface_port?: number | null;
|
interface_port?: number | null;
|
||||||
|
// Optional: basenames of install scripts (without extension)
|
||||||
|
install_basenames?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GitHubFile {
|
export interface GitHubFile {
|
||||||
|
|||||||
Reference in New Issue
Block a user