feat: post-deploy info card with app link, first steps, and credentials
After successful deploy, shows a rich info card instead of auto-redirecting to the apps list. Includes direct app link, first steps from catalog metadata, default credentials info, and link to settings page for password reveal. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### v0.28.5 — Post-Deploy Info Card (2026-02-23)
|
||||||
|
|
||||||
|
#### Added
|
||||||
|
- **Post-deploy success page** (`web/templates/deploy.html`) — After a successful deploy, instead of auto-redirecting to the apps list, shows a rich info card with: direct app link ("Alkalmazás megnyitása ↗"), first steps from catalog metadata (with DOMAIN placeholders replaced), default credentials info, documentation link, and a link to the settings page where passwords can be revealed. Also shown for unhealthy/timeout states since apps may still be usable during initialization.
|
||||||
|
|
||||||
### v0.28.4 — Telemetry: Skip Stopped Apps (2026-02-23)
|
### v0.28.4 — Telemetry: Skip Stopped Apps (2026-02-23)
|
||||||
|
|
||||||
#### Fixed
|
#### Fixed
|
||||||
|
|||||||
@@ -393,6 +393,61 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
var postDeployInfo = {
|
||||||
|
firstSteps: {{json .Meta.AppInfo.FirstSteps}},
|
||||||
|
defaultCreds: {{json .Meta.AppInfo.DefaultCreds}},
|
||||||
|
docsURL: {{json .Meta.AppInfo.DocsURL}},
|
||||||
|
domain: {{json .Domain}},
|
||||||
|
displayName: {{json .Meta.DisplayName}}
|
||||||
|
};
|
||||||
|
|
||||||
|
function buildPostDeployCard(stackName) {
|
||||||
|
var subdomain = '';
|
||||||
|
var sdField = document.getElementById('field-SUBDOMAIN');
|
||||||
|
if (sdField) subdomain = sdField.value.trim();
|
||||||
|
if (!subdomain && '{{.Meta.Subdomain}}') subdomain = '{{.Meta.Subdomain}}';
|
||||||
|
|
||||||
|
var html = '';
|
||||||
|
|
||||||
|
// App link
|
||||||
|
if (subdomain && postDeployInfo.domain) {
|
||||||
|
var appURL = 'https://' + subdomain + '.' + postDeployInfo.domain;
|
||||||
|
html += '<div style="text-align:center;margin:1.5rem 0">' +
|
||||||
|
'<a href="' + appURL + '" target="_blank" class="btn btn-primary btn-lg">Alkalmazás megnyitása ↗</a>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// First steps
|
||||||
|
if (postDeployInfo.firstSteps && postDeployInfo.firstSteps.length > 0) {
|
||||||
|
html += '<div class="app-info-card" style="margin-top:1rem"><h4>Első lépések</h4><ol class="app-info-list">';
|
||||||
|
for (var i = 0; i < postDeployInfo.firstSteps.length; i++) {
|
||||||
|
var step = postDeployInfo.firstSteps[i].replace(/DOMAIN/g, postDeployInfo.domain);
|
||||||
|
html += '<li>' + step + '</li>';
|
||||||
|
}
|
||||||
|
html += '</ol></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default creds
|
||||||
|
if (postDeployInfo.defaultCreds) {
|
||||||
|
var creds = postDeployInfo.defaultCreds.replace(/DOMAIN/g, postDeployInfo.domain);
|
||||||
|
html += '<div class="app-info-card" style="margin-top:1rem"><h4>Bejelentkezés</h4>' +
|
||||||
|
'<p class="app-info-creds">' + creds + '</p></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Docs link
|
||||||
|
if (postDeployInfo.docsURL) {
|
||||||
|
html += '<div style="margin-top:1rem"><a href="' + postDeployInfo.docsURL + '" target="_blank" class="btn btn-sm btn-outline">Dokumentáció ↗</a></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action buttons
|
||||||
|
html += '<div style="display:flex;gap:.75rem;margin-top:1.5rem;flex-wrap:wrap">' +
|
||||||
|
'<a href="/stacks/' + stackName + '/deploy" class="btn btn-outline">Beállítások és jelszavak megtekintése</a>' +
|
||||||
|
'<a href="/stacks" class="btn btn-sm btn-outline">← Alkalmazások</a>' +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
function toggleCrossDriveFields() {
|
function toggleCrossDriveFields() {
|
||||||
var enabled = document.getElementById('cross-drive-enabled').checked;
|
var enabled = document.getElementById('cross-drive-enabled').checked;
|
||||||
var fields = document.querySelectorAll('.cross-drive-field');
|
var fields = document.querySelectorAll('.cross-drive-field');
|
||||||
@@ -635,7 +690,7 @@ document.getElementById('deploy-form').addEventListener('submit', async function
|
|||||||
setStep(stepHealth, 'warn', 'Időtúllépés — az alkalmazás még indulhat');
|
setStep(stepHealth, 'warn', 'Időtúllépés — az alkalmazás még indulhat');
|
||||||
resultEl.innerHTML = '<div class="alert alert-warning" style="margin-top:1rem">' +
|
resultEl.innerHTML = '<div class="alert alert-warning" style="margin-top:1rem">' +
|
||||||
'A telepítés időtúllépésbe futott. Az alkalmazás még indulhat.' +
|
'A telepítés időtúllépésbe futott. Az alkalmazás még indulhat.' +
|
||||||
'</div><a href="/stacks" class="btn btn-primary" style="margin-top:.75rem">Alkalmazások megtekintése</a>';
|
'</div>' + buildPostDeployCard(stackName);
|
||||||
resultEl.style.display = 'block';
|
resultEl.style.display = 'block';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -667,21 +722,21 @@ document.getElementById('deploy-form').addEventListener('submit', async function
|
|||||||
setStep(stepHealth, 'done', 'Alkalmazás kész!');
|
setStep(stepHealth, 'done', 'Alkalmazás kész!');
|
||||||
progressEl.querySelector('h3').textContent = 'Telepítés sikeres!';
|
progressEl.querySelector('h3').textContent = 'Telepítés sikeres!';
|
||||||
resultEl.innerHTML = '<div class="alert alert-info" style="margin-top:1rem">' +
|
resultEl.innerHTML = '<div class="alert alert-info" style="margin-top:1rem">' +
|
||||||
'Az alkalmazás fut. Átirányítás 3 másodperc múlva...' +
|
'Az alkalmazás sikeresen telepítve és fut!' +
|
||||||
'</div>';
|
'</div>' + buildPostDeployCard(stackName);
|
||||||
resultEl.style.display = 'block';
|
resultEl.style.display = 'block';
|
||||||
setTimeout(function() { window.location.href = '/stacks'; }, 3000);
|
|
||||||
} else if (state === 'starting') {
|
} else if (state === 'starting') {
|
||||||
setStep(stepContainers, 'done', 'Konténerek elindultak');
|
setStep(stepContainers, 'done', 'Konténerek elindultak');
|
||||||
setStep(stepHealth, 'active', 'Alkalmazás inicializálása...');
|
setStep(stepHealth, 'active', 'Alkalmazás inicializálása...');
|
||||||
} else if (state === 'unhealthy') {
|
} else if (state === 'unhealthy') {
|
||||||
clearInterval(pollTimer);
|
clearInterval(pollTimer);
|
||||||
setStep(stepContainers, 'done', 'Konténerek elindultak');
|
setStep(stepContainers, 'done', 'Konténerek elindultak');
|
||||||
setStep(stepHealth, 'warn', 'Állapotjelző: nem egészséges');
|
setStep(stepHealth, 'warn', 'Állapotjelző: még inicializál');
|
||||||
|
progressEl.querySelector('h3').textContent = 'Telepítés sikeres!';
|
||||||
resultEl.innerHTML = '<div class="alert alert-warning" style="margin-top:1rem">' +
|
resultEl.innerHTML = '<div class="alert alert-warning" style="margin-top:1rem">' +
|
||||||
'Az alkalmazás elindult, de az állapotjelző nem egészséges. ' +
|
'Az alkalmazás elindult, de még inicializálódik. ' +
|
||||||
'Ez normális lehet az első percekben.' +
|
'Ez normális az első percekben — az alkalmazás már elérhető lehet.' +
|
||||||
'</div><a href="/stacks" class="btn btn-primary" style="margin-top:.75rem">Alkalmazások megtekintése</a>';
|
'</div>' + buildPostDeployCard(stackName);
|
||||||
resultEl.style.display = 'block';
|
resultEl.style.display = 'block';
|
||||||
} else if (state === 'exited' || state === 'stopped') {
|
} else if (state === 'exited' || state === 'stopped') {
|
||||||
clearInterval(pollTimer);
|
clearInterval(pollTimer);
|
||||||
|
|||||||
Reference in New Issue
Block a user