@lifeaitools/clauth 1.5.83 → 1.5.84

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.
@@ -607,9 +607,14 @@ function dashboardHtml(port, whitelist, isStaged = false) {
607
607
  .project-tab{background:none;border:none;border-bottom:2px solid transparent;color:#64748b;padding:8px 16px;font-size:.82rem;font-weight:500;cursor:pointer;white-space:nowrap;transition:all .15s}
608
608
  .project-tab:hover{color:#94a3b8;background:rgba(59,130,246,.05)}
609
609
  .project-tab.active{color:#60a5fa;border-bottom-color:#3b82f6;background:rgba(59,130,246,.08)}
610
- .project-tab .tab-count{font-size:.7rem;color:#475569;margin-left:4px;font-weight:400}
611
- .project-tab.active .tab-count{color:#3b82f6}
612
- .project-edit{display:none;margin-top:8px;padding:8px 10px;background:#0f172a;border:1px solid #334155;border-radius:6px}
610
+ .project-tab .tab-count{font-size:.7rem;color:#475569;margin-left:4px;font-weight:400}
611
+ .project-tab.active .tab-count{color:#3b82f6}
612
+ .service-search{display:flex;align-items:center;gap:10px;margin:-.35rem 0 1rem;background:#0f172a;border:1px solid #1e293b;border-radius:8px;padding:9px 12px}
613
+ .service-search-label{font-size:.76rem;color:#64748b;font-weight:600;letter-spacing:.02em;text-transform:uppercase;white-space:nowrap}
614
+ .service-search-input{flex:1;min-width:180px;background:#0a0f1a;border:1px solid #334155;border-radius:6px;color:#e2e8f0;font-family:'Courier New',monospace;font-size:.88rem;padding:8px 11px;outline:none;transition:border-color .15s}
615
+ .service-search-input:focus{border-color:#3b82f6}
616
+ .service-search-count{font-size:.78rem;color:#64748b;white-space:nowrap}
617
+ .project-edit{display:none;margin-top:8px;padding:8px 10px;background:#0f172a;border:1px solid #334155;border-radius:6px}
613
618
  .project-edit.open{display:flex;gap:6px;align-items:center}
614
619
  .project-edit input{background:#1e293b;border:1px solid #334155;border-radius:4px;color:#e2e8f0;font-size:.78rem;padding:4px 8px;outline:none;flex:1;font-family:'Courier New',monospace;transition:border-color .15s}
615
620
  .project-edit input:focus{border-color:#3b82f6}
@@ -863,8 +868,13 @@ function dashboardHtml(port, whitelist, isStaged = false) {
863
868
  <div class="wizard-foot" id="wizard-foot"></div>
864
869
  </div>
865
870
 
866
- <div id="project-tabs" class="project-tabs" style="display:none"></div>
867
- <div id="grid" class="grid"><p class="loading">Loading services…</p></div>
871
+ <div id="project-tabs" class="project-tabs" style="display:none"></div>
872
+ <div id="service-search" class="service-search">
873
+ <span class="service-search-label">Search</span>
874
+ <input id="service-search-input" class="service-search-input" type="search" placeholder="service name or display name" autocomplete="off" spellcheck="false" oninput="setServiceSearch(this.value)">
875
+ <span id="service-search-count" class="service-search-count"></span>
876
+ </div>
877
+ <div id="grid" class="grid"><p class="loading">Loading services…</p></div>
868
878
  <div class="footer">localhost:${port} · 127.0.0.1 only · 10-strike lockout</div>
869
879
  </div>
870
880
 
@@ -1158,8 +1168,25 @@ async function stopDaemon() {
1158
1168
  }
1159
1169
 
1160
1170
  // ── Load services ───────────────────────────
1161
- let allServices = [];
1162
- let activeProjectTab = "all";
1171
+ let allServices = [];
1172
+ let activeProjectTab = "all";
1173
+ let serviceSearchQuery = "";
1174
+
1175
+ function serviceSort(a, b) {
1176
+ return String(a.name || "").localeCompare(String(b.name || ""), undefined, { sensitivity: "base", numeric: true });
1177
+ }
1178
+
1179
+ function matchesServiceSearch(s, query) {
1180
+ if (!query) return true;
1181
+ const q = query.toLowerCase();
1182
+ return String(s.name || "").toLowerCase().includes(q) ||
1183
+ String(s.label || "").toLowerCase().includes(q);
1184
+ }
1185
+
1186
+ function setServiceSearch(value) {
1187
+ serviceSearchQuery = value || "";
1188
+ renderServiceGrid(allServices);
1189
+ }
1163
1190
 
1164
1191
  function renderProjectTabs(services) {
1165
1192
  const tabsEl = document.getElementById("project-tabs");
@@ -1185,21 +1212,35 @@ function renderProjectTabs(services) {
1185
1212
  ).join("");
1186
1213
  }
1187
1214
 
1188
- function switchProjectTab(key) {
1189
- activeProjectTab = key;
1190
- renderProjectTabs(allServices);
1191
- renderServiceGrid(allServices);
1192
- }
1215
+ function switchProjectTab(key) {
1216
+ activeProjectTab = key;
1217
+ renderProjectTabs(allServices);
1218
+ renderServiceGrid(allServices);
1219
+ }
1193
1220
 
1194
1221
  function renderServiceGrid(services) {
1195
1222
  const grid = document.getElementById("grid");
1196
1223
  let filtered = services;
1197
1224
  if (activeProjectTab === "unassigned") {
1198
1225
  filtered = services.filter(s => !s.project);
1199
- } else if (activeProjectTab !== "all") {
1200
- filtered = services.filter(s => s.project === activeProjectTab);
1201
- }
1202
- if (!filtered.length) { grid.innerHTML = '<p class="loading">No services in this group.</p>'; return; }
1226
+ } else if (activeProjectTab !== "all") {
1227
+ filtered = services.filter(s => s.project === activeProjectTab);
1228
+ }
1229
+ filtered = filtered
1230
+ .filter(s => matchesServiceSearch(s, serviceSearchQuery))
1231
+ .slice()
1232
+ .sort(serviceSort);
1233
+ const searchCount = document.getElementById("service-search-count");
1234
+ if (searchCount) {
1235
+ const trimmed = serviceSearchQuery.trim();
1236
+ searchCount.textContent = trimmed ? filtered.length + " match" + (filtered.length === 1 ? "" : "es") : filtered.length + " shown";
1237
+ }
1238
+ if (!filtered.length) {
1239
+ grid.innerHTML = serviceSearchQuery.trim()
1240
+ ? '<p class="loading">No services match that search.</p>'
1241
+ : '<p class="loading">No services in this group.</p>';
1242
+ return;
1243
+ }
1203
1244
  grid.innerHTML = filtered.map(s => \`
1204
1245
  <div class="card">
1205
1246
  <div style="display:flex;align-items:flex-start;justify-content:space-between">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/clauth",
3
- "version": "1.5.83",
3
+ "version": "1.5.84",
4
4
  "description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
5
5
  "type": "module",
6
6
  "bin": {