feat(cloudron): add tirreno package artifacts

- 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.
This commit is contained in:
2025-10-30 11:43:06 -05:00
parent 0ce353ea9d
commit 91d52d2de5
1692 changed files with 202851 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
const MAX_STRING_LONG_NETNAME_IN_TABLE = 48;
const MAX_STRING_SHORT_NETNAME_IN_TABLE = 25;
const MAX_STRING_LENGTH_IN_TABLE = 18;
const MAX_STRING_USERID_LENGTH_IN_TABLE = 15;
const MAX_STRING_USER_SHORT_LENGTH_IN_TABLE = 19;
const MAX_STRING_USER_MEDIUM_LENGTH_IN_TABLE = 23;
const MAX_STRING_USER_LONG_LENGTH_IN_TABLE = 32;
const MAX_STRING_USER_LONG_LENGTH_IN_TILE = 26;
const MAX_STRING_USER_NAME_IN_TABLE = 10;
const MAX_STRING_LENGTH_IN_TABLE_ON_DASHBOARD = 24;
const MAX_STRING_LENGTH_FOR_EMAIL = 14;
const MAX_STRING_LENGTH_FOR_PHONE = 17;
const MAX_STRING_LENGTH_FULL_COUNTRY = 23;
const MAX_STRING_LENGTH_FOR_TILE = 15;
const MAX_STRING_DEVICE_OS_LENGTH = 10;
const MAX_STRING_LENGTH_URL = 32;
const MAX_TOOLTIP_URL_LENGTH = 50;
const MAX_TOOLTIP_LENGTH = 121;
const COLOR_RED = '#FB6E88';
const COLOR_GREEN = '#01EE99';
const COLOR_YELLOW = '#F5B944';
const COLOR_PURPLE = '#BE95EB';
const COLOR_LIGHT_GREEN = 'rgba(64,220,97,0.03)';
const COLOR_LIGHT_YELLOW = 'rgba(225,224,137,0.03)';
const COLOR_LIGHT_RED = 'rgba(255,51,102,0.03)';
const COLOR_LIGHT_PURPLE = 'rgba(190,149,235,0.03)';
const USER_LOW_TRUST_SCORE_INF = 0;
const USER_LOW_TRUST_SCORE_SUP = 33;
const USER_MEDIUM_TRUST_SCORE_INF = 33;
const USER_MEDIUM_TRUST_SCORE_SUP = 67;
const USER_HIGH_TRUST_SCORE_INF = 67;
const USER_IPS_CRITICAL_VALUE = 9;
const USER_EVENTS_CRITICAL_VALUE = Infinity;
const USER_DEVICES_CRITICAL_VALUE = 4;
const USER_COUNTRIES_CRITICAL_VALUE = 3;
const MAX_HOURS_CHART = 96;
const MIN_HOURS_CHART = 3;
const DAYS_IN_RANGE = 1;
const X_AXIS_SERIFS = 8;
const ASN_OVERRIDE = {
'0': 'LAN',
'64496': 'N/A',
};
const COUNTRIES_EXCEPTIONS = [null, undefined, 'N/A', 'AN', 'CS', 'YU'];
const NORMAL_DEVICES = ['smartphone', 'desktop', 'bot', 'tablet'];
const PHONE_LANDLINE = [
'landline',
'FIXED_LINE',
'FIXED_LINE_OR_MOBILE',
'TOLL_FREE',
'SHARED_COST',
];
const NO_RULES_MSG = {
value: 'No rule',
tooltip: 'User currently doesn\'t correspond to selected rules.',
};
const UNDEFINED_RULES_MSG = {
value: 'In queue',
tooltip: 'Waiting for a score to be calculated.',
};
const MIDLINE_HELLIP = '\u22EF';
const HELLIP = '\u2026';
const HYPHEN = '\uFF0D';
const COLOR_MAP = {
'red': {
'main': COLOR_RED,
'light': COLOR_LIGHT_RED,
},
'yellow': {
'main': COLOR_YELLOW,
'light': COLOR_LIGHT_YELLOW,
},
'green': {
'main': COLOR_GREEN,
'light': COLOR_LIGHT_GREEN,
},
'purple': {
'main': COLOR_PURPLE,
'light': COLOR_LIGHT_PURPLE,
},
};
export {
MAX_STRING_LONG_NETNAME_IN_TABLE,
MAX_STRING_SHORT_NETNAME_IN_TABLE,
MAX_STRING_LENGTH_IN_TABLE,
MAX_STRING_USERID_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_USER_NAME_IN_TABLE,
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_DEVICE_OS_LENGTH,
MAX_STRING_LENGTH_URL,
MAX_TOOLTIP_URL_LENGTH,
MAX_TOOLTIP_LENGTH,
COLOR_RED,
COLOR_GREEN,
COLOR_YELLOW,
COLOR_PURPLE,
COLOR_LIGHT_GREEN,
COLOR_LIGHT_YELLOW,
COLOR_LIGHT_RED,
COLOR_LIGHT_PURPLE,
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,
USER_IPS_CRITICAL_VALUE,
USER_EVENTS_CRITICAL_VALUE,
USER_DEVICES_CRITICAL_VALUE,
USER_COUNTRIES_CRITICAL_VALUE,
MAX_HOURS_CHART,
MIN_HOURS_CHART,
DAYS_IN_RANGE,
X_AXIS_SERIFS,
ASN_OVERRIDE,
COUNTRIES_EXCEPTIONS,
NORMAL_DEVICES,
PHONE_LANDLINE,
NO_RULES_MSG,
UNDEFINED_RULES_MSG,
MIDLINE_HELLIP,
HELLIP,
HYPHEN,
COLOR_MAP,
};

View File

