Compare commits

..

26 Commits

Author SHA1 Message Date
Girish Ramakrishnan 497b3016c0 7.7.2 changes 2024-03-27 10:12:37 +01:00
Johannes Zellner fe9bd52b04 frontend: make uploads cancellable 2024-03-26 09:54:59 +01:00
Johannes Zellner 0705c77333 Frontend: update pankow for pretty fileupload size 2024-03-25 14:56:07 +01:00
Girish Ramakrishnan b66e77a2d8 Fix crash when system has no swap 2024-03-22 10:39:35 +01:00
Girish Ramakrishnan 4b4c8d8052 7.7.2 changes 2024-03-21 19:11:57 +01:00
Girish Ramakrishnan 4ee56782ba move syslog.js to top level 2024-03-21 19:09:51 +01:00
Girish Ramakrishnan 104997d77c syslog: change it to unix domain socket
docker is using a extra udp port for every container. when there is
a lot of containers, a lot of random udp ports get used up. this causes
problems when installing apps that require contiguous port ranges
2024-03-21 18:59:08 +01:00
Girish Ramakrishnan 8e07b3c96d remove unused variable 2024-03-21 17:11:17 +01:00
Johannes Zellner 4e618540f8 dashboard: preserve app link paths 2024-03-18 11:40:17 +01:00
Girish Ramakrishnan 49941a34b9 backups: deleted apps must also be displayed in contents 2024-03-14 16:14:50 +01:00
Johannes Zellner 771b797a23 frontend: update dependencies to fix filemanager empty folder content layout 2024-03-13 11:42:47 +01:00
Girish Ramakrishnan d09915bf6e scheduler: typo
(cherry picked from commit 09e00e6d58)
2024-03-12 18:06:24 +01:00
Johannes Zellner 264c94ff34 dashboard: remove bootstrap slider component 2024-03-12 17:33:38 +01:00
Johannes Zellner a90df99331 dashboard: migrate rsync concurrency settings to native range slider 2024-03-12 17:31:07 +01:00
Johannes Zellner 78f0d61627 dashboard: make backup upload part size steps explicit with native widget 2024-03-12 17:09:35 +01:00
Johannes Zellner 8c106b3435 dashboard: replace old slider with native widget 2024-03-12 16:44:08 +01:00
Johannes Zellner 42555c7231 dashboard: use native slider for mailbox storage quota 2024-03-12 15:43:08 +01:00
Johannes Zellner ab035a2afe dashboard: use native slider for mail size 2024-03-12 15:35:20 +01:00
Johannes Zellner 3a30eed3cd dashboard: remove commented slider 2024-03-12 15:29:30 +01:00
Johannes Zellner 4cb390374b dashboard: use native range slider for services 2024-03-12 15:28:47 +01:00
Girish Ramakrishnan 50179dd7eb 7.7.1 changes 2024-03-12 11:28:27 +01:00
Girish Ramakrishnan 2956c3360c postgresql: fix whitelist ext loading 2024-03-12 11:27:42 +01:00
Girish Ramakrishnan c634bdbd34 scheduler: do not create jobs of suspended apps
otherwise, when an app is uninstalling, it creates the docker containers
by calling getDynamicEnvironment. This ends up adding addonConfigs for the
docker addon and prevents the app from getting uninstalled.
2024-03-12 00:55:06 +01:00
Johannes Zellner 1892c0cd80 dashboard: use native slider element for app memory and cpu 2024-03-11 21:36:18 +01:00
Johannes Zellner 63b395982c dashboard: use less gulp processing for css turns out it actually made the files much larger 2024-03-11 19:03:42 +01:00
Johannes Zellner d50c8539b2 dashboard: update dependencies 2024-03-11 18:49:30 +01:00
52 changed files with 514 additions and 5954 deletions
+9
View File
@@ -2755,4 +2755,13 @@
[7.7.1]
* postgresql: fix bug in loading of contrib extensions
* dashboard: use native slider element for app memory and cpu
[7.7.2]
* docker: use unix domain socket based logging instead of udp
* dashboard: use native slider element for app memory and cpu
* filemanager: fix empty folder content layout
* dashboard: preserve app link paths
* backups: deleted apps must also be displayed in contents
* filemanager: make uploads cancellable
* Fix crash on systemds with no swap
-6
View File
@@ -3,9 +3,7 @@
'use strict';
const argv = require('yargs').argv,
autoprefixer = require('gulp-autoprefixer'),
concat = require('gulp-concat'),
cssnano = require('gulp-cssnano'),
ejs = require('gulp-ejs'),
execSync = require('child_process').execSync,
fs = require('fs'),
@@ -163,11 +161,7 @@ gulp.task('html', gulp.series(['html-views', 'html-templates', 'html-raw']));
gulp.task('css', function () {
return gulp.src('src/*.scss')
.pipe(sourcemaps.init())
.pipe(sass({ includePaths: ['node_modules/bootstrap-sass/assets/stylesheets/'] }).on('error', sass.logError))
.pipe(autoprefixer())
.pipe(cssnano())
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist'));
});
+29 -3425
View File
File diff suppressed because it is too large Load Diff
+4 -6
View File
@@ -13,19 +13,17 @@
"author": "",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@fortawesome/fontawesome-free": "^6.4.0",
"@fortawesome/fontawesome-free": "^6.5.1",
"bootstrap-sass": "^3.4.3",
"chart.js": "^4.3.0",
"chart.js": "^4.4.2",
"gulp": "^4.0.2",
"gulp-autoprefixer": "^8.0.0",
"gulp-concat": "^2.6.1",
"gulp-cssnano": "^2.1.3",
"gulp-ejs": "^5.1.0",
"gulp-sass": "^5.1.0",
"gulp-serve": "^1.4.0",
"gulp-sourcemaps": "^3.0.0",
"moment": "^2.29.4",
"sass": "^1.63.3",
"moment": "^2.30.1",
"sass": "^1.71.1",
"yargs": "^17.7.2"
},
"eslintConfig": {
@@ -1,255 +0,0 @@
/*! =======================================================
VERSION 6.0.12
========================================================= */
/*! =========================================================
* bootstrap-slider.js
*
* Maintainers:
* Kyle Kemp
* - Twitter: @seiyria
* - Github: seiyria
* Rohit Kalkur
* - Twitter: @Rovolutionary
* - Github: rovolution
*
* =========================================================
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
.slider {
display: inline-block;
vertical-align: middle;
position: relative;
}
.slider.slider-horizontal {
width: 210px;
height: 20px;
}
.slider.slider-horizontal .slider-track {
height: 10px;
width: 100%;
margin-top: -5px;
top: 50%;
left: 0;
}
.slider.slider-horizontal .slider-selection,
.slider.slider-horizontal .slider-track-low,
.slider.slider-horizontal .slider-track-high {
height: 100%;
top: 0;
bottom: 0;
}
.slider.slider-horizontal .slider-tick,
.slider.slider-horizontal .slider-handle {
margin-left: -10px;
margin-top: -5px;
}
.slider.slider-horizontal .slider-tick.triangle,
.slider.slider-horizontal .slider-handle.triangle {
border-width: 0 10px 10px 10px;
width: 0;
height: 0;
border-bottom-color: #0480be;
margin-top: 0;
}
.slider.slider-horizontal .slider-tick-label-container {
white-space: nowrap;
margin-top: 20px;
}
.slider.slider-horizontal .slider-tick-label-container .slider-tick-label {
padding-top: 4px;
display: inline-block;
text-align: center;
}
.slider.slider-vertical {
height: 210px;
width: 20px;
}
.slider.slider-vertical .slider-track {
width: 10px;
height: 100%;
margin-left: -5px;
left: 50%;
top: 0;
}
.slider.slider-vertical .slider-selection {
width: 100%;
left: 0;
top: 0;
bottom: 0;
}
.slider.slider-vertical .slider-track-low,
.slider.slider-vertical .slider-track-high {
width: 100%;
left: 0;
right: 0;
}
.slider.slider-vertical .slider-tick,
.slider.slider-vertical .slider-handle {
margin-left: -5px;
margin-top: -10px;
}
.slider.slider-vertical .slider-tick.triangle,
.slider.slider-vertical .slider-handle.triangle {
border-width: 10px 0 10px 10px;
width: 1px;
height: 1px;
border-left-color: #0480be;
margin-left: 0;
}
.slider.slider-vertical .slider-tick-label-container {
white-space: nowrap;
}
.slider.slider-vertical .slider-tick-label-container .slider-tick-label {
padding-left: 4px;
}
.slider.slider-disabled .slider-handle {
background-image: -webkit-linear-gradient(top, #dfdfdf 0%, #bebebe 100%);
background-image: -o-linear-gradient(top, #dfdfdf 0%, #bebebe 100%);
background-image: linear-gradient(to bottom, #dfdfdf 0%, #bebebe 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdfdfdf', endColorstr='#ffbebebe', GradientType=0);
}
.slider.slider-disabled .slider-track {
background-image: -webkit-linear-gradient(top, #e5e5e5 0%, #e9e9e9 100%);
background-image: -o-linear-gradient(top, #e5e5e5 0%, #e9e9e9 100%);
background-image: linear-gradient(to bottom, #e5e5e5 0%, #e9e9e9 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe5e5e5', endColorstr='#ffe9e9e9', GradientType=0);
cursor: not-allowed;
}
.slider input {
display: none;
}
.slider .tooltip.top {
margin-top: -36px;
}
.slider .tooltip-inner {
white-space: nowrap;
}
.slider .hide {
display: none;
}
.slider-track {
position: absolute;
cursor: pointer;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #f9f9f9 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #f9f9f9 100%);
background-image: linear-gradient(to bottom, #f5f5f5 0%, #f9f9f9 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
.slider-selection {
position: absolute;
background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);
background-image: linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
border-radius: 4px;
}
.slider-selection.tick-slider-selection {
background-image: -webkit-linear-gradient(top, #89cdef 0%, #81bfde 100%);
background-image: -o-linear-gradient(top, #89cdef 0%, #81bfde 100%);
background-image: linear-gradient(to bottom, #89cdef 0%, #81bfde 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff89cdef', endColorstr='#ff81bfde', GradientType=0);
}
.slider-track-low,
.slider-track-high {
position: absolute;
background: transparent;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
border-radius: 4px;
}
.slider-handle {
position: absolute;
width: 20px;
height: 20px;
background-color: #337ab7;
background-image: -webkit-linear-gradient(top, #149bdf 0%, #0480be 100%);
background-image: -o-linear-gradient(top, #149bdf 0%, #0480be 100%);
background-image: linear-gradient(to bottom, #149bdf 0%, #0480be 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
filter: none;
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
border: 0px solid transparent;
}
.slider-handle.round {
border-radius: 50%;
}
.slider-handle.triangle {
background: transparent none;
}
.slider-handle.custom {
background: transparent none;
}
.slider-handle.custom::before {
line-height: 20px;
font-size: 20px;
content: '\2605';
color: #726204;
}
.slider-tick {
position: absolute;
width: 20px;
height: 20px;
background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);
background-image: linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
filter: none;
opacity: 0.8;
border: 0px solid transparent;
}
.slider-tick.round {
border-radius: 50%;
}
.slider-tick.triangle {
background: transparent none;
}
.slider-tick.custom {
background: transparent none;
}
.slider-tick.custom::before {
line-height: 20px;
font-size: 20px;
content: '\2605';
color: #726204;
}
.slider-tick.in-selection {
background-image: -webkit-linear-gradient(top, #89cdef 0%, #81bfde 100%);
background-image: -o-linear-gradient(top, #89cdef 0%, #81bfde 100%);
background-image: linear-gradient(to bottom, #89cdef 0%, #81bfde 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff89cdef', endColorstr='#ff81bfde', GradientType=0);
opacity: 1;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-232
View File
@@ -1,232 +0,0 @@
(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['angular', 'bootstrap-slider'], factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = factory(require('angular'), require('bootstrap-slider'));
} else if (window) {
factory(window.angular, window.Slider);
}
})(function (angular, Slider) {
angular.module('ui.bootstrap-slider', [])
.directive('slider', ['$parse', '$timeout', '$rootScope', function ($parse, $timeout, $rootScope) {
return {
restrict: 'AE',
replace: true,
template: '<div><input class="slider-input" type="text" style="width:100%" /></div>',
require: 'ngModel',
scope: {
max: "=",
min: "=",
step: "=",
value: "=",
ngModel: '=',
ngDisabled: '=',
range: '=',
sliderid: '=',
ticks: '=',
ticksLabels: '=',
ticksSnapBounds: '=',
ticksPositions: '=',
scale: '=',
focus: '=',
formatter: '&',
onStartSlide: '&',
onStopSlide: '&',
onSlide: '&'
},
link: function ($scope, element, attrs, ngModelCtrl, $compile) {
var ngModelDeregisterFn, ngDisabledDeregisterFn;
var slider = initSlider();
function initSlider() {
var options = {};
function setOption(key, value, defaultValue) {
options[key] = value || defaultValue;
}
function setFloatOption(key, value, defaultValue) {
options[key] = value || value === 0 ? parseFloat(value) : defaultValue;
}
function setBooleanOption(key, value, defaultValue) {
options[key] = value ? value + '' === 'true' : defaultValue;
}
function getArrayOrValue(value) {
return (angular.isString(value) && value.indexOf("[") === 0) ? angular.fromJson(value) : value;
}
setOption('id', $scope.sliderid);
setOption('orientation', attrs.orientation, 'horizontal');
setOption('selection', attrs.selection, 'before');
setOption('handle', attrs.handle, 'round');
setOption('tooltip', attrs.sliderTooltip || attrs.tooltip, 'show');
setOption('tooltip_position', attrs.sliderTooltipPosition, 'top');
setOption('tooltipseparator', attrs.tooltipseparator, ':');
setOption('ticks', $scope.ticks);
setOption('ticks_labels', $scope.ticksLabels);
setOption('ticks_snap_bounds', $scope.ticksSnapBounds);
setOption('ticks_positions', $scope.ticksPositions);
setOption('scale', $scope.scale, 'linear');
setOption('focus', $scope.focus);
setFloatOption('min', $scope.min, 0);
setFloatOption('max', $scope.max, 10);
setFloatOption('step', $scope.step, 1);
var strNbr = options.step + '';
var dotPos = strNbr.search(/[^.,]*$/);
var decimals = strNbr.substring(dotPos);
setFloatOption('precision', attrs.precision, decimals.length);
setBooleanOption('tooltip_split', attrs.tooltipsplit, false);
setBooleanOption('enabled', attrs.enabled, true);
setBooleanOption('naturalarrowkeys', attrs.naturalarrowkeys, false);
setBooleanOption('reversed', attrs.reversed, false);
setBooleanOption('range', $scope.range, false);
if (options.range) {
if (angular.isArray($scope.value)) {
options.value = $scope.value;
}
else if (angular.isString($scope.value)) {
options.value = getArrayOrValue($scope.value);
if (!angular.isArray(options.value)) {
var value = parseFloat($scope.value);
if (isNaN(value)) value = 5;
if (value < $scope.min) {
value = $scope.min;
options.value = [value, options.max];
}
else if (value > $scope.max) {
value = $scope.max;
options.value = [options.min, value];
}
else {
options.value = [options.min, options.max];
}
}
}
else {
options.value = [options.min, options.max]; // This is needed, because of value defined at $.fn.slider.defaults - default value 5 prevents creating range slider
}
$scope.ngModel = options.value; // needed, otherwise turns value into [null, ##]
}
else {
setFloatOption('value', $scope.value, 5);
}
if (attrs.formatter) {
options.formatter = function(value) {
return $scope.formatter({value: value});
}
}
// check if slider jQuery plugin exists
if ('$' in window && $.fn.slider) {
// adding methods to jQuery slider plugin prototype
$.fn.slider.constructor.prototype.disable = function () {
this.picker.off();
};
$.fn.slider.constructor.prototype.enable = function () {
this.picker.on();
};
}
// destroy previous slider to reset all options
if (element[0].__slider)
element[0].__slider.destroy();
var slider = new Slider(element[0].getElementsByClassName('slider-input')[0], options);
element[0].__slider = slider;
// everything that needs slider element
var updateEvent = getArrayOrValue(attrs.updateevent);
if (angular.isString(updateEvent)) {
// if only single event name in string
updateEvent = [updateEvent];
}
else {
// default to slide event
updateEvent = ['slide'];
}
angular.forEach(updateEvent, function (sliderEvent) {
slider.on(sliderEvent, function (ev) {
ngModelCtrl.$setViewValue(ev);
});
});
slider.on('change', function (ev) {
ngModelCtrl.$setViewValue(ev.newValue);
});
// Event listeners
var sliderEvents = {
slideStart: 'onStartSlide',
slide: 'onSlide',
slideStop: 'onStopSlide'
};
angular.forEach(sliderEvents, function (sliderEventAttr, sliderEvent) {
var fn = $parse(attrs[sliderEventAttr]);
slider.on(sliderEvent, function (ev) {
if ($scope[sliderEventAttr]) {
$scope.$apply(function () {
fn($scope.$parent, { $event: ev, value: ev });
});
}
});
});
// deregister ngDisabled watcher to prevent memory leaks
if (angular.isFunction(ngDisabledDeregisterFn)) {
ngDisabledDeregisterFn();
ngDisabledDeregisterFn = null;
}
ngDisabledDeregisterFn = $scope.$watch('ngDisabled', function (value) {
if (value) {
slider.disable();
}
else {
slider.enable();
}
});
// deregister ngModel watcher to prevent memory leaks
if (angular.isFunction(ngModelDeregisterFn)) ngModelDeregisterFn();
ngModelDeregisterFn = $scope.$watch('ngModel', function (value) {
if($scope.range){
slider.setValue(value);
}else{
slider.setValue(parseFloat(value));
}
slider.relayout();
}, true);
return slider;
}
var watchers = ['min', 'max', 'step', 'range', 'scale', 'ticksLabels', 'ticks'];
angular.forEach(watchers, function (prop) {
$scope.$watch(prop, function () {
slider = initSlider();
});
});
var globalEvents = ['relayout', 'refresh', 'resize'];
angular.forEach(globalEvents, function(event) {
if(angular.isFunction(slider[event])) {
$scope.$on('slider:' + event, function () {
slider[event]();
});
}
});
}
};
}])
;
});
+1 -1
View File
@@ -23,7 +23,7 @@
height: 100%;
width: 100%;
text-align: center;
font-family: "Roboto","Helvetica Neue",Helvetica,Arial,sans-serif;
font-family: Roboto, Helvetica, Arial, sans-serif;
line-height: 1.846;
}
+1 -6
View File
@@ -15,11 +15,10 @@
<!-- CSS -->
<link type="text/css" rel="stylesheet" href="/3rdparty/slick.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/3rdparty/angular-ui-notification.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/3rdparty/bootstrap-slider/bootstrap-slider.min.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/theme.css?<%= revision %>">
<!-- Fontawesome -->
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.min.css?<%= revision %>"/>
<!-- jQuery-->
<script type="text/javascript" src="/3rdparty/js/jquery.min.js?<%= revision %>"></script>
@@ -73,10 +72,6 @@
<!-- Showdown (markdown converter) -->
<script type="text/javascript" src="/3rdparty/js/showdown-1.9.1.min.js?<%= revision %>"></script>
<!-- Bootstrap slider -->
<script type="text/javascript" src="/3rdparty/bootstrap-slider/bootstrap-slider.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/bootstrap-slider/slider.js?<%= revision %>"></script>
<!-- Anugular Multiselect https://github.com/sebastianha/angular-bootstrap-multiselect -->
<script type="text/javascript" src="/3rdparty/js/angular-bootstrap-multiselect.js?<%= revision %>"></script>
+1 -1
View File
@@ -2216,7 +2216,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
// amend properties to mimick full app
data.applinks.forEach(function (applink) {
applink.type = APP_TYPES.LINK;
applink.fqdn = new URL(applink.upstreamUri).hostname;
applink.fqdn = applink.upstreamUri;
applink.manifest = { addons: {}};
applink.installationState = ISTATES.INSTALLED;
applink.runState = RSTATES.RUNNING;
+1 -1
View File
@@ -19,7 +19,7 @@ if (search.accessToken) {
}
// create main application module
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'ngFitText', 'ngRoute', 'ngAnimate', 'ngSanitize', 'angular-md5', 'base64', 'slick', 'ui-notification', 'ui.bootstrap', 'ui.bootstrap-slider', 'ngTld', 'ui.multiselect']);
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'ngFitText', 'ngRoute', 'ngAnimate', 'ngSanitize', 'angular-md5', 'base64', 'slick', 'ui-notification', 'ui.bootstrap', 'ngTld', 'ui.multiselect']);
app.config(['NotificationProvider', function (NotificationProvider) {
NotificationProvider.setOptions({
+1 -1
View File
@@ -23,7 +23,7 @@
height: 100%;
width: 100%;
text-align: center;
font-family: "Roboto","Helvetica Neue",Helvetica,Arial,sans-serif;
font-family: Roboto, Helvetica, Arial, sans-serif;
font-size: 13px;
line-height: 1.846;
}
+1 -1
View File
@@ -15,7 +15,7 @@
<link type="text/css" rel="stylesheet" href="/theme.css?<%= revision %>">
<!-- Fontawesome -->
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.min.css?<%= revision %>"/>
<!-- jQuery-->
<script type="text/javascript" src="/3rdparty/js/jquery.min.js?<%= revision %>"></script>
+1 -1
View File
@@ -13,7 +13,7 @@
<link type="text/css" rel="stylesheet" href="/theme.css">
<!-- Fontawesome -->
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.min.css?<%= revision %>"/>
<!-- jQuery-->
<script type="text/javascript" src="/3rdparty/js/jquery.min.js"></script>
+1 -1
View File
@@ -13,7 +13,7 @@
<link type="text/css" rel="stylesheet" href="/theme.css">
<!-- Fontawesome -->
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.min.css?<%= revision %>"/>
<!-- jQuery-->
<script type="text/javascript" src="/3rdparty/js/jquery.min.js"></script>
+1 -1
View File
@@ -14,7 +14,7 @@
<link type="text/css" rel="stylesheet" href="/theme.css?<%= revision %>">
<!-- Fontawesome -->
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.min.css?<%= revision %>"/>
<!-- jQuery-->
<script type="text/javascript" src="/3rdparty/js/jquery.min.js?<%= revision %>"></script>
+1 -1
View File
@@ -13,7 +13,7 @@
<link type="text/css" rel="stylesheet" href="/theme.css">
<!-- Fontawesome -->
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.css?<%= revision %>"/>
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.min.css?<%= revision %>"/>
<!-- jQuery-->
<script type="text/javascript" src="/3rdparty/js/jquery.min.js"></script>
+14 -16
View File
@@ -995,12 +995,11 @@
<form role="form" name="resourcesForm" ng-submit="resources.submitMemoryLimit()" autocomplete="off">
<div class="form-group">
<label class="control-label" for="memoryLimit">{{ 'app.resources.memory.title' | tr }} <sup><a ng-href="https://docs.cloudron.io/apps/#memory-limit" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup> : <b>{{ resources.memoryLimit | prettyBinarySize:'Default (256 MiB)' }}</b></label>
<div style="padding: 0 10px;">
<slider id="memoryLimit" ng-model="resources.memoryLimit" step="134217728" tooltip="hide" ticks="resources.memoryTicks" ticks-snap-bounds="67108864"></slider>
</div>
<input type="range" id="memoryLimit" ng-model="resources.memoryLimit" step="134217728" min="{{ resources.memoryTicks[0] }}" max="{{ resources.memoryTicks[resources.memoryTicks.length-1] }}" list="memoryLimitTicks" />
<datalist id="memoryLimitTicks">
<option ng-repeat="limit in resources.memoryTicks" value="{{ limit }}"></option>
</datalist>
</div>
<input class="ng-hide" type="submit" ng-disabled="resources.memoryLimit === resources.currentMemoryLimit || resourcesForm.$invalid || resources.busy"/>
</form>
</div>
</div>
@@ -1009,9 +1008,7 @@
<span ng-show="resources.error.memoryLimit" class="text-danger">{{ 'app.resources.memory.error' | tr }}</span>
</div>
<div class="col-md-4 text-right">
<button class="btn btn-outline btn-primary pull-right" ng-click="resources.submitMemoryLimit()" ng-disabled="resources.memoryLimit === resources.currentMemoryLimit || resourcesForm.$invalid || resources.busy || app.error || app.taskId" tooltip-enable="app.error || app.taskId" uib-tooltip="{{ app.error ? 'App is in error state' : 'App is busy' }}">
<i class="fa fa-circle-notch fa-spin" ng-show="resources.busy"></i> {{ 'app.resources.memory.resizeAction' | tr }}
</button>
<button class="btn btn-outline btn-primary pull-right" ng-click="resources.submitMemoryLimit()" ng-disabled="resources.memoryLimit === resources.currentMemoryLimit || resourcesForm.$invalid || resources.busy || app.error || app.taskId" tooltip-enable="app.error || app.taskId" uib-tooltip="{{ app.error ? 'App is in error state' : 'App is busy' }}">{{ 'app.resources.memory.resizeAction' | tr }}</button>
</div>
</div>
<hr/>
@@ -1022,21 +1019,22 @@
<div class="form-group">
<label class="control-label" for="cpuShares">{{ 'app.resources.cpu.title' | tr }} <sup><a ng-href="https://docs.cloudron.io/apps/#cpu-shares" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup> : <b>{{ (resources.cpuShares * 100 / 1024 | number:0) + ' %' }}</b></label>
<p>{{ 'app.resources.cpu.description' | tr }}</p>
<div style="padding: 0 10px;">
<slider id="cpuShares" ng-model="resources.cpuShares" ticks="[32, 256, 512, 768, 1024]" step="32" ticks-snap-bounds="32" min="32" max="1024" tooltip="hide"></slider>
</div>
<input type="range" id="cpuShares" ng-model="resources.cpuShares" step="32" min="32" max="1024" list="cpuSharesTicks" />
<datalist id="cpuSharesTicks">
<option value="32"></option>
<option value="256"></option>
<option value="512"></option>
<option value="768"></option>
<option value="1024"></option>
</datalist>
</div>
<input class="ng-hide" type="submit" ng-disabled="resources.cpuShares === resources.currentCpuShares || resourcesForm.$invalid || resources.busyCpuShares"/>
</fieldset>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12 text-right">
<button class="btn btn-outline btn-primary pull-right" ng-click="resources.submitCpuShares()" ng-disabled="resources.cpuShares === resources.currentCpuShares || resourcesForm.$invalid || resources.busyCpuShares || app.error || app.taskId" tooltip-enable="app.error || app.taskId" uib-tooltip="{{ app.error ? 'App is in error state' : 'App is busy' }}">
<i class="fa fa-circle-notch fa-spin" ng-show="resources.busyCpuShares"></i> {{ 'app.resources.cpu.setAction' | tr }}
</button>
<button class="btn btn-outline btn-primary pull-right" ng-click="resources.submitCpuShares()" ng-disabled="resources.cpuShares === resources.currentCpuShares || resourcesForm.$invalid || resources.busy || app.error || app.taskId" tooltip-enable="app.error || app.taskId" uib-tooltip="{{ app.error ? 'App is in error state' : 'App is busy' }}">{{ 'app.resources.cpu.setAction' | tr }}</button>
</div>
</div>
</div>
+15 -8
View File
@@ -543,17 +543,15 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
memoryLimit: 0,
memoryTicks: [],
busyCpuShares: false,
currentCpuShares: 0,
cpuShares: 0,
show: function () {
var app = $scope.app;
$scope.resources.busy = true;
$scope.resources.error = {};
$scope.resources.currentMemoryLimit = app.memoryLimit || app.manifest.memoryLimit || (256 * 1024 * 1024);
$scope.resources.memoryLimit = $scope.resources.currentMemoryLimit;
$scope.resources.currentCpuShares = $scope.resources.cpuShares = app.cpuShares;
Client.getAppLimits(app.id, function (error, limits) {
if (error) return console.error(error);
@@ -569,14 +567,23 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
$scope.resources.memoryTicks.unshift(app.manifest.memoryLimit);
}
});
// for firefox widget update
$timeout(function() {
$scope.resources.currentCpuShares = $scope.resources.cpuShares = app.cpuShares;
$scope.resources.memoryLimit = $scope.resources.currentMemoryLimit;
$scope.resources.busy = false;
}, 500);
},
submitMemoryLimit: function () {
$scope.resources.busy = true;
$scope.resources.error = {};
var memoryLimit = $scope.resources.memoryLimit === $scope.resources.memoryTicks[0] ? 0 : $scope.resources.memoryLimit;
Client.configureApp($scope.app.id, 'memory_limit', { memoryLimit: memoryLimit }, function (error) {
const tmp = parseInt($scope.resources.memoryLimit);
const memoryLimit = tmp === $scope.resources.memoryTicks[0] ? 0 : tmp;
Client.configureApp($scope.app.id, 'memory_limit', { memoryLimit }, function (error) {
if (error && error.statusCode === 400) {
$scope.resources.busy = false;
$scope.resources.error.memoryLimit = true;
@@ -595,10 +602,10 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
},
submitCpuShares: function () {
$scope.resources.busyCpuShares = true;
$scope.resources.busy = true;
$scope.resources.error = {};
Client.configureApp($scope.app.id, 'cpu_shares', { cpuShares: $scope.resources.cpuShares }, function (error) {
Client.configureApp($scope.app.id, 'cpu_shares', { cpuShares: parseInt($scope.resources.cpuShares) }, function (error) {
if (error) return Client.error(error);
$scope.resources.currentCpuShares = $scope.resources.cpuShares;
@@ -606,7 +613,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
refreshApp($scope.app.id, function (error) {
if (error) return Client.error(error);
$timeout(function () { $scope.resources.busyCpuShares = false; }, 1000);
$timeout(function () { $scope.resources.busy = false; }, 1000);
});
});
},
+23 -23
View File
@@ -32,8 +32,10 @@
</div>
<br/>
<p class="text-muted">{{ 'backups.backupDetails.list' | tr:{ appCount: backupDetails.backup.contents.length } }}:</p>
<span ng-repeat="app in backupDetails.backup.contents | orderBy:['label','fqdn']">
<a ng-href="/#/app/{{app.id}}/backups">{{ app.label || app.fqdn }}</a><span ng-hide="$last">,</span>
<span ng-repeat="content in backupDetails.backup.contents | orderBy:['label','fqdn']">
<a ng-if="content.fqdn" ng-href="/#/app/{{content.id}}/backups">{{ content.label || content.fqdn }}</a>
<a ng-if="!content.fqdn" ng-href="/#/eventlog?search={{content.id}}">{{ content.id }}</a>
<span ng-hide="$last">,</span>
</span>
</div>
<div class="modal-footer">
@@ -388,48 +390,46 @@
</div>
<a href="" ng-click="configureBackup.advancedVisible = true" ng-hide="configureBackup.advancedVisible">{{ 'backups.configureBackupStorage.advancedSettings' | tr }}</a>
<div uib-collapse="!configureBackup.advancedVisible">
<div uib-collapse="!configureBackup.advancedVisible">
<div class="form-group">
<label class="control-label">{{ 'backups.configureBackupStorage.memoryLimit' | tr }}: <b>{{ configureBackup.memoryLimit | prettyBinarySize:'1024 MB' }}</b></label>
<label class="control-label" for="sliderConfigureBackupMemoryLimit">{{ 'backups.configureBackupStorage.memoryLimit' | tr }}: <b>{{ configureBackup.memoryLimit | prettyBinarySize:'1024 MB' }}</b></label>
<p class="small">{{ 'backups.configureBackupStorage.memoryLimitDescription' | tr }}</p>
<div style="padding: 0 10px;">
<slider id="sliderConfigureBackupMemoryLimit" ng-model="configureBackup.memoryLimit" tooltip="hide" step="268435456" ticks="configureBackup.memoryTicks"></slider>
</div>
<input type="range" id="sliderConfigureBackupMemoryLimit" ng-model="configureBackup.memoryLimit" step="{{ 256*1024*1024 }}" min="{{ MIN_MEMORY_LIMIT }}" max="{{ MAX_MEMORY_LIMIT }}" />
</div>
<div class="form-group" ng-show="s3like(configureBackup.provider)">
<label class="control-label">{{ 'backups.configureBackupStorage.uploadPartSize' | tr }}: <b>{{ configureBackup.uploadPartSize | prettyBinarySize:'Default (50 MiB)' }}</b></label>
<label class="control-label" for="sliderConfigureBackupUploadPartSize">{{ 'backups.configureBackupStorage.uploadPartSize' | tr }}: <b>{{ configureBackup.uploadPartSize | prettyBinarySize:'Default (50 MiB)' }}</b></label>
<p class="small">{{ 'backups.configureBackupStorage.uploadPartSizeDescription' | tr }}</p>
<div style="padding: 0 10px;">
<slider id="sliderConfigureBackupUploadPartSize" ng-model="configureBackup.uploadPartSize" step="1048576" tooltip="hide" ticks="configureBackup.uploadPartSizeTicks" ticks-snap-bounds="2097152"></slider>
</div>
<input type="range" id="sliderConfigureBackupUploadPartSize" ng-model="configureBackup.uploadPartSize" list="uploadPartSizeTicks" step="{{ 1024*1024 }}" min="{{ 1024*1024 }}" max="{{ 1024*1024*1024 }}" />
<datalist id="uploadPartSizeTicks">
<option value="{{ 1024*1024 }}"></option>
<option value="{{ 64*1024*1024 }}"></option>
<option value="{{ 128*1024*1024 }}"></option>
<option value="{{ 256*1024*1024 }}"></option>
<option value="{{ 512*1024*1024 }}"></option>
<option value="{{ 1024*1024*1024 }}"></option>
</datalist>
</div>
<div class="form-group" ng-show="configureBackup.format === 'rsync' && configureBackup.provider !== 'noop'">
<label class="control-label">{{ 'backups.configureBackupStorage.uploadConcurrency' | tr }}: <b>{{ configureBackup.syncConcurrency }}</b></label>
<label class="control-label" for="sliderConfigureBackupSyncConcurrency">{{ 'backups.configureBackupStorage.uploadConcurrency' | tr }}: <b>{{ configureBackup.syncConcurrency }}</b></label>
<p class="small">{{ 'backups.configureBackupStorage.uploadConcurrencyDescription' | tr }}</p>
<div style="padding: 0 10px;">
<slider id="sliderConfigureBackupSyncConcurrency" ng-model="configureBackup.syncConcurrency" tooltip="hide" min="10" max="200" step="10"></slider>
</div>
<input type="range" id="sliderConfigureBackupSyncConcurrency" ng-model="configureBackup.syncConcurrency" step="10" min="10" max="200" />
</div>
<div class="form-group" ng-show="configureBackup.format === 'rsync' && (s3like(configureBackup.provider) || configureBackup.provider === 'gcs')">
<label class="control-label">{{ 'backups.configureBackupStorage.downloadConcurrency' | tr }}: <b>{{ configureBackup.downloadConcurrency }}</b></label>
<label class="control-label" for="sliderConfigureBackupDownloadConcurrency">{{ 'backups.configureBackupStorage.downloadConcurrency' | tr }}: <b>{{ configureBackup.downloadConcurrency }}</b></label>
<p class="small">{{ 'backups.configureBackupStorage.downloadConcurrencyDescription' | tr }}</p>
<div style="padding: 0 10px;">
<slider id="sliderConfigureBackupCopyConcurrency" ng-model="configureBackup.downloadConcurrency" tooltip="hide" min="10" max="200" step="10"></slider>
</div>
<input type="range" id="sliderConfigureBackupDownloadConcurrency" ng-model="configureBackup.downloadConcurrency" step="10" min="10" max="200" />
</div>
<div class="form-group" ng-show="configureBackup.format === 'rsync' && (s3like(configureBackup.provider) || configureBackup.provider === 'gcs')">
<label class="control-label">{{ 'backups.configureBackupStorage.copyConcurrency' | tr }}: <b>{{ configureBackup.copyConcurrency }}</b></label>
<label class="control-label" for="sliderConfigureBackupCopyConcurrency">{{ 'backups.configureBackupStorage.copyConcurrency' | tr }}: <b>{{ configureBackup.copyConcurrency }}</b></label>
<p class="small">{{ 'backups.configureBackupStorage.copyConcurrencyDescription' | tr }}
<span ng-show="configureBackup.provider === 'digitalocean-spaces'">{{ 'backups.configureBackupStorage.copyConcurrencyDigitalOceanNote' | tr }}</span>
</p>
<div style="padding: 0 10px;">
<slider id="sliderConfigureBackupCopyConcurrency" ng-model="configureBackup.copyConcurrency" tooltip="hide" min="10" max="500" step="10"></slider>
</div>
<input type="range" id="sliderConfigureBackupCopyConcurrency" ng-model="configureBackup.copyConcurrency" step="10" min="10" max="500" />
</div>
</div> <!-- advanced -->
+25 -25
View File
@@ -8,6 +8,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
$scope.SECRET_PLACEHOLDER = SECRET_PLACEHOLDER;
$scope.MIN_MEMORY_LIMIT = 1024 * 1024 * 1024; // 1 GB
$scope.MAX_MEMORY_LIMIT = $scope.MIN_MEMORY_LIMIT; // set later
$scope.config = Client.getConfig();
$scope.user = Client.getUserInfo();
@@ -463,7 +464,6 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
memoryTicks: [],
memoryLimit: $scope.MIN_MEMORY_LIMIT,
uploadPartSizeTicks: [],
uploadPartSize: 50 * 1024 * 1024,
copyConcurrency: '',
downloadConcurrency: '',
@@ -540,25 +540,14 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
$scope.configureBackup.useHardlinks = !$scope.backupConfig.noHardlinks;
$scope.configureBackup.chown = $scope.backupConfig.chown;
var limits = $scope.backupConfig.limits || {};
$scope.configureBackup.memoryLimit = Math.max(limits.memoryLimit, $scope.MIN_MEMORY_LIMIT);
const limits = $scope.backupConfig.limits || {};
$scope.configureBackup.memoryLimit = Math.max(limits.memoryLimit, $scope.MIN_MEMORY_LIMIT);
$scope.configureBackup.uploadPartSize = limits.uploadPartSize || ($scope.configureBackup.provider === 'scaleway-objectstorage' ? 100 * 1024 * 1024 : 10 * 1024 * 1024);
$scope.configureBackup.downloadConcurrency = limits.downloadConcurrency || ($scope.backupConfig.provider === 's3' ? 30 : 10);
$scope.configureBackup.syncConcurrency = limits.syncConcurrency || ($scope.backupConfig.provider === 's3' ? 20 : 10);
$scope.configureBackup.copyConcurrency = limits.copyConcurrency || ($scope.backupConfig.provider === 's3' ? 500 : 10);
var totalMemory = Math.max(($scope.memory.memory + $scope.memory.swap) * 1.5, 2 * 1024 * 1024);
$scope.configureBackup.memoryTicks = [ $scope.MIN_MEMORY_LIMIT ];
for (var i = 1024; i <= totalMemory/1024/1024; i *= 2) {
$scope.configureBackup.memoryTicks.push(i * 1024 * 1024);
}
$scope.configureBackup.uploadPartSizeTicks = [ 5 * 1024 * 1024 ];
for (var j = 32; j <= 1 * 1024; j *= 2) { // 5 GB is max for s3. but let's keep things practical for now. we upload 3 parts in parallel
$scope.configureBackup.uploadPartSizeTicks.push(j * 1024 * 1024);
}
var mountOptions = $scope.backupConfig.mountOptions || {};
$scope.configureBackup.mountOptions = {
host: mountOptions.host || '',
@@ -607,7 +596,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
schedulePattern: $scope.backupConfig.schedulePattern,
retentionPolicy: $scope.backupConfig.retentionPolicy,
limits: {
memoryLimit: $scope.configureBackup.memoryLimit,
memoryLimit: parseInt($scope.configureBackup.memoryLimit),
},
};
if ($scope.configureBackup.password) {
@@ -713,12 +702,12 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
backupConfig.noHardlinks = !$scope.configureBackup.useHardlinks;
}
backupConfig.limits.uploadPartSize = $scope.configureBackup.uploadPartSize;
backupConfig.limits.uploadPartSize = parseInt($scope.configureBackup.uploadPartSize);
if (backupConfig.format === 'rsync') {
backupConfig.limits.downloadConcurrency = $scope.configureBackup.downloadConcurrency;
backupConfig.limits.syncConcurrency = $scope.configureBackup.syncConcurrency;
backupConfig.limits.copyConcurrency = $scope.configureBackup.copyConcurrency;
backupConfig.limits.downloadConcurrency = parseInt($scope.configureBackup.downloadConcurrency);
backupConfig.limits.syncConcurrency = parseInt($scope.configureBackup.syncConcurrency);
backupConfig.limits.copyConcurrency = parseInt($scope.configureBackup.copyConcurrency);
}
Client.setBackupConfig(backupConfig, function (error) {
@@ -794,14 +783,23 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
});
$scope.backups.forEach(function (backup) {
backup.contents = [];
backup.contents = []; // { id, label, fqdn }
backup.dependsOn.forEach(function (appBackupId) {
let match = appBackupId.match(/app_(.*?)_.*/); // *? means non-greedy
if (!match) return;
if (match[1].indexOf('.') !== -1) { // newer backups have fqdn in them
if (appsByFqdn[match[1]]) backup.contents.push(appsByFqdn[match[1]]);
if (!match) return; // for example, 'mail'
const app = appsById[match[1]];
if (app) {
backup.contents.push({
id: app.id,
label: app.label,
fqdn: app.fqdn
});
} else {
if (appsById[match[1]]) backup.contents.push(appsById[match[1]]);
backup.contents.push({
id: match[1],
label: null,
fqdn: null
});
}
});
});
@@ -850,6 +848,8 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
if (error) console.error(error);
$scope.memory = memory;
const limit = Math.max((memory.memory + memory.swap) * 1.5, 2 * 1024 * 1024);
$scope.MAX_MEMORY_LIMIT = parseInt(limit/1024/1024/1024) * 1024 * 1024 * 1024; // round to value matching 250mb steps
fetchBackups();
getBackupConfig();
@@ -887,7 +887,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
// setup all the dialog focus handling
['configureBackupModal', 'editBackupModal'].forEach(function (id) {
$('#' + id).on('shown.bs.modal', function () {
$(this).find("[autofocus]:first").focus();
$(this).find('[autofocus]:first').focus();
});
});
+4 -3
View File
@@ -157,9 +157,10 @@
{{ 'email.editMailboxDialog.enableStorageQuota' | tr }} <b ng-hide="!mailboxes.edit.storageQuotaEnabled">: {{ mailboxes.edit.storageQuota | prettyDecimalSize }}</b>
</input>
</label>
<div style="padding: 0 10px;">
<slider id="storageQuota" ng-disabled="!mailboxes.edit.storageQuotaEnabled" ng-model="mailboxes.edit.storageQuota" step="500000000" ticks-snap-bounds="1000000000" tooltip="hide" ticks="storageQuotaTicks"></slider>
</div>
<input type="range" id="storageQuota" ng-disabled="!mailboxes.edit.storageQuotaEnabled" ng-model="mailboxes.edit.storageQuota" step="500000000" min="{{ storageQuotaTicks[0] }}" max="{{ storageQuotaTicks[storageQuotaTicks.length-1] }}" list="storageQuotaTicks" />
<datalist id="storageQuotaTicks">
<option ng-repeat="quota in storageQuotaTicks" value="{{ quota }}"></option>
</datalist>
</div>
<div class="checkbox">
+2 -2
View File
@@ -42,7 +42,7 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
$scope.domain = null;
$scope.adminDomain = null;
$scope.mailUsage = null;
$scope.storageQuotaTicks = [ 500*1000*1000, 1*1000*1000*1000, 15*1000*1000*1000, 50*1000*1000*1000, 100*1000*1000*1000 ];
$scope.storageQuotaTicks = [ 500*1000*1000, 5*1000*1000*1000, 15*1000*1000*1000, 50*1000*1000*1000, 100*1000*1000*1000 ];
$scope.expectedDnsRecords = {
mx: { },
@@ -639,7 +639,7 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
ownerType: $scope.mailboxes.edit.owner.type,
active: $scope.mailboxes.edit.active,
enablePop3: $scope.mailboxes.edit.enablePop3,
storageQuota: $scope.mailboxes.edit.storageQuotaEnabled ? $scope.mailboxes.edit.storageQuota : 0,
storageQuota: $scope.mailboxes.edit.storageQuotaEnabled ? parseInt($scope.mailboxes.edit.storageQuota) : 0,
messagesQuota: 0
};
+2 -2
View File
@@ -10,8 +10,8 @@
<br>
<form name="maxEmailSizeChangeForm" role="form" novalidate ng-submit="maxEmailSize.submit()" autocomplete="off">
<div class="form-group">
<label class="control-label">{{ 'emails.changeMailSizeDialog.size' | tr }} <b>{{ maxEmailSize.size | prettyDecimalSize }}</b></label>
<slider ng-model="maxEmailSize.size" tooltip="hide" min="1000000" max="1000000000" step="1000000"></slider>
<label class="control-label" for="maxEmailSizeInput">{{ 'emails.changeMailSizeDialog.size' | tr }} <b>{{ maxEmailSize.size | prettyDecimalSize }}</b></label>
<input type="range" id="maxEmailSizeInput" ng-model="maxEmailSize.size" step="1000000" min="1000000" max="1000000000" />
</div>
<input class="ng-hide" type="submit"/>
</form>
+1 -1
View File
@@ -121,7 +121,7 @@ angular.module('Application').controller('EmailsController', ['$scope', '$locati
submit: function () {
$scope.maxEmailSize.busy = true;
Client.setMaxEmailSize($scope.maxEmailSize.size, function (error) {
Client.setMaxEmailSize(parseInt($scope.maxEmailSize.size), function (error) {
$scope.maxEmailSize.busy = false;
if (error) return console.error(error);
+1
View File
@@ -142,6 +142,7 @@ angular.module('Application').controller('EventLogController', ['$scope', '$loca
};
Client.onReady(function () {
$scope.search = $location.search().search || ''; // sent from the backups view when app is deleted
fetchEventLogs();
});
+4 -1
View File
@@ -16,7 +16,10 @@
<button type="button" class="btn btn-xs btn-default pull-right" ng-click="serviceConfigure.resetToDefaults()">{{ 'services.configure.resetToDefaults' | tr }}</button>
</label>
<div style="padding: 0 10px;">
<slider id="memoryLimit" ng-model="serviceConfigure.memoryLimit" step="134217728" tooltip="hide" ticks="serviceConfigure.memoryTicks" ticks-snap-bounds="67108864"></slider>
<input type="range" id="memoryLimit" ng-model="serviceConfigure.memoryLimit" step="134217728" min="{{ serviceConfigure.memoryTicks[0] }}" max="{{ serviceConfigure.memoryTicks[serviceConfigure.memoryTicks.length-1] }}" list="memoryLimitTicks" />
<datalist id="memoryLimitTicks">
<option ng-repeat="limit in serviceConfigure.memoryTicks" value="{{ limit }}"></option>
</datalist>
</div>
</div>
+6 -2
View File
@@ -75,7 +75,6 @@ angular.module('Application').controller('ServicesController', ['$scope', '$loca
$scope.serviceConfigure.reset();
$scope.serviceConfigure.service = service;
$scope.serviceConfigure.memoryLimit = service.config.memoryLimit;
$scope.serviceConfigure.recoveryMode = !!service.config.recoveryMode;
$scope.serviceConfigure.memoryTicks = [];
@@ -88,6 +87,11 @@ angular.module('Application').controller('ServicesController', ['$scope', '$loca
$scope.serviceConfigure.memoryTicks.push(i * 1024 * 1024);
}
// for firefox widget update
$timeout(function() {
$scope.serviceConfigure.memoryLimit = service.config.memoryLimit;
}, 500);
$('#serviceConfigureModal').modal('show');
},
@@ -96,7 +100,7 @@ angular.module('Application').controller('ServicesController', ['$scope', '$loca
$scope.serviceConfigure.error = null;
var data = {
memoryLimit: $scope.serviceConfigure.memoryLimit,
memoryLimit: parseInt($scope.serviceConfigure.memoryLimit),
recoveryMode: $scope.serviceConfigure.recoveryMode
};
+246 -196
View File
@@ -8,26 +8,26 @@
"name": "my-vue-app",
"version": "0.0.0",
"dependencies": {
"@fontsource/noto-sans": "^5.0.19",
"@fontsource/noto-sans": "^5.0.21",
"@xterm/addon-attach": "^0.10.0",
"@xterm/addon-fit": "^0.9.0",
"@xterm/xterm": "^5.4.0",
"anser": "^2.1.1",
"combokeys": "^3.0.1",
"filesize": "^10.1.0",
"filesize": "^10.1.1",
"marked": "^12.0.1",
"moment": "^2.30.1",
"pankow": "^1.2.1",
"pankow": "^1.3.1",
"primeicons": "^6.0.1",
"primevue": "^3.49.1",
"primevue": "^3.50.0",
"superagent": "^8.1.2",
"vue": "^3.4.21",
"vue-i18n": "^9.10.1",
"vue-i18n": "^9.10.2",
"vue-router": "^4.3.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"vite": "^5.1.5"
"vite": "^5.2.6"
}
},
"node_modules/@babel/parser": {
@@ -41,10 +41,26 @@
"node": ">=6.0.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
"integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.7.tgz",
"integrity": "sha512-YGSPnndkcLo4PmVl2tKatEn+0mlVMr3yEpOOT0BeMria87PhvoJb5dg5f5Ft9fbCVgtAz4pWMzZVgSEGpDAlww==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
"integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
"cpu": [
"arm"
],
@@ -58,9 +74,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.7.tgz",
"integrity": "sha512-YEDcw5IT7hW3sFKZBkCAQaOCJQLONVcD4bOyTXMZz5fr66pTHnAet46XAtbXAkJRfIn2YVhdC6R9g4xa27jQ1w==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
"integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
"cpu": [
"arm64"
],
@@ -74,9 +90,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.7.tgz",
"integrity": "sha512-jhINx8DEjz68cChFvM72YzrqfwJuFbfvSxZAk4bebpngGfNNRm+zRl4rtT9oAX6N9b6gBcFaJHFew5Blf6CvUw==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
"integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
"cpu": [
"x64"
],
@@ -90,9 +106,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.7.tgz",
"integrity": "sha512-dr81gbmWN//3ZnBIm6YNCl4p3pjnabg1/ZVOgz2fJoUO1a3mq9WQ/1iuEluMs7mCL+Zwv7AY5e3g1hjXqQZ9Iw==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
"integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
"cpu": [
"arm64"
],
@@ -106,9 +122,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.7.tgz",
"integrity": "sha512-Lc0q5HouGlzQEwLkgEKnWcSazqr9l9OdV2HhVasWJzLKeOt0PLhHaUHuzb8s/UIya38DJDoUm74GToZ6Wc7NGQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
"integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
"cpu": [
"x64"
],
@@ -122,9 +138,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.7.tgz",
"integrity": "sha512-+y2YsUr0CxDFF7GWiegWjGtTUF6gac2zFasfFkRJPkMAuMy9O7+2EH550VlqVdpEEchWMynkdhC9ZjtnMiHImQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
"integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
"cpu": [
"arm64"
],
@@ -138,9 +154,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.7.tgz",
"integrity": "sha512-CdXOxIbIzPJmJhrpmJTLx+o35NoiKBIgOvmvT+jeSadYiWJn0vFKsl+0bSG/5lwjNHoIDEyMYc/GAPR9jxusTA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
"integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
"cpu": [
"x64"
],
@@ -154,9 +170,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.7.tgz",
"integrity": "sha512-Y+SCmWxsJOdQtjcBxoacn/pGW9HDZpwsoof0ttL+2vGcHokFlfqV666JpfLCSP2xLxFpF1lj7T3Ox3sr95YXww==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
"integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
"cpu": [
"arm"
],
@@ -170,9 +186,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.7.tgz",
"integrity": "sha512-inHqdOVCkUhHNvuQPT1oCB7cWz9qQ/Cz46xmVe0b7UXcuIJU3166aqSunsqkgSGMtUCWOZw3+KMwI6otINuC9g==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
"integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
"cpu": [
"arm64"
],
@@ -186,9 +202,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.7.tgz",
"integrity": "sha512-2BbiL7nLS5ZO96bxTQkdO0euGZIUQEUXMTrqLxKUmk/Y5pmrWU84f+CMJpM8+EHaBPfFSPnomEaQiG/+Gmh61g==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
"integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
"cpu": [
"ia32"
],
@@ -202,9 +218,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.7.tgz",
"integrity": "sha512-BVFQla72KXv3yyTFCQXF7MORvpTo4uTA8FVFgmwVrqbB/4DsBFWilUm1i2Oq6zN36DOZKSVUTb16jbjedhfSHw==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
"integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
"cpu": [
"loong64"
],
@@ -218,9 +234,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.7.tgz",
"integrity": "sha512-DzAYckIaK+pS31Q/rGpvUKu7M+5/t+jI+cdleDgUwbU7KdG2eC3SUbZHlo6Q4P1CfVKZ1lUERRFP8+q0ob9i2w==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
"integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
"cpu": [
"mips64el"
],
@@ -234,9 +250,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.7.tgz",
"integrity": "sha512-JQ1p0SmUteNdUaaiRtyS59GkkfTW0Edo+e0O2sihnY4FoZLz5glpWUQEKMSzMhA430ctkylkS7+vn8ziuhUugQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
"integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
"cpu": [
"ppc64"
],
@@ -250,9 +266,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.7.tgz",
"integrity": "sha512-xGwVJ7eGhkprY/nB7L7MXysHduqjpzUl40+XoYDGC4UPLbnG+gsyS1wQPJ9lFPcxYAaDXbdRXd1ACs9AE9lxuw==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
"integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
"cpu": [
"riscv64"
],
@@ -266,9 +282,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.7.tgz",
"integrity": "sha512-U8Rhki5PVU0L0nvk+E8FjkV8r4Lh4hVEb9duR6Zl21eIEYEwXz8RScj4LZWA2i3V70V4UHVgiqMpszXvG0Yqhg==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
"integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
"cpu": [
"s390x"
],
@@ -282,9 +298,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.7.tgz",
"integrity": "sha512-ZYZopyLhm4mcoZXjFt25itRlocKlcazDVkB4AhioiL9hOWhDldU9n38g62fhOI4Pth6vp+Mrd5rFKxD0/S+7aQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
"integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
"cpu": [
"x64"
],
@@ -298,9 +314,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.7.tgz",
"integrity": "sha512-/yfjlsYmT1O3cum3J6cmGG16Fd5tqKMcg5D+sBYLaOQExheAJhqr8xOAEIuLo8JYkevmjM5zFD9rVs3VBcsjtQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
"integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
"cpu": [
"x64"
],
@@ -314,9 +330,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.7.tgz",
"integrity": "sha512-MYDFyV0EW1cTP46IgUJ38OnEY5TaXxjoDmwiTXPjezahQgZd+j3T55Ht8/Q9YXBM0+T9HJygrSRGV5QNF/YVDQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
"integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
"cpu": [
"x64"
],
@@ -330,9 +346,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.7.tgz",
"integrity": "sha512-JcPvgzf2NN/y6X3UUSqP6jSS06V0DZAV/8q0PjsZyGSXsIGcG110XsdmuWiHM+pno7/mJF6fjH5/vhUz/vA9fw==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
"integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
"cpu": [
"x64"
],
@@ -346,9 +362,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.7.tgz",
"integrity": "sha512-ZA0KSYti5w5toax5FpmfcAgu3ZNJxYSRm0AW/Dao5up0YV1hDVof1NvwLomjEN+3/GMtaWDI+CIyJOMTRSTdMw==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
"integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
"cpu": [
"arm64"
],
@@ -362,9 +378,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.7.tgz",
"integrity": "sha512-CTOnijBKc5Jpk6/W9hQMMvJnsSYRYgveN6O75DTACCY18RA2nqka8dTZR+x/JqXCRiKk84+5+bRKXUSbbwsS0A==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
"integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
"cpu": [
"ia32"
],
@@ -378,9 +394,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.7.tgz",
"integrity": "sha512-gRaP2sk6hc98N734luX4VpF318l3w+ofrtTu9j5L8EQXF+FzQKV6alCOHMVoJJHvVK/mGbwBXfOL1HETQu9IGQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
"integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
"cpu": [
"x64"
],
@@ -394,17 +410,26 @@
}
},
"node_modules/@fontsource/noto-sans": {
"version": "5.0.19",
"resolved": "https://registry.npmjs.org/@fontsource/noto-sans/-/noto-sans-5.0.19.tgz",
"integrity": "sha512-5PmyWnplHmjuUwkaSpOljOcZ2GrdV4H2fDQS/OpmcgpgvgRM+8YYAoEI4xOlXb15kwWy/nHAFQYw3EYu7gPeng=="
"version": "5.0.21",
"resolved": "https://registry.npmjs.org/@fontsource/noto-sans/-/noto-sans-5.0.21.tgz",
"integrity": "sha512-1rIZsv6nObjg0rNY0EBBTta5lujmQ1agKn6HN5rY3L2pVvHJqK5n/cNO2HTqfqK837f9PEE/yowVm9mjniDhuw=="
},
"node_modules/@fortawesome/fontawesome-free": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.5.1.tgz",
"integrity": "sha512-CNy5vSwN3fsUStPRLX7fUYojyuzoEMSXPl7zSLJ8TgtRfjv24LOnOWKT2zYwaHZCJGkdyRnTmstR0P+Ah503Gw==",
"hasInstallScript": true,
"engines": {
"node": ">=6"
}
},
"node_modules/@intlify/core-base": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.10.1.tgz",
"integrity": "sha512-0+Wtjj04GIyglh5KKiNjRwgjpHrhqqGZhaKY/QVjjogWKZq5WHROrTi84pNVsRN18QynyPmjtsVUWqFKPQ45xQ==",
"version": "9.10.2",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.10.2.tgz",
"integrity": "sha512-HGStVnKobsJL0DoYIyRCGXBH63DMQqEZxDUGrkNI05FuTcruYUtOAxyL3zoAZu/uDGO6mcUvm3VXBaHG2GdZCg==",
"dependencies": {
"@intlify/message-compiler": "9.10.1",
"@intlify/shared": "9.10.1"
"@intlify/message-compiler": "9.10.2",
"@intlify/shared": "9.10.2"
},
"engines": {
"node": ">= 16"
@@ -414,11 +439,11 @@
}
},
"node_modules/@intlify/message-compiler": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.10.1.tgz",
"integrity": "sha512-b68UTmRhgZfswJZI7VAgW6BXZK5JOpoi5swMLGr4j6ss2XbFY13kiw+Hu+xYAfulMPSapcHzdWHnq21VGnMCnA==",
"version": "9.10.2",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.10.2.tgz",
"integrity": "sha512-ntY/kfBwQRtX5Zh6wL8cSATujPzWW2ZQd1QwKyWwAy5fMqJyyixHMeovN4fmEyCqSu+hFfYOE63nU94evsy4YA==",
"dependencies": {
"@intlify/shared": "9.10.1",
"@intlify/shared": "9.10.2",
"source-map-js": "^1.0.2"
},
"engines": {
@@ -429,9 +454,9 @@
}
},
"node_modules/@intlify/shared": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.10.1.tgz",
"integrity": "sha512-liyH3UMoglHBUn70iCYcy9CQlInx/lp50W2aeSxqqrvmG+LDj/Jj7tBJhBoQL4fECkldGhbmW0g2ommHfL6Wmw==",
"version": "9.10.2",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.10.2.tgz",
"integrity": "sha512-ttHCAJkRy7R5W2S9RVnN9KYQYPIpV2+GiS79T4EE37nrPyH6/1SrOh3bmdCRC1T3ocL8qCDx7x2lBJ0xaITU7Q==",
"engines": {
"node": ">= 16"
},
@@ -465,9 +490,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.5.0.tgz",
"integrity": "sha512-OINaBGY+Wc++U0rdr7BLuFClxcoWaVW3vQYqmQq6B3bqQ/2olkaoz+K8+af/Mmka/C2yN5j+L9scBkv4BtKsDA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
"integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==",
"cpu": [
"arm"
],
@@ -478,9 +503,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.5.0.tgz",
"integrity": "sha512-UdMf1pOQc4ZmUA/NTmKhgJTBimbSKnhPS2zJqucqFyBRFPnPDtwA8MzrGNTjDeQbIAWfpJVAlxejw+/lQyBK/w==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz",
"integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==",
"cpu": [
"arm64"
],
@@ -491,9 +516,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.5.0.tgz",
"integrity": "sha512-L0/CA5p/idVKI+c9PcAPGorH6CwXn6+J0Ys7Gg1axCbTPgI8MeMlhA6fLM9fK+ssFhqogMHFC8HDvZuetOii7w==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz",
"integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==",
"cpu": [
"arm64"
],
@@ -504,9 +529,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.5.0.tgz",
"integrity": "sha512-QZCbVqU26mNlLn8zi/XDDquNmvcr4ON5FYAHQQsyhrHx8q+sQi/6xduoznYXwk/KmKIXG5dLfR0CvY+NAWpFYQ==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz",
"integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==",
"cpu": [
"x64"
],
@@ -517,9 +542,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.5.0.tgz",
"integrity": "sha512-VpSQ+xm93AeV33QbYslgf44wc5eJGYfYitlQzAi3OObu9iwrGXEnmu5S3ilkqE3Pr/FkgOiJKV/2p0ewf4Hrtg==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz",
"integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==",
"cpu": [
"arm"
],
@@ -530,9 +555,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.5.0.tgz",
"integrity": "sha512-OrEyIfpxSsMal44JpEVx9AEcGpdBQG1ZuWISAanaQTSMeStBW+oHWwOkoqR54bw3x8heP8gBOyoJiGg+fLY8qQ==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz",
"integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==",
"cpu": [
"arm64"
],
@@ -543,9 +568,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.5.0.tgz",
"integrity": "sha512-1H7wBbQuE6igQdxMSTjtFfD+DGAudcYWhp106z/9zBA8OQhsJRnemO4XGavdzHpGhRtRxbgmUGdO3YQgrWf2RA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz",
"integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==",
"cpu": [
"arm64"
],
@@ -555,10 +580,23 @@
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz",
"integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.5.0.tgz",
"integrity": "sha512-FVyFI13tXw5aE65sZdBpNjPVIi4Q5mARnL/39UIkxvSgRAIqCo5sCpCELk0JtXHGee2owZz5aNLbWNfBHzr71Q==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz",
"integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==",
"cpu": [
"x64"
],
@@ -569,9 +607,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.5.0.tgz",
"integrity": "sha512-eBPYl2sLpH/o8qbSz6vPwWlDyThnQjJfcDOGFbNjmjb44XKC1F5dQfakOsADRVrXCNzM6ZsSIPDG5dc6HHLNFg==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz",
"integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==",
"cpu": [
"x64"
],
@@ -582,9 +620,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.5.0.tgz",
"integrity": "sha512-xaOHIfLOZypoQ5U2I6rEaugS4IYtTgP030xzvrBf5js7p9WI9wik07iHmsKaej8Z83ZDxN5GyypfoyKV5O5TJA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz",
"integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==",
"cpu": [
"arm64"
],
@@ -595,9 +633,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.5.0.tgz",
"integrity": "sha512-Al6quztQUrHwcOoU2TuFblUQ5L+/AmPBXFR6dUvyo4nRj2yQRK0WIUaGMF/uwKulvRcXkpHe3k9A8Vf93VDktA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz",
"integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==",
"cpu": [
"ia32"
],
@@ -608,9 +646,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.5.0.tgz",
"integrity": "sha512-8kdW+brNhI/NzJ4fxDufuJUjepzINqJKLGHuxyAtpPG9bMbn8P5mtaCcbOm0EzLJ+atg+kF9dwg8jpclkVqx5w==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz",
"integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==",
"cpu": [
"x64"
],
@@ -620,6 +658,12 @@
"win32"
]
},
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"dev": true
},
"node_modules/@types/node": {
"version": "18.14.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.2.tgz",
@@ -1000,9 +1044,9 @@
}
},
"node_modules/esbuild": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.7.tgz",
"integrity": "sha512-6brbTZVqxhqgbpqBR5MzErImcpA0SQdoKOkcWK/U30HtQxnokIpG3TX2r0IJqbFUzqLjhU/zC1S5ndgakObVCQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
"integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
"dev": true,
"hasInstallScript": true,
"bin": {
@@ -1012,28 +1056,29 @@
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.19.7",
"@esbuild/android-arm64": "0.19.7",
"@esbuild/android-x64": "0.19.7",
"@esbuild/darwin-arm64": "0.19.7",
"@esbuild/darwin-x64": "0.19.7",
"@esbuild/freebsd-arm64": "0.19.7",
"@esbuild/freebsd-x64": "0.19.7",
"@esbuild/linux-arm": "0.19.7",
"@esbuild/linux-arm64": "0.19.7",
"@esbuild/linux-ia32": "0.19.7",
"@esbuild/linux-loong64": "0.19.7",
"@esbuild/linux-mips64el": "0.19.7",
"@esbuild/linux-ppc64": "0.19.7",
"@esbuild/linux-riscv64": "0.19.7",
"@esbuild/linux-s390x": "0.19.7",
"@esbuild/linux-x64": "0.19.7",
"@esbuild/netbsd-x64": "0.19.7",
"@esbuild/openbsd-x64": "0.19.7",
"@esbuild/sunos-x64": "0.19.7",
"@esbuild/win32-arm64": "0.19.7",
"@esbuild/win32-ia32": "0.19.7",
"@esbuild/win32-x64": "0.19.7"
"@esbuild/aix-ppc64": "0.20.2",
"@esbuild/android-arm": "0.20.2",
"@esbuild/android-arm64": "0.20.2",
"@esbuild/android-x64": "0.20.2",
"@esbuild/darwin-arm64": "0.20.2",
"@esbuild/darwin-x64": "0.20.2",
"@esbuild/freebsd-arm64": "0.20.2",
"@esbuild/freebsd-x64": "0.20.2",
"@esbuild/linux-arm": "0.20.2",
"@esbuild/linux-arm64": "0.20.2",
"@esbuild/linux-ia32": "0.20.2",
"@esbuild/linux-loong64": "0.20.2",
"@esbuild/linux-mips64el": "0.20.2",
"@esbuild/linux-ppc64": "0.20.2",
"@esbuild/linux-riscv64": "0.20.2",
"@esbuild/linux-s390x": "0.20.2",
"@esbuild/linux-x64": "0.20.2",
"@esbuild/netbsd-x64": "0.20.2",
"@esbuild/openbsd-x64": "0.20.2",
"@esbuild/sunos-x64": "0.20.2",
"@esbuild/win32-arm64": "0.20.2",
"@esbuild/win32-ia32": "0.20.2",
"@esbuild/win32-x64": "0.20.2"
}
},
"node_modules/estree-walker": {
@@ -1047,9 +1092,9 @@
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
},
"node_modules/filesize": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.0.tgz",
"integrity": "sha512-GTLKYyBSDz3nPhlLVPjPWZCnhkd9TrrRArNcy8Z+J2cqScB7h2McAzR6NBX6nYOoWafql0roY8hrocxnZBv9CQ==",
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.1.tgz",
"integrity": "sha512-L0cdwZrKlwZQkMSFnCflJ6J2Y+5egO/p3vgRSDQGxQt++QbUZe5gMbRO6kg6gzwQDPvq2Fk9AmoxUNfZ5gdqaQ==",
"engines": {
"node": ">= 10.4.0"
}
@@ -1443,9 +1488,9 @@
}
},
"node_modules/monaco-editor": {
"version": "0.46.0",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.46.0.tgz",
"integrity": "sha512-ADwtLIIww+9FKybWscd7OCfm9odsFYHImBRI1v9AviGce55QY8raT+9ihH8jX/E/e6QVSGM+pKj4jSUSRmALNQ=="
"version": "0.47.0",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.47.0.tgz",
"integrity": "sha512-VabVvHvQ9QmMwXu4du008ZDuyLnHs9j7ThVFsiJoXSOQk18+LF89N4ADzPbFenm0W4V2bGHnFBztIRQTgBfxzw=="
},
"node_modules/ms": {
"version": "2.1.2",
@@ -1548,14 +1593,15 @@
}
},
"node_modules/pankow": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/pankow/-/pankow-1.2.1.tgz",
"integrity": "sha512-tlPxzyAOVCV40k3yLCJltqde30/mcCMfn80zWU5f/4t4oTgdPwL/e9vkv7lAxdNpJx3tkfu/UIvDzAnZP7h/Ig==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/pankow/-/pankow-1.3.1.tgz",
"integrity": "sha512-+HYBLx7UVBE8FJlkT27V/MUxf61FW1uqKB6F/m7PKPpJKgOYYafoUIAeUMQUGsAZhaf113P5quF1mHGPmpHkzQ==",
"dependencies": {
"filesize": "^10.1.0",
"monaco-editor": "^0.46.0",
"@fortawesome/fontawesome-free": "^6.5.1",
"filesize": "^10.1.1",
"monaco-editor": "^0.47.0",
"pdfjs-dist": "^3.11.174",
"primevue": "^3.49.1",
"primevue": "^3.50.0",
"superagent": "^8.1.2"
}
},
@@ -1595,9 +1641,9 @@
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/postcss": {
"version": "8.4.35",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
"integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
"version": "8.4.38",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
"integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
"funding": [
{
"type": "opencollective",
@@ -1615,7 +1661,7 @@
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
"source-map-js": "^1.2.0"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -1627,9 +1673,9 @@
"integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA=="
},
"node_modules/primevue": {
"version": "3.49.1",
"resolved": "https://registry.npmjs.org/primevue/-/primevue-3.49.1.tgz",
"integrity": "sha512-OmUTqbKbPB63Zqf7uA49cipDi+Qh+/13AYJPwgvsVsI4QmAKIkeibBwkOgj1CNIFlopfF79YmyBshFUAPqlw9A==",
"version": "3.50.0",
"resolved": "https://registry.npmjs.org/primevue/-/primevue-3.50.0.tgz",
"integrity": "sha512-vYpQzvIXSmF0hWUkviHEGnwbFY/G8jI2RSxoa75noJloI2rWhzOX+JarJ8iaesVOr7b2se31N/p7zOx6uh3ddQ==",
"peerDependencies": {
"vue": "^3.0.0"
}
@@ -1678,10 +1724,13 @@
}
},
"node_modules/rollup": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.5.0.tgz",
"integrity": "sha512-41xsWhzxqjMDASCxH5ibw1mXk+3c4TNI2UjKbLxe6iEzrSQnqOzmmK8/3mufCPbzHNJ2e04Fc1ddI35hHy+8zg==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
"integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.5"
},
"bin": {
"rollup": "dist/bin/rollup"
},
@@ -1690,18 +1739,19 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.5.0",
"@rollup/rollup-android-arm64": "4.5.0",
"@rollup/rollup-darwin-arm64": "4.5.0",
"@rollup/rollup-darwin-x64": "4.5.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.5.0",
"@rollup/rollup-linux-arm64-gnu": "4.5.0",
"@rollup/rollup-linux-arm64-musl": "4.5.0",
"@rollup/rollup-linux-x64-gnu": "4.5.0",
"@rollup/rollup-linux-x64-musl": "4.5.0",
"@rollup/rollup-win32-arm64-msvc": "4.5.0",
"@rollup/rollup-win32-ia32-msvc": "4.5.0",
"@rollup/rollup-win32-x64-msvc": "4.5.0",
"@rollup/rollup-android-arm-eabi": "4.13.0",
"@rollup/rollup-android-arm64": "4.13.0",
"@rollup/rollup-darwin-arm64": "4.13.0",
"@rollup/rollup-darwin-x64": "4.13.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.13.0",
"@rollup/rollup-linux-arm64-gnu": "4.13.0",
"@rollup/rollup-linux-arm64-musl": "4.13.0",
"@rollup/rollup-linux-riscv64-gnu": "4.13.0",
"@rollup/rollup-linux-x64-gnu": "4.13.0",
"@rollup/rollup-linux-x64-musl": "4.13.0",
"@rollup/rollup-win32-arm64-msvc": "4.13.0",
"@rollup/rollup-win32-ia32-msvc": "4.13.0",
"@rollup/rollup-win32-x64-msvc": "4.13.0",
"fsevents": "~2.3.2"
}
},
@@ -1796,9 +1846,9 @@
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
"engines": {
"node": ">=0.10.0"
}
@@ -1888,14 +1938,14 @@
"optional": true
},
"node_modules/vite": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz",
"integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==",
"version": "5.2.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz",
"integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==",
"dev": true,
"dependencies": {
"esbuild": "^0.19.3",
"postcss": "^8.4.35",
"rollup": "^4.2.0"
"esbuild": "^0.20.1",
"postcss": "^8.4.36",
"rollup": "^4.13.0"
},
"bin": {
"vite": "bin/vite.js"
@@ -1963,12 +2013,12 @@
}
},
"node_modules/vue-i18n": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.10.1.tgz",
"integrity": "sha512-37HVJQZ/pZaRXGzFmmMomM1u1k7kndv3xCBPYHKEVfv5W3UVK67U/TpBug71ILYLNmjHLHdvTUPRF81pFT5fFg==",
"version": "9.10.2",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.10.2.tgz",
"integrity": "sha512-ECJ8RIFd+3c1d3m1pctQ6ywG5Yj8Efy1oYoAKQ9neRdkLbuKLVeW4gaY5HPkD/9ssf1pOnUrmIFjx2/gkGxmEw==",
"dependencies": {
"@intlify/core-base": "9.10.1",
"@intlify/shared": "9.10.1",
"@intlify/core-base": "9.10.2",
"@intlify/shared": "9.10.2",
"@vue/devtools-api": "^6.5.0"
},
"engines": {
+6 -6
View File
@@ -9,18 +9,18 @@
"preview": "vite preview"
},
"dependencies": {
"@fontsource/noto-sans": "^5.0.19",
"@fontsource/noto-sans": "^5.0.21",
"anser": "^2.1.1",
"combokeys": "^3.0.1",
"filesize": "^10.1.0",
"filesize": "^10.1.1",
"marked": "^12.0.1",
"moment": "^2.30.1",
"pankow": "^1.2.1",
"pankow": "^1.3.1",
"primeicons": "^6.0.1",
"primevue": "^3.49.1",
"primevue": "^3.50.0",
"superagent": "^8.1.2",
"vue": "^3.4.21",
"vue-i18n": "^9.10.1",
"vue-i18n": "^9.10.2",
"vue-router": "^4.3.0",
"@xterm/xterm": "^5.4.0",
"@xterm/addon-attach": "^0.10.0",
@@ -28,6 +28,6 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"vite": "^5.1.5"
"vite": "^5.2.6"
}
}
+2 -2
View File
@@ -67,11 +67,11 @@ export function createDirectoryModel(origin, accessToken, api) {
return result.body.entries;
},
async upload(targetDir, file, progressHandler) {
upload(targetDir, file, progressHandler) {
// file may contain a file name or a file path + file name
const relativefilePath = (file.webkitRelativePath ? file.webkitRelativePath : file.name);
await superagent.post(`${origin}/api/v1/${api}/files/${encodeURIComponent(sanitize(targetDir + '/' + relativefilePath))}`)
return superagent.post(`${origin}/api/v1/${api}/files/${encodeURIComponent(sanitize(targetDir + '/' + relativefilePath))}`)
.query({ access_token: accessToken })
.attach('file', file)
.on('progress', progressHandler);
+19 -2
View File
@@ -107,6 +107,7 @@
<FileUploader
ref="fileUploader"
:upload-handler="uploadHandler"
:cancel-handler="onCancelUpload"
@finished="onUploadFinished"
:tr="$t"
/>
@@ -131,6 +132,7 @@ import ProgressSpinner from 'primevue/progressspinner';
import { useConfirm } from 'primevue/useconfirm';
import { DirectoryView, TopBar, PathBreadcrumbs, BottomBar, MainLayout, FileUploader } from 'pankow';
import Icon from 'pankow/components/Icon.vue';
import { sanitize, sleep } from 'pankow/utils';
import { ISTATES } from '../constants.js';
@@ -160,7 +162,8 @@ export default {
PathBreadcrumbs,
PreviewPanel,
ProgressSpinner,
TopBar
TopBar,
Icon
},
data() {
return {
@@ -188,6 +191,7 @@ export default {
resourceType: '',
resourceId: '',
visible: true,
uploadRequest: null,
newFileDialog: {
visible: false,
busy: false,
@@ -233,6 +237,10 @@ export default {
onUploadMenu(event) {
this.$refs.uploadMenu.toggle(event);
},
onCancelUpload() {
if (!this.uploadRequest) return;
this.uploadRequest.abort();
},
// generic dialog focus handler
onDialogShow(focusElementId) {
setTimeout(() => document.getElementById(focusElementId).focus(), 0);
@@ -449,7 +457,16 @@ export default {
this.extractInProgress = false;
},
async uploadHandler(targetDir, file, progressHandler) {
await this.directoryModel.upload(targetDir, file, progressHandler);
this.uploadRequest = this.directoryModel.upload(targetDir, file, progressHandler);
try {
await this.uploadRequest;
} catch (e) {
console.log('Upload cancelled.');
}
this.uploadRequest = null;
await this.loadCwd();
},
async loadCwd() {
+1 -1
View File
@@ -8,7 +8,7 @@ export default defineConfig({
server: {
fs: {
// Allow serving files from one level up to the project root for monaco editor assets
allow: ['..']
allow: [ '../..' ]
},
},
// https://vitejs.dev/guide/build.html#multi-page-app
+2 -2
View File
@@ -3,9 +3,9 @@ Description=Cloudron Syslog
After=network.target
[Service]
ExecStart=/home/yellowtent/box/syslog/service.js
ExecStart=/home/yellowtent/box/syslog.js
WorkingDirectory=/home/yellowtent/box
Environment="NODE_ENV=production" "DEBUG=syslog:*"
Environment="NODE_ENV=production" "DEBUG=syslog:*" "BOX_ENV=cloudron"
Restart=always
User=yellowtent
Group=yellowtent
-1
View File
@@ -218,7 +218,6 @@ function validatePortBindings(portBindings, manifest) {
993, /* imaps */
995, /* pop3s */
2003, /* graphite (lo) */
2514, /* cloudron-syslog (lo) */
constants.PORT, /* app server (lo) */
constants.AUTHWALL_PORT, /* protected sites */
constants.INTERNAL_SMTP_PORT, /* internal smtp port (lo) */
-1
View File
@@ -24,7 +24,6 @@ const apps = require('./apps.js'),
dns = require('./dns.js'),
docker = require('./docker.js'),
ejs = require('ejs'),
execSync = require('child_process').execSync,
fs = require('fs'),
iputils = require('./iputils.js'),
manifestFormat = require('cloudron-manifestformat'),
+1 -1
View File
@@ -345,7 +345,7 @@ async function createSubcontainer(app, name, cmd, options) {
Type: 'syslog',
Config: {
'tag': app.id,
'syslog-address': 'udp://127.0.0.1:2514', // see apps.js:validatePortBindings()
'syslog-address': `unix://${paths.SYSLOG_SOCKET_FILE}`,
'syslog-format': 'rfc5424'
}
},
+1 -1
View File
@@ -67,7 +67,7 @@ async function containersCreate(req, res, next) {
safe.set(req.body, 'HostConfig.NetworkMode', 'cloudron'); // overwrite the network the container lives in
safe.set(req.body, 'NetworkingConfig', {}); // drop any custom network configs
safe.set(req.body, 'Labels', Object.assign({}, safe.query(req.body, 'Labels'), { appId: req.app.id, isCloudronManaged: String(false) })); // overwrite the app id to track containers of an app
safe.set(req.body, 'HostConfig.LogConfig', { Type: 'syslog', Config: { 'tag': req.app.id, 'syslog-address': 'udp://127.0.0.1:2514', 'syslog-format': 'rfc5424' }});
safe.set(req.body, 'HostConfig.LogConfig', { Type: 'syslog', Config: { 'tag': req.app.id, 'syslog-address': `unix://${paths.SYSLOG_SOCKET_FILE}`, 'syslog-format': 'rfc5424' }});
const appDataDir = path.join(paths.APPS_DATA_DIR, req.app.id, 'data');
+1 -1
View File
@@ -6,7 +6,7 @@
exports = module.exports = {
// a version change recreates all containers with latest docker config
'version': '49.5.0',
'version': '49.6.0',
// a major version bump in the db containers will trigger the restore logic that uses the db dumps
// docker inspect --format='{{index .RepoDigests 0}}' $IMAGE to get the sha256
+1 -1
View File
@@ -179,7 +179,7 @@ async function configureMail(mailFqdn, mailDomain, serviceConfig) {
--net cloudron \
--net-alias mail \
--log-driver syslog \
--log-opt syslog-address=udp://127.0.0.1:2514 \
--log-opt syslog-address=unix://${paths.SYSLOG_SOCKET_FILE} \
--log-opt syslog-format=rfc5424 \
--log-opt tag=mail \
-m ${memory} \
+2
View File
@@ -68,5 +68,7 @@ exports = module.exports = {
BACKUP_LOG_FILE: path.join(baseDir(), 'platformdata/logs/backup/app.log'),
UPDATER_LOG_FILE: path.join(baseDir(), 'platformdata/logs/updater/app.log'),
SYSLOG_SOCKET_FILE: path.join(baseDir(), 'platformdata/logs/syslog.sock'),
OIDC_STORE_DIR: path.join(baseDir(), 'platformdata/oidc'),
};
+6 -6
View File
@@ -941,7 +941,7 @@ async function startTurn(existingInfra) {
--hostname turn \
--net host \
--log-driver syslog \
--log-opt syslog-address=udp://127.0.0.1:2514 \
--log-opt syslog-address=unix://${paths.SYSLOG_SOCKET_FILE} \
--log-opt syslog-format=rfc5424 \
--log-opt tag=turn \
-m ${memory} \
@@ -1149,7 +1149,7 @@ async function startMysql(existingInfra) {
--net cloudron \
--net-alias mysql \
--log-driver syslog \
--log-opt syslog-address=udp://127.0.0.1:2514 \
--log-opt syslog-address=unix://${paths.SYSLOG_SOCKET_FILE} \
--log-opt syslog-format=rfc5424 \
--log-opt tag=mysql \
--dns 172.18.0.1 \
@@ -1370,7 +1370,7 @@ async function startPostgresql(existingInfra) {
--net cloudron \
--net-alias postgresql \
--log-driver syslog \
--log-opt syslog-address=udp://127.0.0.1:2514 \
--log-opt syslog-address=unix://${paths.SYSLOG_SOCKET_FILE} \
--log-opt syslog-format=rfc5424 \
--log-opt tag=postgresql \
--dns 172.18.0.1 \
@@ -1517,7 +1517,7 @@ async function startMongodb(existingInfra) {
--net cloudron \
--net-alias mongodb \
--log-driver syslog \
--log-opt syslog-address=udp://127.0.0.1:2514 \
--log-opt syslog-address=unix://${paths.SYSLOG_SOCKET_FILE} \
--log-opt syslog-format=rfc5424 \
--log-opt tag=mongodb \
--dns 172.18.0.1 \
@@ -1668,7 +1668,7 @@ async function startGraphite(existingInfra) {
--net cloudron \
--net-alias graphite \
--log-driver syslog \
--log-opt syslog-address=udp://127.0.0.1:2514 \
--log-opt syslog-address=unix://${paths.SYSLOG_SOCKET_FILE} \
--log-opt syslog-format=rfc5424 \
--log-opt tag=graphite \
-m ${memory} \
@@ -1789,7 +1789,7 @@ async function setupRedis(app, options) {
--net cloudron \
--net-alias ${redisName} \
--log-driver syslog \
--log-opt syslog-address=udp://127.0.0.1:2514 \
--log-opt syslog-address=unix://${paths.SYSLOG_SOCKET_FILE} \
--log-opt syslog-format=rfc5424 \
--log-opt tag=${redisName} \
-m ${memory} \
+1 -1
View File
@@ -108,7 +108,7 @@ async function start(existingInfra) {
--net cloudron \
--net-alias sftp \
--log-driver syslog \
--log-opt syslog-address=udp://127.0.0.1:2514 \
--log-opt syslog-address=unix://${paths.SYSLOG_SOCKET_FILE} \
--log-opt syslog-format=rfc5424 \
--log-opt tag=sftp \
-m ${memory} \
+3 -1
View File
@@ -70,9 +70,11 @@ async function hdparm(file) {
async function getSwaps() {
const [error, stdout] = await safe(shell.exec('getSwaps', 'swapon --noheadings --raw --bytes --show=type,size,used,name', {}));
if (error) return {};
const output = stdout.trim();
if (!output) return {}; // no swaps
const swaps = {};
for (const line of stdout.trim().split('\n')) {
for (const line of output.split('\n')) {
const parts = line.split(' ', 4);
const name = parts[3];
swaps[name] = {
Executable
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env node
'use strict';
const debug = require('debug')('syslog:server'),
fs = require('fs'),
net = require('net'),
path = require('path'),
paths = require('./src/paths.js'),
parser = require('nsyslog-parser'),
util = require('util');
let gServer = null;
async function start() {
debug('==========================================');
debug(' Cloudron Syslog Daemon ');
debug('==========================================');
gServer = net.createServer();
gServer.on('error', function (error) {
console.error(`server error: ${error}`);
});
gServer.on('connection', function (socket) {
socket.on('data', function (msg) {
const info = parser(msg.toString());
if (!info || !info.appName) return debug('Ignore unknown app log:', msg.toString());
// remove line breaks to avoid holes in the log file
// we do not ignore empty log lines, to allow gaps for potential ease of readability
const message = info.message.replace(/\n/g, '');
const appLogDir = path.join(paths.LOG_DIR, info.appName);
try {
fs.mkdirSync(appLogDir, { recursive: true });
fs.appendFileSync(`${appLogDir}/app.log`, info.ts.toISOString() + ' ' + message + '\n');
} catch (error) {
console.error(error);
}
});
socket.on('error', function (error) {
console.error(`socket error: ${error}`);
});
});
await fs.promises.rm(paths.SYSLOG_SOCKET_FILE, { force: true });
await util.promisify(gServer.listen.bind(gServer))(paths.SYSLOG_SOCKET_FILE);
debug(`Listening on ${paths.SYSLOG_SOCKET_FILE}`);
}
async function stop() {
await fs.promises.rm(paths.SYSLOG_SOCKET_FILE, { force: true });
gServer.unref(); // TODO : cleanup client connections. otherwise server.close() won't return
gServer = null;
}
async function main() {
await start();
process.on('SIGTERM', async function () {
debug('Received SIGTERM. Shutting down.');
await stop();
setTimeout(process.exit.bind(process), 1000);
});
}
main();
-1
View File
@@ -1 +0,0 @@
node_modules/
-9
View File
@@ -1,9 +0,0 @@
{
"node": true,
"browser": true,
"unused": true,
"multistr": true,
"globalstrict": true,
"predef": [ "angular", "$" ],
"esnext": true
}
-64
View File
@@ -1,64 +0,0 @@
'use strict';
exports = module.exports = {
start,
stop
};
const LOG_FILENAME = 'app.log';
const assert = require('assert'),
debug = require('debug')('syslog:server'),
dgram = require('dgram'),
fs = require('fs'),
path = require('path'),
parser = require('nsyslog-parser'),
util = require('util');
let server = null;
async function start(options) {
assert.strictEqual(typeof options, 'object');
assert.strictEqual(typeof options.port, 'number');
assert.strictEqual(typeof options.logFolder, 'string');
debug('==========================================');
debug(' Cloudron Syslog Daemon ');
debug('==========================================');
server = dgram.createSocket('udp4');
server.on('error', function (error) {
console.error(`socket error: ${error}`);
});
server.on('message', function (msg /*, rinfo */) {
const info = parser(msg.toString());
if (!info || !info.appName) return debug('Ignore unknown app log:', msg.toString());
// remove line breaks to avoid holes in the log file
// we do not ignore empty log lines, to allow gaps for potential ease of readability
const message = info.message.replace(/\n/g, '');
const filePath = path.join(options.logFolder, info.appName);
const fileName = path.join(filePath, LOG_FILENAME);
try {
fs.mkdirSync(filePath, { recursive: true });
fs.appendFileSync(fileName, info.ts.toISOString() + ' ' + message + '\n');
} catch (error) {
console.error(error);
}
});
await util.promisify(server.bind.bind(server))(options.port); // intentional double "bind"
debug(`Listening on port ${options.port}`);
}
async function stop() {
if (!server) return;
await util.promisify(server.close.bind(server))();
server = null;
}
-16
View File
@@ -1,16 +0,0 @@
#!/usr/bin/env node
'use strict';
const server = require('./server.js');
const options = {
logFolder: process.argv[2] || '/home/yellowtent/platformdata/logs',
port: 2514
};
async function main() {
await server.start(options);
}
main();