- Add CloudronStack/output/CloudronPackages-Artifacts/tirreno/ directory and its contents - Includes package manifest, Dockerfile, source code, documentation, and build artifacts - Add tirreno-1761840148.tar.gz as a build artifact - Add tirreno-cloudron-package-1761841304.tar.gz as the Cloudron package - Include all necessary files for the tirreno Cloudron package This adds the complete tirreno Cloudron package artifacts to the repository.
		
			
				
	
	
		
			2013 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			2013 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import {padZero} from './utils/Date.js?v=2';
 | 
						||
import {
 | 
						||
    //truncateWithHellip,
 | 
						||
    getRuleClass,
 | 
						||
    formatTime,
 | 
						||
    openJson,
 | 
						||
} from './utils/String.js?v=2';
 | 
						||
 | 
						||
import {
 | 
						||
    MAX_STRING_LONG_NETNAME_IN_TABLE,
 | 
						||
    MAX_STRING_SHORT_NETNAME_IN_TABLE,
 | 
						||
    MAX_STRING_LENGTH_IN_TABLE,
 | 
						||
    MAX_STRING_USER_SHORT_LENGTH_IN_TABLE,
 | 
						||
    MAX_STRING_USER_MEDIUM_LENGTH_IN_TABLE,
 | 
						||
    MAX_STRING_USER_LONG_LENGTH_IN_TABLE,
 | 
						||
    MAX_STRING_USER_LONG_LENGTH_IN_TILE,
 | 
						||
    MAX_STRING_LENGTH_IN_TABLE_ON_DASHBOARD,
 | 
						||
    MAX_STRING_LENGTH_FOR_EMAIL,
 | 
						||
    MAX_STRING_LENGTH_FOR_PHONE,
 | 
						||
    MAX_STRING_LENGTH_FULL_COUNTRY,
 | 
						||
    MAX_STRING_LENGTH_FOR_TILE,
 | 
						||
    MAX_STRING_USERID_LENGTH_IN_TABLE,
 | 
						||
    MAX_STRING_USER_NAME_IN_TABLE,
 | 
						||
    MAX_STRING_DEVICE_OS_LENGTH,
 | 
						||
    MAX_STRING_LENGTH_URL,
 | 
						||
    MAX_TOOLTIP_URL_LENGTH,
 | 
						||
    MAX_TOOLTIP_LENGTH,
 | 
						||
 | 
						||
    USER_LOW_TRUST_SCORE_INF,
 | 
						||
    USER_LOW_TRUST_SCORE_SUP,
 | 
						||
    USER_MEDIUM_TRUST_SCORE_INF,
 | 
						||
    USER_MEDIUM_TRUST_SCORE_SUP,
 | 
						||
    USER_HIGH_TRUST_SCORE_INF,
 | 
						||
 | 
						||
    ASN_OVERRIDE,
 | 
						||
    COUNTRIES_EXCEPTIONS,
 | 
						||
    NORMAL_DEVICES,
 | 
						||
    PHONE_LANDLINE,
 | 
						||
    NO_RULES_MSG,
 | 
						||
    UNDEFINED_RULES_MSG,
 | 
						||
    MIDLINE_HELLIP,
 | 
						||
    HELLIP,
 | 
						||
    HYPHEN,
 | 
						||
} from './utils/Constants.js?v=2';
 | 
						||
 | 
						||
const isDashboardPage = () => !!document.getElementById('most-active-users');
 | 
						||
 | 
						||
const getNumberOfSymbols = (length = 'default') => {
 | 
						||
    if (isDashboardPage()) {
 | 
						||
        return MAX_STRING_LENGTH_IN_TABLE_ON_DASHBOARD;
 | 
						||
    } else {
 | 
						||
        if (length === 'long') {
 | 
						||
            return MAX_STRING_USER_LONG_LENGTH_IN_TABLE;
 | 
						||
        } else if (length === 'short') {
 | 
						||
            return MAX_STRING_USER_SHORT_LENGTH_IN_TABLE;
 | 
						||
        } else if (length === 'medium') {
 | 
						||
            return MAX_STRING_USER_MEDIUM_LENGTH_IN_TABLE;
 | 
						||
        } else if (length === 'tile') {
 | 
						||
            return MAX_STRING_USER_LONG_LENGTH_IN_TILE;
 | 
						||
        } else {
 | 
						||
            return MAX_STRING_LENGTH_IN_TABLE;
 | 
						||
        }
 | 
						||
    }
 | 
						||
};
 | 
						||
 | 
						||
const tooltipWrap = (tooltip, value, wrap = true, wordBreak = false) => {
 | 
						||
    let node = (typeof value === 'string') ? document.createTextNode(value) : value;
 | 
						||
 | 
						||
    let result = (wrap) ? document.createElement('span') : node;
 | 
						||
 | 
						||
    if (wrap) {
 | 
						||
        result.appendChild(node);
 | 
						||
    }
 | 
						||
 | 
						||
    if (tooltip !== null && tooltip !== undefined && tooltip !== '') {
 | 
						||
        result.classList.add('tooltip');
 | 
						||
        if (wordBreak) {
 | 
						||
            result.classList.add('tooltipster-word-break');
 | 
						||
        }
 | 
						||
        result.title = tooltip;
 | 
						||
    }
 | 
						||
 | 
						||
    return result;
 | 
						||
};
 | 
						||
 | 
						||
