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,65 @@
import {BasePage} from './Base.js';
import {UsageStatsGrid} from '../parts/grid/UsageStats.js?v=2';
import {EnrichAllPopUp} from '../parts/EnrichAllPopUp.js?v=2';
export class ApiPage extends BasePage {
constructor() {
super();
this.initUi();
}
initUi() {
const onSelectChange = this.onSelectChange.bind(this);
this.versionSelect.addEventListener('change', onSelectChange, false);
const onTextAreaClick = this.onTextAreaClick.bind(this);
this.snippetTextareas.forEach(txt => txt.addEventListener('click', onTextAreaClick, false));
const gridParams = {
url: '/admin/loadUsageStats',
tableId: 'usage-stats-table',
tileId: 'totalUsageStats',
isSortable: false,
getParams: function() {
return {};
}
};
new UsageStatsGrid(gridParams);
new EnrichAllPopUp();
}
onTextAreaClick(e) {
const txt = e.target;
const value = txt.value;
txt.setSelectionRange(0, value.length);
}
onSelectChange(e) {
const value = event.target.value;
this.snippetTextareas.forEach(txt => {
const container = txt.closest('div');
const isHidden = container.classList.contains('is-hidden');
if (!isHidden) {
container.classList.add('is-hidden');
}
});
const textarea = document.getElementById(value);
textarea.closest('div').classList.remove('is-hidden');
}
get versionSelect() {
return document.querySelector('select[name=version]');
}
get snippetTextareas() {
return document.querySelectorAll('.code-snippet');
}
}

View File

@@ -0,0 +1,168 @@
import {SearchLine} from '../parts/SearchLine.js';
import {Tooltip} from '../parts/Tooltip.js?v=2';
export class BasePage {
constructor(name, single = false) {
this.initCommonUi();
if (name) {
this.name = name;
if (single) {
let path = (this.name !== 'user') ? this.name : 'id';
this.id = parseInt(window.location.pathname.replace('/' + path + '/', ''), 10);
const key = this.name + 'Id';
this.getParams = () => {
return {[key]: this.id};
};
}
}
}
initCommonUi() {
new SearchLine();
document.addEventListener('keyup', e => {
if (e.key !== '/' || e.ctrlKey || e.metaKey) return;
if (/^(?:input|textarea|select|button)$/i.test(e.target.tagName)) return;
e.preventDefault();
document.getElementById('auto-complete').focus();
});
const initTooltip = this.initTooltip;
if (initTooltip) {
Tooltip.init();
}
const closeNotificationButtons = this.closeNotificationButtons;
if (closeNotificationButtons && closeNotificationButtons.length) {
const onCloseNotificationButtonClick = this.onCloseNotificationButtonClick.bind(this);
closeNotificationButtons.forEach(
button => button.addEventListener('click', onCloseNotificationButtonClick, false)
);
}
this.procedureNotifications.forEach(notification => {
const btn = notification.querySelector('.delete');
if (!btn) return;
btn.addEventListener('click', () => {notification.remove();}, false);
});
}
onCloseNotificationButtonClick() {
const notification = event.target.closest('.notification.system');
if (notification) {
notification.remove();
}
}
getDevicesGridParams() {
return {
url: '/admin/loadDevices',
tileId: 'totalDevices',
tableId: 'devices-table',
panelType: 'device',
isSortable: false,
getParams: this.getParams,
};
}
getIpsGridParams() {
return {
url: '/admin/loadIps',
tileId: 'totalIps',
tableId: 'ips-table',
isSortable: false,
orderByLastseen: true,
getParams: this.getParams,
};
}
getEventsGridParams() {
return {
url: '/admin/loadEvents',
tileId: 'totalEvents',
tableId: 'user-events-table',
panelType: 'event',
isSortable: false,
getParams: this.getParams,
};
}
getUsersGridParams() {
return {
url: '/admin/loadUsers',
tileId: 'totalUsers',
tableId: 'users-table',
isSortable: false,
getParams: this.getParams,
};
}
getIspsGridParams() {
return {
url: '/admin/loadIsps',
tableId: 'isps-table',
isSortable: false,
getParams: this.getParams,
};
}
getMapParams() {
return {
getParams: this.getParams,
tooltipString: 'event',
tooltipField: 'total_visit',
tileId: 'totalCountries',
};
}
getBarChartParams() {
return {
getParams: () => ({
mode: this.name,
id: this.id,
}),
};
}
getChartParams(datesFilter, searchFilter) {
return {
getParams: () => {
const mode = this.name;
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {mode, dateRange, searchValue};
},
};
}
getSelfDetails() {
return {
getParams: this.getParams,
};
}
get initTooltip() {
return true;
}
get closeNotificationButtons() {
return document.querySelectorAll('.notification.system:not(.is-hidden) .delete');
}
get procedureNotifications() {
return document.querySelectorAll('#success-procedure-notification, #error-procedure-notification');
}
}

