agent-discover 1.3.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.3.2] - 2026-04-12
9
+
10
+ ### Changed
11
+
12
+ - **Time picker redesigned** — replaced native `datetime-local` inputs in the filter bar with a popover dropdown. Default view shows preset time ranges (Last 15 min, 1h, 6h, 24h, 7d, 30d, All time). "Custom range" section at the bottom opens labeled From/To datetime pickers inside the popover. The button label updates to show the selected range (e.g. "Last 1 hour" or "2026-04-12 10:00 – 14:00").
13
+ - **Filter bar layout** — search bar is now full-width on its own row with descriptive placeholder. Server, status, and time picker sit on the second row. Title + Clear All on top row.
14
+ - **Hash-based tab routing** — active tab is persisted in the URL hash (`#servers`, `#browse`, `#logs`). Refreshing the page restores the last-viewed tab.
15
+
8
16
  ## [1.3.1] - 2026-04-12
9
17
 
10
18
  ### Added
@@ -2,7 +2,7 @@
2
2
  "id": "agent-discover",
3
3
  "name": "Discover",
4
4
  "icon": "explore",
5
- "version": "1.3.1",
5
+ "version": "1.3.2",
6
6
  "description": "MCP server registry — browse, install, configure, monitor",
7
7
  "ui": "./dist/ui/app.js",
8
8
  "css": "./dist/ui/styles.css",
package/dist/ui/app.js CHANGED
@@ -78,26 +78,37 @@
78
78
  // Tab navigation
79
79
  // -------------------------------------------------------------------------
80
80
 
81
+ function switchTab(tab) {
82
+ currentTab = tab;
83
+ var navItems = AD._root.querySelectorAll('.nav-item');
84
+ navItems.forEach(function (n) {
85
+ n.classList.remove('active');
86
+ if (n.dataset.tab === tab) n.classList.add('active');
87
+ });
88
+ AD._root.querySelectorAll('.tab-panel').forEach(function (p) {
89
+ p.classList.remove('active');
90
+ });
91
+ AD._root.getElementById('tab-' + tab).classList.add('active');
92
+ if (tab === 'logs') renderLogs();
93
+ try {
94
+ history.replaceState(null, '', '#' + tab);
95
+ } catch (e) {
96
+ /* ignore */
97
+ }
98
+ }
99
+
81
100
  function initTabs() {
82
101
  var navItems = AD._root.querySelectorAll('.nav-item');
83
102
  navItems.forEach(function (item) {
84
103
  item.addEventListener('click', function () {
85
- var tab = this.dataset.tab;
86
- currentTab = tab;
87
-
88
- navItems.forEach(function (n) {
89
- n.classList.remove('active');
90
- });
91
- this.classList.add('active');
92
-
93
- AD._root.querySelectorAll('.tab-panel').forEach(function (p) {
94
- p.classList.remove('active');
95
- });
96
- AD._root.getElementById('tab-' + tab).classList.add('active');
97
-
98
- if (tab === 'logs') renderLogs();
104
+ switchTab(this.dataset.tab);
99
105
  });
100
106
  });
107
+
108
+ var hash = location.hash.replace('#', '');
109
+ if (hash && AD._root.getElementById('tab-' + hash)) {
110
+ switchTab(hash);
111
+ }
101
112
  }
102
113
 
103
114
  // -------------------------------------------------------------------------
@@ -1212,8 +1223,7 @@
1212
1223
  var serverSel = AD._root.getElementById('log-filter-server');
1213
1224
  var statusSel = AD._root.getElementById('log-filter-status');
1214
1225
  var searchInput = AD._root.getElementById('log-filter-search');
1215
- var fromInput = AD._root.getElementById('log-filter-from');
1216
- var toInput = AD._root.getElementById('log-filter-to');
1226
+
1217
1227
  if (serverSel)
1218
1228
  serverSel.addEventListener('change', function () {
1219
1229
  logFilter.server = this.value;
@@ -1229,16 +1239,84 @@
1229
1239
  logFilter.search = this.value;
1230
1240
  renderLogs();
1231
1241
  });
