From 03974e82b2b21c40634f0899834821abec689f20 Mon Sep 17 00:00:00 2001 From: NamesMT Date: Fri, 2 May 2025 05:10:35 +0000 Subject: [PATCH] refactor: move `isValidUrl` to global util, prop/scope cleaning --- src/utils/url.ts | 8 ++++ .../components/MarketplaceItemActionsMenu.tsx | 28 ++++++++++++-- .../components/MarketplaceItemCard.tsx | 37 ++----------------- 3 files changed, 36 insertions(+), 37 deletions(-) create mode 100644 src/utils/url.ts diff --git a/src/utils/url.ts b/src/utils/url.ts new file mode 100644 index 0000000000..7ec6a77993 --- /dev/null +++ b/src/utils/url.ts @@ -0,0 +1,8 @@ +export const isValidUrl = (urlString: string): boolean => { + try { + new URL(urlString) + return true + } catch (e) { + return false + } +} diff --git a/webview-ui/src/components/marketplace/components/MarketplaceItemActionsMenu.tsx b/webview-ui/src/components/marketplace/components/MarketplaceItemActionsMenu.tsx index c8b0708728..daf435113e 100644 --- a/webview-ui/src/components/marketplace/components/MarketplaceItemActionsMenu.tsx +++ b/webview-ui/src/components/marketplace/components/MarketplaceItemActionsMenu.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React, { useCallback, useMemo } from "react" import { Button } from "@/components/ui/button" import { DropdownMenu, @@ -10,18 +10,40 @@ import { MoreVertical, ExternalLink, Download } from "lucide-react" import { InstallMarketplaceItemOptions, MarketplaceItem } from "../../../../../src/services/marketplace/types" import { vscode } from "@/utils/vscode" import { useAppTranslation } from "@/i18n/TranslationContext" +import { isValidUrl } from "@roo/utils/url" interface MarketplaceItemActionsMenuProps { item: MarketplaceItem - handleOpenSourceUrl: () => void } export const MarketplaceItemActionsMenu: React.FC = ({ item, - handleOpenSourceUrl, }) => { const { t } = useAppTranslation() + const itemSourceUrl = useMemo(() => { + if (item.sourceUrl && isValidUrl(item.sourceUrl)) { + return item.sourceUrl + } + + let url = item.repoUrl + if (item.defaultBranch) { + url = `${url}/tree/${item.defaultBranch}` + if (item.path) { + const normalizedPath = item.path.replace(/\\/g, "/").replace(/^\/+/, "") + url = `${url}/${normalizedPath}` + } + } + return url + }, [item.sourceUrl, item.repoUrl, item.defaultBranch, item.path]) + + const handleOpenSourceUrl = useCallback(() => { + vscode.postMessage({ + type: "openExternal", + url: itemSourceUrl, + }) + }, [itemSourceUrl]) + const handleInstall = (options?: InstallMarketplaceItemOptions) => { vscode.postMessage({ type: "installMarketplaceItem", diff --git a/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx b/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx index 88b33b362c..aff4b0e9da 100644 --- a/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx +++ b/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useCallback } from "react" +import React, { useMemo } from "react" import { MarketplaceItem } from "../../../../../src/services/marketplace/types" import { vscode } from "@/utils/vscode" import { groupItemsByType, GroupedItems } from "../utils/grouping" @@ -7,6 +7,7 @@ import { TypeGroup } from "./TypeGroup" import { ViewState } from "../MarketplaceViewStateManager" import { useAppTranslation } from "@/i18n/TranslationContext" import { MarketplaceItemActionsMenu } from "./MarketplaceItemActionsMenu" +import { isValidUrl } from "@roo/utils/url" interface MarketplaceItemCardProps { item: MarketplaceItem @@ -24,14 +25,6 @@ export const MarketplaceItemCard: React.FC = ({ setActiveTab, }) => { const { t } = useAppTranslation() - const isValidUrl = (urlString: string): boolean => { - try { - new URL(urlString) - return true - } catch (e) { - return false - } - } const typeLabel = useMemo(() => { switch (item.type) { @@ -63,30 +56,6 @@ export const MarketplaceItemCard: React.FC = ({ } }, [item.type]) - // Memoize URL calculation - const itemSourceUrl = useMemo(() => { - if (item.sourceUrl && isValidUrl(item.sourceUrl)) { - return item.sourceUrl - } - - let url = item.repoUrl - if (item.defaultBranch) { - url = `${url}/tree/${item.defaultBranch}` - if (item.path) { - const normalizedPath = item.path.replace(/\\/g, "/").replace(/^\/+/, "") - url = `${url}/${normalizedPath}` - } - } - return url - }, [item.sourceUrl, item.repoUrl, item.defaultBranch, item.path]) - - const handleOpenSourceUrl = useCallback(() => { - vscode.postMessage({ - type: "openExternal", - url: itemSourceUrl, - }) - }, [itemSourceUrl]) - // Group items by type const groupedItems = useMemo(() => { if (!item.items?.length) { @@ -194,7 +163,7 @@ export const MarketplaceItemCard: React.FC = ({ )} - + {item.type === "package" && (