front end for n8n version

This commit is contained in:
usmannasir
2025-04-12 20:21:43 +05:00
parent a7b1a18ac8
commit c4580479ad
5 changed files with 52 additions and 244 deletions

View File

@@ -168,55 +168,3 @@ def restartContainer(request):
'status': 0,
'error_message': str(e)
}))
@csrf_exempt
@require_login
def executeCommand(request):
try:
if request.method == 'POST':
userID = request.session['userID']
currentACL = ACLManager.loadedACL(userID)
admin = Administrator.objects.get(pk=userID)
data = json.loads(request.body)
container_id = data.get('container_id')
command = data.get('command')
site_name = data.get('name')
# Verify Docker site ownership
try:
docker_site = DockerSites.objects.get(SiteName=site_name)
if currentACL['admin'] != 1 and docker_site.admin != admin and docker_site.admin.owner != admin.pk:
return HttpResponse(json.dumps({
'status': 0,
'error_message': 'Not authorized to access this container'
}))
except DockerSites.DoesNotExist:
return HttpResponse(json.dumps({
'status': 0,
'error_message': 'Docker site not found'
}))
docker_manager = DockerManager()
container = docker_manager.get_container(container_id)
if not container:
return HttpResponse(json.dumps({
'status': 0,
'error_message': 'Container not found'
}))
# Execute the command
result = container.exec_run(command)
return HttpResponse(json.dumps({
'status': 1,
'output': result.output.decode('utf-8')
}))
return HttpResponse('Not allowed')
except Exception as e:
return HttpResponse(json.dumps({
'status': 0,
'error_message': str(e)
}))

View File

@@ -347,99 +347,4 @@ app.controller('ListDockersitecontainer', function ($scope, $http) {
// Add location service to the controller for the n8n URL
$scope.location = window.location;
// Initialize n8n version info for containers
$scope.initializeN8nVersion = function(container) {
if (!container || !container.id) return;
$http({
method: 'POST',
url: '/docker/fetchN8nVersions',
data: {
container_id: container.id
}
}).then(function(response) {
if (response.data.status === 1) {
container.n8nVersion = {
current: response.data.current_version,
latest: response.data.latest_version,
updateAvailable: response.data.update_available
};
} else {
console.error('Error fetching n8n versions:', response.data.error_message);
}
}, function(error) {
console.error('Error fetching n8n versions:', error);
});
};
// Update n8n function
$scope.updateN8n = function(container) {
if (!container || container.updatingN8n) return;
container.updatingN8n = true;
// First stop the container
$http({
method: 'POST',
url: '/docker/stopContainer',
data: {
container_id: container.id,
name: container.name
}
}).then(function(response) {
if (response.data.status === 1) {
// Execute update command
return $http({
method: 'POST',
url: '/docker/executeCommand',
data: {
container_id: container.id,
command: 'npm install -g n8n@latest'
}
});
} else {
throw new Error('Failed to stop container');
}
}).then(function(response) {
if (response.data.status === 1) {
// Start the container back
return $http({
method: 'POST',
url: '/docker/startContainer',
data: {
container_id: container.id,
name: container.name
}
});
} else {
throw new Error('Failed to update n8n');
}
}).then(function(response) {
if (response.data.status === 1) {
// Refresh version info
$scope.initializeN8nVersion(container);
} else {
throw new Error('Failed to start container');
}
}).catch(function(error) {
console.error('Error updating n8n:', error);
}).finally(function() {
container.updatingN8n = false;
});
};
// Hook into existing container loading
var originalLunchcontainer = $scope.Lunchcontainer;
if (originalLunchcontainer) {
$scope.Lunchcontainer = function(containerId) {
var result = originalLunchcontainer(containerId);
// Initialize version info after container is loaded
if ($scope.web && $scope.web.environment &&
$scope.web.environment.some(function(env) { return env.includes('n8n'); })) {
$scope.initializeN8nVersion($scope.web);
}
return result;
};
}
});

View File

@@ -889,6 +889,49 @@
i.fa:not(.btn i.fa) {
margin-right: 10px;
}
/* Version badge styling */
.version-badge {
display: inline-flex;
align-items: center;
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 2px 8px;
margin: 0 8px;
font-size: 12px;
color: #495057;
}
.version-badge i {
margin-right: 4px;
color: #6c757d;
}
.update-available {
display: inline-flex;
align-items: center;
background: #fff3cd;
color: #856404;
border-radius: 4px;
padding: 2px 8px;
margin-left: 8px;
font-size: 12px;
border: 1px solid #ffeeba;
}
.update-available i {
margin-right: 4px;
color: #856404;
}
/* Ensure proper spacing in container header */
.container-header h3 {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
</style>
<script>
@@ -915,7 +958,7 @@
}
});
// Add n8n version checking and update functionality
// Angular extension for container action handling
angular.module('WebsitesApp').run(['$rootScope', function($rootScope) {
// Add custom icon rendering for container actions
$rootScope.renderIcon = function(iconName) {
@@ -948,39 +991,6 @@
}
};
}
// Initialize n8n version info for containers
$rootScope.initializeN8nVersion = function(container) {
// This would normally come from the backend
container.n8nVersion = {
current: '1.0.0',
latest: '1.1.0',
updateAvailable: true
};
};
// Add n8n update function
$rootScope.updateN8n = function(container) {
container.updatingN8n = true;
// Simulate update process
setTimeout(function() {
container.n8nVersion.current = container.n8nVersion.latest;
container.n8nVersion.updateAvailable = false;
container.updatingN8n = false;
}, 3000);
};
// Initialize version info when loading containers
var originalLunchcontainer = $rootScope.Lunchcontainer;
if (originalLunchcontainer) {
$rootScope.Lunchcontainer = function(containerId) {
var result = originalLunchcontainer(containerId);
// Initialize version info after container is loaded
$rootScope.initializeN8nVersion($rootScope.web);
return result;
};
}
}]);
});
</script>
@@ -1155,12 +1165,12 @@
<h3>
<i class="fa fa-cube"></i>
n8n Container: {$ web.name $}
<div class="version-info" style="font-size: 14px; margin-top: 5px; color: #666;">
<i class="fa fa-code-fork"></i> Version {$ web.n8nVersion.current || '...' $}
<span ng-if="web.n8nVersion.updateAvailable" class="label label-warning" style="margin-left: 10px;">
Update available: {$ web.n8nVersion.latest $}
<span class="version-badge">
<i class="fa fa-tag"></i> v{$ web.version $}
<span ng-if="web.updateAvailable" class="update-available">
<i class="fa fa-arrow-up"></i> Update Available
</span>
</span>
</div>
<span class="workflow-status" ng-class="{'active': web.status === 'running', 'error': web.status !== 'running'}">
<i class="fa" ng-class="{'fa-check-circle': web.status === 'running', 'fa-times-circle': web.status !== 'running'}"></i>
{$ web.status $}
@@ -1179,14 +1189,12 @@
<button class="btn btn-primary" ng-click="openSettings(web)">
<i class="fa fa-cog"></i><span>Settings</span>
</button>
<button class="btn btn-info" ng-click="handleAction('update', web)" ng-if="web.updateAvailable">
<i class="fa fa-download"></i><span>Update</span>
</button>
<a class="btn btn-info" href="http://{$ location.hostname $}:{$ web.ports['5678/tcp'][0].HostPort $}" target="_blank" ng-if="web.status === 'running'">
<i class="fa fa-external-link"></i><span>Open n8n</span>
</a>
<button class="btn btn-success" ng-click="updateN8n(web)" ng-if="web.status === 'running' && web.n8nVersion.updateAvailable" ng-disabled="web.updatingN8n">
<i class="fa" ng-class="{'fa-refresh fa-spin': web.updatingN8n, 'fa-arrow-up': !web.updatingN8n}"></i>
<span ng-if="!web.updatingN8n">Update to {$ web.n8nVersion.latest $}</span>
<span ng-if="web.updatingN8n">Updating...</span>
</button>
</div>
</div>

View File

@@ -183,8 +183,6 @@ urlpatterns = [
path('docker/startContainer', views.startContainer, name='startContainer'),
path('docker/stopContainer', views.stopContainer, name='stopContainer'),
path('docker/restartContainer', views.restartContainer, name='restartContainer'),
path('docker/executeCommand', views.executeCommand, name='executeCommand'),
path('docker/fetchN8nVersions', views.fetchN8nVersions, name='fetchN8nVersions'),
# SSH Configs
path('getSSHConfigs', views.getSSHConfigs, name='getSSHConfigs'),
@@ -202,5 +200,4 @@ urlpatterns = [
# Catch all for domains
path('<domain>/<childDomain>', views.launchChild, name='launchChild'),
path('<domain>', views.domain, name='domain'),
path('fetchN8nVersions', views.fetchN8nVersions, name='fetchN8nVersions'),
]

View File

@@ -17,8 +17,6 @@ from django.views.decorators.csrf import csrf_exempt
from .dockerviews import startContainer as docker_startContainer
from .dockerviews import stopContainer as docker_stopContainer
from .dockerviews import restartContainer as docker_restartContainer
from .dockerviews import DockerManager
from .dockerviews import executeCommand as docker_executeCommand
def loadWebsitesHome(request):
val = request.session['userID']
@@ -1885,51 +1883,3 @@ def restartContainer(request):
return HttpResponse('Not allowed')
except KeyError:
return redirect(loadLoginPage)
@csrf_exempt
def fetchN8nVersions(request):
try:
userID = request.session['userID']
data = json.loads(request.body)
container_id = data.get('container_id')
docker_manager = DockerManager()
container = docker_manager.get_container(container_id)
if not container:
return HttpResponse(json.dumps({
'status': 0,
'error_message': 'Container not found'
}))
# Execute command in container to get current n8n version
current_version_cmd = container.exec_run("npm list n8n --json")
current_version_output = current_version_cmd.output.decode('utf-8')
current_version_data = json.loads(current_version_output)
current_version = current_version_data.get('dependencies', {}).get('n8n', {}).get('version', 'unknown')
# Get latest version from npm
latest_version_cmd = container.exec_run("npm show n8n version")
latest_version = latest_version_cmd.output.decode('utf-8').strip()
return HttpResponse(json.dumps({
'status': 1,
'current_version': current_version,
'latest_version': latest_version,
'update_available': current_version != latest_version
}))
except Exception as e:
return HttpResponse(json.dumps({
'status': 0,
'error_message': str(e)
}))
@csrf_exempt
def executeCommand(request):
try:
if request.method == 'POST':
return docker_executeCommand(request)
return HttpResponse('Not allowed')
except KeyError:
return redirect(loadLoginPage)