const truncateWithHellip = (value, n, wordBreak = false) => {
 | 
						||
    let tooltip = value;
 | 
						||
 | 
						||
    if (value && value.length > (n + 2)) {
 | 
						||
        value = value.slice(0, n) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    if (tooltip && tooltip.length > MAX_TOOLTIP_LENGTH) {
 | 
						||
        tooltip = tooltip.slice(0, MAX_TOOLTIP_LENGTH) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    return tooltipWrap(tooltip, renderDefaultIfEmpty(value), true, wordBreak);
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithCountryDiv = html => {
 | 
						||
    let node = document.createElement('div');
 | 
						||
    node.className = 'flag';
 | 
						||
    node.appendChild(html);
 | 
						||
 | 
						||
    return node;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithImportantSpan = (span, record) => {
 | 
						||
    if (!record.is_important) {
 | 
						||
        return span;
 | 
						||
    }
 | 
						||
 | 
						||
    const el = document.createElement('span');
 | 
						||
    el.className = 'important-user';
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithUserLink = (span, record) => {
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/id/${record.accountid}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithResourceLink = (span, record) => {
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/resource/${record.url_id}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithIpLink = (span, record) => {
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/ip/${record.ipid}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithIspLink = (span, record) => {
 | 
						||
    if (!record.ispid) {
 | 
						||
        return span;
 | 
						||
    }
 | 
						||
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/isp/${record.ispid}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithCountryLink = (span, record) => {
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/country/${record.country_id}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithBotLink = (span, record) => {
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/bot/${record.id}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithPhoneLink = (span, record) => {
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/phones/${record.id}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithDomainLink = (span, record) => {
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/domain/${record.id}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const wrapWithRuleLink = (span, ruleUid) => {
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = `/id?ruleUid=${ruleUid}`;
 | 
						||
    el.appendChild(span);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
/*const wrapWithFraudSpan = (html, record) => {
 | 
						||
    if (record.fraud_detected) {
 | 
						||
        html = `<span class="fraud">${html}</span>`;
 | 
						||
    }
 | 
						||
 | 
						||
    return html;
 | 
						||
};*/
 | 
						||
 | 
						||
const normalizeTimestamp = (ts) => {
 | 
						||
    //Fix for ie and safari: https://www.linkedin.com/pulse/fix-invalid-date-safari-ie-hatem-ahmad
 | 
						||
    ts = ts.replace(/-/g, '/');
 | 
						||
    ts = ts.split('.');
 | 
						||
 | 
						||
    return ts[0];
 | 
						||
};
 | 
						||
 | 
						||
const renderTimeString = (data) => {
 | 
						||
    if (data) {
 | 
						||
        data = normalizeTimestamp(data);
 | 
						||
    }
 | 
						||
 | 
						||
    const dt = new Date(data);
 | 
						||
 | 
						||
    if (dt instanceof Date && !isNaN(dt)) {
 | 
						||
        let [month, day, year] = [
 | 
						||
            dt.getMonth() + 1,
 | 
						||
            dt.getDate(),
 | 
						||
            dt.getFullYear(),
 | 
						||
        ];
 | 
						||
 | 
						||
        let [hours, minutes, seconds] = [
 | 
						||
            dt.getHours(),
 | 
						||
            dt.getMinutes(),
 | 
						||
            dt.getSeconds(),
 | 
						||
        ];
 | 
						||
 | 
						||
        day     = padZero(day);
 | 
						||
        month   = padZero(month);
 | 
						||
        year    = padZero(year, 4);
 | 
						||
        hours   = padZero(hours);
 | 
						||
        minutes = padZero(minutes);
 | 
						||
        seconds = padZero(seconds);
 | 
						||
 | 
						||
        data = `${day}/${month}/${year} ${hours}:${minutes}:${seconds}`;
 | 
						||
    }
 | 
						||
 | 
						||
    return data;
 | 
						||
};
 | 
						||
 | 
						||
const renderTime = (data) => {
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = renderTimeString(data);
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderTimeMsString = (data) => {
 | 
						||
    let milliseconds = 0;
 | 
						||
    if (data) {
 | 
						||
        //Fix for ie and safari: https://www.linkedin.com/pulse/fix-invalid-date-safari-ie-hatem-ahmad
 | 
						||
        data = data.replace(/-/g, '/');
 | 
						||
        const s = data.split('.');
 | 
						||
        data = s[0];
 | 
						||
        // safari issue
 | 
						||
        // not equivalent to dt.getMilliseconds(); in case of 01:01:01.7 getMilliseconds() returns 700 and split returns 7
 | 
						||
        milliseconds = (s.length > 1) ? s[1] : 0;
 | 
						||
    }
 | 
						||
 | 
						||
    const dt = new Date(data);
 | 
						||
 | 
						||
    if (dt instanceof Date && !isNaN(dt)) {
 | 
						||
        let [month, day, year] = [
 | 
						||
            dt.getMonth() + 1,
 | 
						||
            dt.getDate(),
 | 
						||
            dt.getFullYear(),
 | 
						||
        ];
 | 
						||
 | 
						||
        let [hours, minutes, seconds] = [
 | 
						||
            dt.getHours(),
 | 
						||
            dt.getMinutes(),
 | 
						||
            dt.getSeconds(),
 | 
						||
        ];
 | 
						||
 | 
						||
        day             = padZero(day);
 | 
						||
        month           = padZero(month);
 | 
						||
        year            = padZero(year, 4);
 | 
						||
        hours           = padZero(hours);
 | 
						||
        minutes         = padZero(minutes);
 | 
						||
        seconds         = padZero(seconds);
 | 
						||
        milliseconds    = padZero(milliseconds, -3);
 | 
						||
 | 
						||
        data = `${day}/${month}/${year} ${hours}:${minutes}:${seconds}.${milliseconds}`;
 | 
						||
    }
 | 
						||
 | 
						||
    return data;
 | 
						||
};
 | 
						||
 | 
						||
const renderTimeMs = (data) => {
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = renderTimeMsString(data);
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderDateString = (data) => {
 | 
						||
    if (data) {
 | 
						||
        data = normalizeTimestamp(data);
 | 
						||
    } else {
 | 
						||
        data = renderDefaultIfEmpty(data);
 | 
						||
        return data;
 | 
						||
    }
 | 
						||
 | 
						||
    const dt = new Date(data);
 | 
						||
 | 
						||
    if (dt instanceof Date && !isNaN(dt)) {
 | 
						||
        let [month, day, year] = [
 | 
						||
            dt.getMonth() + 1,
 | 
						||
            dt.getDate(),
 | 
						||
            dt.getFullYear(),
 | 
						||
        ];
 | 
						||
 | 
						||
        day   = padZero(day);
 | 
						||
        month = padZero(month);
 | 
						||
        year  = padZero(year, 4);
 | 
						||
 | 
						||
        data = `${day}/${month}/${year}`;
 | 
						||
    }
 | 
						||
 | 
						||
    return data;
 | 
						||
};
 | 
						||
 | 
						||
const renderDate = (data) => {
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = renderDateString(data);
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderChoicesSelectorItem = (classNames, data, innerHtml) => {
 | 
						||
    const itemClass = data.highlighted ? classNames.highlightedState : classNames.itemSelectable;
 | 
						||
 | 
						||
    const button = document.createElement('button');
 | 
						||
    button.type = 'button';
 | 
						||
    button.className = classNames.button;
 | 
						||
    button.textContent = 'Remove item';
 | 
						||
    button.setAttribute('aria-label', 'Remove item');
 | 
						||
    button.setAttribute('data-button', '');
 | 
						||
 | 
						||
    const div = document.createElement('div');
 | 
						||
    div.className = `${classNames.item} ${itemClass}`;
 | 
						||
 | 
						||
    div.setAttribute('data-item', true);
 | 
						||
    div.setAttribute('data-id', data.id);
 | 
						||
    div.setAttribute('data-value', data.value);
 | 
						||
 | 
						||
    if (data.active) {
 | 
						||
        div.setAttribute('aria-selected', 'true');
 | 
						||
    }
 | 
						||
    if (data.disabled) {
 | 
						||
        div.setAttribute('aria-disabled', 'true');
 | 
						||
    }
 | 
						||
 | 
						||
    div.appendChild(innerHtml);
 | 
						||
    div.appendChild(button);
 | 
						||
 | 
						||
    return div.outerHTML;
 | 
						||
};
 | 
						||
 | 
						||
const renderChoicesSelectorChoice = (classNames, data, itemSelectText, innerHtml) => {
 | 
						||
    const choiceClass = data.disabled ? classNames.itemDisabled : classNames.itemSelectable;
 | 
						||
 | 
						||
    const div = document.createElement('div');
 | 
						||
    div.className = `${classNames.item} ${classNames.itemChoice} ${choiceClass}`;
 | 
						||
    div.role = (data.groupId > 0) ? 'treeitem' : 'option';
 | 
						||
 | 
						||
    div.setAttribute('data-select-text', itemSelectText);
 | 
						||
    div.setAttribute('data-choice', true);
 | 
						||
    div.setAttribute('data-id', data.id);
 | 
						||
    div.setAttribute('data-value', data.value);
 | 
						||
 | 
						||
    if (data.disabled) {
 | 
						||
        div.setAttribute('data-choice-disabled', true);
 | 
						||
        div.setAttribute('aria-disabled', 'true');
 | 
						||
    } else {
 | 
						||
        div.setAttribute('data-choice-selectable', true);
 | 
						||
    }
 | 
						||
 | 
						||
    div.appendChild(innerHtml);
 | 
						||
 | 
						||
    return div.outerHTML;
 | 
						||
};
 | 
						||
 | 
						||
const splitLabel = (label) => {
 | 
						||
    const node = document.createElement('div');
 | 
						||
    node.innerHTML = label;
 | 
						||
 | 
						||
    return node.textContent.split('|');
 | 
						||
};
 | 
						||
 | 
						||
const renderRuleSelectorItem = (classNames, data) => {
 | 
						||
    const [uid, className, title] = splitLabel(data.label);
 | 
						||
 | 
						||
    const innerHtml = document.createDocumentFragment();
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.className = `ruleHighlight ${className}`;
 | 
						||
    span.textContent = uid;
 | 
						||
    innerHtml.appendChild(span);
 | 
						||
    const el = document.createTextNode(title);
 | 
						||
    innerHtml.appendChild(el);
 | 
						||
 | 
						||
    return renderChoicesSelectorItem(classNames, data, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderRuleSelectorChoice = (classNames, data, itemSelectText) => {
 | 
						||
    const [uid, className, title] = splitLabel(data.label);
 | 
						||
 | 
						||
    const innerHtml = document.createDocumentFragment();
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.className = `ruleHighlight ${className}`;
 | 
						||
    span.textContent = uid;
 | 
						||
    innerHtml.appendChild(span);
 | 
						||
    const el = document.createTextNode(title);
 | 
						||
    innerHtml.appendChild(el);
 | 
						||
 | 
						||
    return renderChoicesSelectorChoice(classNames, data, itemSelectText, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderEventTypeSelectorItem = (classNames, data) => {
 | 
						||
    const [value, name] = splitLabel(data.label);
 | 
						||
 | 
						||
    const innerHtml = document.createDocumentFragment();
 | 
						||
    const node = document.createElement('p');
 | 
						||
    node.className = `bullet ${value}`;
 | 
						||
    innerHtml.appendChild(node);
 | 
						||
    const el = document.createTextNode(name);
 | 
						||
    innerHtml.appendChild(el);
 | 
						||
 | 
						||
    return renderChoicesSelectorItem(classNames, data, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderEventTypeSelectorChoice = (classNames, data, itemSelectText) => {
 | 
						||
    const [value, name] = splitLabel(data.label);
 | 
						||
 | 
						||
    const innerHtml = document.createDocumentFragment();
 | 
						||
    const node = document.createElement('p');
 | 
						||
    node.className = `bullet ${value}`;
 | 
						||
    innerHtml.appendChild(node);
 | 
						||
    const el = document.createTextNode(name);
 | 
						||
    innerHtml.appendChild(el);
 | 
						||
 | 
						||
    return renderChoicesSelectorChoice(classNames, data, itemSelectText, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderIpTypeSelectorItem = (classNames, data) => {
 | 
						||
    const [value] = splitLabel(data.label);
 | 
						||
    const innerHtml = document.createElement('span');
 | 
						||
    innerHtml.textContent = value;
 | 
						||
 | 
						||
    return renderChoicesSelectorItem(classNames, data, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderIpTypeSelectorChoice = (classNames, data, itemSelectText) => {
 | 
						||
    const [value] = splitLabel(data.label);
 | 
						||
    const innerHtml = document.createElement('span');
 | 
						||
    innerHtml.textContent = value;
 | 
						||
 | 
						||
    return renderChoicesSelectorChoice(classNames, data, itemSelectText, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderDeviceTypeSelectorItem = (classNames, data) => {
 | 
						||
    const [value] = splitLabel(data.label);
 | 
						||
    const innerHtml = document.createElement('span');
 | 
						||
 | 
						||
    const deviceIsNormal = NORMAL_DEVICES.includes(value);
 | 
						||
    const deviceTypeImg = deviceIsNormal ? value : 'unknown';
 | 
						||
    const img = document.createElement('img');
 | 
						||
    img.src = `/ui/images/icons/${deviceTypeImg}.svg`;
 | 
						||
    img.className = 'device-choice';
 | 
						||
 | 
						||
    const name = document.createTextNode(value);
 | 
						||
 | 
						||
    innerHtml.appendChild(img);
 | 
						||
    innerHtml.appendChild(name);
 | 
						||
 | 
						||
    return renderChoicesSelectorItem(classNames, data, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderDeviceTypeSelectorChoice = (classNames, data, itemSelectText) => {
 | 
						||
    const [value] = splitLabel(data.label);
 | 
						||
    const innerHtml = document.createElement('span');
 | 
						||
 | 
						||
    const deviceIsNormal = NORMAL_DEVICES.includes(value);
 | 
						||
    const deviceTypeImg = deviceIsNormal ? value : 'unknown';
 | 
						||
    const img = document.createElement('img');
 | 
						||
    img.src = `/ui/images/icons/${deviceTypeImg}.svg`;
 | 
						||
    img.className = 'device-choice';
 | 
						||
 | 
						||
    const name = document.createTextNode(value);
 | 
						||
 | 
						||
    innerHtml.appendChild(img);
 | 
						||
    innerHtml.appendChild(name);
 | 
						||
 | 
						||
    return renderChoicesSelectorChoice(classNames, data, itemSelectText, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderEntityTypeSelectorItem = (classNames, data) => {
 | 
						||
    const [value] = splitLabel(data.label);
 | 
						||
    const innerHtml = document.createElement('span');
 | 
						||
    innerHtml.textContent = value;
 | 
						||
 | 
						||
    return renderChoicesSelectorItem(classNames, data, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderEntityTypeSelectorChoice = (classNames, data, itemSelectText) => {
 | 
						||
    const [value] = splitLabel(data.label);
 | 
						||
    const innerHtml = document.createElement('span');
 | 
						||
    innerHtml.textContent = value;
 | 
						||
 | 
						||
    return renderChoicesSelectorChoice(classNames, data, itemSelectText, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderScoresRangeSelectorItem = (classNames, data) => {
 | 
						||
    const [bottom, top] = splitLabel(data.label);
 | 
						||
    const innerHtml = document.createElement('span');
 | 
						||
    innerHtml.textContent = `${bottom} - ${top}`;
 | 
						||
 | 
						||
    return renderChoicesSelectorItem(classNames, data, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderScoresRangeSelectorChoice = (classNames, data, itemSelectText) => {
 | 
						||
    const [bottom, top] = splitLabel(data.label);
 | 
						||
    const innerHtml = document.createElement('span');
 | 
						||
    innerHtml.textContent = `${bottom} - ${top}`;
 | 
						||
 | 
						||
    return renderChoicesSelectorChoice(classNames, data, itemSelectText, innerHtml);
 | 
						||
};
 | 
						||
 | 
						||
const renderHttpCode = record => {
 | 
						||
    let span = null;
 | 
						||
    const code = record.http_code;
 | 
						||
 | 
						||
    if (code) {
 | 
						||
        let tooltip = '';
 | 
						||
 | 
						||
        switch (Math.floor(code / 100)) {
 | 
						||
            case 1:
 | 
						||
                tooltip = 'Informational responses (100 – 199)';
 | 
						||
                break;
 | 
						||
            case 2:
 | 
						||
                tooltip = 'Successful responses (200 – 299)';
 | 
						||
                break;
 | 
						||
            case 3:
 | 
						||
                tooltip = 'Redirection messages (300 – 399)';
 | 
						||
                break;
 | 
						||
            case 4:
 | 
						||
                tooltip = 'Client error responses (400 – 499)';
 | 
						||
                break;
 | 
						||
            case 5:
 | 
						||
                tooltip = 'Server error responses (500 – 599)';
 | 
						||
                break;
 | 
						||
            default:
 | 
						||
                tooltip = 'Unexpected status code';
 | 
						||
                break;
 | 
						||
        }
 | 
						||
 | 
						||
        let style = (code < 400) ? 'nolight' : 'highlight';
 | 
						||
 | 
						||
        span = document.createElement('span');
 | 
						||
        span.className = `${style} ${record.http_code}`;
 | 
						||
        span.textContent = record.http_code;
 | 
						||
 | 
						||
        span = tooltipWrap(tooltip, span, false);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderHttpMethod = record => {
 | 
						||
    let span = null;
 | 
						||
 | 
						||
    const type = record.http_method;
 | 
						||
    if (type) {
 | 
						||
        let style = (type === 'POST' || type === 'GET') ? 'nolight' : 'highlight';
 | 
						||
        span = document.createElement('span');
 | 
						||
        span.className = style;
 | 
						||
        span.textContent = type;
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderTotalFrame = (base, val) => {
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
    if (parseInt(base, 10) > parseInt(val, 10)) {
 | 
						||
        const rest = (base !== null && base !== undefined && base > 0 && base >= val) ? (base - val) : MIDLINE_HELLIP;
 | 
						||
        const span = document.createElement('span');
 | 
						||
        span.className = 'addlight';
 | 
						||
        span.textContent = val + '/';
 | 
						||
 | 
						||
        frag.appendChild(span);
 | 
						||
        frag.appendChild(document.createTextNode(rest));
 | 
						||
    } else {
 | 
						||
        frag.appendChild(document.createTextNode(base));
 | 
						||
    }
 | 
						||
 | 
						||
    return frag;
 | 
						||
};
 | 
						||
 | 
						||
const renderUserCounter = (data, critical = 1, hyphenOnEmpty = false) => {
 | 
						||
    let span = null;
 | 
						||
 | 
						||
    if (hyphenOnEmpty && !data) {
 | 
						||
        return renderDefaultIfEmptyElement(data);
 | 
						||
    }
 | 
						||
 | 
						||
    if (Number.isInteger(data) && data >= 0) {
 | 
						||
        let style = (data >= critical) ? 'highlight' : 'nolight';
 | 
						||
        span = document.createElement('span');
 | 
						||
        span.className = style;
 | 
						||
        span.textContent = data;
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderBoolean = (data) => {
 | 
						||
    let node = document.createElement('span');
 | 
						||
 | 
						||
    if (data === false) {
 | 
						||
        node.className = 'nolight';
 | 
						||
        node.textContent = 'No';
 | 
						||
    } else if (data === true) {
 | 
						||
        node.className = 'highlight';
 | 
						||
        node.textContent = 'Yes';
 | 
						||
    } else {
 | 
						||
        node.textContent = HYPHEN;
 | 
						||
    }
 | 
						||
 | 
						||
    return node;
 | 
						||
};
 | 
						||
 | 
						||
const renderProportion = (n, t) => {
 | 
						||
    const number = (typeof n === 'number' && Number.isFinite(n) && n >= 0 && n <= 100)
 | 
						||
        ? (n > 0.0 && n < 1.0 ? '<1%' : `${Math.floor(n)}%`)
 | 
						||
        : '−';
 | 
						||
    const tooltip = t ? `Last updated: ${renderDateString(t)}` : '\u2212';
 | 
						||
 | 
						||
    return tooltipWrap(tooltip, number, true);
 | 
						||
};
 | 
						||
 | 
						||
const renderUserScore = record => {
 | 
						||
    let score = (record.score !== null && record.score !== undefined) ? record.score : '\u2212';
 | 
						||
    let cls = 'empty';
 | 
						||
 | 
						||
    if (record.fraud !== undefined && record.fraud !== null) {
 | 
						||
        score = (record.fraud) ? 'X' : 'OK';
 | 
						||
        cls = (record.fraud) ? 'low' : 'high';
 | 
						||
    } else {
 | 
						||
        if (score >= USER_HIGH_TRUST_SCORE_INF) {
 | 
						||
            cls = 'high';
 | 
						||
        }
 | 
						||
 | 
						||
        if (score >= USER_MEDIUM_TRUST_SCORE_INF && score < USER_MEDIUM_TRUST_SCORE_SUP) {
 | 
						||
            cls = 'medium';
 | 
						||
        }
 | 
						||
 | 
						||
        if (score >= USER_LOW_TRUST_SCORE_INF && score < USER_LOW_TRUST_SCORE_SUP) {
 | 
						||
            cls = 'low';
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.className = `ignore-select score ${cls}`;
 | 
						||
    span.textContent = score;
 | 
						||
 | 
						||
    const lastUpdate = `Last updated: ${renderDateString(record.score_updated_at)}`;
 | 
						||
 | 
						||
    return tooltipWrap(lastUpdate, span, true);
 | 
						||
};
 | 
						||
 | 
						||
//User
 | 
						||
const renderUserId = (value) => {
 | 
						||
    let span = null;
 | 
						||
 | 
						||
    if (value) {
 | 
						||
        span = truncateWithHellip(value, MAX_STRING_USERID_LENGTH_IN_TABLE);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderUser = (record, length = 'default') => {
 | 
						||
    let span = null;
 | 
						||
    const n = getNumberOfSymbols(length);
 | 
						||
    const email = record.email;
 | 
						||
 | 
						||
    if (email) {
 | 
						||
        span = truncateWithHellip(email, n);
 | 
						||
    } else if (record.accounttitle) {
 | 
						||
        span = renderUserId(record.accounttitle);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderImportantUser = (record, length = 'default') => {
 | 
						||
    const user = renderUser(record, length);
 | 
						||
    const html = wrapWithImportantSpan(user, record);
 | 
						||
 | 
						||
    return html;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableUser = (record, length = 'long') => {
 | 
						||
    const user = renderUser(record, length);
 | 
						||
    const html = wrapWithUserLink(user, record);
 | 
						||
 | 
						||
    return html;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableImportantUser = (record, length = 'default') => {
 | 
						||
    const user = renderClickableUser(record, length);
 | 
						||
    const html = wrapWithImportantSpan(user, record);
 | 
						||
 | 
						||
    return html;
 | 
						||
};
 | 
						||
 | 
						||
const renderUserWithScore = (record, length = 'default') => {
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
    frag.appendChild(renderUserScore(record));
 | 
						||
    frag.appendChild(renderUser(record, length));
 | 
						||
 | 
						||
    return frag;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableImportantUserWithScore = (record, length = 'default') => {
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
    frag.appendChild(renderUserScore(record));
 | 
						||
    frag.appendChild(renderClickableImportantUser(record, length));
 | 
						||
 | 
						||
    return frag;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableImportantUserWithScoreTile = (record) => {
 | 
						||
    return renderClickableImportantUserWithScore(record, 'tile');
 | 
						||
};
 | 
						||
 | 
						||
const renderSession = (record) => {
 | 
						||
    let result = null;
 | 
						||
 | 
						||
    if (record.session_cnt) {
 | 
						||
        const cnt = record.session_cnt;
 | 
						||
        const max_t = renderTimeString(record.session_max_t).split(' ');
 | 
						||
        const min_t = renderTimeString(record.session_min_t).split(' ');
 | 
						||
        let value = `${cnt} action`;
 | 
						||
        value += (cnt > 1) ? `s (${formatTime(record.session_duration)})` : '';
 | 
						||
        const tooltip = (cnt > 1)
 | 
						||
            ? `${min_t[0]} ${min_t[1] || ''} - ${max_t[1] || ''}`
 | 
						||
            : `${max_t[0]} ${max_t[1] || ''}`;
 | 
						||
        const el = document.createTextNode(value);
 | 
						||
        result = tooltipWrap(tooltip, el, true);
 | 
						||
    } else {
 | 
						||
        result = renderAngrtSpan();
 | 
						||
    }
 | 
						||
 | 
						||
    return result;
 | 
						||
};
 | 
						||
 | 
						||
const renderAngrtSpan = () => {
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.className = 'angrt';
 | 
						||
    span.textContent = '\u221F';
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderUserForEvent = (record, length, sessionGroup, singleUser) => {
 | 
						||
    if (!sessionGroup) return renderUserWithScore(record, length);  // regular events
 | 
						||
    if (singleUser) return renderSession(record);                   // events on /user/abc page
 | 
						||
 | 
						||
    if (record.session_cnt) return renderUserWithScore(record, length); // events on /event page
 | 
						||
 | 
						||
    return renderAngrtSpan();
 | 
						||
};
 | 
						||
 | 
						||
const renderTimestampForEvent = (record, sessionGroup, singleUser) => {
 | 
						||
    if (sessionGroup && !singleUser && record.session_cnt && record.session_cnt > 1) return renderSession(record);  // events on /event page on session-end rows
 | 
						||
 | 
						||
    return renderTime(record.time); // events on other pages and on /event page in a middle of the session
 | 
						||
};
 | 
						||
 | 
						||
const capitalizeValue = value => {
 | 
						||
    return value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
 | 
						||
};
 | 
						||
 | 
						||
const renderUserFirstname = record => {
 | 
						||
    let span = null;
 | 
						||
    let name = record.firstname;
 | 
						||
 | 
						||
    if (name) {
 | 
						||
        name = name.replace(/\b\w+/g, capitalizeValue);
 | 
						||
        span = truncateWithHellip(name, MAX_STRING_USER_NAME_IN_TABLE);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderUserLastname = record => {
 | 
						||
    let span = null;
 | 
						||
    let name = record.lastname;
 | 
						||
 | 
						||
    if (name) {
 | 
						||
        name = name.replace(/\b\w+/g, capitalizeValue);
 | 
						||
        span = truncateWithHellip(name, MAX_STRING_USER_NAME_IN_TABLE);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderUserReviewedStatus = record => {
 | 
						||
    let span = document.createElement('span');
 | 
						||
 | 
						||
    if (record.fraud !== null) {
 | 
						||
        const reviewStatus = (record.fraud) ? 'Blacklisted' : 'Whitelisted';
 | 
						||
        const latestDecision = renderDateString(record.latest_decision);
 | 
						||
 | 
						||
        span.className = `reviewstatus ${reviewStatus}`;
 | 
						||
        span.textContent = reviewStatus;
 | 
						||
        span = tooltipWrap(latestDecision, span, false);
 | 
						||
    } else if (record.added_to_review !== null) {
 | 
						||
        span.className = 'reviewstatus in-review';
 | 
						||
        span.textContent = 'In review';
 | 
						||
    } else {
 | 
						||
        span.className = 'reviewstatus';
 | 
						||
        span.textContent = 'Normal';
 | 
						||
    }
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderUserActionButtons = (record, small = true) => {
 | 
						||
    let html;
 | 
						||
    if (record.reviewed) {
 | 
						||
        html = getFraudLegitButtons(record, small);
 | 
						||
    } else {
 | 
						||
        html = getToBeReviewedButton(record, small);
 | 
						||
    }
 | 
						||
 | 
						||
    return html;
 | 
						||
};
 | 
						||
 | 
						||
const renderBlacklistButtons = record => {
 | 
						||
    const button = document.createElement('button');
 | 
						||
    button.type = 'button';
 | 
						||
    button.className = 'button is-small dark-loader';
 | 
						||
    button.textContent = 'Remove';
 | 
						||
    button.setAttribute('data-item-id', record.entity_id);
 | 
						||
    button.setAttribute('data-item-type', record.type);
 | 
						||
    button.setAttribute('data-button-type', 'deleteButton');
 | 
						||
 | 
						||
    return button;
 | 
						||
};
 | 
						||
 | 
						||
const getFraudLegitButtons = (record, small = true) => {
 | 
						||
    let fraudBtnCls = 'is-neutral';
 | 
						||
    let legitBtnCls = 'is-neutral';
 | 
						||
 | 
						||
    if (true === record.fraud) {
 | 
						||
        fraudBtnCls = 'is-highlighted';
 | 
						||
        legitBtnCls = 'is-neutral';
 | 
						||
    }
 | 
						||
 | 
						||
    if (false === record.fraud) {
 | 
						||
        fraudBtnCls = 'is-neutral';
 | 
						||
        legitBtnCls = 'is-highlighted';
 | 
						||
    }
 | 
						||
 | 
						||
    const whitelistButton = document.createElement('button');
 | 
						||
    whitelistButton.type = 'button';
 | 
						||
    whitelistButton.className = `button light-loader ${legitBtnCls}` + ((small) ? ' is-small' : '');
 | 
						||
    whitelistButton.textContent = 'Whitelist';
 | 
						||
    if (record.fraud === false) {
 | 
						||
        whitelistButton.disabled = true;
 | 
						||
    }
 | 
						||
    whitelistButton.setAttribute('data-type', 'legit');
 | 
						||
    whitelistButton.setAttribute('data-user-id', record.accountid);
 | 
						||
    whitelistButton.setAttribute('data-button-type', 'fraudButton');
 | 
						||
 | 
						||
    const blacklistButton = document.createElement('button');
 | 
						||
    blacklistButton.type = 'button';
 | 
						||
    blacklistButton.className = `button light-loader ${fraudBtnCls}` + ((small) ? ' is-small' : '');
 | 
						||
    blacklistButton.textContent = 'Blacklist';
 | 
						||
    if (record.fraud === true) {
 | 
						||
        blacklistButton.disabled = true;
 | 
						||
    }
 | 
						||
    blacklistButton.setAttribute('data-type', 'fraud');
 | 
						||
    blacklistButton.setAttribute('data-user-id', record.accountid);
 | 
						||
    blacklistButton.setAttribute('data-button-type', 'fraudButton');
 | 
						||
 | 
						||
    const div = document.createElement('div');
 | 
						||
    div.className = 'legitfraud';
 | 
						||
    div.appendChild(whitelistButton);
 | 
						||
    div.appendChild(blacklistButton);
 | 
						||
 | 
						||
    return div;
 | 
						||
};
 | 
						||
 | 
						||
const getToBeReviewedButton = (record, small = true) => {
 | 
						||
    const button = document.createElement('button');
 | 
						||
    button.type = 'button';
 | 
						||
    button.className = 'reviewed button dark-loader' + ((small) ? ' is-small' : '');
 | 
						||
    button.textContent = 'Not reviewed';
 | 
						||
 | 
						||
    button.setAttribute('data-type', 'reviewed');
 | 
						||
    button.setAttribute('data-user-id', record.accountid);
 | 
						||
    button.setAttribute('data-button-type', 'reviewedButton');
 | 
						||
 | 
						||
    return button;
 | 
						||
};
 | 
						||
 | 
						||
const renderScoreDetails = record => {
 | 
						||
    if (!record.score_calculated) {
 | 
						||
        const span = document.createElement('span');
 | 
						||
        span.className = 'no-rules-tile';
 | 
						||
        span.textContent = UNDEFINED_RULES_MSG.value;
 | 
						||
 | 
						||
        return tooltipWrap(UNDEFINED_RULES_MSG.tooltip, span, true);
 | 
						||
    }
 | 
						||
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
    const extra = document.createDocumentFragment();
 | 
						||
    const result = document.createDocumentFragment();
 | 
						||
    const details = record.score_details;
 | 
						||
 | 
						||
    if (Array.isArray(details)) {
 | 
						||
        let uid = '';
 | 
						||
        let descr = '';
 | 
						||
        let name = '';
 | 
						||
        //let part = '';
 | 
						||
 | 
						||
        for (let i = 0; i < details.length; i++) {
 | 
						||
            uid = (details[i].uid !== null && details[i].uid !== undefined) ? details[i].uid : '';
 | 
						||
            descr = (details[i].descr !== null && details[i].descr !== undefined) ? details[i].descr : '';
 | 
						||
            name = (details[i].name!== null && details[i].name !== undefined) ? details[i].name : '';
 | 
						||
 | 
						||
            const span = document.createElement('span');
 | 
						||
            span.className = `ruleHighlight ${getRuleClass(details[i].score)}`;
 | 
						||
            span.textContent = uid;
 | 
						||
 | 
						||
            const el = document.createTextNode('\u00A0');
 | 
						||
 | 
						||
            let t = document.createElement('span');
 | 
						||
            t.className = 'ruleName';
 | 
						||
            t.textContent = name;
 | 
						||
            t = tooltipWrap(descr, t, false);
 | 
						||
 | 
						||
            const part = document.createElement('p');
 | 
						||
            part.appendChild(span);
 | 
						||
            part.appendChild(el);
 | 
						||
            part.appendChild(t);
 | 
						||
 | 
						||
            if (details[i].score !== 0) {
 | 
						||
                frag.appendChild(wrapWithRuleLink(part, uid));
 | 
						||
            } else {
 | 
						||
                extra.appendChild(wrapWithRuleLink(part, uid));
 | 
						||
            }
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    let firstArray = null;
 | 
						||
    let secondArray = null;
 | 
						||
 | 
						||
    if (frag.childNodes.length) {
 | 
						||
        const div = document.createElement('div');
 | 
						||
        div.appendChild(frag);
 | 
						||
        firstArray = div;
 | 
						||
    }
 | 
						||
 | 
						||
    if (extra.childNodes.length) {
 | 
						||
        const div = document.createElement('div');
 | 
						||
        div.id = 'score-details-weightless';
 | 
						||
        div.appendChild(extra);
 | 
						||
        secondArray = div;
 | 
						||
    }
 | 
						||
 | 
						||
    if (firstArray !== null) {
 | 
						||
        result.append(firstArray);
 | 
						||
 | 
						||
        if (secondArray !== null) {
 | 
						||
            const button = document.createElement('button');
 | 
						||
            button.className = 'button-score-details';
 | 
						||
            button.textContent = 'Show all';
 | 
						||
            button.onclick = (e) => {
 | 
						||
                const el = document.getElementById('score-details-weightless');
 | 
						||
                if (el) {
 | 
						||
                    const isHidden = el.classList.toggle('is-hidden');
 | 
						||
                    button.textContent = isHidden ? 'Show all' : 'Show less';
 | 
						||
                }
 | 
						||
            };
 | 
						||
 | 
						||
            const tooltip = 'Show all rules that were triggered but are inactive according to your rule settings';
 | 
						||
            const wrappedButton = tooltipWrap(tooltip, button, true);
 | 
						||
 | 
						||
            secondArray.classList.add('is-hidden');
 | 
						||
 | 
						||
            result.append(wrappedButton);
 | 
						||
            result.append(secondArray);
 | 
						||
        }
 | 
						||
    } else {
 | 
						||
        if (secondArray !== null) {
 | 
						||
            result.append(secondArray);
 | 
						||
        } else {
 | 
						||
            const span = document.createElement('span');
 | 
						||
            span.className = 'no-rules-tile';
 | 
						||
            span.textContent = NO_RULES_MSG.value;
 | 
						||
 | 
						||
            result.appendChild(tooltipWrap(NO_RULES_MSG.tooltip, span, false));
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    return result;
 | 
						||
};
 | 
						||
 | 
						||
//Email
 | 
						||
const renderEmail = (record, length = MAX_STRING_LENGTH_FOR_EMAIL) => {
 | 
						||
    let span = null;
 | 
						||
    const email = record.email;
 | 
						||
 | 
						||
    if (email) {
 | 
						||
        const n = (length === MAX_STRING_LENGTH_FOR_EMAIL) ? length : getNumberOfSymbols(length);
 | 
						||
 | 
						||
        span = truncateWithHellip(email, n);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableEmail = record => {
 | 
						||
    const email = renderEmail(record);
 | 
						||
 | 
						||
    //Overwrite ID attribute, because we are going to wrap it with domain link, not email
 | 
						||
    record.id = record.domain_id;
 | 
						||
 | 
						||
    return wrapWithDomainLink(email, record);
 | 
						||
};
 | 
						||
 | 
						||
const renderReputation = record => {
 | 
						||
    record = (record !== null && record !== undefined) ? record : {};
 | 
						||
 | 
						||
    let icon = 'reputation-none';
 | 
						||
    let reputation = record.reputation;
 | 
						||
    let text = reputation.charAt(0).toUpperCase() + reputation.slice(1);
 | 
						||
 | 
						||
    if ('low' === reputation)    icon = 'reputation-low';
 | 
						||
    if ('medium' === reputation) icon = 'reputation-medium';
 | 
						||
    if ('high' === reputation)   icon = 'reputation-high';
 | 
						||
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
    const img = document.createElement('img');
 | 
						||
    img.src = `/ui/images/icons/${icon}.svg`;
 | 
						||
    img.alt = reputation;
 | 
						||
    frag.appendChild(tooltipWrap(reputation, img, false));
 | 
						||
 | 
						||
    if (reputation !== 'none') {
 | 
						||
        const el = document.createTextNode(reputation.charAt(0).toUpperCase() + reputation.slice(1));
 | 
						||
        frag.appendChild(el);
 | 
						||
    }
 | 
						||
 | 
						||
    return frag;
 | 
						||
};
 | 
						||
 | 
						||
//Phone
 | 
						||
const renderPhone = (record) => {
 | 
						||
    let result;
 | 
						||
    const phone = record.phonenumber;
 | 
						||
 | 
						||
    if (phone) {
 | 
						||
        const code = !COUNTRIES_EXCEPTIONS.includes(record.country_iso) ? record.country_iso : 'lh';
 | 
						||
        const tooltip = (record.full_country !== null && record.full_country !== undefined) ? record.full_country : '';
 | 
						||
 | 
						||
        const n       = MAX_STRING_LENGTH_FOR_PHONE;
 | 
						||
        const number  = truncateWithHellip(phone, n);
 | 
						||
 | 
						||
        const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
        const img = document.createElement('img');
 | 
						||
        img.src = `/ui/images/flags/${code.toLowerCase()}.svg`;
 | 
						||
        img.alt = tooltip;
 | 
						||
 | 
						||
        frag.appendChild(tooltipWrap(tooltip, img, true));
 | 
						||
        frag.appendChild(number);
 | 
						||
 | 
						||
        result = wrapWithCountryDiv(frag);
 | 
						||
    } else {
 | 
						||
        const div = document.createElement('div');
 | 
						||
        div.textContent = HYPHEN;
 | 
						||
 | 
						||
        result = div;
 | 
						||
    }
 | 
						||
 | 
						||
    return result;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickablePhone = record => {
 | 
						||
    const phone = renderPhone(record);
 | 
						||
    const html  = wrapWithPhoneLink(phone, record);
 | 
						||
 | 
						||
    return html;
 | 
						||
};
 | 
						||
 | 
						||
const renderFullCountry = value => {
 | 
						||
    return renderDefaultIfEmptySpan(truncateWithHellip(value, MAX_STRING_LENGTH_FULL_COUNTRY));
 | 
						||
};
 | 
						||
 | 
						||
const renderPhoneCarrierName = (record, length = 'medium') => {
 | 
						||
    let span = null;
 | 
						||
    let carrierName = record.carrier_name;
 | 
						||
 | 
						||
    if (carrierName) {
 | 
						||
        const n = getNumberOfSymbols(length);
 | 
						||
        carrierName = carrierName.replace(',', '');
 | 
						||
        span = truncateWithHellip(carrierName, n);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderPhoneType = record => {
 | 
						||
    const type = record.type;
 | 
						||
    let span = null;
 | 
						||
 | 
						||
    if (type) {
 | 
						||
        let src = 'smartphone.svg';
 | 
						||
        if (PHONE_LANDLINE.includes(type)) src = 'landline.svg';
 | 
						||
        if (['nonFixedVoip', 'VOIP'].includes(type)) src = 'voip.svg';
 | 
						||
 | 
						||
        const tooltip = type.toLowerCase().replace(/_/g, ' ');
 | 
						||
 | 
						||
        const img = document.createElement('img');
 | 
						||
        img.src = `/ui/images/icons/${src}`;
 | 
						||
 | 
						||
        span = tooltipWrap(tooltip, img, true);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderUsersList = (data) => {
 | 
						||
    // data should be an array
 | 
						||
    //let html = '';
 | 
						||
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
    if (Array.isArray(data)) {
 | 
						||
        let user = null;
 | 
						||
        for (let i = 0; i < data.length; i++) {
 | 
						||
            user = renderClickableImportantUserWithScore(
 | 
						||
                {
 | 
						||
                    accountid:          data[i].accountid,
 | 
						||
                    accounttitle:       data[i].accounttitle,
 | 
						||
                    email:              data[i].email,
 | 
						||
                    score_updated_at:   data[i].score_updated_at,
 | 
						||
                    score:              data[i].score,
 | 
						||
                },
 | 
						||
                'long');
 | 
						||
            const div = document.createElement('div');
 | 
						||
            div.appendChild(user);
 | 
						||
            frag.append(div);
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    if (frag.childNodes.length) {
 | 
						||
        return frag;
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(null);
 | 
						||
};
 | 
						||
 | 
						||
//Resource
 | 
						||
const renderResource = (value, tooltip) => {
 | 
						||
    const n = isDashboardPage() ? getNumberOfSymbols() : MAX_STRING_LENGTH_URL;
 | 
						||
    value = value ? value : '/';
 | 
						||
 | 
						||
    const el = truncateWithHellip(value, n, true);
 | 
						||
    el.title = tooltip ? tooltip : '/';
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const renderResourceWithoutQuery = record => {
 | 
						||
    let value = record.url;
 | 
						||
    if (record.title) {
 | 
						||
        value = record.title;
 | 
						||
    }
 | 
						||
 | 
						||
    const tooltip  = record.url;
 | 
						||
 | 
						||
    return renderResource(value, tooltip);
 | 
						||
};
 | 
						||
 | 
						||
const renderResourceWithQueryAndEventType = record => {
 | 
						||
    let url = record.url;
 | 
						||
    if (record.query) {
 | 
						||
        url += record.query;
 | 
						||
    }
 | 
						||
 | 
						||
    let tooltip = url;
 | 
						||
    if (url && url.length > MAX_TOOLTIP_URL_LENGTH) {
 | 
						||
        tooltip = url.slice(0, MAX_TOOLTIP_URL_LENGTH) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
    const el = document.createElement('p');
 | 
						||
    el.className = `bullet ${record.event_type}`;
 | 
						||
    frag.appendChild(tooltipWrap(tooltip, el, false, true));
 | 
						||
 | 
						||
    const text = document.createTextNode(record.event_type_name);
 | 
						||
    frag.appendChild(tooltipWrap(tooltip, text, true, true));
 | 
						||
 | 
						||
    return frag;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableResourceWithoutQuery = record => {
 | 
						||
    const url  = renderResourceWithoutQuery(record);
 | 
						||
    const html = wrapWithResourceLink(url, record);
 | 
						||
 | 
						||
    return html;
 | 
						||
};
 | 
						||
 | 
						||
//IP
 | 
						||
const renderIp = record => {
 | 
						||
    const n = getNumberOfSymbols();
 | 
						||
 | 
						||
    let span = truncateWithHellip(record.ip, n);
 | 
						||
 | 
						||
    if (record.isp_name) {
 | 
						||
        span.title = record.isp_name;
 | 
						||
    }
 | 
						||
 | 
						||
    //html = wrapWithFraudSpan(html, record);
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableIp = record => {
 | 
						||
    const ip  = renderIp(record);
 | 
						||
    const html = wrapWithIpLink(ip, record);
 | 
						||
 | 
						||
    return html;
 | 
						||
};
 | 
						||
 | 
						||
const renderIpAndFlag = (ip, record) => {
 | 
						||
    const countryCode = record.country_iso;
 | 
						||
    const code = !COUNTRIES_EXCEPTIONS.includes(countryCode) ? countryCode.toLowerCase() : 'lh';
 | 
						||
    const iso = (countryCode !== null && countryCode !== undefined) ? countryCode : '';
 | 
						||
 | 
						||
    const net = record.isp_name;
 | 
						||
    const tooltip = (net !== null && net !== undefined && net !== '') ? `${iso} - ${net}` : `${iso}`;
 | 
						||
    const alternative = (record.full_country !== null && record.full_country !== undefined) ? record.full_country : '';
 | 
						||
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
    const img = document.createElement('img');
 | 
						||
    img.src = `/ui/images/flags/${code}.svg`;
 | 
						||
    img.alt = alternative;
 | 
						||
    frag.appendChild(img);
 | 
						||
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.appendChild(ip);
 | 
						||
    frag.appendChild(span);
 | 
						||
 | 
						||
    const result = tooltipWrap(tooltip, frag, true);
 | 
						||
 | 
						||
    return wrapWithCountryDiv(result);
 | 
						||
};
 | 
						||
 | 
						||
const renderIpWithCountry = record => {
 | 
						||
    let ip = record.ip;
 | 
						||
    const n = getNumberOfSymbols();
 | 
						||
 | 
						||
    if (ip && ip.length > n) {
 | 
						||
        ip = ip.slice(0, n) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    const el = document.createTextNode(ip);
 | 
						||
 | 
						||
    return renderIpAndFlag(el, record);
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableIpWithCountry = record => {
 | 
						||
    let ip = record.ip;
 | 
						||
    const n = getNumberOfSymbols();
 | 
						||
 | 
						||
    if (ip && ip.length > n) {
 | 
						||
        ip = ip.slice(0, n) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    const el = document.createTextNode(ip);
 | 
						||
 | 
						||
    return renderIpAndFlag(wrapWithIpLink(el, record), record);
 | 
						||
};
 | 
						||
 | 
						||
const renderIpType = record => {
 | 
						||
    const tooltipMap = {
 | 
						||
        'blacklisted'   : 'Is on a blacklist.',
 | 
						||
        'localhost'     : 'Belongs to a local network.',
 | 
						||
        'residential'   : 'Is assigned by an ISP to a homeowner.',
 | 
						||
        'datacenter'    : 'Belongs to a datacenter.',
 | 
						||
        'applerelay'    : 'Belongs to the iCloud Private Relay.',
 | 
						||
        'starlink'      : 'Belongs to SpaceX satellites.',
 | 
						||
        'spam_list'     : 'Is on a spam list.',
 | 
						||
        'tor'           : 'Belongs to The Onion Router network.',
 | 
						||
        'vpn'           : 'Belongs to a virtual private network.'
 | 
						||
    };
 | 
						||
 | 
						||
    const ipType  = record.ip_type.toLowerCase().replace(' ', '_');
 | 
						||
    let tooltip = tooltipMap[ipType];
 | 
						||
    tooltip = (tooltip !== null && tooltip !== undefined) ? tooltip : record.ip_type;
 | 
						||
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.className = `iptype ${ipType}`;
 | 
						||
    span.textContent = record.ip_type;
 | 
						||
 | 
						||
    return tooltipWrap(tooltip, span, false);
 | 
						||
};
 | 
						||
 | 
						||
//Net
 | 
						||
const renderNetName = (record, length = 'default') => {
 | 
						||
    let name = record.netname || record.description || record.asn || '';
 | 
						||
    let span = null;
 | 
						||
 | 
						||
    if (name) {
 | 
						||
        const regex = /-|_/ig;
 | 
						||
        name = name.replace(regex, ' ');
 | 
						||
        name = name.replace(/\b\w+/g, capitalizeValue);
 | 
						||
 | 
						||
        //TODO: move to constants
 | 
						||
        const len = length === 'long' ? MAX_STRING_LONG_NETNAME_IN_TABLE : MAX_STRING_SHORT_NETNAME_IN_TABLE;
 | 
						||
        span = truncateWithHellip(name, len);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderCidr = record => {
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = renderDefaultIfEmpty(record.cidr);
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderAsn = record => {
 | 
						||
    const asn = (ASN_OVERRIDE[record.asn] !== undefined) ? ASN_OVERRIDE[record.asn] : record.asn;
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = renderDefaultIfEmpty(asn);
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableAsn = record => {
 | 
						||
    const asn  = renderAsn(record);
 | 
						||
    const html = wrapWithIspLink(asn, record);
 | 
						||
 | 
						||
    return html;
 | 
						||
};
 | 
						||
 | 
						||
//Country
 | 
						||
const renderCountry = (code, value, tooltip) => {
 | 
						||
    code = !COUNTRIES_EXCEPTIONS.includes(code) ? code : 'lh';
 | 
						||
    value = (value !== null && value !== undefined) ? value : '';
 | 
						||
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
    const img = document.createElement('img');
 | 
						||
    img.src = `/ui/images/flags/${code.toLowerCase()}.svg`;
 | 
						||
    img.alt = tooltip ? tooltip : value;
 | 
						||
    frag.appendChild(img);
 | 
						||
 | 
						||
    const span = tooltipWrap(tooltip, value, true);
 | 
						||
    frag.appendChild(span);
 | 
						||
 | 
						||
    return wrapWithCountryDiv(frag);
 | 
						||
};
 | 
						||
 | 
						||
const renderCountryFull = (record, applyTooltip = true) => {
 | 
						||
    const code    = record.country_iso;
 | 
						||
    const value   = record.full_country;
 | 
						||
    const tooltip = applyTooltip ? record.full_country : null;
 | 
						||
 | 
						||
    return renderCountry(code, value, tooltip);
 | 
						||
};
 | 
						||
 | 
						||
const renderCountryIso = record => {
 | 
						||
    const code    = record.country_iso;
 | 
						||
    const value   = record.country_iso;
 | 
						||
    const tooltip = record.full_country;
 | 
						||
 | 
						||
    return renderCountry(code, value, tooltip);
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableCountry = (record, applyTooltip = true) => {
 | 
						||
    const country = renderCountryFull(record, applyTooltip);
 | 
						||
 | 
						||
    return wrapWithCountryLink(country, record);
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableCountryName = record => {
 | 
						||
    const value   = record.full_country;
 | 
						||
    const country = (value !== null && value !== undefined) ? value : '';
 | 
						||
 | 
						||
    const el = document.createTextNode(country);
 | 
						||
 | 
						||
    return wrapWithCountryLink(el, record);
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableCountryTruncated = record => {
 | 
						||
    const fullValue = record.full_country;
 | 
						||
    let value   = record.full_country;
 | 
						||
    value = (value !== null && value !== undefined) ? value : '';
 | 
						||
    value = value.length <= MAX_STRING_LENGTH_FOR_TILE ? value : record.country_iso;
 | 
						||
 | 
						||
    const span = tooltipWrap(fullValue, value, true);
 | 
						||
 | 
						||
    return wrapWithCountryLink(span, record);
 | 
						||
};
 | 
						||
 | 
						||
//Audit Trail
 | 
						||
const renderAuditValue = (data, type, record, meta) => {
 | 
						||
    if (data) {
 | 
						||
        data = truncateWithHellip(data, getNumberOfSymbols());
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(data);
 | 
						||
};
 | 
						||
 | 
						||
const renderAuditParent = record => {
 | 
						||
    const n = getNumberOfSymbols();
 | 
						||
 | 
						||
    let tooltip = record.parent_id;
 | 
						||
    let value = record.parent_name;
 | 
						||
 | 
						||
    if (value && value.length > (n + 2)) {
 | 
						||
        value = value.slice(0, n) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    if (tooltip && tooltip.length > MAX_TOOLTIP_LENGTH) {
 | 
						||
        tooltip = tooltip.slice(0, MAX_TOOLTIP_LENGTH) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    return tooltipWrap(renderDefaultIfEmpty(tooltip), renderDefaultIfEmpty(value), true);
 | 
						||
};
 | 
						||
 | 
						||
const renderAuditField = record => {
 | 
						||
    const n = getNumberOfSymbols();
 | 
						||
 | 
						||
    let tooltip = record.field_id;
 | 
						||
    let value = record.field_name;
 | 
						||
 | 
						||
    if (value && value.length > (n + 2)) {
 | 
						||
        value = value.slice(0, n) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    if (tooltip && tooltip.length > MAX_TOOLTIP_LENGTH) {
 | 
						||
        tooltip = tooltip.slice(0, MAX_TOOLTIP_LENGTH) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    return tooltipWrap(renderDefaultIfEmpty(tooltip), renderDefaultIfEmpty(value), true);
 | 
						||
};
 | 
						||
 | 
						||
//Device
 | 
						||
const renderClickableBotId = record => {
 | 
						||
    const device = document.createTextNode(record.id);
 | 
						||
 | 
						||
    return wrapWithBotLink(device, record);
 | 
						||
};
 | 
						||
 | 
						||
const renderDevice = record => {
 | 
						||
    const deviceIsNormal = NORMAL_DEVICES.includes(record.device_name);
 | 
						||
 | 
						||
    const deviceTypeTooltip = record.device_name ? record.device_name : 'unknown';
 | 
						||
    const deviceTypeImg = deviceIsNormal ? record.device_name : 'unknown';
 | 
						||
 | 
						||
    let deviceTypeName = 'unknown';
 | 
						||
 | 
						||
    if (record.device_name && record.device_name !== 'unknown') {
 | 
						||
        deviceTypeName = deviceIsNormal ? record.device_name : 'other device';
 | 
						||
    }
 | 
						||
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
    const img = document.createElement('img');
 | 
						||
    img.src = `/ui/images/icons/${deviceTypeImg}.svg`;
 | 
						||
    frag.appendChild(tooltipWrap(deviceTypeTooltip, img, true));
 | 
						||
 | 
						||
    const el = document.createTextNode(deviceTypeName);
 | 
						||
    frag.appendChild(tooltipWrap(record.ua, el, true));
 | 
						||
 | 
						||
    return frag;
 | 
						||
};
 | 
						||
 | 
						||
const renderDeviceWithOs = record => {
 | 
						||
    const deviceTypeTooltip = record.device_name ? record.device_name : 'unknown';
 | 
						||
    const deviceTypeImg = NORMAL_DEVICES.includes(record.device_name) ? record.device_name : 'unknown';
 | 
						||
 | 
						||
    let os = record.os_name ? record.os_name : 'N/A';
 | 
						||
    os += record.os_version ? ' ' + record.os_version : '';
 | 
						||
 | 
						||
    if (os && os.length > MAX_STRING_DEVICE_OS_LENGTH) {
 | 
						||
        os = os.slice(0, MAX_STRING_DEVICE_OS_LENGTH) + HELLIP;
 | 
						||
    }
 | 
						||
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
    const img = document.createElement('img');
 | 
						||
    img.src = `/ui/images/icons/${deviceTypeImg}.svg`;
 | 
						||
    frag.appendChild(tooltipWrap(deviceTypeTooltip, img, true));
 | 
						||
 | 
						||
    const el = document.createTextNode(os);
 | 
						||
    frag.appendChild(tooltipWrap(record.ua, el, true));
 | 
						||
 | 
						||
    return frag;
 | 
						||
};
 | 
						||
 | 
						||
const renderLanguage = record => {
 | 
						||
    const language  = record.lang;
 | 
						||
    const languages = parse(language);
 | 
						||
 | 
						||
    const rec1 = languages.find(rec => rec.code);
 | 
						||
    const rec2 = languages.find(rec => rec.region);
 | 
						||
 | 
						||
    let codeAndRegion = [];
 | 
						||
    let el = null;
 | 
						||
 | 
						||
    if (rec1) {
 | 
						||
        codeAndRegion.push(rec1.code.toUpperCase());
 | 
						||
    }
 | 
						||
 | 
						||
    if (rec2) {
 | 
						||
        codeAndRegion.push(rec2.region.toUpperCase());
 | 
						||
    }
 | 
						||
 | 
						||
    codeAndRegion = codeAndRegion.join('-');
 | 
						||
    if (codeAndRegion) {
 | 
						||
        el = tooltipWrap(language, codeAndRegion, true, true);
 | 
						||
        el.classList.add('nolight');
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(el);
 | 
						||
};
 | 
						||
 | 
						||
const renderOs = record => {
 | 
						||
    let os = record.os;
 | 
						||
 | 
						||
    if ('string' == typeof os) {
 | 
						||
        os = os.trim();
 | 
						||
    }
 | 
						||
 | 
						||
    if (os) {
 | 
						||
        os = truncateWithHellip(os, MAX_STRING_LENGTH_FOR_TILE);
 | 
						||
    }
 | 
						||
 | 
						||
    os = renderDefaultIfEmptySpan(os);
 | 
						||
 | 
						||
    return os;
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableOs = record => {
 | 
						||
    const os   = renderOs(record);
 | 
						||
    const el   = wrapWithBotLink(os, record);
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const renderBrowser = record => {
 | 
						||
    let browser = record.browser;
 | 
						||
 | 
						||
    if ('string' == typeof browser) {
 | 
						||
        browser = browser.trim();
 | 
						||
    }
 | 
						||
 | 
						||
    if (browser) {
 | 
						||
        browser = browser.split('.');
 | 
						||
        browser = browser[0].trim();
 | 
						||
 | 
						||
        browser = truncateWithHellip(browser, MAX_STRING_LENGTH_FOR_TILE);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(browser);
 | 
						||
};
 | 
						||
 | 
						||
const renderDomain = (record, length = 'short') => {
 | 
						||
    let domain = record.domain;
 | 
						||
 | 
						||
    if (domain) {
 | 
						||
        domain = truncateWithHellip(domain, getNumberOfSymbols(length));
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(domain);
 | 
						||
};
 | 
						||
 | 
						||
const renderClickableDomain = (record, length = 'short') => {
 | 
						||
    let span = renderDomain(record, length);
 | 
						||
    const el = (record.id !== null && record.id !== undefined) ? wrapWithDomainLink(span, record) : span;
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const renderTextarea = (value, h=4, w=37) => {
 | 
						||
    const textarea = document.createElement('textarea');
 | 
						||
    textarea.readOnly = true;
 | 
						||
    textarea.rows = h;
 | 
						||
    textarea.cols = w;
 | 
						||
    textarea.textContent = renderDefaultIfEmpty(value);
 | 
						||
 | 
						||
    return textarea;
 | 
						||
};
 | 
						||
 | 
						||
const renderQuery = record => {
 | 
						||
    const result = renderTextarea(record.query);
 | 
						||
    result.classList.add('word-break');
 | 
						||
 | 
						||
    return result;
 | 
						||
};
 | 
						||
 | 
						||
const renderReferer = record => {
 | 
						||
    const result = renderTextarea(record.referer);
 | 
						||
    result.classList.add('word-break');
 | 
						||
 | 
						||
    return result;
 | 
						||
};
 | 
						||
 | 
						||
const renderUserAgent = record => {
 | 
						||
    return renderTextarea(record.ua, 5);
 | 
						||
};
 | 
						||
 | 
						||
const renderDefaultIfEmptyElement = (value) => {
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = (value) ? value : HYPHEN;
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderDefaultIfEmpty = (value) => {
 | 
						||
    if (value) {
 | 
						||
        return value;
 | 
						||
    }
 | 
						||
 | 
						||
    return HYPHEN;
 | 
						||
};
 | 
						||
 | 
						||
const renderDefaultIfEmptySpan = (span) => {
 | 
						||
    if (!span) {
 | 
						||
        span = document.createElement('span');
 | 
						||
    }
 | 
						||
 | 
						||
    if (!span.childNodes.length) {
 | 
						||
        span.textContent = renderDefaultIfEmpty(span.textContent);
 | 
						||
    }
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const renderBlacklistItem = record => {
 | 
						||
    let span = null;
 | 
						||
    let rec = {};
 | 
						||
 | 
						||
    const type = record.type;
 | 
						||
 | 
						||
    if (type === 'ip') {
 | 
						||
        rec.ip = record.value;
 | 
						||
        rec.ipid = record.entity_id;
 | 
						||
        span = renderClickableIp(rec);
 | 
						||
    }
 | 
						||
    if (type === 'email' || type === 'phone') {
 | 
						||
        const el = document.createTextNode(renderDefaultIfEmpty(record.value));
 | 
						||
        rec.accountid = record.accountid;
 | 
						||
        span = wrapWithUserLink(el, rec);
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderBlacklistType = record => {
 | 
						||
    const span = document.createElement('span');
 | 
						||
    let type = record.type;
 | 
						||
 | 
						||
    if (type) {
 | 
						||
        if (type.toUpperCase() === 'IP') {
 | 
						||
            type = 'IP';
 | 
						||
        } else {
 | 
						||
            type = type.replace(/\b\w+/g, capitalizeValue);
 | 
						||
        }
 | 
						||
 | 
						||
        span.textContent = type;
 | 
						||
        span.className = 'typestatus';
 | 
						||
    }
 | 
						||
 | 
						||
    return renderDefaultIfEmptySpan(span);
 | 
						||
};
 | 
						||
 | 
						||
const renderSensorErrorColumn = record => {
 | 
						||
    const obj = openJson(record.error_text);
 | 
						||
    const s = (obj !== null) ? obj.join('; ') : null;
 | 
						||
    return truncateWithHellip(s, MAX_STRING_LONG_NETNAME_IN_TABLE);
 | 
						||
};
 | 
						||
 | 
						||
const renderSensorError = record => {
 | 
						||
    const obj = openJson(record.error_text);
 | 
						||
    const s = (obj !== null) ? obj.join(';\n') : null;
 | 
						||
 | 
						||
    return renderTextarea(s);
 | 
						||
};
 | 
						||
 | 
						||
const renderJsonTextarea = value => {
 | 
						||
    const obj = openJson(value);
 | 
						||
    const s = (obj !== null) ? JSON.stringify(obj, null, 2) : null;
 | 
						||
 | 
						||
    const rows = s ? s.split(/\r\n|\r|\n/).length : 0;
 | 
						||
    const h = rows > 24 ? 24 : (rows < 4 ? 4 : rows);;
 | 
						||
 | 
						||
    return renderTextarea(s, h);
 | 
						||
};
 | 
						||
 | 
						||
const renderErrorType = record => {
 | 
						||
    const frag = document.createDocumentFragment();
 | 
						||
 | 
						||
    const el = document.createElement('p');
 | 
						||
    el.className = `bullet ${record.error_value}`;
 | 
						||
    frag.appendChild(el);
 | 
						||
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = record.error_name;
 | 
						||
    frag.appendChild(span);
 | 
						||
 | 
						||
    return frag;
 | 
						||
};
 | 
						||
 | 
						||
const renderMailto = record => {
 | 
						||
    const subject = 'Request body';
 | 
						||
    const body = record.raw;
 | 
						||
 | 
						||
    const href = `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
 | 
						||
 | 
						||
    const el = document.createElement('a');
 | 
						||
    el.href = href;
 | 
						||
    el.textContent = 'Email request data';
 | 
						||
 | 
						||
    return el;
 | 
						||
};
 | 
						||
 | 
						||
const currentPlanRender = (data, type, record, _meta) => {
 | 
						||
    const value = record.sub_plan_api_calls;
 | 
						||
    const text = (value !== null && value !== undefined) ? value + ' API calls' : MIDLINE_HELLIP;
 | 
						||
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = text;
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const currentStatusRender = (data, type, record, meta) => {
 | 
						||
    const value = record.sub_status;
 | 
						||
    const text = (value !== null && value !== undefined) ? value : MIDLINE_HELLIP;
 | 
						||
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = text;
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const currentUsageRender = (data, type, record, meta) => {
 | 
						||
    let value = record.sub_calls_used;
 | 
						||
    const used = (value !== null && value !== undefined) ? value : MIDLINE_HELLIP;
 | 
						||
    value = record.sub_calls_limit;
 | 
						||
    const limit = (value !== null && value !== undefined) ? value : MIDLINE_HELLIP;
 | 
						||
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = used + '/' + limit;
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const currentBillingEndRender = (data, type, record, meta) => {
 | 
						||
    const value = record.sub_next_billed;
 | 
						||
    const text = (value !== null && value !== undefined) ? renderDateString(value.replace('T', ' ')) : MIDLINE_HELLIP;
 | 
						||
 | 
						||
    const span = document.createElement('span');
 | 
						||
    span.textContent = text;
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
const updateCardButtonRender = (data, type, record, meta) => {
 | 
						||
    const url = record.sub_update_url;
 | 
						||
    const token = record.apiToken;
 | 
						||
    const disabled = (url !== null && url !== undefined && token !== null && token !== undefined) ? '' : 'disabled';
 | 
						||
 | 
						||
    const button = document.createElement('button');
 | 
						||
    button.className = 'button is-primary';
 | 
						||
    button.type = 'submit';
 | 
						||
    button.textContent = 'Update';
 | 
						||
    button.onclick = (e) => {
 | 
						||
        window.open(url, '_blank');
 | 
						||
    };
 | 
						||
 | 
						||
    if (disabled) {
 | 
						||
        button.disabled = true;
 | 
						||
    }
 | 
						||
 | 
						||
    return button;
 | 
						||
};
 | 
						||
 | 
						||
const renderEnrichmentCalculation = data => {
 | 
						||
    const keys = {
 | 
						||
        ip: 'IP',
 | 
						||
        //ua: 'Devices',
 | 
						||
        phone: 'Phones',
 | 
						||
        email: 'Emails',
 | 
						||
        domain: 'Domains',
 | 
						||
    };
 | 
						||
    let result = [];
 | 
						||
    let sum = 0;
 | 
						||
 | 
						||
    for (const key in keys) {
 | 
						||
        const c = (data[key] === undefined || data[key] === null) ? 0 : data[key];
 | 
						||
        sum += c;
 | 
						||
        result.push(keys[key].padEnd(16, '.') + String(c));
 | 
						||
    }
 | 
						||
 | 
						||
    result.push(''.padEnd(16, '='));
 | 
						||
    result.push('Total: ' + String(sum));
 | 
						||
    const text = result.join('\n');
 | 
						||
 | 
						||
    return renderTextarea(text, 6);
 | 
						||
};
 | 
						||
 | 
						||
const renderRulePlayResult = (users, count, uid) => {
 | 
						||
    if (!count) {
 | 
						||
        return document.createTextNode(`There are no users that match ${uid} rule.`);
 | 
						||
    }
 | 
						||
 | 
						||
    const result = document.createDocumentFragment();
 | 
						||
    const txt = (count === 1) ? `One user matching ${uid} rule: ` : `${count} users matching ${uid} rule: `;
 | 
						||
    result.appendChild(document.createTextNode(txt));
 | 
						||
 | 
						||
    const list = document.createDocumentFragment();
 | 
						||
    users.forEach((record, idx) => {
 | 
						||
        if (idx > 0) list.appendChild(document.createTextNode(', '));
 | 
						||
        list.appendChild(renderClickableUser(record));
 | 
						||
    });
 | 
						||
 | 
						||
    result.appendChild(list);
 | 
						||
 | 
						||
    return result;
 | 
						||
};
 | 
						||
 | 
						||
const renderChartTooltipPart = (color, label, val) => {
 | 
						||
    const span = document.createElement('span');
 | 
						||
 | 
						||
    if (label !== null) {
 | 
						||
        span.style.backgroundColor = color;
 | 
						||
        span.className = 'chart-tooltip';
 | 
						||
        span.textContent = `${label}: ${val}`;
 | 
						||
    } else {
 | 
						||
        span.style.color = color;
 | 
						||
        span.textContent = val;
 | 
						||
    }
 | 
						||
 | 
						||
    return span;
 | 
						||
};
 | 
						||
 | 
						||
export {
 | 
						||
    //Primitive
 | 
						||
    renderBoolean,
 | 
						||
    renderDefaultIfEmptyElement,
 | 
						||
    renderProportion,
 | 
						||
 | 
						||
    //Event
 | 
						||
    renderHttpCode,
 | 
						||
    renderHttpMethod,
 | 
						||
    renderTotalFrame,
 | 
						||
 | 
						||
    //Time
 | 
						||
    renderTime,
 | 
						||
    renderDate,
 | 
						||
    renderTimeMs,
 | 
						||
 | 
						||
    //Choices selector
 | 
						||
    renderRuleSelectorItem,
 | 
						||
    renderRuleSelectorChoice,
 | 
						||
    renderEventTypeSelectorItem,
 | 
						||
    renderEventTypeSelectorChoice,
 | 
						||
    renderIpTypeSelectorItem,
 | 
						||
    renderIpTypeSelectorChoice,
 | 
						||
    renderDeviceTypeSelectorItem,
 | 
						||
    renderDeviceTypeSelectorChoice,
 | 
						||
    renderEntityTypeSelectorItem,
 | 
						||
    renderEntityTypeSelectorChoice,
 | 
						||
    renderScoresRangeSelectorItem,
 | 
						||
    renderScoresRangeSelectorChoice,
 | 
						||
 | 
						||
    //User
 | 
						||
    renderUser,                                 //! only internal usage
 | 
						||
    renderUserId,
 | 
						||
    renderUserScore,                            //! only internal usage
 | 
						||
    renderUserWithScore,                        //! only internal usage
 | 
						||
    renderClickableImportantUserWithScore,
 | 
						||
    renderClickableImportantUserWithScoreTile,
 | 
						||
    renderUserForEvent,
 | 
						||
    renderTimestampForEvent,
 | 
						||
    renderUserFirstname,
 | 
						||
    renderUserLastname,
 | 
						||
    renderClickableUser,
 | 
						||
    renderImportantUser,                        //! not used
 | 
						||
    renderClickableImportantUser,               //! only internal usage
 | 
						||
    renderUserActionButtons,
 | 
						||
    renderUserReviewedStatus,
 | 
						||
    renderBlacklistButtons,
 | 
						||
    renderScoreDetails,
 | 
						||
    renderUserCounter,
 | 
						||
 | 
						||
    //Email
 | 
						||
    renderEmail,
 | 
						||
    renderReputation,
 | 
						||
    renderClickableEmail,                       //! not used
 | 
						||
 | 
						||
    //Phone
 | 
						||
    renderPhone,
 | 
						||
    renderFullCountry,
 | 
						||
    renderPhoneType,
 | 
						||
    renderClickablePhone,                       //! not used
 | 
						||
    renderPhoneCarrierName,
 | 
						||
    renderUsersList,
 | 
						||
 | 
						||
    //Country
 | 
						||
    renderCountryIso,
 | 
						||
    renderCountryFull,                          //! only internal usage
 | 
						||
    renderClickableCountry,
 | 
						||
    renderClickableCountryName,
 | 
						||
    renderClickableCountryTruncated,
 | 
						||
 | 
						||
    //Resource
 | 
						||
    renderResourceWithQueryAndEventType,
 | 
						||
    renderResourceWithoutQuery,                 //! only internal usage
 | 
						||
    renderClickableResourceWithoutQuery,
 | 
						||
 | 
						||
    //IP
 | 
						||
    renderIp,
 | 
						||
    renderIpType,
 | 
						||
    renderClickableIp,
 | 
						||
    renderIpWithCountry,
 | 
						||
    renderClickableIpWithCountry,
 | 
						||
 | 
						||
    //Net
 | 
						||
    renderAsn,
 | 
						||
    renderClickableAsn,
 | 
						||
    renderNetName,
 | 
						||
    renderCidr,
 | 
						||
 | 
						||
    //Audit Trail
 | 
						||
    renderAuditField,
 | 
						||
    renderAuditValue,
 | 
						||
    renderAuditParent,
 | 
						||
 | 
						||
    //Device
 | 
						||
    renderDevice,
 | 
						||
    renderDeviceWithOs,
 | 
						||
    renderClickableBotId,
 | 
						||
 | 
						||
    //OS
 | 
						||
    renderOs,
 | 
						||
    renderClickableOs,                          //! not used
 | 
						||
 | 
						||
    //Domain
 | 
						||
    renderDomain,
 | 
						||
    renderClickableDomain,
 | 
						||
 | 
						||
    //Browser
 | 
						||
    renderBrowser,
 | 
						||
 | 
						||
    //Language
 | 
						||
    renderLanguage,
 | 
						||
 | 
						||
    //Details panel
 | 
						||
    renderQuery,
 | 
						||
    renderUserAgent,
 | 
						||
    renderReferer,
 | 
						||
 | 
						||
    //Blacklist item
 | 
						||
    renderBlacklistType,
 | 
						||
    renderBlacklistItem,
 | 
						||
 | 
						||
    //Logbook
 | 
						||
    renderSensorErrorColumn,
 | 
						||
    renderSensorError,
 | 
						||
    renderJsonTextarea,
 | 
						||
    renderErrorType,
 | 
						||
    renderMailto,
 | 
						||
 | 
						||
    //UsageStats
 | 
						||
    currentPlanRender,
 | 
						||
    currentStatusRender,
 | 
						||
    currentUsageRender,
 | 
						||
    currentBillingEndRender,
 | 
						||
    updateCardButtonRender,
 | 
						||
 | 
						||
    //Enrichment
 | 
						||
    renderEnrichmentCalculation,
 | 
						||
 | 
						||
    //Rule
 | 
						||
    renderRulePlayResult,
 | 
						||
 | 
						||
    //Chart
 | 
						||
    renderChartTooltipPart,
 | 
						||
};
 |