viberadar 0.3.214 → 0.3.216

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.
@@ -1793,6 +1793,7 @@ let loadDurationDraft = '30s';
1793
1793
  let loadDataDirDraft = '';
1794
1794
  let loadResultDirDraft = '';
1795
1795
  let loadAccountsJsonDraft = '';
1796
+ let loadImportedEnvVarsDraft = {};
1796
1797
  let loadView = 'library'; // 'library' | 'editor'
1797
1798
 
1798
1799
  function toggleObsHint(id) {
@@ -7767,6 +7768,8 @@ function applyLoadConfigToFields(cfg) {
7767
7768
  loadDurationDraft = cfg.duration || loadDurationDraft;
7768
7769
  loadDataDirDraft = cfg.dataDir || loadDataDirDraft;
7769
7770
  loadResultDirDraft = cfg.resultDir || loadResultDirDraft;
7771
+ if (cfg.accountsJson) loadAccountsJsonDraft = cfg.accountsJson;
7772
+ if (cfg.accounts) loadAccountsJsonDraft = typeof cfg.accounts === 'string' ? cfg.accounts : JSON.stringify(cfg.accounts, null, 2);
7770
7773
  const baseEl = document.getElementById('loadBaseUrl');
7771
7774
  const vusEl = document.getElementById('loadVus');
7772
7775
  const durEl = document.getElementById('loadDuration');
@@ -7800,6 +7803,155 @@ function normalizeAccountsJson(raw) {
7800
7803
  }
7801
7804
  }
7802
7805
 
7806
+ function normalizeLoadImport(raw, sourceName) {
7807
+ const root = raw && typeof raw === 'object' ? raw : {};
7808
+ const cfg = root.config && typeof root.config === 'object' ? { ...root.config, ...root } : root;
7809
+ const envVars = cfg.envVars && typeof cfg.envVars === 'object' && !Array.isArray(cfg.envVars) ? { ...cfg.envVars } : {};
7810
+ const imported = {
7811
+ scriptName: cfg.scriptName || cfg.name || (sourceName || '').replace(/\.json$/i, '') || '',
7812
+ script: cfg.script || cfg.k6Script || cfg.code || '',
7813
+ baseUrl: cfg.baseUrl || envVars.BASE_URL || '',
7814
+ vus: cfg.vus || cfg.VUs || cfg.users || '',
7815
+ duration: cfg.duration || cfg.testDuration || '',
7816
+ dataDir: cfg.dataDir || cfg.dataPath || '',
7817
+ resultDir: cfg.resultDir || cfg.resultsDir || '',
7818
+ accounts: cfg.accounts || cfg.usersJson || cfg.accountsJson || envVars.TEST_ACCOUNTS_JSON || '',
7819
+ envVars,
7820
+ };
7821
+ delete imported.envVars.BASE_URL;
7822
+ delete imported.envVars.TEST_ACCOUNTS_JSON;
7823
+ delete imported.envVars.TEST_EMAIL;
7824
+ delete imported.envVars.TEST_PASSWORD;
7825
+ return imported;
7826
+ }
7827
+
7828
+ function applyLoadImport(raw, sourceName) {
7829
+ const imported = normalizeLoadImport(raw, sourceName);
7830
+ if (imported.script) loadScriptDraft = String(imported.script);
7831
+ if (imported.scriptName) loadScriptNameDraft = String(imported.scriptName);
7832
+ if (imported.baseUrl) loadBaseUrlDraft = String(imported.baseUrl);
7833
+ if (imported.vus) loadVusDraft = parseInt(String(imported.vus), 10) || loadVusDraft;
7834
+ if (imported.duration) loadDurationDraft = String(imported.duration);
7835
+ if (imported.dataDir) loadDataDirDraft = String(imported.dataDir);
7836
+ if (imported.resultDir) loadResultDirDraft = String(imported.resultDir);
7837
+ if (imported.accounts) {
7838
+ loadAccountsJsonDraft = typeof imported.accounts === 'string'
7839
+ ? imported.accounts
7840
+ : JSON.stringify(imported.accounts, null, 2);
7841
+ }
7842
+ loadImportedEnvVarsDraft = imported.envVars || {};
7843
+ loadView = 'editor';
7844
+ renderContent();
7845
+ }
7846
+
7847
+ function loadImportConfigClick() {
7848
+ openLoadImportConfigModal();
7849
+ }
7850
+
7851
+ function readLoadImportConfigText(text, sourceName) {
7852
+ const raw = JSON.parse(String(text || '{}'));
7853
+ applyLoadImport(raw, sourceName);
7854
+ }
7855
+
7856
+ function loadImportConfigFile(input) {
7857
+ const file = input && input.files && input.files[0];
7858
+ if (!file) return;
7859
+ const reader = new FileReader();
7860
+ reader.onload = () => {
7861
+ try {
7862
+ readLoadImportConfigText(reader.result || '{}', file.name);
7863
+ const overlay = document.getElementById('loadImportConfigOverlay');
7864
+ if (overlay) overlay.remove();
7865
+ } catch (e) {
7866
+ alert('Конфиг не импортирован: ' + e.message);
7867
+ }
7868
+ };
7869
+ reader.onerror = () => alert('Не удалось прочитать файл конфига');
7870
+ reader.readAsText(file);
7871
+ }
7872
+
7873
+ function openLoadImportConfigModal() {
7874
+ let overlay = document.getElementById('loadImportConfigOverlay');
7875
+ if (overlay) overlay.remove();
7876
+ overlay = document.createElement('div');
7877
+ overlay.id = 'loadImportConfigOverlay';
7878
+ overlay.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.62);display:flex;align-items:center;justify-content:center;z-index:9999;padding:18px';
7879
+ overlay.innerHTML = `
7880
+ <div style="background:var(--bg-card);border:1px solid var(--border);border-radius:8px;padding:18px;width:720px;max-width:96vw;max-height:92vh;overflow:auto">
7881
+ <div style="display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px">
7882
+ <div>
7883
+ <div style="font-size:15px;font-weight:600;color:var(--text)">Импорт k6 конфига</div>
7884
+ <div style="font-size:12px;color:var(--muted);margin-top:3px">Вставь JSON из буфера или выбери файл. После импорта поля можно править вручную.</div>
7885
+ </div>
7886
+ <button id="loadImportClose" class="load-btn" style="padding:4px 9px">Закрыть</button>
7887
+ </div>
7888
+ <textarea id="loadImportConfigText" spellcheck="false" placeholder='{"name":"auth-browse","baseUrl":"https://demo.unica.hopper-it.ru","vus":10,"duration":"2m","accounts":[{"email":"user@example.com","password":"pass"}],"script":"import http from ..."}' style="width:100%;min-height:260px;resize:vertical;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;line-height:1.45;padding:10px;outline:none"></textarea>
7889
+ <div id="loadImportStatus" style="min-height:18px;margin-top:8px;font-size:12px;color:var(--muted)">JSON пока не вставлен</div>
7890
+ <div style="display:flex;gap:8px;justify-content:space-between;align-items:center;margin-top:14px;flex-wrap:wrap">
7891
+ <div>
7892
+ <input id="loadConfigImportFile" type="file" accept=".json,application/json" style="display:none" onchange="loadImportConfigFile(this)" />
7893
+ <button class="load-btn" id="loadImportFileBtn">Выбрать JSON-файл</button>
7894
+ </div>
7895
+ <div style="display:flex;gap:8px">
7896
+ <button class="load-btn" id="loadImportCancel">Отмена</button>
7897
+ <button class="load-btn load-btn-run" id="loadImportApply" disabled>Импорт</button>
7898
+ </div>
7899
+ </div>
7900
+ </div>`;
7901
+ document.body.appendChild(overlay);
7902
+
7903
+ const textEl = overlay.querySelector('#loadImportConfigText');
7904
+ const statusEl = overlay.querySelector('#loadImportStatus');
7905
+ const applyBtn = overlay.querySelector('#loadImportApply');
7906
+ const close = () => overlay.remove();
7907
+ const validate = () => {
7908
+ const text = textEl.value.trim();
7909
+ if (!text) {
7910
+ statusEl.textContent = 'JSON пока не вставлен';
7911
+ statusEl.style.color = 'var(--muted)';
7912
+ applyBtn.disabled = true;
7913
+ return;
7914
+ }
7915
+ try {
7916
+ const raw = JSON.parse(text);
7917
+ const imported = normalizeLoadImport(raw, 'clipboard');
7918
+ const parts = [];
7919
+ if (imported.scriptName) parts.push(imported.scriptName);
7920
+ if (imported.baseUrl) parts.push(imported.baseUrl);
7921
+ if (imported.vus) parts.push(`${imported.vus} VUs`);
7922
+ if (imported.duration) parts.push(imported.duration);
7923
+ statusEl.textContent = `JSON валидный${parts.length ? ': ' + parts.join(' · ') : ''}`;
7924
+ statusEl.style.color = 'var(--green)';
7925
+ applyBtn.disabled = false;
7926
+ } catch (e) {
7927
+ statusEl.textContent = 'JSON невалидный: ' + e.message;
7928
+ statusEl.style.color = 'var(--red)';
7929
+ applyBtn.disabled = true;
7930
+ }
7931
+ };
7932
+
7933
+ overlay.addEventListener('click', e => { if (e.target === overlay) close(); });
7934
+ overlay.querySelector('#loadImportClose').addEventListener('click', close);
7935
+ overlay.querySelector('#loadImportCancel').addEventListener('click', close);
7936
+ overlay.querySelector('#loadImportFileBtn').addEventListener('click', () => {
7937
+ const input = overlay.querySelector('#loadConfigImportFile');
7938
+ input.value = '';
7939
+ input.click();
7940
+ });
7941
+ textEl.addEventListener('input', validate);
7942
+ applyBtn.addEventListener('click', () => {
7943
+ try {
7944
+ readLoadImportConfigText(textEl.value, 'clipboard');
7945
+ close();
7946
+ } catch (e) {
7947
+ statusEl.textContent = 'Конфиг не импортирован: ' + e.message;
7948
+ statusEl.style.color = 'var(--red)';
7949
+ applyBtn.disabled = true;
7950
+ }
7951
+ });
7952
+ setTimeout(() => textEl.focus(), 0);
7953
+ }
7954
+
7803
7955
  function renderLoad(c) {
7804
7956
  const isRunning = loadState && loadState.status === 'running';
7805
7957
  const isDone = loadState && (loadState.status === 'done' || loadState.status === 'stopped');
@@ -7853,12 +8005,15 @@ function renderLoad(c) {
7853
8005
  <div class="load-library-header">
7854
8006
  <div>
7855
8007
  <div style="font-size:16px;font-weight:600;color:var(--fg)">Нагрузочные тесты</div>
7856
- <div style="font-size:12px;color:var(--muted);margin-top:2px">${loadK6Version ? escapeHtml(loadK6Version) : ''} · ${loadSavedScripts.length} сохранённых</div>
7857
- </div>
7858
- <button class="load-btn load-btn-run" style="font-size:13px;padding:8px 20px" onclick="loadNewTest()">+ Новый тест</button>
7859
- </div>
7860
-
7861
- ${loadSavedScripts.length === 0
8008
+ <div style="font-size:12px;color:var(--muted);margin-top:2px">${loadK6Version ? escapeHtml(loadK6Version) : ''} · ${loadSavedScripts.length} сохранённых</div>
8009
+ </div>
8010
+ <div class="load-btns" style="margin:0">
8011
+ <button class="load-btn" style="font-size:13px;padding:8px 14px" onclick="loadImportConfigClick()">Импорт конфига</button>
8012
+ <button class="load-btn load-btn-run" style="font-size:13px;padding:8px 20px" onclick="loadNewTest()">+ Новый тест</button>
8013
+ </div>
8014
+ </div>
8015
+
8016
+ ${loadSavedScripts.length === 0
7862
8017
  ? `<div class="load-library-empty">
7863
8018
  <div style="font-size:32px;margin-bottom:12px">📋</div>
7864
8019
  <div style="font-size:14px;font-weight:500;margin-bottom:6px">Нет сохранённых тестов</div>
@@ -7905,10 +8060,11 @@ function renderLoad(c) {
7905
8060
 
7906
8061
  c.innerHTML = `<div class="load-screen">
7907
8062
 
7908
- <div class="load-editor-topbar">
7909
- ${!isRunning ? `<button class="load-back-btn" onclick="loadView='library';renderContent()">← Все тесты</button>` : ''}
7910
- <span style="font-size:12px;color:var(--muted);margin-left:4px">${statusBadge}</span>
7911
- </div>
8063
+ <div class="load-editor-topbar">
8064
+ ${!isRunning ? `<button class="load-back-btn" onclick="loadView='library';renderContent()">← Все тесты</button>` : ''}
8065
+ ${!isRunning ? `<button class="load-btn" style="font-size:12px;padding:5px 10px" onclick="loadImportConfigClick()">Импорт конфига</button>` : ''}
8066
+ <span style="font-size:12px;color:var(--muted);margin-left:4px">${statusBadge}</span>
8067
+ </div>
7912
8068
 
7913
8069
  <div class="load-section">
7914
8070
  <div class="load-section-title">Конфигурация ${loadK6Version ? `<span style="color:var(--dim);font-weight:400">${escapeHtml(loadK6Version)}</span>` : ''}</div>
@@ -8021,18 +8177,20 @@ function renderLoad(c) {
8021
8177
  }
8022
8178
  }
8023
8179
 
8024
- function loadNewTest() {
8025
- loadScriptDraft = '';
8026
- loadScriptNameDraft = '';
8027
- loadView = 'editor';
8028
- renderContent();
8029
- }
8180
+ function loadNewTest() {
8181
+ loadScriptDraft = '';
8182
+ loadScriptNameDraft = '';
8183
+ loadImportedEnvVarsDraft = {};
8184
+ loadView = 'editor';
8185
+ renderContent();
8186
+ }
8030
8187
 
8031
8188
  function loadOpenScript(name) {
8032
8189
  const s = loadSavedScripts.find(x => x.name === name);
8033
8190
  if (!s) return;
8034
8191
  loadScriptDraft = s.script;
8035
8192
  loadScriptNameDraft = s.name;
8193
+ loadImportedEnvVarsDraft = {};
8036
8194
  if (s.baseUrl) loadBaseUrlDraft = s.baseUrl;
8037
8195
  if (s.vus) loadVusDraft = s.vus;
8038
8196
  if (s.duration) loadDurationDraft = s.duration;
@@ -8082,8 +8240,8 @@ async function runLoadTest() {
8082
8240
  loadLogLines = [];
8083
8241
  loadBuckets = [];
8084
8242
 
8085
- try {
8086
- const envVars = {};
8243
+ try {
8244
+ const envVars = { ...(loadImportedEnvVarsDraft || {}) };
8087
8245
  if (accountsInfo.accounts.length > 0) {
8088
8246
  envVars.TEST_ACCOUNTS_JSON = accountsInfo.text;
8089
8247
  envVars.TEST_EMAIL = accountsInfo.accounts[0].email;
@@ -8278,6 +8436,7 @@ async function loadOpenRun(runId) {
8278
8436
  loadLogLines = d.logs || [];
8279
8437
  loadScriptDraft = d.script || '';
8280
8438
  loadScriptNameDraft = d.config?.scriptName || d.scriptName || '';
8439
+ loadImportedEnvVarsDraft = {};
8281
8440
  if (d.config) applyLoadConfigToFields(d.config);
8282
8441
  loadView = 'editor';
8283
8442
  renderContent();
@@ -8321,6 +8480,7 @@ async function loadLoadScript(name) {
8321
8480
  if (!s) return;
8322
8481
  loadScriptDraft = s.script;
8323
8482
  loadScriptNameDraft = s.name;
8483
+ loadImportedEnvVarsDraft = {};
8324
8484
  if (s.baseUrl) loadBaseUrlDraft = s.baseUrl;
8325
8485
  if (s.vus) loadVusDraft = s.vus;
8326
8486
  if (s.duration) loadDurationDraft = s.duration;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.214",
3
+ "version": "0.3.216",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {