1
<html>
2
+
3
<head>
4
<title>Install Plugin</title>
5
<script type="module">
6
import { store } from "/plugins/plugin_installer/webui/pluginInstallStore.js";
7
</script>
8
</head>
9
+
10
<body>
11
<div x-data>
12
<template x-if="$store.pluginInstallStore">
13
<div x-init="$store.pluginInstallStore.setTab('store')"
12
- x-destroy="$store.pluginInstallStore.refreshPluginList()">
14
+ x-destroy="$store.pluginInstallStore.refreshPluginList()">
15
16
<ul class="nav nav-tabs" role="tablist">
17
<li class="nav-item" role="presentation">
16
- <button class="nav-link"
17
- :class="{ active: $store.pluginInstallStore.activeTab === 'store' }"
18
- type="button" role="tab"
19
- @click="$store.pluginInstallStore.setTab('store')">
18
+ <button class="nav-link" :class="{ active: $store.pluginInstallStore.activeTab === 'store' }"
19
+ type="button" role="tab" @click="$store.pluginInstallStore.setTab('store')">
20
<span class="material-symbols-outlined pi-tab-icon">store</span> Browse
21
</button>
22
</li>
23
<li class="nav-item" role="presentation">
24
- <button class="nav-link"
25
- :class="{ active: $store.pluginInstallStore.activeTab === 'git' }"
26
- type="button" role="tab"
27
- @click="$store.pluginInstallStore.setTab('git')">
24
+ <button class="nav-link" :class="{ active: $store.pluginInstallStore.activeTab === 'git' }"
25
+ type="button" role="tab" @click="$store.pluginInstallStore.setTab('git')">
26
<span class="material-symbols-outlined pi-tab-icon">terminal</span> Git
27
</button>
28
</li>
29
<li class="nav-item" role="presentation">
32
- <button class="nav-link"
33
- :class="{ active: $store.pluginInstallStore.activeTab === 'zip' }"
34
- type="button" role="tab"
35
- @click="$store.pluginInstallStore.setTab('zip')">
30
+ <button class="nav-link" :class="{ active: $store.pluginInstallStore.activeTab === 'zip' }"
31
+ type="button" role="tab" @click="$store.pluginInstallStore.setTab('zip')">
32
<span class="material-symbols-outlined pi-tab-icon">upload_file</span> ZIP
33
</button>
34
</li>
36
37
<!-- ═══ Store Tab ═══ -->
38
<div x-show="$store.pluginInstallStore.activeTab === 'store'"
43
- x-init="$store.pluginInstallStore.resetIndex(); $store.pluginInstallStore.fetchIndex()">
39
+ x-init="$store.pluginInstallStore.resetIndex(); $store.pluginInstallStore.fetchIndex()">
40
41
<div class="pi-browse-shell">
42
<section class="pi-browse-hero">
43
<div class="pi-browse-copy">
44
<div class="pi-browse-eyebrow">Community Marketplace</div>
49
- <h2 class="pi-browse-title">Discover plugins for Agent Zero</h2>
45
+ <h2 class="pi-browse-title">Discover community plugins for Agent Zero</h2>
46
<p class="pi-browse-description">
51
- Browse community plugins, filter by what you already have installed, and open each listing for screenshots, README, and install actions.
47
+ These plugins are provided by the community of Agent Zero. Contribute by publishing
48
+ in the <a href="https://github.com/agent0ai/a0-plugins" target="_blank">index
49
+ repository</a>.
50
</p>
51
</div>
54
- <div class="pi-browse-summary" x-text="$store.pluginInstallStore.browseResultsSummary"></div>
52
+ <div class="pi-browse-summary" x-text="$store.pluginInstallStore.browseResultsSummary">
53
+ </div>
54
</section>
55
56
<div class="pi-index-toolbar">
57
<label class="pi-search-field">
58
<span class="material-symbols-outlined">search</span>
60
- <input type="text"
61
- class="pi-search-input"
62
- x-model="$store.pluginInstallStore.search"
59
+ <input type="text" class="pi-search-input" x-model="$store.pluginInstallStore.search"
60
@input="$store.pluginInstallStore.page = 1"
61
placeholder="Search plugins, authors, or tags...">
62
</label>
63
64
<label class="pi-sort-field">
65
<span class="pi-field-label">Sort</span>
69
- <select class="pi-sort-select"
70
- x-model="$store.pluginInstallStore.sortBy">
66
+ <select class="pi-sort-select" x-model="$store.pluginInstallStore.sortBy">
67
<option value="stars">Stars</option>
68
<option value="name">Name</option>
69
</select>
72
73
<div class="pi-filter-row" x-show="$store.pluginInstallStore.browseFilters.length > 1">
74
<template x-for="filter in $store.pluginInstallStore.browseFilters" :key="filter.key">
79
- <button type="button"
80
- class="pi-filter-chip"
75
+ <button type="button" class="pi-filter-chip"
76
:class="{ active: $store.pluginInstallStore.browseFilter === filter.key }"
77
@click="$store.pluginInstallStore.setBrowseFilter(filter.key)">
78
<span x-text="filter.label"></span>
85
<span class="material-symbols-outlined">progress_activity</span>
86
<div>
87
<div class="pi-state-title">Loading marketplace</div>
93
- <div class="pi-state-text" x-text="$store.pluginInstallStore.loadingMessage || 'Loading plugins...'"></div>
88
+ <div class="pi-state-text"
89
+ x-text="$store.pluginInstallStore.loadingMessage || 'Loading plugins...'"></div>
90
</div>
91
</div>
92
97
- <div x-show="$store.pluginInstallStore.error && !$store.pluginInstallStore.loading" class="pi-state-card pi-state-error">
93
+ <div x-show="$store.pluginInstallStore.error && !$store.pluginInstallStore.loading"
94
+ class="pi-state-card pi-state-error">
95
<span class="material-symbols-outlined">error</span>
96
<div>
97
<div class="pi-state-title">Marketplace unavailable</div>
102
<div x-show="$store.pluginInstallStore.index && !$store.pluginInstallStore.loading && $store.pluginInstallStore.filteredPlugins.length > 0"
103
class="pi-grid">
104
<template x-for="plugin in $store.pluginInstallStore.paginatedPlugins" :key="plugin.key">
108
- <button type="button" class="pi-card" @click="$store.pluginInstallStore.openDetail(plugin)">
105
+ <button type="button" class="pi-card"
106
+ @click="$store.pluginInstallStore.openDetail(plugin)">
107
<div class="pi-card-thumb">
108
<template x-if="plugin.thumbnail">
109
<img :src="plugin.thumbnail" :alt="plugin.title" loading="lazy">
161
</div>
162
163
<div x-show="$store.pluginInstallStore.totalPages > 1" class="pi-pagination">
166
- <button class="button"
167
- :disabled="$store.pluginInstallStore.page <= 1"
164
+ <button class="button" :disabled="$store.pluginInstallStore.page <= 1"
165
@click="$store.pluginInstallStore.setPage($store.pluginInstallStore.page - 1)">
166
<span class="material-symbols-outlined">chevron_left</span>
167
</button>
179
180
<!-- ═══ Git Tab ═══ -->
181
<div x-show="$store.pluginInstallStore.activeTab === 'git'"
185
- x-init="$store.pluginInstallStore.resetGit()">
182
+ x-init="$store.pluginInstallStore.resetGit()">
183
184
<div class="pi-form-group">
185
<label class="pi-label">Git Repository URL</label>
189
- <input type="text" class="pi-input"
190
- x-model="$store.pluginInstallStore.gitUrl"
186
+ <input type="text" class="pi-input" x-model="$store.pluginInstallStore.gitUrl"
187
:disabled="$store.pluginInstallStore.loading"
188
placeholder="https://github.com/user/my-plugin.git">
189
</div>
190
191
<div class="pi-form-group">
196
- <label class="pi-label">Access Token <span class="pi-optional">(optional, for private repos)</span></label>
197
- <input type="password" class="pi-input"
198
- x-model="$store.pluginInstallStore.gitToken"
199
- :disabled="$store.pluginInstallStore.loading"
200
- placeholder="ghp_xxxx or glpat-xxxx">
192
+ <label class="pi-label">Access Token <span class="pi-optional">(optional, for private
193
+ repos)</span></label>
194
+ <input type="password" class="pi-input" x-model="$store.pluginInstallStore.gitToken"
195
+ :disabled="$store.pluginInstallStore.loading" placeholder="ghp_xxxx or glpat-xxxx">
196
<div class="pi-hint">Token is used only for cloning and is not stored.</div>
197
</div>
198
199
<div class="pi-actions">
205
- <button class="button confirm"
206
- @click="$store.pluginInstallStore.installGit()"
200
+ <button class="button confirm" @click="$store.pluginInstallStore.installGit()"
201
:disabled="$store.pluginInstallStore.loading || !$store.pluginInstallStore.gitUrl.trim()">
202
<template x-if="$store.pluginInstallStore.loading">
203
<span class="pi-button-loading">
222
<span class="material-symbols-outlined">check_circle</span>
223
</div>
224
<div class="pi-result-text">
231
- <strong x-text="'Plugin installed: ' + ($store.pluginInstallStore.result?.title || $store.pluginInstallStore.result?.plugin_name || '')"></strong>
225
+ <strong
226
+ x-text="'Plugin installed: ' + ($store.pluginInstallStore.result?.title || $store.pluginInstallStore.result?.plugin_name || '')"></strong>
227
<div class="pi-result-path" x-text="$store.pluginInstallStore.result?.path || ''"></div>
228
</div>
229
</div>
231
232
<!-- ═══ ZIP Tab ═══ -->
233
<div x-show="$store.pluginInstallStore.activeTab === 'zip'"
239
- x-init="$store.pluginInstallStore.resetZip()">
234
+ x-init="$store.pluginInstallStore.resetZip()">
235
236
<div class="pi-upload-section">
237
<label for="plugin-zip-file" class="pi-upload-btn button confirm"
247
</div>
248
249
<div x-show="$store.pluginInstallStore.zipFile" class="pi-actions-center">
255
- <button class="button confirm"
256
- @click="$store.pluginInstallStore.installZip()"
250
+ <button class="button confirm" @click="$store.pluginInstallStore.installZip()"
251
:disabled="$store.pluginInstallStore.loading">
252
<span class="icon material-symbols-outlined">download</span> Install Plugin
253
</button>
266
<span class="material-symbols-outlined">check_circle</span>
267
</div>
268
<div class="pi-result-text">
275
- <strong x-text="'Plugin installed: ' + ($store.pluginInstallStore.result?.title || $store.pluginInstallStore.result?.plugin_name || '')"></strong>
269
+ <strong
270
+ x-text="'Plugin installed: ' + ($store.pluginInstallStore.result?.title || $store.pluginInstallStore.result?.plugin_name || '')"></strong>
271
<div class="pi-result-path" x-text="$store.pluginInstallStore.result?.path || ''"></div>
272
</div>
273
</div>
691
height: 164px;
692
}
693
}
694
+
695
/* ── Git Tab ─────────────────────────── */
696
.pi-form-group {
697
margin-bottom: 1rem;
771
.pi-error {
772
color: var(--color-error);
773
padding: 0.75rem;
778
- background: var(--color-error-bg, rgba(239,68,68,0.1));
774
+ background: var(--color-error-bg, rgba(239, 68, 68, 0.1));
775
border-radius: 4px;
776
margin-top: 0.75rem;
777
}
793
align-items: center;
794
gap: 0.75rem;
795
padding: 0.75rem;
800
- background: rgba(34,197,94,0.1);
801
- border: 1px solid rgba(34,197,94,0.3);
796
+ background: rgba(34, 197, 94, 0.1);
797
+ border: 1px solid rgba(34, 197, 94, 0.3);
798
border-radius: 4px;
799
margin-top: 0.75rem;
800
}
818
}
819
</style>
820
</body>
825
-</html>
821
+
822
+</html>
\ No newline at end of file