@@ -0,0 +1,20 @@
const getQueryParams = (params) => {
const data = {};
Object.assign(data, params);
if (params.dateRange) {
data['dateTo'] = params.dateRange.dateTo;
data['dateFrom'] = params.dateRange.dateFrom;
data['keepDates'] = params.dateRange.keepDates;
}
if (params.searchValue) {
data['search'] = {
value: params.searchValue
};
}
return data;
};
export {getQueryParams};

View File

@@ -0,0 +1,85 @@
const addDays = (date, days) => {
const dateCopy = new Date(date);
dateCopy.setDate(date.getDate() + days);
return dateCopy;
};
const addHours = (date, hours) => {
const ms = hours * 60 * 60 * 1000;
const dateCopy = new Date(date);
dateCopy.setTime(date.getTime() + ms);
return dateCopy;
};
//https://stackoverflow.com/a/12550320
const padZero = (n, s = 2) => {
return (s > 0) ? ('000'+n).slice(-s) : (n+'000').slice(0, -s);
};
const notificationTime = () => {
const dt = new Date();
const day = padZero(dt.getDate());
const month = padZero(dt.getMonth() + 1);
const year = padZero(dt.getFullYear(), 4);
const hours = padZero(dt.getHours());
const minutes = padZero(dt.getMinutes());
const seconds = padZero(dt.getSeconds());
return `[${day}/${month}/${year} ${hours}:${minutes}:${seconds}]`;
};
// offsetInSeconds is not inverted as .getTimezoneOffset() result
const formatIntTimeUtc = (ts, useTime, offsetInSeconds = 0) => {
const dt = new Date(ts + ((new Date()).getTimezoneOffset() * 60 + offsetInSeconds) * 1000);
let m = dt.getMonth() + 1;
let d = dt.getDate();
let y = dt.getFullYear();
m = padZero(m);
d = padZero(d);
y = padZero(y, 4);
if (!useTime) {
return `${d}/${m}/${y}`;
}
let h = dt.getHours();
let i = dt.getMinutes();
let s = dt.getSeconds();
h = padZero(h);
i = padZero(i);
s = padZero(s);
return `${d}/${m}/${y} ${h}:${i}:${s}`;
};
const formatStringTime = (dt) => {
let m = dt.getMonth() + 1;
let d = dt.getDate();
let y = dt.getFullYear();
m = padZero(m);
d = padZero(d);
y = padZero(y, 4);
let h = dt.getHours();
let i = dt.getMinutes();
let s = dt.getSeconds();
h = padZero(h);
i = padZero(i);
s = padZero(s);
return `${y}-${m}-${d}T${h}:${i}:${s}`;
};
export {
formatIntTimeUtc,
formatStringTime,
notificationTime,
padZero,
addDays,
addHours,
};

View File

@@ -0,0 +1,43 @@
import {notificationTime} from './Date.js?v=2';
const handleAjaxError = (xhr, status, error) => {
// ignore abort, but not network issues
if ((xhr.status === 0 && xhr.readyState === 0) || (status && status.status === 0)) {
return;
}
if (xhr.status === 401 || xhr.status === 403) {
window.location.href = escape('/login');
return;
}
const time = notificationTime();
const msg = 'An error occurred while requesting resource. Please try again later.';
const notificationEl = document.getElementById('client-error');
const frag = document.createDocumentFragment();
const span = document.createElement('span');
span.className = 'faded';
span.textContent = time;
const el = document.createTextNode('\u00A0\u00A0' + msg);
const button = document.createElement('button');
button.className = 'delete';
frag.appendChild(span);
frag.appendChild(el);
frag.appendChild(button);
notificationEl.replaceChildren(frag);
const deleteButton = notificationEl.querySelector('.delete');
deleteButton.addEventListener('click', () => {
notificationEl.classList.add('is-hidden');
});
notificationEl.classList.remove('is-hidden');
};
export {handleAjaxError};

View File

@@ -0,0 +1,8 @@
const fireEvent = (name, data) => {
const details = {detail: data};
const event = new CustomEvent(name, details);
dispatchEvent(event);
};
export {fireEvent};

View File

@@ -0,0 +1,10 @@
const debounce = callback => {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => callback.apply(this, args), 500);
};
};
export {debounce};

View File

@@ -0,0 +1,71 @@
const replaceAll = (str, search, replacement) => {
return str.split(search).join(replacement);
};
const getRuleClass = (value) => {
switch (value) {
case -20:
return 'positive';
case 10:
return 'medium';
case 20:
return 'high';
case 70:
return 'extreme';
default:
return 'none';
}
};
const formatTime = (str) => {
const dayPattern = /(\d+)\s+days?/;
let days = 0;
const dayMatch = str.match(dayPattern);
if (dayMatch) {
days = parseInt(dayMatch[1], 10);
str = str.replace(dayPattern, '').trim();
}
// remove milliseconds part if exists
str = str.split('.')[0];
const timePattern = /^\d{2}:\d{2}:\d{2}$/;
if (!timePattern.test(str)) {
return '';
}
const parts = str.split(':');
const hours = parseInt(parts[0], 10);
let minutes = parseInt(parts[1], 10);
const seconds = parseInt(parts[2], 10);
let humanTime = '';
if (days > 0) {
humanTime += `${days} d ${hours} h `;
} else {
minutes += 60 * hours;
}
if (minutes > 0) humanTime += `${minutes} min `;
if (seconds > 0) humanTime += `${seconds} s`;
if (humanTime === '') humanTime = '1 s';
return humanTime.trim();
};
const openJson = (str) => {
try {
return JSON.parse(str);
} catch (e) {
return null;
}
};
export {
replaceAll,
getRuleClass,
formatTime,
openJson,
};