View File

@@ -0,0 +1,56 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {EntityTypeFilter} from '../parts/choices/EntityTypeFilter.js?v=2';
import {BlacklistGridActionButtons} from '../parts/BlacklistGridActionButtons.js?v=2';
import {BlacklistChart} from '../parts/chart/Blacklist.js?v=2';
import {BlacklistGrid} from '../parts/grid/Blacklist.js?v=2';
export class BlacklistPage extends BasePage {
constructor() {
super('blacklist');
this.tableId = 'blacklist-table';
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const gridParams = {
url: '/admin/loadBlacklist',
tileId: 'totalBlacklist',
tableId: 'blacklist-table',
dateRangeGrid: true,
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {dateRange, searchValue};
},
};
if (document.getElementById('entity-type-selectors')) {
const entityTypeFilter = new EntityTypeFilter();
gridParams.choicesFilterEvents = [entityTypeFilter.getEventType()];
gridParams.getParams = function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
const entityTypeIds = entityTypeFilter.getValues();
return {dateRange, searchValue, entityTypeIds};
};
}
const chartParams = this.getChartParams(datesFilter, searchFilter);
new BlacklistChart(chartParams);
new BlacklistGrid(gridParams);
new BlacklistGridActionButtons(this.tableId);
}
}

View File

@@ -0,0 +1,44 @@
import {BasePage} from './Base.js';
import {SequentialLoad} from '../parts/SequentialLoad.js?v=2';
import {Map} from '../parts/Map.js?v=2';
import {IpsGrid} from '../parts/grid/Ips.js?v=2';
import {UsersGrid} from '../parts/grid/Users.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
import {BaseBarChart} from '../parts/chart/BaseBar.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
import {BotTiles} from '../parts/details/BotTiles.js?v=2';
import {ReenrichmentButton} from '../parts/ReenrichmentButton.js?v=2';
export class BotPage extends BasePage {
constructor() {
super('bot', true);
this.initUi();
}
initUi() {
const usersGridParams = this.getUsersGridParams();
const eventsGridParams = this.getEventsGridParams();
const ipsGridParams = this.getIpsGridParams();
const mapParams = this.getMapParams();
const botDetailsTiles = this.getSelfDetails();
const chartParams = this.getBarChartParams();
new EventPanel();
new ReenrichmentButton();
const elements = [
[BotTiles, botDetailsTiles],
[Map, mapParams],
[IpsGrid, ipsGridParams],
[UsersGrid, usersGridParams],
[BaseBarChart, chartParams],
[EventsGrid, eventsGridParams],
];
new SequentialLoad(elements);
}
}

View File

@@ -0,0 +1,40 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {BotsChart} from '../parts/chart/Bots.js?v=2';
import {BotsGrid} from '../parts/grid/Bots.js?v=2';
export class BotsPage extends BasePage {
constructor() {
super('bots');
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const gridParams = {
url: '/admin/loadBots',
// tileId: 'totalDevices',
tableId: 'bots-table',
dateRangeGrid: true,
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {dateRange, searchValue};
},
};
const chartParams = this.getChartParams(datesFilter, searchFilter);
new BotsChart(chartParams);
new BotsGrid(gridParams);
}
}

View File

@@ -0,0 +1,54 @@
import {BasePage} from './Base.js';
import {Map} from '../parts/Map.js?v=2';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {CountriesGrid} from '../parts/grid/Countries.js?v=2';
export class CountriesPage extends BasePage {
constructor() {
super();
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const getMapParams = () => {
const dateRange = datesFilter.getValue();
return {dateRange};
};
const gridParams = {
url: '/admin/loadCountries',
tileId: 'totalCountries',
tableId: 'countries-table',
dateRangeGrid: true,
calculateTotals: true,
totals: {
type: 'country',
columns: ['total_visit', 'total_account', 'total_ip'],
},
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {dateRange, searchValue};
}
};
const mapParams = {
getParams: getMapParams,
tooltipString: 'user',
tooltipField: 'total_account'
};
new Map(mapParams);
new CountriesGrid(gridParams);
}
}

View File