1232
- if (fromInput)
1233
- fromInput.addEventListener('change', function () {
1234
- logFilter.from = this.value;
1242
+
1243
+ initTimePicker();
1244
+ }
1245
+
1246
+ function initTimePicker() {
1247
+ var btn = AD._root.getElementById('log-time-btn');
1248
+ var dropdown = AD._root.getElementById('log-time-dropdown');
1249
+ var label = AD._root.getElementById('log-time-label');
1250
+ var applyBtn = AD._root.getElementById('log-time-apply');
1251
+ var fromInput = AD._root.getElementById('log-time-from');
1252
+ var toInput = AD._root.getElementById('log-time-to');
1253
+ if (!btn || !dropdown) return;
1254
+
1255
+ btn.addEventListener('click', function (e) {
1256
+ e.stopPropagation();
1257
+ dropdown.classList.toggle('open');
1258
+ });
1259
+
1260
+ document.addEventListener('click', function (e) {
1261
+ if (!dropdown.contains(e.target) && e.target !== btn && !btn.contains(e.target)) {
1262
+ dropdown.classList.remove('open');
1263
+ }
1264
+ });
1265
+
1266
+ var presetBtns = dropdown.querySelectorAll('.log-time-presets button');
1267
+ presetBtns.forEach(function (pb) {
1268
+ pb.addEventListener('click', function () {
1269
+ var minutes = parseInt(this.dataset.minutes, 10);
1270
+ presetBtns.forEach(function (b) {
1271
+ b.classList.remove('active');
1272
+ });
1273
+ this.classList.add('active');
1274
+ if (minutes === 0) {
1275
+ logFilter.from = '';
1276
+ logFilter.to = '';
1277
+ if (label) label.textContent = 'All time';
1278
+ } else {
1279
+ logFilter.from = new Date(Date.now() - minutes * 60000).toISOString();
1280
+ logFilter.to = '';
1281
+ if (label) label.textContent = this.textContent;
1282
+ }
1283
+ if (fromInput) fromInput.value = '';
1284
+ if (toInput) toInput.value = '';
1285
+ dropdown.classList.remove('open');
1235
1286
  renderLogs();
1236
1287
  });
1237
- if (toInput)
1238
- toInput.addEventListener('change', function () {
1239
- logFilter.to = this.value;
1288
+ });
1289
+
1290
+ if (applyBtn) {
1291
+ applyBtn.addEventListener('click', function () {
1292
+ var f = fromInput ? fromInput.value : '';
1293
+ var t = toInput ? toInput.value : '';
1294
+ var fd = f ? new Date(f) : null;
1295
+ var td = t ? new Date(t) : null;
1296
+ logFilter.from = fd ? fd.toISOString() : '';
1297
+ logFilter.to = td ? td.toISOString() : '';
1298
+ presetBtns.forEach(function (b) {
1299
+ b.classList.remove('active');
1300
+ });
1301
+ function fmtShort(d) {
1302
+ return (
1303
+ d.getFullYear() +
1304
+ '-' +
1305
+ String(d.getMonth() + 1).padStart(2, '0') +
1306
+ '-' +
1307
+ String(d.getDate()).padStart(2, '0') +
1308
+ ' ' +
1309
+ String(d.getHours()).padStart(2, '0') +
1310
+ ':' +
1311
+ String(d.getMinutes()).padStart(2, '0')
1312
+ );
1313
+ }
1314
+ var rangeLabel = (fd ? fmtShort(fd) : '...') + ' \u2013 ' + (td ? fmtShort(td) : 'now');
1315
+ if (label) label.textContent = rangeLabel;
1316
+ dropdown.classList.remove('open');
1240
1317
  renderLogs();
1241
1318
  });
1319
+ }
1242
1320
  }
1243
1321
 
1244
1322
  function fetchLogs() {
@@ -154,18 +154,24 @@
154
154
  </section>
155
155
 
156
156
  <section class="tab-panel" id="tab-logs">
157
- <div class="panel-header">
158
- <h2 class="section-title">Call Logs</h2>
157
+ <div class="log-header">
158
+ <div class="log-header-top">
159
+ <h2 class="section-title">Call Logs</h2>
160
+ <button class="btn-clear-logs" data-action="clear-logs">
161
+ <span class="material-symbols-outlined" style="font-size: 14px">delete_sweep</span>
162
+ Clear All
163
+ </button>
164
+ </div>
165
+ <div class="log-filter-search-wrap">
166
+ <span class="material-symbols-outlined" style="font-size: 16px">search</span>
167
+ <input
168
+ type="text"
169
+ id="log-filter-search"
170
+ placeholder="Search server, tool, args, response..."
171
+ autocomplete="off"
172
+ />
173
+ </div>
159
174
  <div class="log-filters">
160
- <div class="log-filter-search-wrap">
161
- <span class="material-symbols-outlined" style="font-size: 14px">search</span>
162
- <input
163
- type="text"
164
- id="log-filter-search"
165
- placeholder="Search logs..."
166
- autocomplete="off"
167
- />
168
- </div>
169
175
  <select id="log-filter-server">
170
176
  <option value="">All servers</option>
171
177
  </select>
@@ -174,12 +180,38 @@
174
180
  <option value="success">Success</option>
175
181
  <option value="fail">Failed</option>
176
182
  </select>
177
- <input type="datetime-local" id="log-filter-from" title="From" />
178
- <input type="datetime-local" id="log-filter-to" title="To" />
179
- <button class="btn-clear-logs" data-action="clear-logs">
180
- <span class="material-symbols-outlined" style="font-size: 14px">delete_sweep</span>
181
- Clear All
182
- </button>
183
+ <div class="log-time-picker" id="log-time-picker">
184
+ <button class="log-time-btn" id="log-time-btn">
185
+ <span class="material-symbols-outlined" style="font-size: 14px">schedule</span>
186
+ <span id="log-time-label">All time</span>
187
+ <span class="material-symbols-outlined" style="font-size: 14px">expand_more</span>
188
+ </button>
189
+ <div class="log-time-dropdown" id="log-time-dropdown">
190
+ <div class="log-time-presets">
191
+ <button data-minutes="15">Last 15 min</button>
192
+ <button data-minutes="60">Last 1 hour</button>
193
+ <button data-minutes="360">Last 6 hours</button>
194
+ <button data-minutes="1440">Last 24 hours</button>
195
+ <button data-minutes="10080">Last 7 days</button>
196
+ <button data-minutes="43200">Last 30 days</button>
197
+ <button data-minutes="0" class="active">All time</button>
198
+ </div>
199
+ <div class="log-time-custom">
200
+ <div class="log-time-custom-label">Custom range</div>
201
+ <div class="log-time-custom-fields">
202
+ <div class="log-time-field">
203
+ <label>From</label>
204
+ <input type="datetime-local" id="log-time-from" />
205
+ </div>
206
+ <div class="log-time-field">
207
+ <label>To</label>
208
+ <input type="datetime-local" id="log-time-to" />
209
+ </div>
210
+ <button class="log-time-apply" id="log-time-apply">Apply</button>
211
+ </div>
212
+ </div>
213
+ </div>
214
+ </div>
183
215
  </div>
184
216
  </div>
185
217
  <div id="logs-list" class="logs-table-wrap">
@@ -1111,54 +1111,207 @@ body {
1111
1111
  Logs tab
1112
1112
  --------------------------------------------------------------------------- */
1113
1113
 
1114
+ .log-header {
1115
+ padding: 16px 24px 12px;
1116
+ }
1117
+
1118
+ .log-header-top {
1119
+ display: flex;
1120
+ align-items: center;
1121
+ justify-content: space-between;
1122
+ margin-bottom: 10px;
1123
+ }
1124
+
1125
+ .log-filter-search-wrap {
1126
+ display: flex;
1127
+ align-items: center;
1128
+ gap: 6px;
1129
+ background: var(--bg-elevated);
1130
+ border: 1px solid var(--border);
1131
+ border-radius: 6px;
1132
+ padding: 0 10px;
1133
+ height: 36px;
1134
+ margin-bottom: 8px;
1135
+ }
1136
+
1137
+ .log-filter-search-wrap .material-symbols-outlined {
1138
+ color: var(--text-dim);
1139
+ flex-shrink: 0;
1140
+ }
1141
+
1142
+ .log-filter-search-wrap input {
1143
+ background: none;
1144
+ border: none;
1145
+ outline: none;
1146
+ font-size: 13px;
1147
+ font-family: var(--font-mono);
1148
+ color: var(--text);
1149
+ width: 100%;
1150
+ }
1151
+
1152
+ .log-filter-search-wrap input::placeholder {
1153
+ color: var(--text-dim);
1154
+ }
1155
+
1114
1156
  .log-filters {
1115
1157
  display: flex;
1116
1158
  gap: 8px;
1117
1159
  align-items: center;
1118
- flex-wrap: wrap;
1119
1160
  }
1120
1161
 
1121
- .log-filters select,
1122
- .log-filters input[type='datetime-local'] {
1162
+ .log-filters select {
1123
1163
  background: var(--bg-elevated);
1124
1164
  border: 1px solid var(--border);
1125
1165
  border-radius: 6px;
1126
- padding: 5px 10px;
1166
+ padding: 6px 10px;
1127
1167
  font-size: 12px;
1128
1168
  font-family: var(--font-mono);
1129
1169
  color: var(--text);
1170
+ height: 32px;
1130
1171
  }
1131
1172
 
1132
- .log-filters input[type='datetime-local']::-webkit-calendar-picker-indicator {
1133
- filter: invert(0.7);
1173
+ .log-time-picker {
1174
+ position: relative;
1134
1175
  }
1135
1176
 
1136
- .log-filter-search-wrap {
1177
+ .log-time-btn {
1137
1178
  display: flex;
1138
1179
  align-items: center;
1139
- gap: 4px;
1180
+ gap: 6px;
1140
1181
  background: var(--bg-elevated);
1141
1182
  border: 1px solid var(--border);
1142
1183
  border-radius: 6px;
1143
- padding: 4px 8px;
1184
+ padding: 0 10px;
1185
+ height: 32px;
1186
+ font-size: 12px;
1187
+ font-family: var(--font-mono);
1188
+ color: var(--text);
1189
+ cursor: pointer;
1190
+ white-space: nowrap;
1144
1191
  }
1145
1192
 
1146
- .log-filter-search-wrap .material-symbols-outlined {
1147
- color: var(--text-dim);
1193
+ .log-time-btn:hover {
1194
+ border-color: var(--accent);
1148
1195
  }
1149
1196
 
1150
- .log-filter-search-wrap input {
1197
+ .log-time-dropdown {
1198
+ display: none;
1199
+ position: absolute;
1200
+ top: 100%;
1201
+ right: 0;
1202
+ margin-top: 4px;
1203
+ background: var(--bg-surface);
1204
+ border: 1px solid var(--border);
1205
+ border-radius: var(--radius);
1206
+ box-shadow: var(--shadow-3);
1207
+ z-index: 100;
1208
+ min-width: 220px;
1209
+ overflow: hidden;
1210
+ }
1211
+
1212
+ .log-time-dropdown.open {
1213
+ display: block;
1214
+ }
1215
+
1216
+ .log-time-presets {
1217
+ display: flex;
1218
+ flex-direction: column;
1219
+ padding: 4px;
1220
+ }
1221
+
1222
+ .log-time-presets button {
1151
1223
  background: none;
1152
1224
  border: none;
1153
- outline: none;
1225
+ padding: 8px 12px;
1226
+ font-size: 13px;
1227
+ font-family: var(--font-sans);
1228
+ color: var(--text);
1229
+ text-align: left;
1230
+ cursor: pointer;
1231
+ border-radius: 6px;
1232
+ }
1233
+
1234
+ .log-time-presets button:hover {
1235
+ background: var(--bg-hover);
1236
+ }
1237
+
1238
+ .log-time-presets button.active {
1239
+ background: var(--accent-dim);
1240
+ color: var(--accent);
1241
+ font-weight: 500;
1242
+ }
1243
+
1244
+ .log-time-custom {
1245
+ border-top: 1px solid var(--border);
1246
+ padding: 10px 12px;
1247
+ }
1248
+
1249
+ .log-time-custom-label {
1250
+ font-size: 10px;
1251
+ font-weight: 600;
1252
+ text-transform: uppercase;
1253
+ letter-spacing: 0.5px;
1254
+ color: var(--text-dim);
1255
+ margin-bottom: 8px;
1256
+ font-family: var(--font-sans);
1257
+ }
1258
+
1259
+ .log-time-custom-fields {
1260
+ display: flex;
1261
+ flex-direction: column;
1262
+ gap: 6px;
1263
+ }
1264
+
1265
+ .log-time-field {
1266
+ display: flex;
1267
+ align-items: center;
1268
+ gap: 8px;
1269
+ }
1270
+
1271
+ .log-time-field label {
1272
+ font-size: 11px;
1273
+ color: var(--text-muted);
1274
+ width: 34px;
1275
+ flex-shrink: 0;
1276
+ font-family: var(--font-sans);
1277
+ }
1278
+
1279
+ .log-time-field input {
1280
+ flex: 1;
1281
+ background: var(--bg-elevated);
1282
+ border: 1px solid var(--border);
1283
+ border-radius: 4px;
1284
+ padding: 5px 8px;
1154
1285
  font-size: 12px;
1155
1286
  font-family: var(--font-mono);
1156
1287
  color: var(--text);
1157
- width: 140px;
1158
1288
  }
1159
1289
 
1160
- .log-filter-search-wrap input::placeholder {
1161
- color: var(--text-dim);
1290
+ .log-time-field input:focus {
1291
+ outline: none;
1292
+ border-color: var(--accent);
1293
+ }
1294
+
1295
+ .log-time-field input::-webkit-calendar-picker-indicator {
1296
+ filter: invert(0.7);
1297
+ cursor: pointer;
1298
+ }
1299
+
1300
+ .log-time-apply {
1301
+ background: var(--accent);
1302
+ color: #fff;
1303
+ border: none;
1304
+ border-radius: 4px;
1305
+ padding: 6px 12px;
1306
+ font-size: 12px;
1307
+ font-family: var(--font-sans);
1308
+ font-weight: 500;
1309
+ cursor: pointer;
1310
+ margin-top: 4px;
1311
+ }
1312
+
1313
+ .log-time-apply:hover {
1314
+ background: var(--accent-hover);
1162
1315
  }
1163
1316
 
1164
1317
  .logs-table {
@@ -100,15 +100,21 @@ AD._template = function () {
100
100
  '</div>' +
101
101
  '</section>' +
102
102
  '<section class="tab-panel" id="tab-logs">' +
103
- '<div class="panel-header">' +
103
+ '<div class="log-header">' +
104
+ '<div class="log-header-top">' +
104
105
  '<h2 class="section-title">Call Logs</h2>' +
106
+ '<button class="btn-clear-logs" data-action="clear-logs"><span class="material-symbols-outlined" style="font-size:14px">delete_sweep</span> Clear All</button>' +
107
+ '</div>' +
108
+ '<div class="log-filter-search-wrap"><span class="material-symbols-outlined" style="font-size:16px">search</span><input type="text" id="log-filter-search" placeholder="Search server, tool, args, response..." autocomplete="off" /></div>' +
105
109
  '<div class="log-filters">' +
106
- '<div class="log-filter-search-wrap"><span class="material-symbols-outlined" style="font-size:14px">search</span><input type="text" id="log-filter-search" placeholder="Search logs..." autocomplete="off" /></div>' +
107
110
  '<select id="log-filter-server"><option value="">All servers</option></select>' +
108
111
  '<select id="log-filter-status"><option value="">All</option><option value="success">Success</option><option value="fail">Failed</option></select>' +
109
- '<input type="datetime-local" id="log-filter-from" title="From" />' +
110
- '<input type="datetime-local" id="log-filter-to" title="To" />' +
111
- '<button class="btn-clear-logs" data-action="clear-logs"><span class="material-symbols-outlined" style="font-size:14px">delete_sweep</span> Clear All</button>' +
112
+ '<div class="log-time-picker" id="log-time-picker">' +
113
+ '<button class="log-time-btn" id="log-time-btn"><span class="material-symbols-outlined" style="font-size:14px">schedule</span><span id="log-time-label">All time</span><span class="material-symbols-outlined" style="font-size:14px">expand_more</span></button>' +
114
+ '<div class="log-time-dropdown" id="log-time-dropdown">' +
115
+ '<div class="log-time-presets"><button data-minutes="15">Last 15 min</button><button data-minutes="60">Last 1 hour</button><button data-minutes="360">Last 6 hours</button><button data-minutes="1440">Last 24 hours</button><button data-minutes="10080">Last 7 days</button><button data-minutes="43200">Last 30 days</button><button data-minutes="0" class="active">All time</button></div>' +
116
+ '<div class="log-time-custom"><div class="log-time-custom-label">Custom range</div><div class="log-time-custom-fields"><div class="log-time-field"><label>From</label><input type="datetime-local" id="log-time-from" /></div><div class="log-time-field"><label>To</label><input type="datetime-local" id="log-time-to" /></div><button class="log-time-apply" id="log-time-apply">Apply</button></div></div>' +
117
+ '</div></div>' +
112
118
  '</div>' +
113
119
  '</div>' +
114
120
  '<div id="logs-list" class="logs-table-wrap">' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-discover",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "mcpName": "io.github.keshrath/agent-discover",
5
5
  "description": "MCP server registry and marketplace — discover, install, activate, and manage MCP tools on demand",
6
6
  "type": "module",