From a801eb1eeb7cdfc13395b3ac40b263339bfc8c86 Mon Sep 17 00:00:00 2001 From: Kobe Date: Thu, 12 Jun 2025 15:40:57 +0200 Subject: [PATCH] steps for launching --- routes/__pycache__/main.cpython-313.pyc | Bin 88871 -> 88952 bytes routes/admin_api.py | 40 ++ routes/main.py | 4 +- templates/main/instances.html | 480 ++++++++++++++++++++--- templates/settings/tabs/connections.html | 216 ++-------- 5 files changed, 513 insertions(+), 227 deletions(-) diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index 41d000da08f0b48cc9187592fa6c651b0579ae4f..4e8d6e657a25d89d97a50c039445032cf8a8690c 100644 GIT binary patch delta 4224 zcmb7HYgAO%6`nnhJHP;XR|KsXL39Sh86G)z6pdLbw%W#E zwI1uuYPA~uk%djFX4Z15rb!cH(uZ2=lTH-z5m%~_VzpLHjXmEPWsqnevlbuwp0m&X z_TFcoeeQi{zv=FNQ|PUbkRYA-4Lp&*FfnFd=)w7x0Pz?u{%)1%dFqc7`P604^XU4; ze9r<0DSUfliu+vgJeg^m$ z5C*US{9bnP?Jj2T@r%qsyWNx33kHkdrQ1BKE}^%i@Ah5#SL?#lzkPzmtJv&LyUXrl z^I3+%aRF8X(-Dt$M)6~Hndalj#fLh+uVJct_R@*^c$os}^ARYAJe6*cq?1~gpCFcm zR-<4LY=6SkRZh!aq!#zY<#7hZ7ZI;n5u1r%*lhu?^(m}z*sJ5zvL$v~oVs|y0=ue~ zFLpYYS-U@#+#<ru4}m*+brI5G1fHZ&%G9A(oz#swE z0G0{)KWh$$rio35Ln-c|J7$uC#jKUDf7==*_Xll>nE(nvraXl=y*(_-Z@;S(JbLF) zB>{%+@)}E1mYz+A`NdHWUiO_@_JPQ;9oySAT_?d46LvweW=9 zjHdA|yGPI!_tD+mOq9XT?U@viAr>_1*<7B!cS4U2_D03mJTmy&y+E?quc^{y zuTmKnv3KBl1tc5}wh&T>0cH?mjTWEg98Apx%;($or78}Hi+Iz%I9kMS?n|a??#TCB zm6g(LF(&1TS2~v2KrjnX3@E`wC8QaEQam~!O#{rsW0`es~Q=5G$*NBwcy|(laA{mA4(3K?B_54+a}oc2v4m--#T&)=(A+vsnOn ztYn3R;4v2GL~W zDP&ggTmBb*8D*EF{W`DxxKMG59aU{S`lE5~pif?+P^k$h6ro!Ayu+Dvg=>eMwA5|< zbRWfZ&`b8hC+Yc#BmFHVvDnv?U*`{xOrcfoDW8>CXgz=L&qeb$i%D;YTIH%ORqZZU zWp#zh&LJ=70WAUw*%XL~p2-5)1bec~{H20A@P@j|ScTnHx>&U{WNjl9lX%sM5xr$8 zI-z93tjacEZVW$gBA=?b@njNx$p@VrLDjtMWS?jhhu2hFR$*5qk=G!6^A*ZJ`A<(~ zT4bq>f{8x-%*ii@Z-Mxv+iVBMq^}+1?B^JJbVAxrMJdvYjXd;pzPSN;cN%%?gPv~n z^hxvMd!yj|dfLLh=dID$-TNU`WtG)w9jQY4ti&34zm`#!F|h8da&Bu$h?dubf0OSa zgYq`ivn_mAOObK|oatI=x+v>}3*Ya!tKPko90az)Jh|uRFZH84{K2K(B0Uk8$DDa>auC-|WmlGxgoF&q3M@nz4|^0s7-nv9j_hA46%DPCZw< zkVK=cvgLLItK8>xkb1#_%-I?|ZUxk84`axhm}VZs~`-4));De;9heJ}zHtuuti~r-pUI znnxL_Po_yU*>fzJzA`;(E83w{nng>s@H8r=Z#6ZIio&{5Yt3m?Pe1e&r_)4pqU7`^ zNEVhXwoVtc_IW0KkL+4p7R{qxT74EJnjb~2wI; z8s*VkO7xWG(M^;8(tqk|e+;8wCkHSZ&=aCPo=gK@@aIy#iTmHb|A^H3Z-D?NZ-J-9(Mx-4GL@L~#QU#m({Fi>hI@ugp`Yk2 ztuP_m?^x~VG)kR`PiA%>KyXq41Oh?eL(*}iFwfxz1lk&7N#dI-fQKUFM IEJt|uZ#N}8@c;k- delta 4186 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 G*?#~oH!}(V diff --git a/routes/admin_api.py b/routes/admin_api.py index fad2521..cce01af 100644 --- a/routes/admin_api.py +++ b/routes/admin_api.py @@ -756,6 +756,46 @@ def list_gitea_repos(): except Exception as e: return jsonify({'message': f'Failed to list repositories: {str(e)}'}), 400 +@admin_api.route('/list-gitea-branches', methods=['POST']) +@csrf.exempt +def list_gitea_branches(): + """List branches from a Gitea repository""" + data = request.get_json() + if not data or 'url' not in data or 'token' not in data or 'repo' not in data: + return jsonify({'message': 'Missing required fields'}), 400 + + try: + # Try different authentication methods + headers = { + 'Accept': 'application/json' + } + + # First try token in Authorization header + headers['Authorization'] = f'token {data["token"]}' + + # Get repository branches + response = requests.get( + f'{data["url"]}/api/v1/repos/{data["repo"]}/branches', + headers=headers + ) + + # If that fails, try token as query parameter + if response.status_code != 200: + response = requests.get( + f'{data["url"]}/api/v1/repos/{data["repo"]}/branches?token={data["token"]}', + headers={'Accept': 'application/json'} + ) + + if response.status_code == 200: + return jsonify({ + 'branches': response.json() + }), 200 + else: + return jsonify({'message': f'Failed to list branches: {response.json().get("message", "Unknown error")}'}), 400 + + except Exception as e: + return jsonify({'message': f'Failed to list branches: {str(e)}'}), 400 + @admin_api.route('/list-gitlab-repos', methods=['POST']) @csrf.exempt def list_gitlab_repos(): diff --git a/routes/main.py b/routes/main.py index cae30ba..e568619 100644 --- a/routes/main.py +++ b/routes/main.py @@ -379,11 +379,13 @@ def init_routes(main_bp): # Get connection settings portainer_settings = KeyValueSettings.get_value('portainer_settings') nginx_settings = KeyValueSettings.get_value('nginx_settings') + git_settings = KeyValueSettings.get_value('git_settings') return render_template('main/instances.html', instances=instances, portainer_settings=portainer_settings, - nginx_settings=nginx_settings) + nginx_settings=nginx_settings, + git_settings=git_settings) @main_bp.route('/instances/add', methods=['POST']) @login_required diff --git a/templates/main/instances.html b/templates/main/instances.html index 1bb01e4..e5c8afc 100644 --- a/templates/main/instances.html +++ b/templates/main/instances.html @@ -35,7 +35,7 @@ - + @@ -156,18 +156,22 @@
2
-
Configuration
+
Repository
3
-
Resources
+
Company
4
-
Review
+
Variables
5
+
White Label
+
+
+
6
Launch
@@ -176,9 +180,6 @@
-