@@ -0,0 +1,44 @@
import {BasePage} from './Base.js';
import {SequentialLoad} from '../parts/SequentialLoad.js?v=2';
import {IpsGrid} from '../parts/grid/Ips.js?v=2';
import {IspsGrid} from '../parts/grid/Isps.js?v=2';
import {UsersGrid} from '../parts/grid/Users.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
import {BaseBarChart} from '../parts/chart/BaseBar.js?v=2';
import {StaticTiles} from '../parts/StaticTiles.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
export class CountryPage extends BasePage {
constructor() {
super('country', true);
this.initUi();
}
initUi() {
const usersGridParams = this.getUsersGridParams();
const eventsGridParams = this.getEventsGridParams();
const ispsGridParams = this.getIspsGridParams();
const ipsGridParams = this.getIpsGridParams();
const chartParams = this.getBarChartParams();
const tilesParams = {
elems: ['totalUsers', 'totalIps', 'totalEvents']
};
new StaticTiles(tilesParams);
new EventPanel();
const elements = [
[UsersGrid, usersGridParams],
[IpsGrid, ipsGridParams],
[IspsGrid, ispsGridParams],
[BaseBarChart, chartParams],
[EventsGrid, eventsGridParams],
];
new SequentialLoad(elements);
}
}

View File

@@ -0,0 +1,95 @@
import {BasePage} from './Base.js';
import {SequentialLoad} from '../parts/SequentialLoad.js?v=2';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {DashboardTile} from '../parts/DashboardTile.js?v=2';
import {TopTenGrid} from '../parts/grid/TopTen.js?v=2';
import {
renderClickableImportantUserWithScoreTile,
renderClickableCountry,
renderClickableResourceWithoutQuery,
renderClickableIpWithCountry,
} from '../parts/DataRenderers.js?v=2';
export class DashboardPage extends BasePage {
constructor() {
super();
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter(true);
const getParams = () => {
const dateRange = datesFilter.getValue();
return {dateRange};
};
const topTenUsersGridParams = {
getParams: getParams,
mode: 'mostActiveUsers',
tableId: 'most-active-users-table',
dateRangeGrid: true,
renderItemColumn: renderClickableImportantUserWithScoreTile,
};
const topTenCountriesGridParams = {
getParams: getParams,
mode: 'mostActiveCountries',
tableId: 'most-active-countries-table',
dateRangeGrid: true,
renderItemColumn: renderClickableCountry,
};
const topTenResourcesGridParams = {
getParams: getParams,
mode: 'mostActiveUrls',
tableId: 'most-active-urls-table',
dateRangeGrid: true,
renderItemColumn: renderClickableResourceWithoutQuery,
};
const topTenIpsWithMostUsersGridParams = {
getParams: getParams,
mode: 'ipsWithTheMostUsers',
tableId: 'ips-with-the-most-users-table',
dateRangeGrid: true,
renderItemColumn: renderClickableIpWithCountry,
};
const topTenUsersWithMostLoginFailGridParams = {
getParams: getParams,
mode: 'usersWithMostLoginFail',
tableId: 'users-with-most-login-fail-table',
dateRangeGrid: true,
renderItemColumn: renderClickableImportantUserWithScoreTile,
};
const topTenUsersWithMostIpsGridParams = {
getParams: getParams,
mode: 'usersWithMostIps',
tableId: 'users-with-most-ips-table',
dateRangeGrid: true,
renderItemColumn: renderClickableImportantUserWithScoreTile,
};
const elements = [
//[DashboardTile, {getParams: getParams, mode: 'totalEvents'}],
[DashboardTile, {getParams: getParams, mode: 'totalUsers'}],
[DashboardTile, {getParams: getParams, mode: 'totalIps'}],
[DashboardTile, {getParams: getParams, mode: 'totalCountries'}],
[DashboardTile, {getParams: getParams, mode: 'totalUrls'}],
[DashboardTile, {getParams: getParams, mode: 'totalUsersForReview'}],
[DashboardTile, {getParams: getParams, mode: 'totalBlockedUsers'}],
[TopTenGrid, topTenUsersGridParams],
[TopTenGrid, topTenCountriesGridParams],
[TopTenGrid, topTenResourcesGridParams],
[TopTenGrid, topTenIpsWithMostUsersGridParams],
[TopTenGrid, topTenUsersWithMostLoginFailGridParams],
[TopTenGrid, topTenUsersWithMostIpsGridParams],
];
new SequentialLoad(elements);
}
}

View File

@@ -0,0 +1,57 @@
import {BasePage} from './Base.js';
import {SequentialLoad} from '../parts/SequentialLoad.js?v=2';
import {Map} from '../parts/Map.js?v=2';
import {IpsGrid} from '../parts/grid/Ips.js?v=2';
import {UsersGrid} from '../parts/grid/Users.js?v=2';
import {IspsGrid} from '../parts/grid/Isps.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
import {DomainsGrid} from '../parts/grid/Domains.js?v=2';
import {BaseBarChart} from '../parts/chart/BaseBar.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
import {DomainTiles} from '../parts/details/DomainTiles.js?v=2';
import {ReenrichmentButton} from '../parts/ReenrichmentButton.js?v=2';
export class DomainPage extends BasePage {
constructor() {
super('domain', true);
this.initUi();
}
initUi() {
const usersGridParams = this.getUsersGridParams();
const eventsGridParams = this.getEventsGridParams();
const ipsGridParams = this.getIpsGridParams();
const ispsGridParams = this.getIspsGridParams();
const mapParams = this.getMapParams();
const domainDetailsTiles = this.getSelfDetails();
const chartParams = this.getBarChartParams();
const domainsGridParams = {
url: '/admin/loadDomains',
tileId: 'totalDomains',
tableId: 'domains-table',
isSortable: false,
getParams: this.getParams,
};
new EventPanel();
new ReenrichmentButton();
const elements = [
[DomainTiles, domainDetailsTiles],
[UsersGrid, usersGridParams],
[DomainsGrid, domainsGridParams],
[Map, mapParams],
[IpsGrid, ipsGridParams],
[IspsGrid, ispsGridParams],
[BaseBarChart, chartParams],
[EventsGrid, eventsGridParams],
];
new SequentialLoad(elements);
}
}

