Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
body:has(.s-dashboard) {
background-color: var(--layer);
--field: var(--field-02);
--field-hover: var(--field-hover-02);
}
.input-group-addon label {
margin-bottom: 0px;
}
.vector-map {
height: 350px;
color: transparent;
}
.jvectormap-container {
height:100%;
width:100%;
}
.dashboard-widgets .sortable-placeholder {
background-color: #fff;
border: 1px dashed #4e5d9d;
flex-grow: 0;
}
.dashboard-widgets.cards {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
padding: 10px;
}
.dashboard-widgets .tile {
--layer: var(--background);
margin: 5px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-moz-transition-property: background-color, box-shadow, -moz-transform, border;
-o-transition-property: background-color, box-shadow, text-shadow, -o-transform, border;
-webkit-transition-property: background-color, box-shadow, text-shadow, -webkit-transform, border;
transition-property: background-color, box-shadow, text-shadow, transform, border;
-moz-transition-duration: 0.2s;
-o-transition-duration: 0.2s;
-webkit-transition-duration: 0.2s;
transition-duration: 0.2s;
-moz-transition-timing-function: linear;
-o-transition-timing-function: linear;
-webkit-transition-timing-function: linear;
transition-timing-function: linear;
position: relative;
}
.dashboard-widgets .ui-sortable-helper .tile {
box-shadow: rgba(255, 255, 255, 0.1) 0px 1px 1px 0px inset, rgba(50, 50, 93, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px;
max-width: 170px;
max-height: 170px;
overflow: hidden;
transform: rotate(1deg);
-webkit-animation: squareToCircle 1.5s .5s infinite alternate;
}
@-webkit-keyframes squareToCircle {
0% {border-radius: 0 0 0 0;}
100% {border-radius: 20px 20px 20px 20px;}
}
.dashboard-widgets .widget-overlay {
content: '';
width: 101%;
height: 101%;
position: absolute;
top: 0;
left: 0;
transition: var(--transition-all-expressive);
backdrop-filter: blur(0);
pointer-events: none;
opacity: 0;
}
.dashboard-widgets .ui-sortable-helper .widget-overlay {
backdrop-filter: blur(8px);
opacity: 1;
}
.dashboard-widgets h4 {
cursor: -moz-grab;
cursor: -webkit-grab;
cursor: grab;
}
.dashboard-widgets .dropdown-toggle .ri-more-2-fill {
display: inline-block;
font-size: 15px;
color: var(--icon-secondary);
transition: var(--transition-all-productive);
width: 30px;
margin: -10px;
text-align: center;
line-height: 30px;
border-radius: var(--border-radius-md);
}
.dashboard-widgets .card-header h4 {
width: 90%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.dashboard-widgets .tile table {
table-layout: fixed;
}
.dashboard-widgets .tile table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.dashboard-widgets .tile table td:last-child {
width: 30px;
}
.chart-wrapper {
position: relative;
}
.chart-wrapper .legend {
background: #000;
opacity: 0;
position: absolute;
bottom: -17px;
width: 100%;
-moz-border-radius: 0 0 4px 4px;
-webkit-border-radius: 0 0 4px 4px;
border-radius: 0 0 4px 4px;
color: #fff;
-webkit-transition: all 0.3s ease-in-out;
}
.chart-wrapper:hover .legend {
opacity: 0.8;
}
.chart-wrapper .legend ul {
list-style: none;
margin: 0;
padding: 5px 0;
}
.chart-wrapper .legend li {
margin: 0 10px;
padding: 5px 0;
}
.chart-wrapper .legend li span {
display: inline-block;
width: 14px;
height: 8px;
margin-right: 5px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
@media (max-width: 700px) {
.dashboard-widgets .widget {
width: 100% !important;
}
}
#dashboard-widgets .spinner {
text-align: center;
line-height: 250px;
font-size: 24px;
}

View File

@@ -0,0 +1,339 @@
// DashboardBundle
// Use absolute path to keep dashboard working when app is in subdir
Mautic.widgetUrl = mauticBasePath + '/s/dashboard/widget/';
/**
* @type jQuery DOM element to be replaced with spinner
*/
Mautic.dashboardSubmitButton = false; // Button text, to be get and shown instead of spinner
/**
* Init dashboard events
* @param container
*/
Mautic.dashboardOnLoad = function (container) {
Mautic.loadWidgets();
};
/**
* Load all widgets on initial page render
*/
Mautic.loadWidgets = function () {
Mautic.dashboardFilterPreventSubmit();
jQuery('.widget').each(function() {
let widgetId = jQuery(this).attr('data-widget-id');
let container = jQuery('.widget[data-widget-id="'+widgetId+'"]');
jQuery.ajax({
url: Mautic.widgetUrl+widgetId+'?ignoreAjax=true',
}).done(function(response) {
Mautic.widgetOnLoad(container, response);
});
});
jQuery(document).ajaxComplete(function(){
Mautic.initDashboardFilter();
});
};
/**
* Init dashboard filter events after widget load
*/
Mautic.initDashboardFilter = function () {
let form = jQuery('form[name="daterange"]');
form.find('button')
.replaceWith(Mautic.dashboardSubmitButton);
form
.unbind('submit')
.on('submit', function(e){
e.preventDefault();
Mautic.dashboardFilterPreventSubmit();
jQuery('.widget').each(function() {
let widgetId = jQuery(this).attr('data-widget-id');
let element = jQuery('.widget[data-widget-id="' + widgetId + '"]');
jQuery.ajax({
type: 'POST',
url: Mautic.widgetUrl + widgetId + '?ignoreAjax=true',
data: form.serializeArray(),
success: function (response) {
Mautic.widgetOnLoad(element, response);
}
});
});
});
};
/**
* Prevent filter from submit, show spinner instead of send button
*/
Mautic.dashboardFilterPreventSubmit = function() {
let form = jQuery('form[name="daterange"]');
let button = form.find('button:first');
Mautic.dashboardSubmitButton = button.clone();
button.width(button.width()+'px'); // Keep button width
button.html('<i class="ri-loader-3-line ri-spin"></i>');
jQuery('.widget').find('.card-body').html('<div class="spinner"><i class="ri-loader-3-line ri-spin"></i></div>');
form
.unbind('submit')
.on('submit', function(e){
e.preventDefault();
});
};
Mautic.dashboardOnUnload = function(id) {
// Trash initialized dashboard vars on app content change.
mQuery('.jvectormap-tip').remove();
};
/**
* Render widget from XHR to DOM
*
* @param container
* @param response
*/
Mautic.widgetOnLoad = function(container, response) {
if (!response.widgetId) return;
// target in DOM
var widget = mQuery('.widget[data-widget-id="' + response.widgetId + '"]');
// source from response
var widgetHtml = mQuery(response.widgetHtml);
// initialize edit button modal again
widgetHtml.find("*[data-toggle='ajaxmodal']").on('click.ajaxmodal', function (event) {
event.preventDefault();
Mautic.ajaxifyModal(this, event);
});
// Create the new widget wrapper and add it to the 0 position if doesn't exist (probably a new one)
if (!widget.length) {
widget = mQuery('<div/>')
.addClass('widget')
.attr('data-widget-id', response.widgetId);
mQuery('#dashboard-widgets').prepend(widget);
}
widget.html(widgetHtml)
.css('width', response.widgetWidth + '%')
.css('height', response.widgetHeight + '%');
Mautic.renderCharts(widgetHtml);
const map = widgetHtml.find('.vector-map').first();
if (map.length && !map.hasClass('map-rendered')) {
Mautic.initMap(widgetHtml, 'regions');
}
Mautic.initWidgetRemoveEvents();
Mautic.initWidgetSorting();
Mautic.initDashboardFilter();
};
Mautic.initWidgetRemoveEvents = function () {
jQuery('.remove-widget')
.unbind('click')
.on('click', function(e) {
e.preventDefault();
element = jQuery(this);
let url = element.attr('href');
element.closest('.widget').remove();
jQuery.ajax({
url: url,
});
});
};
Mautic.initWidgetSorting = function () {
var widgetsWrapper = mQuery('#dashboard-widgets');
var bodyOverflow = {};
widgetsWrapper.sortable({
handle: '.card-header h4',
placeholder: 'sortable-placeholder',
items: '.widget',
opacity: 0.9,
scroll: true,
scrollSpeed: 10,
tolerance: "pointer",
cursor: 'move',
appendTo: '#dashboard-widgets',
helper: function(e, ui) {
// Ensure the draggable retains it's original size and that the margin doesn't cause things to bounce around
ui.children().each(function() {
mQuery(this).width(mQuery(this).width());
mQuery(this).height(mQuery(this).height());
});
// Fix body overflow that messes sortable up
bodyOverflow.overflowX = mQuery('body').css('overflow-x');
bodyOverflow.overflowY = mQuery('body').css('overflow-y');
mQuery('body').css({
overflowX: 'visible',
overflowY: 'visible'
});
mQuery("#dashboard-widgets .widget").each(function(i) {
var item = mQuery(this);
var item_clone = item.clone();
var canvas = item.find('canvas').first();
if (canvas.length) {
// Copy the canvas
var destCanvas = item_clone.find('canvas').first();
var destCtx = destCanvas[0].getContext('2d');
destCtx.drawImage(canvas[0], 0, 0);
}
item.data("clone", item_clone);
var position = item.position();
item_clone
.css({
left: position.left,
top: position.top,
width: item.width(),
visibility: "visible",
position: "absolute",
zIndex: 1
});
item.css('visibility', 'hidden');
mQuery("#cloned-widgets").append(item_clone);
});
return ui;
},
start: function(e, ui) {
ui.helper.css('visibility', 'visible');
ui.helper.data("clone").hide();
},
sort: function(e, ui) {
var tile = ui.item.find('.tile').first();
// Prevent margin from pushing the elements out of the way
ui.placeholder.css({
marginTop: "5px",
marginBottom: "5px",
marginLeft: 0,
marginRight: 0
});
},
stop: function() {
// Restore original overflow
mQuery('body').css(bodyOverflow);
mQuery("#dashboard-widgets .widget.exclude-me").each(function() {
var item = mQuery(this);
var clone = item.data("clone");
var position = item.position();
clone.css("left", position.left);
clone.css("top", position.top);
clone.show();
item.removeClass("exclude-me");
});
mQuery("#dashboard-widgets .widget").css("visibility", "visible");
mQuery("#cloned-widgets .widget").remove();
Mautic.saveWidgetSorting();
},
change: function(e, ui) {
mQuery("#dashboard-widgets .widget:not(.exclude-me)").each(function() {
var item = mQuery(this);
var clone = item.data("clone");
clone.stop(true, false);
var position = item.position();
clone.animate({
left: position.left,
top: position.top
}, 200);
});
}
}).disableSelection();
}
Mautic.saveWidgetSorting = function () {
var widgetsWrapper = mQuery('#dashboard-widgets');
var widgets = widgetsWrapper.children();
var ordering = [];
widgets.each(function(index, value) {
ordering.push(mQuery(this).attr('data-widget-id'));
});
Mautic.ajaxActionRequest('dashboard:updateWidgetOrdering', {'ordering': ordering}, function(response) {
// @todo handle errors
});
}
Mautic.updateWidgetForm = function (element) {
Mautic.activateLabelLoadingIndicator('widget_type');
var formWrapper = mQuery(element).closest('form');
var WidgetFormValues = formWrapper.serializeArray();
Mautic.ajaxActionRequest('dashboard:updateWidgetForm', WidgetFormValues, function(response) {
if (response.formHtml) {
var formHtml = mQuery(response.formHtml);
formHtml.find('#widget_buttons').addClass('hide hidden');
formWrapper.html(formHtml.children());
Mautic.onPageLoad('#widget_params');
}
Mautic.removeLabelLoadingIndicator();
});
};
Mautic.exportDashboardLayout = function(text, baseUrl) {
var name = prompt(text, "");
if (name !== null) {
if (name) {
baseUrl = baseUrl + "?name=" + encodeURIComponent(name);
}
window.location = baseUrl;
}
};
Mautic.saveDashboardLayout = function(text) {
var name = prompt(text, "");
if (name) {
mQuery.ajax({
type: 'POST',
url: mauticBaseUrl+'s/dashboard/save',
data: {name: name}
});
}
};
Mautic.setDateRange = function(option) {
var today = new Date();
var fromDate, toDate;
switch(option) {
case 'today':
fromDate = today;
toDate = today;
break;
case 'yesterday':
fromDate = new Date(today.getTime() - (24 * 60 * 60 * 1000));
toDate = fromDate;
break;
default:
if (typeof option === 'number') {
fromDate = new Date(today.getTime() - (option * 24 * 60 * 60 * 1000));
toDate = today;
} else {
console.error('Invalid option');
return;
}
}
document.getElementById('daterange_date_from').value = Mautic.formatDate(fromDate);
document.getElementById('daterange_date_to').value = Mautic.formatDate(toDate);
document.getElementById('daterange_apply').click();
};
Mautic.formatDate = function(date) {
var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
];
return monthNames[date.getMonth()] + " " + date.getDate() + ", " + date.getFullYear();
};