Connection Verification

-

Let's verify that your connections are properly configured before proceeding.

-
@@ -223,24 +224,149 @@
-

Configuration

-

Configure your instance settings.

+
+
+
+
+ + +
Select the repository containing your application code
+
+
+ + +
Select the branch to deploy
+
+
+
+
-

Resources

-

Set up your instance resources.

+
+
+
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+
+
-

Review

-

Review your instance configuration.

+
Port Configuration
+
+ + +
Ports below 1024 are reserved for system use. Suggested port: 3000
+
- +
+
+
+
+
White Label Configuration
+
+
+
+ +
+ + +
+
Default: RGB(22,118,123)
+
+
+
+
+ +
+ + +
+
Default: RGB(116,27,95)
+
+
+
+
+
Preview
+
+
+ Primary Color Sample +
+
+ Secondary Color Sample +
+
+
+
+
+
+
+ + +

Launch

Ready to launch your instance!

@@ -448,6 +574,9 @@ let authModal; let launchStepsModal; let currentStep = 1; +// Update the total number of steps +const totalSteps = 6; + document.addEventListener('DOMContentLoaded', function() { addInstanceModal = new bootstrap.Modal(document.getElementById('addInstanceModal')); editInstanceModal = new bootstrap.Modal(document.getElementById('editInstanceModal')); @@ -484,6 +613,47 @@ document.addEventListener('DOMContentLoaded', function() { // Set up periodic status checks (every 30 seconds) setInterval(checkAllInstanceStatuses, 30000); + + // Update color picker functionality + const primaryColor = document.getElementById('primaryColor'); + const secondaryColor = document.getElementById('secondaryColor'); + const primaryColorRGB = document.getElementById('primaryColorRGB'); + const secondaryColorRGB = document.getElementById('secondaryColorRGB'); + const primaryPreview = document.getElementById('primaryPreview'); + const secondaryPreview = document.getElementById('secondaryPreview'); + + function updateColorPreview() { + // Update preview boxes directly instead of using CSS variables + primaryPreview.style.backgroundColor = primaryColor.value; + secondaryPreview.style.backgroundColor = secondaryColor.value; + } + + function hexToRgb(hex) { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? + `${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(result[3], 16)}` : + null; + } + + function rgbToHex(r, g, b) { + return '#' + [r, g, b].map(x => { + const hex = x.toString(16); + return hex.length === 1 ? '0' + hex : hex; + }).join(''); + } + + primaryColor.addEventListener('input', function() { + primaryColorRGB.value = hexToRgb(this.value); + updateColorPreview(); + }); + + secondaryColor.addEventListener('input', function() { + secondaryColorRGB.value = hexToRgb(this.value); + updateColorPreview(); + }); + + // Initialize color preview + updateColorPreview(); }); // Function to check status of all instances @@ -1105,51 +1275,48 @@ function nextStepLaunchInstance() { } function updateStepDisplay() { - // Update step indicators - document.querySelectorAll('.step-item').forEach((item, index) => { - const stepNum = index + 1; - item.classList.remove('active', 'completed'); - if (stepNum === currentStep) { - item.classList.add('active'); - } else if (stepNum < currentStep) { - item.classList.add('completed'); - } + // Hide all steps + document.querySelectorAll('.step-pane').forEach(pane => { + pane.classList.remove('active'); }); - // Update step content - document.querySelectorAll('.step-pane').forEach((pane, index) => { - pane.classList.remove('active'); - if (index + 1 === currentStep) { - pane.classList.add('active'); - } + // Show current step + document.getElementById(`step${currentStep}`).classList.add('active'); + + // Update step indicators + document.querySelectorAll('.step-item').forEach(item => { + const step = parseInt(item.getAttribute('data-step')); + item.classList.toggle('active', step === currentStep); + item.classList.toggle('completed', step < currentStep); }); // Update buttons - const prevButton = document.querySelector('#launchStepsModal .btn-secondary'); - const nextButton = document.querySelector('#launchStepsModal .btn-primary'); + const prevButton = document.querySelector('.modal-footer .btn-secondary'); + const nextButton = document.querySelector('.modal-footer .btn-primary'); prevButton.style.display = currentStep === 1 ? 'none' : 'inline-block'; - nextButton.innerHTML = currentStep === 5 ? 'Launch ' : 'Next '; + nextButton.innerHTML = currentStep === totalSteps ? 'Launch Instance' : 'Next '; + + // If we're on step 4, get the next available port + if (currentStep === 4) { + getNextAvailablePort(); + } } function nextStep() { - if (currentStep < 5) { - // If we're on step 1, verify connections before proceeding - if (currentStep === 1) { - const portainerStatus = document.getElementById('portainerStatus'); - const nginxStatus = document.getElementById('nginxStatus'); - - if (!portainerStatus.innerHTML.includes('Connected') || !nginxStatus.innerHTML.includes('Connected')) { - alert('Please ensure all connections are working before proceeding.'); - return; - } - } - + if (currentStep === 2 && !validateStep2()) { + return; + } + if (currentStep === 3 && !validateStep3()) { + return; + } + + if (currentStep < totalSteps) { currentStep++; updateStepDisplay(); } else { - // Handle launch - console.log('Launching instance...'); + // Handle final step (launch instance) + launchInstance(); } } @@ -1232,5 +1399,226 @@ async function verifyConnections() { nginxDetails.innerHTML = `${error.message || 'Error checking NGINX connection'}`; } } + +// Repository Selection Functions +async function loadRepositories() { + const repoSelect = document.getElementById('giteaRepoSelect'); + const branchSelect = document.getElementById('giteaBranchSelect'); + + try { + const gitSettings = JSON.parse('{{ git_settings|tojson|safe }}'); + if (!gitSettings || !gitSettings.url || !gitSettings.token) { + throw new Error('No Git settings found. Please configure Git in the settings page.'); + } + + // Load repositories using the correct endpoint + const repoResponse = await fetch('/api/admin/list-gitea-repos', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content + }, + body: JSON.stringify({ + url: gitSettings.url, + token: gitSettings.token + }) + }); + + if (!repoResponse.ok) { + throw new Error('Failed to load repositories'); + } + + const data = await repoResponse.json(); + + if (data.repositories) { + repoSelect.innerHTML = '' + + data.repositories.map(repo => + `` + ).join(''); + repoSelect.disabled = false; + + // If we have a saved repository, load its branches + if (gitSettings.repo) { + loadBranches(gitSettings.repo); + } + } else { + repoSelect.innerHTML = ''; + repoSelect.disabled = true; + } + } catch (error) { + console.error('Error loading repositories:', error); + repoSelect.innerHTML = ``; + repoSelect.disabled = true; + } +} + +async function loadBranches(repoId) { + const branchSelect = document.getElementById('giteaBranchSelect'); + + try { + const gitSettings = JSON.parse('{{ git_settings|tojson|safe }}'); + if (!gitSettings || !gitSettings.url || !gitSettings.token) { + throw new Error('No Git settings found. Please configure Git in the settings page.'); + } + + const response = await fetch('/api/admin/list-gitea-branches', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content + }, + body: JSON.stringify({ + url: gitSettings.url, + token: gitSettings.token, + repo: repoId + }) + }); + + if (!response.ok) { + throw new Error('Failed to load branches'); + } + + const data = await response.json(); + + if (data.branches) { + branchSelect.innerHTML = '' + + data.branches.map(branch => + `` + ).join(''); + branchSelect.disabled = false; + } else { + branchSelect.innerHTML = ''; + branchSelect.disabled = true; + } + } catch (error) { + console.error('Error loading branches:', error); + branchSelect.innerHTML = ``; + branchSelect.disabled = true; + } +} + +// Event Listeners for Repository Selection +document.getElementById('giteaRepoSelect').addEventListener('change', function() { + const repoId = this.value; + if (repoId) { + loadBranches(repoId); + } else { + document.getElementById('giteaBranchSelect').innerHTML = ''; + document.getElementById('giteaBranchSelect').disabled = true; + } +}); + +// Load repositories when step 2 is shown +document.addEventListener('DOMContentLoaded', function() { + const step2Content = document.getElementById('step2'); + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.target.classList.contains('active')) { + loadRepositories(); + } + }); + }); + + observer.observe(step2Content, { attributes: true, attributeFilter: ['class'] }); +}); + +// Function to get the next available port +async function getNextAvailablePort() { + try { + // Get all existing instances + const response = await fetch('/instances'); + const text = await response.text(); + const parser = new DOMParser(); + const doc = parser.parseFromString(text, 'text/html'); + + // Get all port numbers from the table + const portCells = doc.querySelectorAll('table tbody tr td:first-child'); + const ports = Array.from(portCells) + .map(cell => { + const portText = cell.textContent.trim(); + // Only parse if it's a number + return /^\d+$/.test(portText) ? parseInt(portText) : null; + }) + .filter(port => port !== null) + .sort((a, b) => a - b); // Sort numerically + + console.log('Found existing ports:', ports); + + // Find the next available port + let nextPort = 10339; // Start from the next port after your highest + while (ports.includes(nextPort)) { + nextPort++; + } + + console.log('Next available port:', nextPort); + + // Set the suggested port + document.getElementById('port').value = nextPort; + } catch (error) { + console.error('Error getting next available port:', error); + // Default to 10339 if there's an error + document.getElementById('port').value = 10339; + } +} + +// Function to validate step 2 +function validateStep2() { + const repositorySelect = document.getElementById('giteaRepoSelect'); + const branchSelect = document.getElementById('giteaBranchSelect'); + + if (!repositorySelect.value) { + alert('Please select a repository'); + return false; + } + + if (!branchSelect.value) { + alert('Please select a branch'); + return false; + } + + return true; +} + +// Function to validate step 3 +function validateStep3() { + const requiredFields = [ + { id: 'companyName', name: 'Company Name' }, + { id: 'streetAddress', name: 'Street Address' }, + { id: 'city', name: 'City' }, + { id: 'zipCode', name: 'ZIP Code' }, + { id: 'country', name: 'Country' }, + { id: 'email', name: 'Email' }, + { id: 'phone', name: 'Phone' } + ]; + + const missingFields = requiredFields.filter(field => { + const element = document.getElementById(field.id); + return !element.value.trim(); + }); + + if (missingFields.length > 0) { + const fieldNames = missingFields.map(field => field.name).join(', '); + alert(`Please fill in all required fields: ${fieldNames}`); + return false; + } + + // Validate email format + const email = document.getElementById('email').value; + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + alert('Please enter a valid email address'); + return false; + } + + // Validate phone format (basic validation) + const phone = document.getElementById('phone').value; + const phoneRegex = /^[\d\s\-\+\(\)]{10,}$/; + if (!phoneRegex.test(phone)) { + alert('Please enter a valid phone number'); + return false; + } + + return true; +} {% endblock %} \ No newline at end of file diff --git a/templates/settings/tabs/connections.html b/templates/settings/tabs/connections.html index 179afe3..2a27be6 100644 --- a/templates/settings/tabs/connections.html +++ b/templates/settings/tabs/connections.html @@ -17,18 +17,18 @@
- + -
The URL of your Portainer instance
+
The URL of your Portainer server
-
You can generate this in Portainer under Settings > API Keys
+
You can generate this in your Portainer user settings
- -
-
-
-
- GitLab Connection -
- -
-
- -
- - -
The URL of your GitLab server (use https://gitlab.com for GitLab.com)
-
-
- - -
-
- - -
You can generate this in your GitLab user settings > Access Tokens
-
-
- -
- - -
-
Select the repository to connect to
-
-
- -
- -
-
-
-
@@ -349,59 +291,11 @@ async function loadGiteaRepos() { } } -// Load GitLab Repositories -async function loadGitlabRepos() { - const url = document.getElementById('gitlabUrl').value; - const token = document.getElementById('gitlabToken').value; - const repoSelect = document.getElementById('gitlabRepo'); - const currentRepo = repoSelect.value; // Store current selection - - if (!url || !token) { - showError('Please fill in the server URL and access token'); - return; - } - - try { - const response = await fetch('/api/admin/list-gitlab-repos', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRF-Token': getCsrfToken() - }, - body: JSON.stringify({ url, token }) - }); - - const data = await response.json(); - - if (response.ok) { - repoSelect.innerHTML = ''; - - data.repositories.forEach(repo => { - const option = document.createElement('option'); - option.value = repo.path_with_namespace; - option.textContent = repo.path_with_namespace; - if (repo.path_with_namespace === currentRepo) { // Restore selection - option.selected = true; - } - repoSelect.appendChild(option); - }); - } else { - throw new Error(data.message || 'Failed to load repositories'); - } - } catch (error) { - showError(error.message); - } -} - // Load repositories on page load if settings exist document.addEventListener('DOMContentLoaded', function() { const gitSettings = JSON.parse('{{ git_settings|tojson|safe }}'); - if (gitSettings) { - if (gitSettings.provider === 'gitea' && gitSettings.url && gitSettings.token) { - loadGiteaRepos(); - } else if (gitSettings.provider === 'gitlab' && gitSettings.url && gitSettings.token) { - loadGitlabRepos(); - } + if (gitSettings && gitSettings.provider === 'gitea' && gitSettings.url && gitSettings.token) { + loadGiteaRepos(); } }); @@ -414,39 +308,21 @@ async function testGitConnection(provider) { saveModal.show(); try { - let data = {}; - if (provider === 'gitea') { - const url = document.getElementById('giteaUrl').value; - const username = document.getElementById('giteaUsername').value; - const token = document.getElementById('giteaToken').value; + const url = document.getElementById('giteaUrl').value; + const username = document.getElementById('giteaUsername').value; + const token = document.getElementById('giteaToken').value; - if (!url || !username || !token) { - throw new Error('Please fill in all required fields'); - } - - data = { - provider: 'gitea', - url: url, - username: username, - token: token - }; - } else if (provider === 'gitlab') { - const url = document.getElementById('gitlabUrl').value; - const username = document.getElementById('gitlabUsername').value; - const token = document.getElementById('gitlabToken').value; - - if (!url || !username || !token) { - throw new Error('Please fill in all required fields'); - } - - data = { - provider: 'gitlab', - url: url, - username: username, - token: token - }; + if (!url || !username || !token) { + throw new Error('Please fill in all required fields'); } + const data = { + provider: 'gitea', + url: url, + username: username, + token: token + }; + const response = await fetch('/settings/test-git-connection', { method: 'POST', headers: { @@ -664,47 +540,27 @@ async function saveGitConnection(event, provider) { messageElement.className = ''; try { - let data = {}; - if (provider === 'gitea') { - const url = document.getElementById('giteaUrl').value; - const username = document.getElementById('giteaUsername').value; - const token = document.getElementById('giteaToken').value; - const repo = document.getElementById('giteaRepo').value; - const password = document.getElementById('giteaPassword').value; - const otp = document.getElementById('giteaOtp').value; + const url = document.getElementById('giteaUrl').value; + const username = document.getElementById('giteaUsername').value; + const token = document.getElementById('giteaToken').value; + const repo = document.getElementById('giteaRepo').value; + const password = document.getElementById('giteaPassword').value; + const otp = document.getElementById('giteaOtp').value; - if (!url || !username || !token || !repo) { - throw new Error('Please fill in all required fields'); - } - - data = { - provider: 'gitea', - url: url, - username: username, - token: token, - repo: repo, - password: password, - otp: otp - }; - } else if (provider === 'gitlab') { - const url = document.getElementById('gitlabUrl').value; - const username = document.getElementById('gitlabUsername').value; - const token = document.getElementById('gitlabToken').value; - const repo = document.getElementById('gitlabRepo').value; - - if (!url || !username || !token || !repo) { - throw new Error('Please fill in all required fields'); - } - - data = { - provider: 'gitlab', - url: url, - username: username, - token: token, - repo: repo - }; + if (!url || !username || !token || !repo) { + throw new Error('Please fill in all required fields'); } + const data = { + provider: 'gitea', + url: url, + username: username, + token: token, + repo: repo, + password: password, + otp: otp + }; + const response = await fetch('/settings/save-git-connection', { method: 'POST', headers: {
NamePORT Company Rooms Conversations