View File

@@ -0,0 +1,45 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {DomainsChart} from '../parts/chart/Domains.js?v=2';
import {DomainsGrid} from '../parts/grid/Domains.js?v=2';
export class DomainsPage extends BasePage {
constructor() {
super('domains');
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const gridParams = {
url: '/admin/loadDomains',
tileId: 'totalDomains',
tableId: 'domains-table',
dateRangeGrid: true,
calculateTotals: true,
totals: {
type: 'domain',
columns: ['total_account'],
},
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {dateRange, searchValue};
}
};
const chartParams = this.getChartParams(datesFilter, searchFilter);
new DomainsChart(chartParams);
new DomainsGrid(gridParams);
}
}

View File

@@ -0,0 +1,61 @@
import {BasePage} from './Base.js';
import {EventsChart} from '../parts/chart/Events.js?v=2';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {EventTypeFilter} from '../parts/choices/EventTypeFilter.js?v=2';
import {DeviceTypeFilter} from '../parts/choices/DeviceTypeFilter.js?v=2';
import {RulesFilter} from '../parts/choices/RulesFilter.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
export class EventsPage extends BasePage {
constructor() {
super('events');
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const eventTypeFilter = new EventTypeFilter();
const deviceTypeFilter = new DeviceTypeFilter();
const rulesFilter = new RulesFilter();
const chartParams = this.getChartParams(datesFilter, searchFilter);
const gridParams = {
url: '/admin/loadEvents',
tileId: 'totalEvents',
tableId: 'user-events-table',
panelType: 'event',
dateRangeGrid: true,
sessionGroup: true,
singleUser: false,
isSortable: true,
choicesFilterEvents: [
eventTypeFilter.getEventType(),
rulesFilter.getEventType(),
deviceTypeFilter.getEventType(),
],
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
const eventTypeIds = eventTypeFilter.getValues();
const ruleUids = rulesFilter.getValues();
const deviceTypes = deviceTypeFilter.getValues();
return {dateRange, searchValue, eventTypeIds, ruleUids, deviceTypes};
}
};
new EventPanel();
new EventsChart(chartParams);
new EventsGrid(gridParams);
}
}

View File

@@ -0,0 +1,41 @@
import {BasePage} from './Base.js';
import {SequentialLoad} from '../parts/SequentialLoad.js?v=2';
import {UsersGrid} from '../parts/grid/Users.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
import {DevicesGrid} from '../parts/grid/Devices.js?v=2';
import {BaseBarChart} from '../parts/chart/BaseBar.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
import {DevicePanel} from '../parts/panel/DevicePanel.js?v=2';
import {IpTiles} from '../parts/details/IpTiles.js?v=2';
import {ReenrichmentButton} from '../parts/ReenrichmentButton.js?v=2';
export class IpPage extends BasePage {
constructor() {
super('ip', true);
this.initUi();
}
initUi() {
const usersGridParams = this.getUsersGridParams();
const devicesGridParams = this.getDevicesGridParams();
const eventsGridParams = this.getEventsGridParams();
const ipDetailsTiles = this.getSelfDetails();
const chartParams = this.getBarChartParams();
new EventPanel();
new DevicePanel();
new ReenrichmentButton();
const elements = [
[IpTiles, ipDetailsTiles],
[UsersGrid, usersGridParams],
[DevicesGrid, devicesGridParams],
[BaseBarChart, chartParams],
[EventsGrid, eventsGridParams],
];
new SequentialLoad(elements);
}
}

View File

