Skip to content

Commit 26986ea

Browse files
authored
feat: better UI for marketplace item list (#11)
* feat: better UI for marketplace item list * feat: better source config UI * refactor: change how we fetch items * fix: update state more optimistically * fix: incorrect tags filter * fix: better tags filtering * feat: more consistent UI * feat: marketplace animation * fix: remove cache, it's fast enough * refactor: make the UI more consistent across themes * feat: integrate install metadata to UI * feat: add translation files * test: add marketplace UI
1 parent 1a11665 commit 26986ea

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3627
-1097
lines changed

src/core/webview/marketplaceMessageHandler.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,8 @@ export async function handleMarketplaceMessages(
117117
try {
118118
marketplaceManager.isFetching = true
119119

120-
// Wrap the entire initialization in a try-catch block
121120
try {
122-
// Initialize default sources if none exist
123-
let sources =
124-
((await provider.contextProxy.getValue("marketplaceSources")) as MarketplaceSource[]) || []
121+
let sources = (provider.contextProxy.getValue("marketplaceSources") as MarketplaceSource[]) || []
125122

126123
if (!sources || sources.length === 0) {
127124
sources = [DEFAULT_MARKETPLACE_SOURCE]
@@ -130,7 +127,6 @@ export async function handleMarketplaceMessages(
130127
await provider.contextProxy.setValue("marketplaceSources", sources)
131128
}
132129

133-
// Fetch items from all enabled sources
134130
const enabledSources = sources.filter((s) => s.enabled)
135131

136132
if (enabledSources.length === 0) {
@@ -165,6 +161,8 @@ export async function handleMarketplaceMessages(
165161

166162
// Send state to webview
167163
await provider.postStateToWebview()
164+
165+
return true
168166
} catch (initError) {
169167
const errorMessage = `Marketplace initialization failed: ${initError instanceof Error ? initError.message : String(initError)}`
170168
console.error("Error in marketplace initialization:", initError)
@@ -176,6 +174,7 @@ export async function handleMarketplaceMessages(
176174
// The state will already be updated with empty items by MarketplaceManager
177175
await provider.postStateToWebview()
178176
marketplaceManager.isFetching = false
177+
return false
179178
}
180179
} catch (error) {
181180
const errorMessage = `Failed to fetch marketplace items: ${error instanceof Error ? error.message : String(error)}`
@@ -186,8 +185,8 @@ export async function handleMarketplaceMessages(
186185
text: errorMessage,
187186
})
188187
marketplaceManager.isFetching = false
188+
return false
189189
}
190-
return true
191190
}
192191

193192
case "filterMarketplaceItems": {
@@ -212,8 +211,7 @@ export async function handleMarketplaceMessages(
212211
if (message.url) {
213212
try {
214213
// Get the current sources
215-
const sources =
216-
((await provider.contextProxy.getValue("marketplaceSources")) as MarketplaceSource[]) || []
214+
const sources = (provider.contextProxy.getValue("marketplaceSources") as MarketplaceSource[]) || []
217215

218216
// Find the source with the matching URL
219217
const source = sources.find((s) => s.url === message.url)

src/i18n/locales/ca/marketplace.json

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,80 @@
2121
"match-count": "{{count}} coincidènci{{count !== 1 ? 'es' : 'a'}}",
2222
"view": "Veure",
2323
"source": "Font"
24+
},
25+
"install-sidebar": {
26+
"title": "Instal·la {{itemName}}",
27+
"installButton": "Instal·lar",
28+
"cancelButton": "Cancel·lar"
29+
},
30+
"filters": {
31+
"search": {
32+
"placeholder": "Cerca al mercat..."
33+
},
34+
"type": {
35+
"label": "Tipus",
36+
"all": "Tots els tipus",
37+
"mode": "Mode",
38+
"mcp server": "Servidor MCP",
39+
"prompt": "Prompt",
40+
"package": "Paquet"
41+
},
42+
"sort": {
43+
"label": "Ordena per",
44+
"name": "Nom",
45+
"lastUpdated": "Última actualització"
46+
},
47+
"tags": {
48+
"label": "Etiquetes",
49+
"clear_one": "Esborra {{count}} etiqueta seleccionada",
50+
"clear_other": "Esborra {{count}} etiquetes seleccionades",
51+
"placeholder": "Cerca etiquetes...",
52+
"noResults": "No s'han trobat etiquetes.",
53+
"selected_one": "{{count}} etiqueta seleccionada",
54+
"selected_other": "{{count}} etiquetes seleccionades"
55+
}
56+
},
57+
"sources": {
58+
"title": "Fonts del mercat",
59+
"description": "Afegeix o gestiona fonts per als elements del mercat. Cada font és un repositori Git que conté definicions d'elements del mercat.",
60+
"errors": {
61+
"maxSources": "Màxim de {{max}} fonts permeses.",
62+
"emptyUrl": "La URL no pot estar buida.",
63+
"nonVisibleChars": "La URL conté caràcters no visibles.",
64+
"invalidGitUrl": "Format d'URL de Git no vàlid.",
65+
"duplicateUrl": "Ja existeix una font amb aquesta URL.",
66+
"nameTooLong": "El nom no pot superar els 20 caràcters.",
67+
"nonVisibleCharsName": "El nom conté caràcters no visibles.",
68+
"duplicateName": "Ja existeix una font amb aquest nom."
69+
},
70+
"add": {
71+
"namePlaceholder": "Nom opcional de la font (p. ex. 'El meu repositori privat')",
72+
"urlPlaceholder": "URL del repositori Git (p. ex. 'https://github.com/user/repo.git')",
73+
"urlFormats": "Formats compatibles: HTTPS, SSH o ruta de fitxer local.",
74+
"button": "Afegeix font"
75+
},
76+
"current": {
77+
"title": "Fonts actuals",
78+
"empty": "Encara no s'han afegit fonts del mercat.",
79+
"emptyHint": "Afegeix una font a dalt per explorar els elements del mercat.",
80+
"refresh": "Actualitza la font",
81+
"remove": "Elimina la font"
82+
}
83+
},
84+
"tabs": {
85+
"browse": "Explora",
86+
"sources": "Fonts"
87+
},
88+
"title": "Mercat",
89+
"items": {
90+
"refresh": {
91+
"refreshing": "Actualitzant elements del mercat..."
92+
},
93+
"empty": {
94+
"noItems": "No s'han trobat elements del mercat.",
95+
"emptyHint": "Prova d'ajustar els filtres o els termes de cerca"
96+
},
97+
"count_one": "{{count}} element",
98+
"count_other": "{{count}} elements"
2499
}
25100
}

src/i18n/locales/de/marketplace.json

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,80 @@
2121
"match-count": "{{count}} Treffer",
2222
"view": "Ansehen",
2323
"source": "Quelle"
24+
},
25+
"install-sidebar": {
26+
"title": "Installiere {{itemName}}",
27+
"installButton": "Installieren",
28+
"cancelButton": "Abbrechen"
29+
},
30+
"filters": {
31+
"search": {
32+
"placeholder": "Marktplatz durchsuchen..."
33+
},
34+
"type": {
35+
"label": "Typ",
36+
"all": "Alle Typen",
37+
"mode": "Modus",
38+
"mcp server": "MCP-Server",
39+
"prompt": "Prompt",
40+
"package": "Paket"
41+
},
42+
"sort": {
43+
"label": "Sortieren nach",
44+
"name": "Name",
45+
"lastUpdated": "Zuletzt aktualisiert"
46+
},
47+
"tags": {
48+
"label": "Tags",
49+
"clear_one": "{{count}} ausgewählten Tag löschen",
50+
"clear_other": "{{count}} ausgewählte Tags löschen",
51+
"placeholder": "Tags durchsuchen...",
52+
"noResults": "Keine Tags gefunden.",
53+
"selected_one": "{{count}} Tag ausgewählt",
54+
"selected_other": "{{count}} Tags ausgewählt"
55+
}
56+
},
57+
"sources": {
58+
"title": "Marktplatz-Quellen",
59+
"description": "Füge Quellen für Marktplatz-Items hinzu oder verwalte sie. Jede Quelle ist ein Git-Repository, das Marktplatz-Item-Definitionen enthält.",
60+
"errors": {
61+
"maxSources": "Maximal {{max}} Quellen erlaubt.",
62+
"emptyUrl": "URL darf nicht leer sein.",
63+
"nonVisibleChars": "URL enthält nicht sichtbare Zeichen.",
64+
"invalidGitUrl": "Ungültiges Git-URL-Format.",
65+
"duplicateUrl": "Quelle mit dieser URL existiert bereits.",
66+
"nameTooLong": "Name darf 20 Zeichen nicht überschreiten.",
67+
"nonVisibleCharsName": "Name enthält nicht sichtbare Zeichen.",
68+
"duplicateName": "Quelle mit diesem Namen existiert bereits."
69+
},
70+
"add": {
71+
"namePlaceholder": "Optionaler Quellname (z.B. 'Mein privates Repo')",
72+
"urlPlaceholder": "Git-Repository-URL (z.B. 'https://github.com/user/repo.git')",
73+
"urlFormats": "Unterstützte Formate: HTTPS, SSH oder lokaler Dateipfad.",
74+
"button": "Quelle hinzufügen"
75+
},
76+
"current": {
77+
"title": "Aktuelle Quellen",
78+
"empty": "Noch keine Marktplatz-Quellen hinzugefügt.",
79+
"emptyHint": "Füge oben eine Quelle hinzu, um Marktplatz-Items zu durchsuchen.",
80+
"refresh": "Quelle aktualisieren",
81+
"remove": "Quelle entfernen"
82+
}
83+
},
84+
"tabs": {
85+
"browse": "Durchsuchen",
86+
"sources": "Quellen"
87+
},
88+
"title": "Marktplatz",
89+
"items": {
90+
"refresh": {
91+
"refreshing": "Marktplatz-Items werden aktualisiert..."
92+
},
93+
"empty": {
94+
"noItems": "Keine Marktplatz-Items gefunden.",
95+
"emptyHint": "Versuche, deine Filter oder Suchbegriffe anzupassen"
96+
},
97+
"count_one": "{{count}} Item",
98+
"count_other": "{{count}} Items"
2499
}
25100
}

src/i18n/locales/en/marketplace.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,84 @@
2121
"match-count": "{{count}} match{{count !== 1 ? 'es' : ''}}",
2222
"view": "View",
2323
"source": "Source"
24+
},
25+
"install-sidebar": {
26+
"title": "Install {{itemName}}",
27+
"installButton": "Install",
28+
"cancelButton": "Cancel"
29+
},
30+
"install-sidebar": {
31+
"title": "Install {{itemName}}",
32+
"installButton": "Install",
33+
"cancelButton": "Cancel"
34+
},
35+
"filters": {
36+
"search": {
37+
"placeholder": "Search marketplace..."
38+
},
39+
"type": {
40+
"label": "Type",
41+
"all": "All Types",
42+
"mode": "Mode",
43+
"mcp server": "MCP Server",
44+
"prompt": "Prompt",
45+
"package": "Package"
46+
},
47+
"sort": {
48+
"label": "Sort By",
49+
"name": "Name",
50+
"lastUpdated": "Last Updated"
51+
},
52+
"tags": {
53+
"label": "Tags",
54+
"clear": "Clear {{count}} selected tag{{count !== 1 ? 's' : ''}}",
55+
"placeholder": "Search tags...",
56+
"noResults": "No tags found.",
57+
"selected": "{{count}} tag{{count !== 1 ? 's' : ''}} selected"
58+
},
59+
"sources": {
60+
"title": "Marketplace Sources",
61+
"description": "Add or manage sources for marketplace items. Each source is a Git repository containing marketplace item definitions.",
62+
"errors": {
63+
"maxSources": "Maximum of {{max}} sources allowed.",
64+
"emptyUrl": "URL cannot be empty.",
65+
"nonVisibleChars": "URL contains non-visible characters.",
66+
"invalidGitUrl": "Invalid Git URL format.",
67+
"duplicateUrl": "Source with this URL already exists.",
68+
"nameTooLong": "Name cannot exceed 20 characters.",
69+
"nonVisibleCharsName": "Name contains non-visible characters.",
70+
"duplicateName": "Source with this name already exists."
71+
},
72+
"add": {
73+
"namePlaceholder": "Optional source name (e.g. 'My Private Repo')",
74+
"urlPlaceholder": "Git repository URL (e.g. 'https://github.com/user/repo.git')",
75+
"urlFormats": "Supported formats: HTTPS, SSH, or local file path.",
76+
"button": "Add Source"
77+
},
78+
"current": {
79+
"title": "Current Sources",
80+
"empty": "No marketplace sources added yet.",
81+
"emptyHint": "Add a source above to browse marketplace items."
82+
},
83+
"current": {
84+
"refresh": "Refresh source",
85+
"remove": "Remove source"
86+
}
87+
},
88+
"tabs": {
89+
"browse": "Browse",
90+
"sources": "Sources"
91+
},
92+
"title": "Marketplace"
93+
},
94+
"items": {
95+
"refresh": {
96+
"refreshing": "Refreshing marketplace items..."
97+
},
98+
"empty": {
99+
"noItems": "No marketplace items found.",
100+
"emptyHint": "Try adjusting your filters or search terms"
101+
},
102+
"count": "{{count}} item{{count !== 1 ? 's' : ''}}"
24103
}
25104
}

src/i18n/locales/es/marketplace.json

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,80 @@
2121
"match-count": "{{count}} coincidencia{{count !== 1 ? 's' : ''}}",
2222
"view": "Ver",
2323
"source": "Fuente"
24+
},
25+
"install-sidebar": {
26+
"title": "Instalar {{itemName}}",
27+
"installButton": "Instalar",
28+
"cancelButton": "Cancelar"
29+
},
30+
"filters": {
31+
"search": {
32+
"placeholder": "Buscar en el mercado..."
33+
},
34+
"type": {
35+
"label": "Tipo",
36+
"all": "Todos los tipos",
37+
"mode": "Modo",
38+
"mcp server": "Servidor MCP",
39+
"prompt": "Prompt",
40+
"package": "Paquete"
41+
},
42+
"sort": {
43+
"label": "Ordenar por",
44+
"name": "Nombre",
45+
"lastUpdated": "Última actualización"
46+
},
47+
"tags": {
48+
"label": "Etiquetas",
49+
"clear_one": "Borrar {{count}} etiqueta seleccionada",
50+
"clear_other": "Borrar {{count}} etiquetas seleccionadas",
51+
"placeholder": "Buscar etiquetas...",
52+
"noResults": "No se encontraron etiquetas.",
53+
"selected_one": "{{count}} etiqueta seleccionada",
54+
"selected_other": "{{count}} etiquetas seleccionadas"
55+
}
56+
},
57+
"sources": {
58+
"title": "Fuentes del mercado",
59+
"description": "Añade o gestiona fuentes para los elementos del mercado. Cada fuente es un repositorio Git que contiene definiciones de elementos del mercado.",
60+
"errors": {
61+
"maxSources": "Máximo de {{max}} fuentes permitidas.",
62+
"emptyUrl": "La URL no puede estar vacía.",
63+
"nonVisibleChars": "La URL contiene caracteres no visibles.",
64+
"invalidGitUrl": "Formato de URL de Git no válido.",
65+
"duplicateUrl": "Ya existe una fuente con esta URL.",
66+
"nameTooLong": "El nombre no puede superar los 20 caracteres.",
67+
"nonVisibleCharsName": "El nombre contiene caracteres no visibles.",
68+
"duplicateName": "Ya existe una fuente con este nombre."
69+
},
70+
"add": {
71+
"namePlaceholder": "Nombre opcional de la fuente (p. ej. 'Mi repositorio privado')",
72+
"urlPlaceholder": "URL del repositorio Git (p. ej. 'https://github.com/user/repo.git')",
73+
"urlFormats": "Formatos compatibles: HTTPS, SSH o ruta de archivo local.",
74+
"button": "Añadir fuente"
75+
},
76+
"current": {
77+
"title": "Fuentes actuales",
78+
"empty": "Aún no se han añadido fuentes del mercado.",
79+
"emptyHint": "Añade una fuente arriba para explorar los elementos del mercado.",
80+
"refresh": "Actualizar fuente",
81+
"remove": "Eliminar fuente"
82+
}
83+
},
84+
"tabs": {
85+
"browse": "Explorar",
86+
"sources": "Fuentes"
87+
},
88+
"title": "Mercado",
89+
"items": {
90+
"refresh": {
91+
"refreshing": "Actualizando elementos del mercado..."
92+
},
93+
"empty": {
94+
"noItems": "No se encontraron elementos del mercado.",
95+
"emptyHint": "Intenta ajustar tus filtros o términos de búsqueda"
96+
},
97+
"count_one": "{{count}} elemento",
98+
"count_other": "{{count}} elementos"
2499
}
25100
}

0 commit comments

Comments
 (0)