📤 Built a useful command? Submit it here — we'll review & add it to the library.

Attach KB Article

Hint: Look up a KB article by number and attach it as a work note

Trigger: \kbattach

(function() {
  var INSTANCE = ''; // same instance, relative API calls

  var href = decodeURIComponent(window.location.href);
  var sysIdMatch = href.match(/sys_id[=%3D]+([a-f0-9]{32})/i);
  if (!sysIdMatch) { alert('Could not find a record sys_id. Open an Incident or RITM first.'); return; }
  var recordSysId = sysIdMatch[1];

  var tableMap = { 'sc_req_item': 'sc_req_item', 'sc_task': 'sc_task', 'change_request': 'change_request', 'incident': 'incident' };
  var currentTable = 'incident';
  Object.keys(tableMap).forEach(function(t) { if (href.indexOf(t) !== -1) currentTable = tableMap[t]; });

  var overlay = document.createElement('div');
  overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.65);z-index:99999;display:flex;align-items:center;justify-content:center;font-family:sans-serif;';
  var box = document.createElement('div');
  box.style.cssText = 'background:#fff;border-radius:8px;padding:24px;width:500px;display:flex;flex-direction:column;box-shadow:0 4px 28px rgba(0,0,0,0.35);';
  var title = document.createElement('div');
  title.textContent = 'Attach KB Article as Work Note';
  title.style.cssText = 'font-size:16px;font-weight:bold;margin-bottom:6px;color:#1a1a1a;';
  var subtitle = document.createElement('div');
  subtitle.textContent = 'Record: ' + currentTable.toUpperCase();
  subtitle.style.cssText = 'font-size:12px;color:#888;margin-bottom:16px;';
  var inputLabel = document.createElement('label');
  inputLabel.textContent = 'KB Article Number';
  inputLabel.style.cssText = 'font-size:13px;font-weight:600;color:#333;margin-bottom:5px;display:block;';
  var kbInput = document.createElement('input');
  kbInput.type = 'text';
  kbInput.placeholder = 'e.g. KB0012345';
  kbInput.style.cssText = 'width:100%;padding:9px 12px;border:1px solid #ccc;border-radius:4px;font-size:14px;box-sizing:border-box;margin-bottom:14px;outline:none;';
  var statusBox = document.createElement('div');
  statusBox.style.cssText = 'font-size:12px;min-height:18px;margin-bottom:12px;color:#555;display:none;';
  var previewWrap = document.createElement('div');
  previewWrap.style.cssText = 'display:none;background:#f4f4f4;border-radius:4px;padding:10px;font-size:12px;font-family:monospace;word-break:break-all;margin-bottom:14px;color:#333;';
  var btnRow = document.createElement('div');
  btnRow.style.cssText = 'display:flex;gap:8px;justify-content:flex-end;';
  var cancelBtn = document.createElement('button');
  cancelBtn.textContent = 'Cancel';
  cancelBtn.style.cssText = 'padding:8px 18px;background:#e0e0e0;color:#333;border:none;border-radius:4px;cursor:pointer;font-size:13px;';
  cancelBtn.onclick = function() { document.body.removeChild(overlay); };
  var attachBtn = document.createElement('button');
  attachBtn.textContent = 'Attach as Work Note';
  attachBtn.style.cssText = 'padding:8px 18px;background:#0070d2;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:600;';
  btnRow.appendChild(cancelBtn); btnRow.appendChild(attachBtn);
  box.appendChild(title); box.appendChild(subtitle); box.appendChild(inputLabel); box.appendChild(kbInput); box.appendChild(statusBox); box.appendChild(previewWrap); box.appendChild(btnRow);
  overlay.appendChild(box); document.body.appendChild(overlay);
  setTimeout(function() { kbInput.focus(); }, 100);
  kbInput.addEventListener('keydown', function(e) { if (e.key === 'Enter') attachBtn.click(); });

  function setStatus(msg, color) { statusBox.textContent = msg; statusBox.style.color = color || '#555'; statusBox.style.display = msg ? 'block' : 'none'; }
  function resetBtn() { attachBtn.disabled = false; attachBtn.textContent = 'Attach as Work Note'; attachBtn.style.background = '#0070d2'; }

  function onKbFound(kbSysId, kbTitle) {
    var codeBlock = '[code]<a title="' + kbTitle + '" href=\'kb_view.do?sys_kb_id=' + kbSysId + '\' >' + kbInput.value.trim().toUpperCase() + ' : ' + kbTitle + '</a>[/code]';
    previewWrap.textContent = codeBlock;
    previewWrap.style.display = 'block';
    setStatus('KB found: ' + kbTitle, '#2e7d32');
    attachBtn.textContent = 'Posting Work Note...';
    var patchXhr = new XMLHttpRequest();
    patchXhr.open('PATCH', INSTANCE + '/api/now/table/' + currentTable + '/' + recordSysId, true);
    patchXhr.setRequestHeader('Content-Type', 'application/json');
    patchXhr.setRequestHeader('Accept', 'application/json');
    patchXhr.setRequestHeader('X-UserToken', window.g_ck);
    patchXhr.onload = function() {
      if (patchXhr.status === 200) {
        setStatus('Work note posted successfully.', '#2e7d32');
        attachBtn.textContent = 'Done';
        attachBtn.style.background = '#2e7d32';
        setTimeout(function() { document.body.removeChild(overlay); window.location.reload(); }, 1500);
      } else { setStatus('Failed to post work note (HTTP ' + patchXhr.status + ')', '#c62828'); resetBtn(); }
    };
    patchXhr.onerror = function() { setStatus('Network error posting work note.', '#c62828'); resetBtn(); };
    patchXhr.send(JSON.stringify({ work_notes: codeBlock }));
  }

  function promptManualFallback(kbNumber) {
    setStatus('', '');
    previewWrap.style.display = 'none';
    inputLabel.textContent = 'KB not found via API. Paste the KB sys_id manually:';
    inputLabel.style.color = '#e65100';
    kbInput.value = '';
    kbInput.placeholder = 'e.g. c43d47123b35be10dde8037aa5e45ac1';
    kbInput.focus();
    attachBtn.disabled = false;
    attachBtn.textContent = 'Use this sys_id';
    attachBtn.style.background = '#e65100';
    setStatus('Open the KB article, copy the sys_id from its URL, paste above.', '#e65100');
    attachBtn.onclick = function() {
      var manualSysId = kbInput.value.trim();
      if (!/^[a-f0-9]{32}$/i.test(manualSysId)) { setStatus('That does not look like a valid sys_id (32 hex chars).', '#c62828'); return; }
      attachBtn.disabled = true; attachBtn.textContent = 'Posting...';
      onKbFound(manualSysId, kbNumber);
    };
  }

  function tryAltLookup(kbNumber) {
    setStatus('Trying alternate lookup...', '#0070d2');
    var altUrl = INSTANCE + '/api/now/table/kb_knowledge?sysparm_query=' + encodeURIComponent('numberSTARTSWITH' + kbNumber + '^workflow_state=published') + '&sysparm_fields=sys_id,number,short_description&sysparm_limit=1&sysparm_suppress_pagination_header=true';
    var altXhr = new XMLHttpRequest();
    altXhr.open('GET', altUrl, true);
    altXhr.setRequestHeader('Accept', 'application/json');
    altXhr.setRequestHeader('X-UserToken', window.g_ck);
    altXhr.onload = function() {
      if (altXhr.status !== 200) { promptManualFallback(kbNumber); return; }
      var results;
      try { results = JSON.parse(altXhr.responseText).result; } catch(e) { results = []; }
      if (!results || results.length === 0) { promptManualFallback(kbNumber); return; }
      onKbFound(results[0].sys_id, results[0].short_description || kbNumber);
    };
    altXhr.onerror = function() { setStatus('Network error on alternate lookup.', '#c62828'); resetBtn(); };
    altXhr.send();
  }

  attachBtn.onclick = function() {
    var kbNumber = kbInput.value.trim().toUpperCase();
    if (!kbNumber) { setStatus('Please enter a KB article number.', '#e65100'); kbInput.focus(); return; }
    if (!/^KB\d+$/i.test(kbNumber)) { setStatus('Invalid format. Use KB followed by digits, e.g. KB0012345', '#e65100'); kbInput.focus(); return; }
    attachBtn.disabled = true;
    attachBtn.textContent = 'Looking up KB...';
    previewWrap.style.display = 'none';
    setStatus('Searching for ' + kbNumber + '...', '#0070d2');
    var spUrl = INSTANCE + '/api/now/sp/search?q=' + encodeURIComponent(kbNumber) + '&kb=true&limit=10';
    var spXhr = new XMLHttpRequest();
    spXhr.open('GET', spUrl, true);
    spXhr.setRequestHeader('Accept', 'application/json');
    spXhr.setRequestHeader('X-UserToken', window.g_ck);
    spXhr.onload = function() {
      if (spXhr.status !== 200) { tryAltLookup(kbNumber); return; }
      var data;
      try { data = JSON.parse(spXhr.responseText); } catch(e) { tryAltLookup(kbNumber); return; }
      var items = [];
      if (data.result) {
        if (Array.isArray(data.result)) items = data.result;
        if (Array.isArray(data.result.kb_results)) items = items.concat(data.result.kb_results);
        if (Array.isArray(data.result.search_results)) items = items.concat(data.result.search_results);
      }
      var kb = null;
      items.forEach(function(item) { if (!kb && item.number && item.number.toUpperCase() === kbNumber) kb = item; });
      if (!kb) { tryAltLookup(kbNumber); return; }
      var kbSysId = kb.sys_id;
      if (!kbSysId && kb.link) { var m = kb.link.match(/([a-f0-9]{32})/i); if (m) kbSysId = m[1]; }
      if (!kbSysId) { tryAltLookup(kbNumber); return; }
      onKbFound(kbSysId, kb.short_description || kb.title || kbNumber);
    };
    spXhr.onerror = function() { tryAltLookup(kbNumber); };
    spXhr.send();
  };
})();