Anurag commited on
Commit
1c87ad6
·
1 Parent(s): 2be260d

Polish env-builder UX with quick guide and required selector

Browse files
Files changed (5) hide show
  1. README.md +1 -1
  2. env-builder.html +19 -0
  3. env-builder.js +7 -1
  4. health-server.js +8 -8
  5. start.sh +1 -1
README.md CHANGED
@@ -241,7 +241,7 @@ Configure password access and network restrictions:
241
 
242
  | Variable | Default | Description |
243
  | :--- | :--- | :--- |
244
- | `OPENCLAW_PASSWORD` | — | Enable simple password auth instead of token |
245
  | `TRUSTED_PROXIES` | — | Comma-separated IPs of HF proxies |
246
  | `ALLOWED_ORIGINS` | — | Comma-separated allowed origins for Control UI |
247
  | `CLOUDFLARE_KEEPALIVE_ENABLED` | `true` | Set to `false` to disable the automatic Cloudflare KeepAlive worker |
 
241
 
242
  | Variable | Default | Description |
243
  | :--- | :--- | :--- |
244
+ | `OPENCLAW_PASSWORD` | — | Enable simple password auth instead of token (applies only when `GATEWAY_TOKEN` is empty) |
245
  | `TRUSTED_PROXIES` | — | Comma-separated IPs of HF proxies |
246
  | `ALLOWED_ORIGINS` | — | Comma-separated allowed origins for Control UI |
247
  | `CLOUDFLARE_KEEPALIVE_ENABLED` | `true` | Set to `false` to disable the automatic Cloudflare KeepAlive worker |
env-builder.html CHANGED
@@ -775,6 +775,9 @@ body {
775
  flex-shrink: 0;
776
  }
777
  .tag-legend[open] .legend-hint { opacity: 0; }
 
 
 
778
  .legend-body {
779
  padding: 8px 12px 10px;
780
  border-top: 1px solid var(--border);
@@ -834,6 +837,7 @@ body {
834
 
835
  <!-- toolbar -->
836
  <div class="toolbar">
 
837
  <div class="search-wrap">
838
  <span class="search-icon">⌕</span>
839
  <input id="search" type="text" placeholder="Search variables…" autocomplete="off" spellcheck="false">
@@ -841,6 +845,7 @@ body {
841
 
842
  <div class="tb-sep"></div>
843
 
 
844
  <button id="selectCommon" class="btn">★ Common</button>
845
  <button id="selectVisible" class="btn">☑ Visible</button>
846
  <button id="clearAll" class="btn btn-ghost">✕ Clear</button>
@@ -893,6 +898,20 @@ body {
893
  <div class="panel-scroll">
894
 
895
  <!-- Summary -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
896
  <div class="pblock">
897
  <div class="pblock-head">
898
  <span class="pblock-title">📊 Summary</span>
 
775
  flex-shrink: 0;
776
  }
777
  .tag-legend[open] .legend-hint { opacity: 0; }
778
+ .toolbar-hint { color: var(--muted); font-size: 12px; margin-right: 10px; white-space: nowrap; }
779
+ .quick-guide { margin: 0; padding-left: 18px; color: var(--muted); display: grid; gap: 6px; font-size: 12.5px; }
780
+ .quick-guide strong { color: var(--text); }
781
  .legend-body {
782
  padding: 8px 12px 10px;
783
  border-top: 1px solid var(--border);
 
837
 
838
  <!-- toolbar -->
839
  <div class="toolbar">
840
+ <div class="toolbar-hint">Tip: Start with <strong>⚡ Required</strong>, then fill keys and click <strong># Generate Bundle</strong>.</div>
841
  <div class="search-wrap">
842
  <span class="search-icon">⌕</span>
843
  <input id="search" type="text" placeholder="Search variables…" autocomplete="off" spellcheck="false">
 
845
 
846
  <div class="tb-sep"></div>
847
 
848
+ <button id="selectRequired" class="btn" title="Select all critical variables first">⚡ Required</button>
849
  <button id="selectCommon" class="btn">★ Common</button>
850
  <button id="selectVisible" class="btn">☑ Visible</button>
851
  <button id="clearAll" class="btn btn-ghost">✕ Clear</button>
 
898
  <div class="panel-scroll">
899
 
900
  <!-- Summary -->
901
+ <div class="pblock">
902
+ <div class="pblock-head">
903
+ <span class="pblock-title">🧭 Quick Guide</span>
904
+ </div>
905
+ <div class="pblock-body">
906
+ <ol class="quick-guide">
907
+ <li>Click <strong>⚡ Required</strong> to select must-have vars.</li>
908
+ <li>Fill values in selected cards (search works by key/tag/group).</li>
909
+ <li>Click <strong># Generate Bundle</strong> and copy Bundle/Env line.</li>
910
+ <li>Paste into HF Space variables or use <strong>↓ Import & Apply</strong>.</li>
911
+ </ol>
912
+ </div>
913
+ </div>
914
+
915
  <div class="pblock">
916
  <div class="pblock-head">
917
  <span class="pblock-title">📊 Summary</span>
env-builder.js CHANGED
@@ -2115,7 +2115,7 @@ function cardHTML(f, origIdx = 0) {
2115
  const tm = TAG_META[f.tag] || TAG_META.optional;
2116
  const badge = `<span class="badge ${tm.cls}">${tm.lbl}</span>`;
2117
 
2118
- return `<div class="env-card" data-row data-orig-idx="${origIdx}" data-group="${esc(f.g)}" data-search="${esc((f.g + ' ' + f.k + ' ' + (f.lbl || '') + ' ' + (f.tag || '')).toLowerCase())}">
2119
  <div class="card-top">
2120
  <input type="checkbox" class="card-check" data-check="${esc(f.k)}" ${f.common ? 'data-common="1"' : ''}>
2121
  <div class="card-info">
@@ -2465,6 +2465,12 @@ refresh();
2465
 
2466
  // ── Events ──
2467
  $('search').oninput = filter;
 
 
 
 
 
 
2468
  $('selectCommon').onclick = () => {
2469
  document.querySelectorAll('[data-common="1"]').forEach(c => c.checked = true);
2470
  sortAllSections();
 
2115
  const tm = TAG_META[f.tag] || TAG_META.optional;
2116
  const badge = `<span class="badge ${tm.cls}">${tm.lbl}</span>`;
2117
 
2118
+ return `<div class="env-card" data-row data-orig-idx="${origIdx}" data-group="${esc(f.g)}" data-search="${esc((f.g + ' ' + f.k + ' ' + (f.lbl || '') + ' ' + (f.tag || '')).toLowerCase())}" data-tag="${esc(f.tag || 'optional')}">
2119
  <div class="card-top">
2120
  <input type="checkbox" class="card-check" data-check="${esc(f.k)}" ${f.common ? 'data-common="1"' : ''}>
2121
  <div class="card-info">
 
2465
 
2466
  // ── Events ──
2467
  $('search').oninput = filter;
2468
+ $('selectRequired').onclick = () => {
2469
+ document.querySelectorAll('[data-row][data-tag="critical"] [data-check]').forEach(c => c.checked = true);
2470
+ sortAllSections();
2471
+ markSelected();
2472
+ refresh();
2473
+ };
2474
  $('selectCommon').onclick = () => {
2475
  document.querySelectorAll('[data-common="1"]').forEach(c => c.checked = true);
2476
  sortAllSections();
health-server.js CHANGED
@@ -664,11 +664,11 @@ const server = http.createServer(async (req, res) => {
664
  const body = await readBody(req);
665
  const token = decodeURIComponent((body.match(/(?:^|&)token=([^&]*)/) || [])[1] || "").replace(/\+/g, " ");
666
  if (safeEqual(token, GATEWAY_TOKEN)) {
667
- const cookie = `hc_env_auth=${encodeURIComponent(GATEWAY_TOKEN)}; Path=/env-builder; HttpOnly; SameSite=Strict; Max-Age=86400`;
668
  res.writeHead(302, { Location: "/env-builder", "Set-Cookie": cookie, "Cache-Control": "no-store" });
669
  return res.end();
670
  }
671
- res.writeHead(200, { "Content-Type": "text/html" });
672
  return res.end(renderEnvBuilderLogin(true));
673
  }
674
  res.writeHead(302, { Location: "/env-builder", "Cache-Control": "no-store" });
@@ -676,31 +676,31 @@ const server = http.createServer(async (req, res) => {
676
  }
677
 
678
  if (pathname === "/env-builder/logout") {
679
- res.writeHead(302, { Location: "/env-builder", "Set-Cookie": "hc_env_auth=; Path=/env-builder; HttpOnly; Max-Age=0", "Cache-Control": "no-store" });
680
  return res.end();
681
  }
682
 
683
  if (pathname === "/env-builder" || pathname === "/env-builder/") {
684
  if (isDirectHfSpaceRequest) {
685
- res.writeHead(200, { "Content-Type": "text/html" });
686
  return res.end(renderPrivateRedirect(HF_SPACE_URL));
687
  }
688
  if (!isEnvBuilderAuthed(req)) {
689
- res.writeHead(200, { "Content-Type": "text/html" });
690
  return res.end(renderEnvBuilderLogin(false));
691
  }
692
- res.writeHead(200, { "Content-Type": "text/html" });
693
  return res.end(renderEnvBuilder());
694
  }
695
 
696
  if (pathname === "/env-builder.js") {
697
  if (!isEnvBuilderAuthed(req)) {
698
- res.writeHead(401, { "Content-Type": "text/plain" });
699
  return res.end("Unauthorized");
700
  }
701
  try {
702
  const js = fs.readFileSync(require("path").join(__dirname, "env-builder.js"), "utf8");
703
- res.writeHead(200, { "Content-Type": "application/javascript" });
704
  return res.end(js);
705
  } catch (exc) {
706
  res.writeHead(404, { "Content-Type": "text/plain" });
 
664
  const body = await readBody(req);
665
  const token = decodeURIComponent((body.match(/(?:^|&)token=([^&]*)/) || [])[1] || "").replace(/\+/g, " ");
666
  if (safeEqual(token, GATEWAY_TOKEN)) {
667
+ const cookie = `hc_env_auth=${encodeURIComponent(GATEWAY_TOKEN)}; Path=/; HttpOnly; SameSite=Strict; Max-Age=86400`;
668
  res.writeHead(302, { Location: "/env-builder", "Set-Cookie": cookie, "Cache-Control": "no-store" });
669
  return res.end();
670
  }
671
+ res.writeHead(200, { "Content-Type": "text/html", "Cache-Control": "no-store" });
672
  return res.end(renderEnvBuilderLogin(true));
673
  }
674
  res.writeHead(302, { Location: "/env-builder", "Cache-Control": "no-store" });
 
676
  }
677
 
678
  if (pathname === "/env-builder/logout") {
679
+ res.writeHead(302, { Location: "/env-builder", "Set-Cookie": "hc_env_auth=; Path=/; HttpOnly; Max-Age=0", "Cache-Control": "no-store" });
680
  return res.end();
681
  }
682
 
683
  if (pathname === "/env-builder" || pathname === "/env-builder/") {
684
  if (isDirectHfSpaceRequest) {
685
+ res.writeHead(200, { "Content-Type": "text/html", "Cache-Control": "no-store" });
686
  return res.end(renderPrivateRedirect(HF_SPACE_URL));
687
  }
688
  if (!isEnvBuilderAuthed(req)) {
689
+ res.writeHead(200, { "Content-Type": "text/html", "Cache-Control": "no-store" });
690
  return res.end(renderEnvBuilderLogin(false));
691
  }
692
+ res.writeHead(200, { "Content-Type": "text/html", "Cache-Control": "no-store" });
693
  return res.end(renderEnvBuilder());
694
  }
695
 
696
  if (pathname === "/env-builder.js") {
697
  if (!isEnvBuilderAuthed(req)) {
698
+ res.writeHead(401, { "Content-Type": "text/plain", "Cache-Control": "no-store", "Vary": "Cookie" });
699
  return res.end("Unauthorized");
700
  }
701
  try {
702
  const js = fs.readFileSync(require("path").join(__dirname, "env-builder.js"), "utf8");
703
+ res.writeHead(200, { "Content-Type": "application/javascript", "Cache-Control": "no-store", "Vary": "Cookie" });
704
  return res.end(js);
705
  } catch (exc) {
706
  res.writeHead(404, { "Content-Type": "text/plain" });
start.sh CHANGED
@@ -676,7 +676,7 @@ CONFIG_JSON=$(jq \
676
  | (if $spaceHost != "" then
677
  .gateway.controlUi.allowedOrigins = ["https://" + $spaceHost]
678
  else . end)
679
- | (if $password != "" then
680
  .gateway.auth.mode = "password" | .gateway.auth.password = $password
681
  else . end)' <<<"$CONFIG_JSON")
682
 
 
676
  | (if $spaceHost != "" then
677
  .gateway.controlUi.allowedOrigins = ["https://" + $spaceHost]
678
  else . end)
679
+ | (if ($password != "" and (.gateway.auth.token // "") == "") then
680
  .gateway.auth.mode = "password" | .gateway.auth.password = $password
681
  else . end)' <<<"$CONFIG_JSON")
682