2025-08-01 14:56:30 +05:00
{% extends "baseTemplate/index.html" %}
{% load i18n %}
{% load static %}
{% block title %}{% trans "Create Docker App - CyberPanel" %}{% endblock %}
{% block header_scripts %}
< style >
/* Create Docker Site Page Specific Styles */
.docker-wrapper {
background: transparent;
padding: 20px;
}
.docker-container {
max-width: 1000px;
margin: 0 auto;
}
.docker-section {
2025-08-02 15:43:18 +05:00
background: var(--bg-secondary, white);
2025-08-01 14:56:30 +05:00
border-radius: 12px;
padding: 25px;
margin-bottom: 25px;
2025-08-02 15:43:18 +05:00
box-shadow: 0 2px 8px var(--shadow-color, rgba(0,0,0,0.08));
border: 1px solid var(--border-color, #e8e9ff);
2025-08-01 14:56:30 +05:00
}
.section-title {
font-size: 16px;
font-weight: 700;
2025-08-02 15:43:18 +05:00
color: var(--text-heading, #2f3640);
2025-08-01 14:56:30 +05:00
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.section-title::before {
content: '';
width: 4px;
height: 24px;
2025-08-02 15:43:18 +05:00
background: var(--accent-color, #5b5fcf);
2025-08-01 14:56:30 +05:00
border-radius: 2px;
}
.docker-description {
2025-08-02 15:43:18 +05:00
color: var(--text-secondary, #8893a7);
2025-08-01 14:56:30 +05:00
font-size: 14px;
margin-bottom: 25px;
line-height: 1.5;
}
/* Form Styles */
.form-container {
2025-08-02 15:43:18 +05:00
background: var(--bg-hover, #fafbff);
border: 1px solid var(--border-color, #e8e9ff);
2025-08-01 14:56:30 +05:00
border-radius: 8px;
padding: 30px;
}
.form-group {
margin-bottom: 20px;
}
.form-row {
display: grid;
grid-template-columns: 200px 1fr;
gap: 20px;
align-items: center;
}
.form-label {
font-size: 13px;
font-weight: 600;
2025-08-02 15:43:18 +05:00
color: var(--text-primary, #2f3640);
2025-08-01 14:56:30 +05:00
text-transform: uppercase;
letter-spacing: 0.5px;
text-align: right;
}
.form-control {
width: 100%;
max-width: 400px;
padding: 12px 16px;
2025-08-02 15:43:18 +05:00
border: 1px solid var(--border-color, #e8e9ff);
2025-08-01 14:56:30 +05:00
border-radius: 8px;
font-size: 14px;
2025-08-02 15:43:18 +05:00
color: var(--text-primary, #2f3640);
background: var(--bg-secondary, white);
2025-08-01 14:56:30 +05:00
transition: all 0.2s ease;
}
.form-control:focus {
outline: none;
2025-08-02 15:43:18 +05:00
border-color: var(--accent-color, #5b5fcf);
2025-08-01 14:56:30 +05:00
box-shadow: 0 0 0 3px rgba(91,95,207,0.1);
}
.form-control::placeholder {
2025-08-02 15:43:18 +05:00
color: var(--text-secondary, #94a3b8);
2025-08-01 14:56:30 +05:00
font-size: 13px;
}
select.form-control {
cursor: pointer;
}
/* Resource Configuration Section */
.resource-section {
2025-08-02 15:43:18 +05:00
background: var(--bg-secondary, white);
border: 1px solid var(--border-color, #e8e9ff);
2025-08-01 14:56:30 +05:00
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
}
.resource-header {
font-size: 14px;
font-weight: 700;
2025-08-02 15:43:18 +05:00
color: var(--text-heading, #2f3640);
2025-08-01 14:56:30 +05:00
margin-bottom: 15px;
text-transform: uppercase;
letter-spacing: 0.5px;
display: flex;
align-items: center;
gap: 8px;
}
.resource-icon {
width: 32px;
height: 32px;
2025-08-02 15:43:18 +05:00
background: var(--bg-hover, #e8e9ff);
2025-08-01 14:56:30 +05:00
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
2025-08-02 15:43:18 +05:00
color: var(--accent-color, #5b5fcf);
2025-08-01 14:56:30 +05:00
}
.resource-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
/* Buttons */
.btn-primary {
2025-08-02 15:43:18 +05:00
background: var(--accent-color, #5b5fcf);
border: 1px solid var(--accent-color, #5b5fcf);
2025-08-01 14:56:30 +05:00
color: white;
padding: 12px 32px;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 8px;
text-decoration: none;
}
.btn-primary:hover {
2025-08-02 15:43:18 +05:00
background: var(--accent-hover, #4b4fbf);
border-color: var(--accent-hover, #4b4fbf);
2025-08-01 14:56:30 +05:00
box-shadow: 0 3px 8px rgba(91,95,207,0.3);
transform: translateY(-1px);
}
.btn-primary:disabled {
2025-08-02 15:43:18 +05:00
background: var(--text-secondary, #94a3b8);
border-color: var(--text-secondary, #94a3b8);
2025-08-01 14:56:30 +05:00
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.btn-secondary {
background: #64748b;
border: 1px solid #64748b;
color: white;
padding: 12px 32px;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 8px;
text-decoration: none;
}
.btn-secondary:hover {
background: #475569;
border-color: #475569;
box-shadow: 0 3px 8px rgba(100,116,139,0.3);
transform: translateY(-1px);
}
/* Progress Section */
.progress-section {
2025-08-02 15:43:18 +05:00
background: var(--bg-hover, #fafbff);
border: 1px solid var(--border-color, #e8e9ff);
2025-08-01 14:56:30 +05:00
border-radius: 8px;
padding: 30px;
text-align: center;
}
.status-message {
2025-08-02 15:43:18 +05:00
background: var(--info-bg, #f0f9ff);
2025-08-01 14:56:30 +05:00
border: 1px solid #bae6fd;
border-radius: 8px;
padding: 20px;
margin-bottom: 25px;
}
.status-message h2 {
font-size: 20px;
font-weight: 700;
2025-08-02 15:43:18 +05:00
color: var(--info-text, #0369a1);
2025-08-01 14:56:30 +05:00
margin: 0;
}
.progress {
background: #e2e8f0;
border-radius: 8px;
height: 24px;
overflow: hidden;
margin-bottom: 25px;
}
.progress-bar {
2025-08-02 15:43:18 +05:00
background: var(--accent-color, #5b5fcf);
2025-08-01 14:56:30 +05:00
height: 100%;
transition: width 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 12px;
font-weight: 600;
}
.alert {
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
line-height: 1.5;
}
.alert-success {
2025-08-02 15:43:18 +05:00
background: var(--success-bg, #f0f9ff);
2025-08-01 14:56:30 +05:00
border: 1px solid #bae6fd;
2025-08-02 15:43:18 +05:00
color: var(--success-text, #0c4a6e);
2025-08-01 14:56:30 +05:00
}
.alert-danger {
2025-08-02 15:43:18 +05:00
background: var(--danger-bg, #fef2f2);
2025-08-01 14:56:30 +05:00
border: 1px solid #fecaca;
2025-08-02 15:43:18 +05:00
color: var(--danger-text, #991b1b);
2025-08-01 14:56:30 +05:00
}
.loading-spinner {
width: 16px;
height: 16px;
margin-left: 8px;
}
.error-text {
2025-08-02 15:43:18 +05:00
color: var(--danger-text, #ef4444);
2025-08-01 14:56:30 +05:00
font-size: 13px;
margin-top: 5px;
}
/* Info Boxes */
.info-box {
2025-08-02 15:43:18 +05:00
background: var(--info-bg, #f0f9ff);
2025-08-01 14:56:30 +05:00
border: 1px solid #bae6fd;
border-radius: 8px;
padding: 15px;
margin-bottom: 20px;
2025-08-02 15:43:18 +05:00
color: var(--info-text, #0c4a6e);
2025-08-01 14:56:30 +05:00
font-size: 14px;
}
.info-box i {
color: #0284c7;
margin-right: 8px;
}
/* Responsive */
@media (max-width: 768px) {
.docker-wrapper {
padding: 15px;
}
.docker-section {
padding: 20px;
}
.form-container {
padding: 20px;
}
.form-row {
grid-template-columns: 1fr;
gap: 10px;
}
.form-label {
text-align: left;
}
.form-control {
max-width: 100%;
}
.resource-grid {
grid-template-columns: 1fr;
}
}
< / style >
{% endblock %}
{% block content %}
< div class = "docker-wrapper" ng-controller = "createDockerSite" >
< div class = "docker-container" >
<!-- Header Section -->
< div class = "docker-section" >
< h2 class = "section-title" > CREATE DOCKER APP< / h2 >
< p class = "docker-description" > {% trans "Deploy containerized applications with custom resource allocation and domain configuration." %}< / p >
< / div >
<!-- Form Section -->
< div class = "docker-section" >
< h3 class = "section-title" >
DOCKER APP DETAILS
< img ng-hide = "cyberpanelLoading" src = "{% static 'images/loading.gif' %}" class = "loading-spinner" >
< / h3 >
< form name = "websiteCreationForm" ng-hide = "installationDetailsForm" >
< div class = "form-container" >
<!-- Basic Details -->
< div class = "form-group" >
< div class = "form-row" >
< label class = "form-label" > {% trans "Site Name" %}< / label >
< input type = "text" class = "form-control" ng-model = "siteName"
placeholder="My Docker App" required>
< / div >
< / div >
< div class = "form-group" >
< div class = "form-row" >
< label class = "form-label" > {% trans "Select Owner" %}< / label >
< select ng-model = "userSelection" class = "form-control" >
{% for admin in adminNames %}
< option > {{ admin }}< / option >
{% endfor %}
< / select >
< / div >
< / div >
< div class = "form-group" >
< div class = "form-row" >
< label class = "form-label" > {% trans "Domain Name" %}< / label >
< div >
< input name = "dom" type = "text" class = "form-control" ng-model = "domainNameCreate"
placeholder="example.com (without www)" required>
< div ng-show = "websiteCreationForm.dom.$error.pattern" class = "error-text" >
{% trans "Invalid Domain (Note: You don't need to add 'http' or 'https')" %}
< / div >
< / div >
< / div >
< / div >
<!-- Resource Configuration -->
< div style = "margin: 30px 0;" >
< div class = "resource-section" >
< div class = "resource-header" >
< div class = "resource-icon" >
< i class = "fas fa-database" > < / i >
< / div >
MySQL Resources
< / div >
< div class = "resource-grid" >
< div class = "form-group" >
< label class = "form-label" style = "text-align: left;" > {% trans "CPU Cores" %}< / label >
< input type = "number" class = "form-control" ng-model = "CPUMysql"
placeholder="1" value="1" min="1" required>
< / div >
< div class = "form-group" >
< label class = "form-label" style = "text-align: left;" > {% trans "RAM (MB)" %}< / label >
< input type = "number" class = "form-control" ng-model = "rammysql"
placeholder="512" value="512" min="128" required>
< / div >
< / div >
< / div >
< div class = "resource-section" >
< div class = "resource-header" >
< div class = "resource-icon" >
< i class = "fas fa-server" > < / i >
< / div >
Application Resources
< / div >
< div class = "resource-grid" >
< div class = "form-group" >
< label class = "form-label" style = "text-align: left;" > {% trans "CPU Cores" %}< / label >
< input type = "number" class = "form-control" ng-model = "CPUSite"
placeholder="1" value="1" min="1" required>
< / div >
< div class = "form-group" >
< label class = "form-label" style = "text-align: left;" > {% trans "RAM (MB)" %}< / label >
< input type = "number" class = "form-control" ng-model = "RamSite"
placeholder="512" value="512" min="128" required>
< / div >
< / div >
< / div >
< / div >
<!-- Application Configuration -->
< div class = "form-group" >
< div class = "form-row" >
< label class = "form-label" > {% trans "Select App" %}< / label >
< select ng-model = "App" class = "form-control" >
< option > n8n< / option >
< / select >
< / div >
< / div >
< div class = "form-group" >
< div class = "form-row" >
< label class = "form-label" > {% trans "Admin Username" %}< / label >
< input type = "text" class = "form-control" ng-model = "WPUsername"
placeholder="cyberpanel" value="cyberpanel" required>
< / div >
< / div >
< div class = "form-group" >
< div class = "form-row" >
< label class = "form-label" > {% trans "Admin Email" %}< / label >
< div >
< input type = "email" name = "email" class = "form-control" ng-model = "wpEmail"
placeholder="admin@example.com" value="example@example.org" required>
< div ng-show = "websiteCreationForm.email.$error.email" class = "error-text" >
{% trans "Invalid Email" %}
< / div >
< / div >
< / div >
< / div >
< div class = "form-group" >
< div class = "form-row" >
< label class = "form-label" > {% trans "Admin Password" %}< / label >
< input type = "password" class = "form-control" ng-model = "WPpassword"
placeholder="Strong password" required>
< / div >
< / div >
<!-- Submit Button -->
< div class = "form-group" style = "margin-top: 30px;" >
< div class = "form-row" >
< label class = "form-label" > < / label >
< button ng-disabled = "websiteCreationForm.dom.$error.required || websiteCreationForm.email.$invalid"
type="button" ng-click="createdockersite()"
class="btn-primary">
< i class = "fas fa-rocket" > < / i >
{% trans "Create Docker Site" %}
< / button >
< / div >
< / div >
< / div >
< / form >
<!-- Progress Section -->
< div ng-hide = "installationProgress" class = "progress-section" >
< div class = "status-message" >
< h2 > {$ currentStatus $}< / h2 >
< / div >
< div class = "progress" >
< div id = "installProgress" class = "progress-bar" role = "progressbar"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%">
< span > 0%< / span >
< / div >
< / div >
< div ng-hide = "errorMessageBox" class = "alert alert-danger" >
< i class = "fas fa-exclamation-triangle" style = "margin-right: 8px;" > < / i >
< strong > {% trans "Error:" %}< / strong > {$ errorMessage $}
< / div >
< div ng-hide = "success" class = "alert alert-success" >
< i class = "fas fa-check-circle" style = "margin-right: 8px;" > < / i >
< strong > {% trans "Success!" %}< / strong > {% trans "Docker site successfully created." %}
< / div >
< div ng-hide = "couldNotConnect" class = "alert alert-danger" >
< i class = "fas fa-exclamation-triangle" style = "margin-right: 8px;" > < / i >
< strong > {% trans "Connection Error" %}< / strong > {% trans "Could not connect to server. Please refresh this page." %}
< / div >
< div style = "margin-top: 30px;" >
< button type = "button" ng-disabled = "goBackDisable" ng-click = "goBack()" class = "btn-secondary" >
< i class = "fas fa-arrow-left" > < / i >
{% trans "Go Back" %}
< / button >
< / div >
< / div >
< / div >
<!-- Info Section -->
< div class = "docker-section" >
< div class = "info-box" >
< i class = "fas fa-info-circle" > < / i >
< strong > Resource Allocation:< / strong > The CPU and RAM values you specify will be allocated to your Docker containers. Ensure your server has sufficient resources available.
< / div >
< / div >
< / div >
< / div >
{% endblock %}