@@ -0,0 +1,53 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {IpTypeFilter} from '../parts/choices/IpTypeFilter.js?v=2';
import {IpsChart} from '../parts/chart/Ips.js?v=2';
import {IpsGrid} from '../parts/grid/Ips.js?v=2';
export class IpsPage extends BasePage {
constructor() {
super('ips');
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const ipTypeFilter = new IpTypeFilter();
const gridParams = {
url: '/admin/loadIps',
tileId: 'totalIps',
tableId: 'ips-table',
dateRangeGrid: true,
calculateTotals: true,
totals: {
type: 'ip',
columns: ['total_visit'],
},
isSortable: true,
orderByLastseen: false,
choicesFilterEvents: [ipTypeFilter.getEventType()],
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
const ipTypeIds = ipTypeFilter.getValues();
return {dateRange, searchValue, ipTypeIds};
}
};
const chartParams = this.getChartParams(datesFilter, searchFilter);
new IpsChart(chartParams);
new IpsGrid(gridParams);
}
}

View File

@@ -0,0 +1,40 @@
import {BasePage} from './Base.js';
import {SequentialLoad} from '../parts/SequentialLoad.js?v=2';
import {Map} from '../parts/Map.js?v=2';
import {IpsGrid} from '../parts/grid/Ips.js?v=2';
import {UsersGrid} from '../parts/grid/Users.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
import {BaseBarChart} from '../parts/chart/BaseBar.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
import {IspTiles} from '../parts/details/IspTiles.js?v=2';
export class IspPage extends BasePage {
constructor() {
super('isp', true);
this.initUi();
}
initUi() {
const ispDetailsTiles = this.getSelfDetails();
const usersGridParams = this.getUsersGridParams();
const eventsGridParams = this.getEventsGridParams();
const ipsGridParams = this.getIpsGridParams();
const mapParams = this.getMapParams();
const chartParams = this.getBarChartParams();
new EventPanel();
const elements = [
[IspTiles, ispDetailsTiles],
[UsersGrid, usersGridParams],
[Map, mapParams],
[IpsGrid, ipsGridParams],
[BaseBarChart, chartParams],
[EventsGrid, eventsGridParams],
];
new SequentialLoad(elements);
}
}

View File

@@ -0,0 +1,45 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {IspsChart} from '../parts/chart/Isps.js?v=2';
import {IspsGrid} from '../parts/grid/Isps.js?v=2';
export class IspsPage extends BasePage {
constructor() {
super('isps');
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const gridParams = {
url: '/admin/loadIsps',
tileId: 'totalIsps',
tableId: 'isps-table',
dateRangeGrid: true,
calculateTotals: true,
totals: {
type: 'isp',
columns: ['total_visit', 'total_account', 'total_ip'],
},
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {dateRange, searchValue};
}
};
const chartParams = this.getChartParams(datesFilter, searchFilter);
new IspsChart(chartParams);
new IspsGrid(gridParams);
}
}

View File

@@ -0,0 +1,46 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {LogbookPanel} from '../parts/panel/LogbookPanel.js?v=2';
import {LogbookGrid} from '../parts/grid/Logbook.js?v=2';
import {LogbookChart} from '../parts/chart/Logbook.js?v=2';
export class LogbookPage extends BasePage {
constructor() {
super('logbook');
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const chartParams = this.getChartParams(datesFilter, searchFilter);
const gridParams = {
url: '/admin/loadLogbook',
tileId: 'totalLogbook',
tableId: 'logbook-table',
panelType: 'logbook',
dateRangeGrid: true,
sessionGroup: false,
singleUser: false,
isSortable: true,
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {dateRange, searchValue};
}
};
new LogbookChart(chartParams);
new LogbookPanel();
new LogbookGrid(gridParams);
}
}

View File

@@ -0,0 +1,28 @@
import {BasePage} from './Base.js';
import {ManualCheckItems} from '../parts/ManualCheckItems.js?v=2';
export class ManualCheckPage extends BasePage {
constructor() {
super();
this.initUi();
}
initUi() {
new ManualCheckItems();
const onTableLinkClick = e => {
e.preventDefault();
const f = e.target.closest('form');
f.submit();
return false;
};
const historyTableLinks = document.querySelectorAll('[data-item-id="manual-check-history-item"]');
historyTableLinks.forEach(link => link.addEventListener('click', onTableLinkClick, false));
}
}

View File

@@ -0,0 +1,51 @@
import {BasePage} from './Base.js';
import {SequentialLoad} from '../parts/SequentialLoad.js?v=2';
import {Map} from '../parts/Map.js?v=2';
import {IpsGrid} from '../parts/grid/Ips.js';
import {IspsGrid} from '../parts/grid/Isps.js?v=2';
import {UsersGrid} from '../parts/grid/Users.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
import {DevicesGrid} from '../parts/grid/Devices.js?v=2';
import {BaseBarChart} from '../parts/chart/BaseBar.js?v=2';
import {StaticTiles} from '../parts/StaticTiles.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
import {DevicePanel} from '../parts/panel/DevicePanel.js?v=2';
export class ResourcePage extends BasePage {
constructor() {
super('resource', true);
this.initUi();
}
initUi() {
const devicesGridParams = this.getDevicesGridParams();
const eventsGridParams = this.getEventsGridParams();
const ipsGridParams = this.getIpsGridParams();
const usersGridParams = this.getUsersGridParams();
const ispsGridParams = this.getIspsGridParams();
const mapParams = this.getMapParams();
const chartParams = this.getBarChartParams();
const tilesParams = {
elems: ['totalUsers', 'totalCountries', 'totalIps', 'totalEvents']
};
new StaticTiles(tilesParams);
new EventPanel();
new DevicePanel();
const elements = [
[UsersGrid, usersGridParams],
[Map, mapParams],
[IpsGrid, ipsGridParams],
[IspsGrid, ispsGridParams],
[DevicesGrid, devicesGridParams],
[BaseBarChart, chartParams],
[EventsGrid, eventsGridParams],
];
new SequentialLoad(elements);
}
}

