- 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.
467 lines
14 KiB
JavaScript
467 lines
14 KiB
JavaScript
import {Loader} from '../Loader.js?v=2';
|
|
import {Tooltip} from '../Tooltip.js?v=2';
|
|
import {fireEvent} from '../utils/Event.js?v=2';
|
|
import {getQueryParams} from '../utils/DataSource.js?v=2';
|
|
import {handleAjaxError} from '../utils/ErrorHandler.js?v=2';
|
|
import {TotalTile} from '../TotalTile.js?v=2';
|
|
import {renderTotalFrame} from '../DataRenderers.js?v=2';
|
|
import {
|
|
MIDLINE_HELLIP,
|
|
} from '../utils/Constants.js?v=2';
|
|
|
|
export class BaseGrid {
|
|
constructor(gridParams) {
|
|
this.config = gridParams;
|
|
|
|
this.loader = new Loader();
|
|
this.tooltip = new Tooltip();
|
|
this.totalTile = new TotalTile();
|
|
|
|
this.firstload = true;
|
|
|
|
this.renderTotalsLoader = this.renderTotalsLoader.bind(this);
|
|
|
|
this.initLoad();
|
|
|
|
if (this.config.dateRangeGrid && !this.config.sequential) {
|
|
const onDateFilterChanged = this.onDateFilterChanged.bind(this);
|
|
window.addEventListener('dateFilterChanged', onDateFilterChanged, false);
|
|
}
|
|
|
|
if (gridParams.choicesFilterEvents) {
|
|
const onChoicesFilterChanged = this.onChoicesFilterChanged.bind(this);
|
|
for (let i = 0; i < gridParams.choicesFilterEvents.length; i++) {
|
|
window.addEventListener(gridParams.choicesFilterEvents[i], onChoicesFilterChanged, false);
|
|
}
|
|
}
|
|
|
|
if (!this.config.sequential) {
|
|
const onSearchFilterChanged = this.onSearchFilterChanged.bind(this);
|
|
window.addEventListener('searchFilterChanged', onSearchFilterChanged, false);
|
|
}
|
|
}
|
|
|
|
initLoad() {
|
|
const me = this;
|
|
const tableId = this.config.tableId;
|
|
|
|
$(document).ready(() => {
|
|
$.extend($.fn.dataTable.ext.classes, {
|
|
sStripeEven: '', sStripeOdd: ''
|
|
});
|
|
|
|
$.fn.dataTable.ext.pager.numbers_length = 9;
|
|
|
|
$.fn.dataTable.ext.errMode = function() {};
|
|
$(`#${tableId}`).on('error.dt', me.onError);
|
|
|
|
const onBeforeLoad = me.onBeforeLoad.bind(me);
|
|
$(`#${tableId}`).on('preXhr.dt', onBeforeLoad);
|
|
|
|
const onBeforePageChange = me.onBeforePageChange.bind(me);
|
|
$(`#${tableId}`).on('page.dt', onBeforePageChange);
|
|
|
|
const config = me.getDataTableConfig();
|
|
$(`#${tableId}`).DataTable(config);
|
|
|
|
const onTableRowClick = me.onTableRowClick.bind(me);
|
|
$(`#${tableId} tbody`).on('click', 'tr', onTableRowClick);
|
|
|
|
const onDraw = me.onDraw.bind(me);
|
|
$(`#${tableId}`).on('draw.dt', onDraw);
|
|
|
|
$(`#${tableId}`).closest('.dt-container').find('nav').empty();
|
|
|
|
document.getElementById(tableId).classList.add('hide-body');
|
|
|
|
if (!me.config.sequential) {
|
|
me.loadData();
|
|
}
|
|
});
|
|
}
|
|
|
|
getDataTableConfig() {
|
|
const me = this;
|
|
const url = this.config.url;
|
|
const columns = this.columns;
|
|
const columnDefs = this.columnDefs;
|
|
const isSortable = this.getConfigParam('isSortable');
|
|
const order = this.orderConfig;
|
|
|
|
const config = {
|
|
ajax: function(data, callback, settings) {
|
|
$.ajax({
|
|
url: url,
|
|
method: 'GET',
|
|
data: data,
|
|
dataType: 'json',
|
|
success: function(response, textStatus, jqXHR) {
|
|
callback(response);
|
|
me.performAdditional(response, me.config);
|
|
me.stopAnimation();
|
|
},
|
|
error: handleAjaxError,
|
|
});
|
|
},
|
|
processing: true,
|
|
serverSide: true,
|
|
deferRender: true,
|
|
deferLoading: 0,
|
|
pageLength: 25,
|
|
autoWidth: false,
|
|
lengthChange: false,
|
|
searching: true,
|
|
ordering: isSortable,
|
|
info: false,
|
|
pagingType: 'simple_numbers',
|
|
language: {
|
|
paginate: {
|
|
previous: '<',
|
|
next: '>',
|
|
},
|
|
},
|
|
|
|
layout: {
|
|
topEnd: null,
|
|
bottomEnd: {
|
|
paging: {
|
|
boundaryNumbers: false,
|
|
type: 'simple_numbers',
|
|
},
|
|
},
|
|
},
|
|
|
|
createdRow: function(row, data, dataIndex) {
|
|
$(row).attr('data-item-id', data.id);
|
|
},
|
|
|
|
drawCallback: function(settings) {
|
|
me.drawCallback(settings);
|
|
me.updateTableFooter(this);
|
|
},
|
|
|
|
columnDefs: columnDefs,
|
|
columns: columns,
|
|
order: order
|
|
};
|
|
|
|
return config;
|
|
}
|
|
|
|
performAdditional(response, config) {
|
|
if (!config.calculateTotals) {
|
|
fireEvent('dateFilterChangedCompleted');
|
|
|
|
return;
|
|
}
|
|
|
|
const ids = response.data.map(item => item.id);
|
|
const token = document.head.querySelector('[name=\'csrf-token\'][content]').content;
|
|
const dateRange = response.dateRange;
|
|
|
|
if (dateRange && ids.length) {
|
|
const requestData = {
|
|
token: token,
|
|
ids: ids,
|
|
type: config.totals.type,
|
|
startDate: dateRange.startDate,
|
|
endDate: dateRange.endDate,
|
|
};
|
|
let preparedBase = {};
|
|
response.data.forEach(rec => {
|
|
preparedBase[rec.id] = rec;
|
|
});
|
|
$.ajax({
|
|
type: 'GET',
|
|
url: '/admin/timeFrameTotal',
|
|
data: requestData,
|
|
success: (data) => this.onTotalsSuccess(data, config, preparedBase),
|
|
error: handleAjaxError,
|
|
complete: function() {
|
|
fireEvent('dateFilterChangedCompleted');
|
|
},
|
|
});
|
|
} else {
|
|
fireEvent('dateFilterChangedCompleted');
|
|
}
|
|
|
|
if (!dateRange && ids.length) {
|
|
// actualy making fake response from server
|
|
let data = {totals: {}};
|
|
let preparedBase = {};
|
|
const cols = config.totals.columns;
|
|
response.data.forEach(item => {
|
|
data.totals[item.id] = {};
|
|
preparedBase[item.id] = {};
|
|
cols.forEach(col => {
|
|
data.totals[item.id][col] = item[col];
|
|
preparedBase[item.id][col] = item[col];
|
|
});
|
|
|
|
});
|
|
this.onTotalsSuccess(data, config, preparedBase);
|
|
}
|
|
}
|
|
|
|
onTotalsSuccess(data, config, base) {
|
|
const table = $(`#${config.tableId}`).DataTable();
|
|
const columns = config.totals.columns;
|
|
|
|
let idxs = {};
|
|
|
|
for (let i = 0; i < columns.length; i++) {
|
|
idxs[columns[i]] = -1;
|
|
}
|
|
|
|
table.settings().init().columns.forEach((col, index) => {
|
|
columns.forEach(colName => {
|
|
if (col.data === colName || col.name === colName) {
|
|
idxs[colName] = index;
|
|
}
|
|
});
|
|
|
|
});
|
|
|
|
if (Object.values(idxs).includes(-1)) return;
|
|
|
|
let rowData;
|
|
let id;
|
|
|
|
table.rows().every(function() {
|
|
rowData = this.data();
|
|
id = String(rowData.id);
|
|
if (id in data.totals) {
|
|
for (const col in idxs) {
|
|
$(table.cell(this, idxs[col]).node()).html(renderTotalFrame(base[id][col], data.totals[id][col]));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
drawCallback(settings) {
|
|
const me = this;
|
|
|
|
this.initTooltips();
|
|
|
|
//this.stopAnimation();
|
|
|
|
const params = {
|
|
tableId: me.config.tableId
|
|
};
|
|
|
|
if (settings && settings.iDraw > 1) {
|
|
const total = settings.json.recordsTotal;
|
|
const tileId = this.config.tileId;
|
|
const tableId = this.config.tableId;
|
|
|
|
this.totalTile.update(tableId, tileId, total);
|
|
this.updateTableTitle(total);
|
|
|
|
fireEvent('tableLoaded', params);
|
|
}
|
|
}
|
|
|
|
updateTableTitle(value) {
|
|
const tableId = this.config.tableId;
|
|
const wrapper = document.getElementById(tableId).closest('.card');
|
|
|
|
if (wrapper) {
|
|
const span = wrapper.querySelector('header span');
|
|
|
|
span.textContent = value;
|
|
}
|
|
}
|
|
|
|
stopAnimation() {
|
|
this.loader.stop();
|
|
const el = document.getElementById(`${this.config.tableId}_loader`);
|
|
if (el) el.remove();
|
|
|
|
const table = document.getElementById(this.config.tableId);
|
|
table.classList.remove('dim-table');
|
|
}
|
|
|
|
updateTableFooter(dataTable) {
|
|
const tableId = this.config.tableId;
|
|
const pagerSelector = `#${tableId}_wrapper .dt-paging`;
|
|
|
|
const api = dataTable.api();
|
|
if (api.ajax && typeof api.ajax.json === 'function' && api.ajax.json() === undefined) {
|
|
return;
|
|
}
|
|
|
|
$(`#${tableId}`).closest('.dt-container').find('nav').show();
|
|
if (api.page.info().pages <= 1) {
|
|
$(pagerSelector).hide();
|
|
} else {
|
|
$(pagerSelector).show();
|
|
}
|
|
}
|
|
|
|
initTooltips() {
|
|
const tableId = this.config.tableId;
|
|
Tooltip.addTooltipsToGridRecords(tableId);
|
|
Tooltip.addTooltipToSpans();
|
|
Tooltip.addTooltipToParagraphs();
|
|
}
|
|
|
|
onBeforeLoad(e, settings, data) {
|
|
if (!this.config.sequential) {
|
|
this.startLoader();
|
|
}
|
|
this.updateTableTitle(MIDLINE_HELLIP);
|
|
|
|
fireEvent('dateFilterChangedCaught');
|
|
|
|
//TODO: move to events grid? Or not?
|
|
const params = this.config.getParams();
|
|
const queryParams = getQueryParams(params);
|
|
|
|
for (let key in queryParams) {
|
|
data[key] = queryParams[key];
|
|
}
|
|
|
|
const token = document.head.querySelector('[name=\'csrf-token\'][content]').content;
|
|
data.token = token;
|
|
}
|
|
|
|
onDraw(e, settings) {
|
|
if (this.firstload) {
|
|
document.getElementById(this.config.tableId).classList.remove('hide-body');
|
|
this.firstload = false;
|
|
}
|
|
}
|
|
|
|
onBeforePageChange(e, settings) {
|
|
const tableId = this.config.tableId;
|
|
const pagesPath = `#${tableId}_paginate a`;
|
|
|
|
[...document.querySelectorAll(pagesPath)].forEach(a => {
|
|
a.outerHTML =
|
|
a.outerHTML
|
|
.replace(/<a/g, '<span')
|
|
.replace(/<\/a>/g, '</span>');
|
|
});
|
|
}
|
|
|
|
onTableRowClick(event) {
|
|
const selection = window.getSelection();
|
|
if ('Range' === selection.type) {
|
|
return;
|
|
}
|
|
|
|
const row = event.target.closest('tr');
|
|
const link = row.querySelector('a');
|
|
|
|
if (link) {
|
|
event.preventDefault();
|
|
if (event.ctrlKey || event.metaKey) {
|
|
window.open(link.href, '_blank');
|
|
} else {
|
|
window.location.href = link.href;
|
|
}
|
|
}
|
|
}
|
|
|
|
//TODO: leave blank and move to the events table
|
|
addTableRowsEvents() {
|
|
const tableId = this.config.tableId;
|
|
const onRowClick = this.onRowClick.bind(this);
|
|
|
|
if ($(this.table).DataTable().data().any()) {
|
|
const rows = document.querySelectorAll(`#${tableId} tbody tr`);
|
|
rows.forEach(row => row.addEventListener('click', onRowClick, false));
|
|
}
|
|
}
|
|
|
|
startLoader() {
|
|
const tableId = this.config.tableId;
|
|
const loaderPath = `${tableId}_processing`;
|
|
|
|
const loaderWrapper = document.getElementById(loaderPath);
|
|
const el = document.createElement('p');
|
|
el.className = 'text-loader';
|
|
loaderWrapper.replaceChildren(el);
|
|
|
|
this.loader.start(el);
|
|
|
|
loaderWrapper.style.display = null;
|
|
|
|
const table = document.getElementById(this.config.tableId);
|
|
table.classList.add('dim-table');
|
|
}
|
|
|
|
onRowClick(e) {
|
|
const selection = window.getSelection();
|
|
if ('Range' === selection.type) {
|
|
return;
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
const row = e.target.closest('tr');
|
|
const itemId = row.dataset.itemId;
|
|
const data = {itemId: itemId};
|
|
|
|
fireEvent('tableRowClicked', data);
|
|
}
|
|
|
|
onError(e, settings, techNote, message) {
|
|
if (settings.jqXHR !== undefined && 403 === settings.jqXHR.status) {
|
|
window.location.href = escape('/');
|
|
}
|
|
|
|
//console.warn('An error has been reported by DataTables: ', message);
|
|
}
|
|
|
|
loadData() {
|
|
//TODO: create getter for table el: $(me.table).DataTable().ajax.reload()
|
|
const me = this;
|
|
$(me.table).DataTable().ajax.reload();
|
|
}
|
|
|
|
onDateFilterChanged() {
|
|
this.loadData();
|
|
}
|
|
|
|
onSearchFilterChanged() {
|
|
this.loadData();
|
|
}
|
|
|
|
onChoicesFilterChanged() {
|
|
this.loadData();
|
|
}
|
|
|
|
getConfigParam(key) {
|
|
const cfg = this.config;
|
|
const value = ('undefined' !== typeof cfg[key]) ? cfg[key] : true;
|
|
|
|
return value;
|
|
}
|
|
|
|
get orderConfig() {
|
|
return this.getConfigParam('isSortable') ? [[1, 'desc']] : [];
|
|
}
|
|
|
|
get table() {
|
|
const tableId = this.config.tableId;
|
|
const tableEl = document.getElementById(tableId);
|
|
|
|
return tableEl;
|
|
}
|
|
|
|
renderTotalsLoader(data, type, record, meta) {
|
|
const span = document.createElement('span');
|
|
|
|
const col_name = meta.settings.aoColumns[meta.col].name;
|
|
if (this.config.calculateTotals && this.config.totals.columns.includes(col_name)) {
|
|
span.className = 'loading-table-total';
|
|
span.textContent = MIDLINE_HELLIP;
|
|
} else {
|
|
span.textContent = data;
|
|
}
|
|
|
|
return span;
|
|
}
|
|
}
|