Compare commits
1 Commits
MickLesk-p
...
v0.4.10.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55783c6bb3 |
@@ -368,54 +368,6 @@ run_container_safe() {
|
||||
" || __handle_general_error "lxc-attach to CT $ct"
|
||||
}
|
||||
|
||||
cleanup_lxc() {
|
||||
msg_info "Cleaning up"
|
||||
|
||||
if is_alpine; then
|
||||
$STD apk cache clean || true
|
||||
rm -rf /var/cache/apk/*
|
||||
else
|
||||
$STD apt -y autoremove || true
|
||||
$STD apt -y autoclean || true
|
||||
$STD apt -y clean || true
|
||||
fi
|
||||
|
||||
# Clear temp artifacts (keep sockets/FIFOs; ignore errors)
|
||||
find /tmp /var/tmp -type f -name 'tmp*' -delete 2>/dev/null || true
|
||||
find /tmp /var/tmp -type f -name 'tempfile*' -delete 2>/dev/null || true
|
||||
|
||||
# Truncate writable log files silently (permission errors ignored)
|
||||
if command -v truncate >/dev/null 2>&1; then
|
||||
find /var/log -type f -writable -print0 2>/dev/null |
|
||||
xargs -0 -n1 truncate -s 0 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Python pip
|
||||
if command -v pip &>/dev/null; then $STD pip cache purge || true; fi
|
||||
# Python uv
|
||||
if command -v uv &>/dev/null; then $STD uv cache clear || true; fi
|
||||
# Node.js npm
|
||||
if command -v npm &>/dev/null; then $STD npm cache clean --force || true; fi
|
||||
# Node.js yarn
|
||||
if command -v yarn &>/dev/null; then $STD yarn cache clean || true; fi
|
||||
# Node.js pnpm
|
||||
if command -v pnpm &>/dev/null; then $STD pnpm store prune || true; fi
|
||||
# Go
|
||||
if command -v go &>/dev/null; then $STD go clean -cache -modcache || true; fi
|
||||
# Rust cargo
|
||||
if command -v cargo &>/dev/null; then $STD cargo clean || true; fi
|
||||
# Ruby gem
|
||||
if command -v gem &>/dev/null; then $STD gem cleanup || true; fi
|
||||
# Composer (PHP)
|
||||
if command -v composer &>/dev/null; then $STD composer clear-cache || true; fi
|
||||
|
||||
if command -v journalctl &>/dev/null; then
|
||||
$STD journalctl --rotate || true
|
||||
$STD journalctl --vacuum-time=10m || true
|
||||
fi
|
||||
msg_ok "Cleaned"
|
||||
}
|
||||
|
||||
check_or_create_swap() {
|
||||
msg_info "Checking for active swap"
|
||||
|
||||
@@ -457,4 +409,4 @@ check_or_create_swap() {
|
||||
trap 'stop_spinner' EXIT INT TERM
|
||||
|
||||
# Initialize functions when core.func is sourced
|
||||
load_functions
|
||||
load_functions
|
||||
@@ -517,26 +517,9 @@ export function InstalledScriptsTab() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteScript = (id: number, script?: InstalledScript) => {
|
||||
const scriptToDelete = script ?? scripts.find(s => s.id === id);
|
||||
|
||||
if (scriptToDelete && scriptToDelete.container_id && scriptToDelete.execution_mode === 'ssh') {
|
||||
// For SSH scripts with container_id, use confirmation modal
|
||||
setConfirmationModal({
|
||||
isOpen: true,
|
||||
variant: 'simple',
|
||||
title: 'Delete Database Record Only',
|
||||
message: `This will only delete the database record for "${scriptToDelete.script_name}" (Container ID: ${scriptToDelete.container_id}).\n\nThe container will remain intact and can be re-detected later via auto-detect.`,
|
||||
onConfirm: () => {
|
||||
void deleteScriptMutation.mutate({ id });
|
||||
setConfirmationModal(null);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// For non-SSH scripts or scripts without container_id, use simple confirm
|
||||
if (confirm('Are you sure you want to delete this installation record?')) {
|
||||
void deleteScriptMutation.mutate({ id });
|
||||
}
|
||||
const handleDeleteScript = (id: number) => {
|
||||
if (confirm('Are you sure you want to delete this installation record?')) {
|
||||
void deleteScriptMutation.mutate({ id });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1585,14 +1568,6 @@ export function InstalledScriptsTab() {
|
||||
>
|
||||
{controllingScriptId === script.id ? 'Working...' : 'Destroy'}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator className="bg-border" />
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteScript(script.id, script)}
|
||||
disabled={deleteScriptMutation.isPending}
|
||||
className="text-muted-foreground hover:text-foreground hover:bg-muted/20 focus:bg-muted/20"
|
||||
>
|
||||
{deleteScriptMutation.isPending ? 'Deleting...' : 'Delete only from DB'}
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)}
|
||||
{(!script.container_id || script.execution_mode !== 'ssh') && (
|
||||
|
||||
@@ -63,26 +63,14 @@ export function ServerForm({ onSubmit, initialData, isEditing = false, onCancel
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for IPv6 with zone identifier (link-local addresses like fe80::...%eth0)
|
||||
let ipv6Address = trimmed;
|
||||
const zoneIdMatch = trimmed.match(/^(.+)%([a-zA-Z0-9_\-]+)$/);
|
||||
if (zoneIdMatch) {
|
||||
ipv6Address = zoneIdMatch[1];
|
||||
// Zone identifier should be a valid interface name (alphanumeric, underscore, hyphen)
|
||||
const zoneId = zoneIdMatch[2];
|
||||
if (!/^[a-zA-Z0-9_\-]+$/.test(zoneId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// IPv6 validation (supports compressed format like ::1 and full format)
|
||||
// Matches: 2001:0db8:85a3:0000:0000:8a2e:0370:7334, ::1, 2001:db8::1, etc.
|
||||
// Also supports IPv4-mapped IPv6 addresses like ::ffff:192.168.1.1
|
||||
// Simplified validation: check for valid hex segments separated by colons
|
||||
const ipv6Pattern = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^::$|^(?:[0-9a-fA-F]{1,4}:)*::(?:[0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:)*::[0-9a-fA-F]{1,4}$|^::(?:[0-9a-fA-F]{1,4}:)+[0-9a-fA-F]{1,4}$|^::ffff:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|^(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||
if (ipv6Pattern.test(ipv6Address)) {
|
||||
if (ipv6Pattern.test(trimmed)) {
|
||||
// Additional validation: ensure only one :: compression exists
|
||||
const compressionCount = (ipv6Address.match(/::/g) || []).length;
|
||||
const compressionCount = (trimmed.match(/::/g) || []).length;
|
||||
if (compressionCount <= 1) {
|
||||
return true;
|
||||
}
|
||||
@@ -285,7 +273,7 @@ export function ServerForm({ onSubmit, initialData, isEditing = false, onCancel
|
||||
className={`w-full px-3 py-2 border rounded-md shadow-sm bg-card text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-ring ${
|
||||
errors.ip ? 'border-destructive' : 'border-border'
|
||||
}`}
|
||||
placeholder="e.g., 192.168.1.100, server.example.com, 2001:db8::1, or fe80::...%eth0"
|
||||
placeholder="e.g., 192.168.1.100, server.example.com, or 2001:db8::1"
|
||||
/>
|
||||
{errors.ip && <p className="mt-1 text-sm text-destructive">{errors.ip}</p>}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user