View File

@@ -0,0 +1,45 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {ResourcesChart} from '../parts/chart/Resources.js?v=2';
import {ResourcesGrid} from '../parts/grid/Resources.js?v=2';
export class ResourcesPage extends BasePage {
constructor() {
super('resources');
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const gridParams = {
url: '/admin/loadResources',
tileId: 'totalResources',
tableId: 'resources-table',
dateRangeGrid: true,
calculateTotals: true,
totals: {
type: 'resource',
columns: ['total_visit', 'total_account', 'total_ip', 'total_country'],
},
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {dateRange, searchValue};
}
};
const chartParams = this.getChartParams(datesFilter, searchFilter);
new ResourcesChart(chartParams);
new ResourcesGrid(gridParams);
}
}

View File

@@ -0,0 +1,46 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {RulesFilter} from '../parts/choices/RulesFilter.js?v=2';
import {UserGridActionButtons} from '../parts/UserGridActionButtons.js?v=2';
import {ReviewQueueGrid} from '../parts/grid/ReviewQueue.js?v=2';
import {ReviewQueueChart} from '../parts/chart/ReviewQueue.js?v=2';
export class ReviewQueuePage extends BasePage {
constructor() {
super('review-queue');
this.tableId = 'review-queue-table';
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const rulesFilter = new RulesFilter();
const chartParams = this.getChartParams(datesFilter, searchFilter);
const gridParams = {
url: '/admin/loadReviewQueue',
tileId: 'totalUsers',
tableId: 'review-queue-table',
dateRangeGrid: true,
choicesFilterEvents: [rulesFilter.getEventType()],
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
const ruleUids = rulesFilter.getValues();
return {dateRange, searchValue, ruleUids};
}
};
new ReviewQueueChart(chartParams);
new ReviewQueueGrid(gridParams);
new UserGridActionButtons(this.tableId);
}
}

View File

