nai-aclab 1.0.10 → 1.0.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nai-aclab",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "Local web UI for experimenting with NovelAI artist tag weight combinations.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
package/web/main.js CHANGED
@@ -149,20 +149,26 @@ function scheduleSave() {
149
149
  saveTimer = setTimeout(saveNow, 450);
150
150
  }
151
151
 
152
- async function saveNow() {
153
- if (!state) return;
154
- syncEditorsToState();
155
- try {
156
- const data = await request("/api/state", {
157
- method: "POST",
158
- body: JSON.stringify({ state }),
159
- });
160
- state = data.state;
161
- setSaveState("자동 저장됨");
162
- } catch (error) {
163
- setSaveState("저장 실패");
164
- console.error(error);
165
- }
152
+ async function saveNow() {
153
+ if (!state) return;
154
+ const tokenInput = $("#api_token");
155
+ const hadPendingToken = Boolean(tokenInput?.value.trim());
156
+ syncEditorsToState();
157
+ try {
158
+ const data = await request("/api/state", {
159
+ method: "POST",
160
+ body: JSON.stringify({ state }),
161
+ });
162
+ state = data.state;
163
+ if (hadPendingToken && tokenInput) {
164
+ tokenInput.value = "";
165
+ tokenInput.placeholder = "저장된 토큰을 사용합니다. 새 토큰을 입력하면 교체됩니다.";
166
+ }
167
+ setSaveState(hadPendingToken ? "API 토큰 변경 저장됨" : "자동 저장됨");
168
+ } catch (error) {
169
+ setSaveState("저장 실패");
170
+ console.error(error);
171
+ }
166
172
  }
167
173
 
168
174
  function syncEditorsToState() {
@@ -601,9 +607,17 @@ function renderSettings() {
601
607
  input.value = key === "token" ? "" : state.api[key] ?? "";
602
608
  }
603
609
  if (key === "token") {
604
- input.placeholder = state.api.token_saved ? "저장된 토큰을 사용합니다" : "API 토큰을 입력하세요";
610
+ input.placeholder = state.api.token_saved
611
+ ? "저장된 토큰을 사용합니다. 새 토큰을 입력하면 교체됩니다."
612
+ : "API 토큰을 입력하세요";
605
613
  input.autocomplete = "off";
606
- }
614
+ const help = document.createElement("small");
615
+ help.className = "field-help";
616
+ help.textContent = state.api.token_saved
617
+ ? "보안을 위해 저장된 토큰은 다시 표시하지 않습니다. 새 토큰을 입력하고 설정 저장을 누르면 기존 토큰을 교체합니다."
618
+ : "토큰은 브라우저에 다시 노출하지 않고 로컬에만 저장합니다.";
619
+ wrap.appendChild(help);
620
+ }
607
621
  if (type === "number") input.step = "any";
608
622
  }
609
623
  $("#mockMode").checked = !!state.api.mock_mode;
@@ -1619,11 +1633,13 @@ function bindAutosaveInputs(root = document) {
1619
1633
  root.querySelectorAll("input, textarea, select").forEach((node) => {
1620
1634
  if (node.id === "compareHistorySelect") return;
1621
1635
  if (node.id === "deleteFilesToggle" || node.closest("#historyList")) return;
1622
- if (node.id === "api_token") {
1623
- node.oninput = null;
1624
- node.onchange = () => {
1625
- syncEditorsToState();
1626
- scheduleSave();
1636
+ if (node.id === "api_token") {
1637
+ node.oninput = () => {
1638
+ setSaveState(node.value.trim() ? "새 API 토큰 입력됨" : "저장된 API 토큰 유지");
1639
+ };
1640
+ node.onchange = () => {
1641
+ syncEditorsToState();
1642
+ scheduleSave();
1627
1643
  };
1628
1644
  return;
1629
1645
  }
package/web/styles.css CHANGED
@@ -319,6 +319,12 @@ label span,
319
319
  font-size: 12px;
320
320
  }
321
321
 
322
+ .field-help {
323
+ color: var(--muted);
324
+ font-size: 11px;
325
+ line-height: 1.45;
326
+ }
327
+
322
328
  input,
323
329
  select,
324
330
  textarea {