feat: viewer 3D + parser 3MF par plaque + échecs filament + portail client
Deploy via Portainer / deploy (push) Successful in 0s
Deploy via Portainer / deploy (push) Successful in 0s
This commit is contained in:
@@ -194,6 +194,83 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header py-3"><i class="bi bi-cloud me-2"></i>Nextcloud — Intégration fichiers 3D</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-semibold">URL Nextcloud</label>
|
||||
<input type="url" name="nc_url" class="form-control"
|
||||
placeholder="https://nextcloud.tondomain.com"
|
||||
value="{{ settings.get('nc_url','') }}">
|
||||
<div class="form-text">Sans slash final.</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-semibold">Identifiant</label>
|
||||
<input type="text" name="nc_username" class="form-control"
|
||||
placeholder="ton_login"
|
||||
value="{{ settings.get('nc_username','') }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-semibold">Mot de passe d'application</label>
|
||||
<input type="password" name="nc_app_password" class="form-control"
|
||||
placeholder="••••••••••••"
|
||||
value="{{ settings.get('nc_app_password','') }}">
|
||||
<div class="form-text">Générer dans Nextcloud → Paramètres → Sécurité.</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-semibold">Dossier racine 3D</label>
|
||||
<input type="text" name="nc_root_path" class="form-control"
|
||||
placeholder="/Impressions3D"
|
||||
value="{{ settings.get('nc_root_path','/3D') }}">
|
||||
<div class="form-text">Chemin de base pour l'explorateur de fichiers.</div>
|
||||
</div>
|
||||
<div class="col-md-8 d-flex align-items-end">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="testNcBtn">
|
||||
<i class="bi bi-plug me-1"></i>Tester la connexion
|
||||
</button>
|
||||
<span id="testNcResult" class="ms-3 small"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- iCal -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header py-3"><i class="bi bi-calendar-check me-2"></i>Calendrier iCal — Abonnement Android / iOS</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-semibold">Token secret (optionnel)</label>
|
||||
<input type="text" name="ical_token" class="form-control font-monospace"
|
||||
placeholder="Laisser vide = pas de protection"
|
||||
value="{{ settings.get('ical_token','') }}">
|
||||
<div class="form-text">Si renseigné, l'URL contiendra <code>?token=xxx</code>.</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<label class="form-label fw-semibold">URL d'abonnement</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="icalUrl" class="form-control font-monospace small" readonly
|
||||
value="{{ request.host_url }}calendar.ics{% if settings.get('ical_token','') %}?token={{ settings.get('ical_token','') }}{% endif %}">
|
||||
<button class="btn btn-outline-secondary" type="button" id="copyIcal" title="Copier">
|
||||
<i class="bi bi-clipboard"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
Dans Google Calendar → Autres agendas → Depuis une URL.
|
||||
Samsung / iOS : Paramètres → Comptes → Ajouter → Calendrier.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
@@ -203,3 +280,31 @@
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.getElementById('copyIcal').addEventListener('click', function () {
|
||||
const url = document.getElementById('icalUrl').value;
|
||||
navigator.clipboard.writeText(url).then(() => {
|
||||
this.innerHTML = '<i class="bi bi-check text-success"></i>';
|
||||
setTimeout(() => { this.innerHTML = '<i class="bi bi-clipboard"></i>'; }, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('testNcBtn').addEventListener('click', async function () {
|
||||
const res = document.getElementById('testNcResult');
|
||||
res.textContent = 'Test en cours…';
|
||||
try {
|
||||
const r = await fetch('/api/nextcloud/browse');
|
||||
const d = await r.json();
|
||||
if (d.error) {
|
||||
res.innerHTML = `<span class="text-danger"><i class="bi bi-x-circle me-1"></i>${d.error}</span>`;
|
||||
} else {
|
||||
res.innerHTML = `<span class="text-success"><i class="bi bi-check-circle me-1"></i>Connexion OK — ${d.items.length} élément(s) dans ${d.path}</span>`;
|
||||
}
|
||||
} catch (e) {
|
||||
res.innerHTML = `<span class="text-danger"><i class="bi bi-x-circle me-1"></i>${e.message}</span>`;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user