@@ -0,0 +1,197 @@
import {BasePage} from './Base.js';
import {Tooltip} from '../parts/Tooltip.js?v=2';
import {handleAjaxError} from '../parts/utils/ErrorHandler.js?v=2';
import {getRuleClass} from '../parts/utils/String.js?v=2';
import {ThresholdsForm} from '../parts/ThresholdsForm.js?v=2';
import {
renderClickableUser,
renderProportion,
renderRulePlayResult,
} from '../parts/DataRenderers.js?v=2';
export class RulesPage extends BasePage {
constructor() {
super();
this.initUi();
}
initUi() {
new ThresholdsForm();
const searchTable = this.searchTable.bind(this);
this.searchInput.addEventListener('keyup', searchTable, false);
const onPlayButtonClick = this.onPlayButtonClick.bind(this);
this.playButtons.forEach(button => button.addEventListener('click', onPlayButtonClick, false));
const onSaveButtonClick = this.onSaveButtonClick.bind(this);
this.saveButtons.forEach(button => button.addEventListener('click', onSaveButtonClick, false));
const onSelectChange = this.onSelectChange.bind(this);
this.selects.forEach(select => select.addEventListener('change', onSelectChange, false));
}
onPlayButtonClick(e) {
e.preventDefault();
this.updateDisabled(true);
const currentPlayButton = e.target.closest('button');
currentPlayButton.classList.add('is-loading');
const ruleUid = currentPlayButton.dataset.ruleUid;
const token = document.head.querySelector('[name=\'csrf-token\'][content]').content;
const params = {ruleUid: currentPlayButton.dataset.ruleUid, token: token};
$.ajax({
url: '/admin/checkRule',
type: 'get',
context: {currentPlayButton: currentPlayButton, ruleUid: ruleUid},
data: params,
success: this.onCheckRuleLoad, // without binding to keep simultaneous calls scopes separate
error: handleAjaxError,
complete: this.updateDisabled.bind(this, false)
});
return false;
}
onCheckRuleLoad(data, status) {
if ('success' !== status || 0 === data.length) {
return;
}
this.currentPlayButton.classList.remove('is-loading');
let row = document.querySelector(`tr[data-rule-uid="${this.ruleUid}"]`);
let nextRow = row.nextElementSibling;
if (!nextRow || nextRow.dataset.ruleUid) {
const ex = document.createElement('tr');
const td = document.createElement('td');
td.colSpan = 6;
ex.replaceChildren(td);
nextRow = row.parentNode.insertBefore(ex, row.nextSibling);
}
nextRow.querySelector('td').replaceChildren(renderRulePlayResult(data.users, data.count, this.ruleUid));
// 3 is index of proportion column
row.children[3].replaceChildren(renderProportion(data.proportion, data.proportion_updated_at));
Tooltip.addTooltipsToRulesProportion();
}
updateDisabled(disabled) {
this.playButtons.forEach(button => button.disabled = disabled);
}
onSelectChange(e) {
e.preventDefault();
const field = e.target;
const parentRow = field.closest('tr');
const saveButton = parentRow.querySelector('button[type="button"]');
const value = field.value;
const cls = getRuleClass(parseInt(value, 10));
const newClassName = `ruleHighlight ${cls}`;
parentRow.querySelector('h3').className = newClassName;
if (field.dataset.initialValue == value) {
parentRow.classList.remove('input-field-changed');
saveButton.classList.add('is-hidden');
} else {
parentRow.classList.add('input-field-changed');
saveButton.classList.remove('is-hidden');
}
return false;
}
onSaveButtonClick(e) {
e.preventDefault();
const currentSaveButton = e.target.closest('button');
currentSaveButton.classList.add('is-loading');
const select = currentSaveButton.closest('tr').querySelector('select');
const token = document.head.querySelector('[name=\'csrf-token\'][content]').content;
const params = {
rule: select.name,
value: select.value,
token: token,
};
$.ajax({
url: '/admin/saveRule',
type: 'post',
data: params,
context: {currentSaveButton: currentSaveButton},
error: handleAjaxError,
success: this.onSaveLoaded, // without binding to keep simultaneous calls scopes separate
});
return false;
}
onSaveLoaded(data, status) {
if ('success' !== status) {
return;
}
this.currentSaveButton.classList.remove('is-loading');
const parentRow = this.currentSaveButton.closest('tr');
const saveButton = parentRow.querySelector('button[type="button"]');
parentRow.classList.remove('input-field-changed');
saveButton.classList.add('is-hidden');
}
searchTable() {
let td, i, txtValue;
const input = document.getElementById('search');
const filter = input.value.toLowerCase();
const table = document.getElementById('rules-table');
const tr = table.getElementsByTagName('tr');
// i = 1 because search must skip first line with column names
for (i = 1; i < tr.length; i++) {
td = tr[i].getElementsByTagName('td');
let found = false;
for (let j = 0; j < Math.min(td.length, 3); j++) {
if (td[j]) {
txtValue = td[j].textContent || td[j].innerText;
if (txtValue.toLowerCase().indexOf(filter) > -1) {
found = true;
break;
}
}
}
tr[i].style.display = found ? '' : 'none';
}
}
get selects() {
return document.querySelectorAll('td select');
}
get saveButtons() {
return document.querySelectorAll('td button[type="button"]');
}
get playButtons() {
return document.querySelectorAll('td button[data-rule-uid]');
}
get searchInput() {
return document.getElementById('search');
}
}

View File

@@ -0,0 +1,15 @@
import {BasePage} from './Base.js';
import {DeleteAccountPopUp} from '../parts/DeleteAccountPopUp.js?v=2';
export class SettingsPage extends BasePage {
constructor() {
super();
this.initUi();
}
initUi() {
new DeleteAccountPopUp();
}
}

View File

