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:
@@ -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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user