@@ -0,0 +1,121 @@
import {BasePage} from './Base.js';
import {SequentialLoad} from '../parts/SequentialLoad.js?v=2';
import {Map} from '../parts/Map.js?v=2';
import {EmailsGrid} from '../parts/grid/Emails.js?v=2';
import {IpsGrid} from '../parts/grid/Ips.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
import {DevicesGrid} from '../parts/grid/Devices.js?v=2';
import {BaseBarChart} from '../parts/chart/BaseBar.js?v=2';
import {BaseSparklineChart} from '../parts/chart/BaseSparkline.js?v=2';
import {UserTiles} from '../parts/details/UserTiles.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
import {SingleReviewButton} from '../parts/SingleReviewButton.js?v=2';
import {ScoreDetails} from '../parts/ScoreDetails.js?v=2';
import {PhonesGrid} from '../parts/grid/Phones.js?v=2';
import {FieldAuditTrailGrid} from '../parts/grid/payloads/FieldAuditTrail.js?v=2';
import {IspsGrid} from '../parts/grid/Isps.js?v=2';
import {EmailPanel} from '../parts/panel/EmailPanel.js?v=2';
import {PhonePanel} from '../parts/panel/PhonePanel.js?v=2';
import {DevicePanel} from '../parts/panel/DevicePanel.js?v=2';
import {ReenrichmentButton} from '../parts/ReenrichmentButton.js?v=2';
export class UserPage extends BasePage {
constructor() {
super('user', true);
this.initUi();
}
initUi() {
const userDetailsTiles = this.getSelfDetails();
const devicesGridParams = this.getDevicesGridParams();
const ipsGridParams = this.getIpsGridParams();
const ispsGridParams = this.getIspsGridParams();
const eventsGridParams = this.getEventsGridParams();
eventsGridParams.sessionGroup = true;
eventsGridParams.singleUser = true;
const mapParams = this.getMapParams();
const chartParams = this.getBarChartParams();
const statsChartParams = {
getParams: () => ({
mode: 'stats',
id: this.id,
}),
};
ipsGridParams.tileId = null;
eventsGridParams.tileId = null;
devicesGridParams.tileId = null;
mapParams.tileId = null;
const emailsGridParams = {
url: '/admin/loadEmails',
tableId: 'emails-table',
panelType: 'email',
isSortable: false,
getParams: this.getParams,
};
const phonesGridParams = {
url: '/admin/loadPhones',
tableId: 'phones-table',
panelType: 'phone',
isSortable: false,
getParams: this.getParams,
};
const fieldAuditTrailGridParams = {
url: '/admin/loadFieldAuditTrail',
tableId: 'field-audit-trail-table',
isSortable: false,
getParams: this.getParams,
};
const userScoreDetails = {
userId: this.id,
};
new ScoreDetails(userScoreDetails);
new SingleReviewButton(this.id);
new EventPanel();
new DevicePanel();
new ReenrichmentButton();
const isEmailPhone = !!document.getElementById('email-card');
if (isEmailPhone) {
new EmailPanel();
new PhonePanel();
}
const elements = [
[UserTiles, userDetailsTiles],
[BaseSparklineChart, statsChartParams],
[Map, mapParams],
[IpsGrid, ipsGridParams],
[IspsGrid, ispsGridParams],
[DevicesGrid, devicesGridParams],
];
if (isEmailPhone) {
elements.push([EmailsGrid, emailsGridParams]);
elements.push([PhonesGrid, phonesGridParams]);
}
elements.push([FieldAuditTrailGrid, fieldAuditTrailGridParams]);
elements.push([BaseBarChart, chartParams]);
elements.push([EventsGrid, eventsGridParams]);
new SequentialLoad(elements);
}
}

View File

@@ -0,0 +1,48 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {RulesFilter} from '../parts/choices/RulesFilter.js?v=2';
import {ScoresRangeFilter} from '../parts/choices/ScoresRangeFilter.js?v=2';
import {UsersGrid} from '../parts/grid/Users.js?v=2';
import {UsersChart} from '../parts/chart/Users.js?v=2';
export class UsersPage extends BasePage {
constructor() {
super('users');
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const rulesFilter = new RulesFilter();
const scoresRangeFilter = new ScoresRangeFilter();
const chartParams = this.getChartParams(datesFilter, searchFilter);
const gridParams = {
url: '/admin/loadUsers',
tileId: 'totalUsers',
tableId: 'users-table',
dateRangeGrid: true,
choicesFilterEvents: [rulesFilter.getEventType(), scoresRangeFilter.getEventType()],
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
const ruleUids = rulesFilter.getValues();
const scoresRange = scoresRangeFilter.getValues();
return {dateRange, searchValue, ruleUids, scoresRange};
},
};
new UsersGrid(gridParams);
new UsersChart(chartParams);
}
}

View File

@@ -0,0 +1,42 @@
import {BasePage} from './Base.js';
import {DatesFilter} from '../parts/DatesFilter.js?v=2';
import {SearchFilter} from '../parts/SearchFilter.js?v=2';
import {EventPanel} from '../parts/panel/EventPanel.js?v=2';
import {WatchlistTags} from '../parts/WatchlistTags.js?v=2';
import {EventsGrid} from '../parts/grid/Events.js?v=2';
export class WatchlistPage extends BasePage {
constructor() {
super();
this.initUi();
}
initUi() {
const datesFilter = new DatesFilter();
const searchFilter = new SearchFilter();
const gridParams = {
url: '/admin/loadEvents?watchlist=true',
tileId: 'totalEvents',
tableId: 'user-events-table',
panelType: 'event',
dateRangeGrid: true,
isSortable: false,
getParams: function() {
const dateRange = datesFilter.getValue();
const searchValue = searchFilter.getValue();
return {dateRange, searchValue};
},
};
new EventPanel();
new WatchlistTags();
new EventsGrid(gridParams);
}
}