dev: automated commit - 2025-06-16 09:37:04
This commit is contained in:
parent
682f25edcd
commit
d71a7e37c5
7 changed files with 1513 additions and 430 deletions
|
@ -1,11 +1,39 @@
|
|||
package templates
|
||||
|
||||
// IndexProps contains the properties for the Index component
|
||||
import "fmt"
|
||||
import "strings"
|
||||
|
||||
type IndexProps struct {
|
||||
Title string
|
||||
Title string
|
||||
IsConfigured bool
|
||||
CurrentIP string
|
||||
Config ConfigData
|
||||
Records []DNSRecord
|
||||
UpdateFreqs []UpdateFrequency
|
||||
}
|
||||
|
||||
type ConfigData struct {
|
||||
ZoneID string
|
||||
Domain string
|
||||
UpdatePeriod string
|
||||
ApiToken string
|
||||
}
|
||||
|
||||
type DNSRecord struct {
|
||||
ID string
|
||||
Type string
|
||||
Name string
|
||||
Content string
|
||||
TTL int
|
||||
Proxied bool
|
||||
CreatedOn string
|
||||
}
|
||||
|
||||
type UpdateFrequency struct {
|
||||
Label string
|
||||
Value string
|
||||
}
|
||||
|
||||
// Index is the main page component
|
||||
templ Index(props IndexProps) {
|
||||
@Layout(props.Title) {
|
||||
<div class="container">
|
||||
|
@ -15,122 +43,214 @@ templ Index(props IndexProps) {
|
|||
<h1>{ props.Title }</h1>
|
||||
<div class="current-ip d-flex align-items-center">
|
||||
<span class="me-2">Current IP:</span>
|
||||
<span id="current-ip" class="fw-bold"></span>
|
||||
<span id="current-ip" class="fw-bold">{ props.CurrentIP }</span>
|
||||
<button
|
||||
id="refresh-ip"
|
||||
class="btn btn-sm btn-outline-secondary ms-2"
|
||||
title="Refresh current IP"
|
||||
hx-get="/refresh-ip"
|
||||
hx-target="#current-ip"
|
||||
hx-indicator="#refresh-spinner"
|
||||
>
|
||||
<i class="bi bi-arrow-clockwise"></i>
|
||||
<span id="refresh-spinner" class="htmx-indicator spinner-border spinner-border-sm ms-1"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Configuration Warning -->
|
||||
<div
|
||||
id="config-warning"
|
||||
class="alert alert-warning config-warning"
|
||||
style="display: none"
|
||||
>
|
||||
<h4>Configuration Required</h4>
|
||||
<p>
|
||||
Please configure your Cloudflare API credentials to manage your
|
||||
DNS records.
|
||||
</p>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#configModal"
|
||||
>
|
||||
Configure Now
|
||||
</button>
|
||||
</div>
|
||||
<!-- Configuration Status -->
|
||||
<div id="config-status" class="card mb-4" style="display: none">
|
||||
<div
|
||||
class="card-header d-flex justify-content-between align-items-center"
|
||||
>
|
||||
<h5 class="mb-0">Configuration</h5>
|
||||
<button
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#configModal"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<strong>Domain:</strong> <span id="domain-name">mz.uy</span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<strong>Zone ID:</strong> <span id="zone-id"></span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<strong>IP Update Schedule:</strong>
|
||||
<span id="update-schedule"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- DNS Records Section -->
|
||||
<div id="dns-records-section" style="display: none">
|
||||
<div class="card">
|
||||
<div
|
||||
class="card-header d-flex justify-content-between align-items-center"
|
||||
>
|
||||
<h5 class="mb-0">DNS Records</h5>
|
||||
<div>
|
||||
<button
|
||||
id="update-all-records"
|
||||
class="btn btn-sm btn-success me-2"
|
||||
>
|
||||
<i class="bi bi-arrow-repeat"></i> Update All to Current IP
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#recordModal"
|
||||
>
|
||||
<i class="bi bi-plus-lg"></i> Add Record
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Name</th>
|
||||
<th>Content</th>
|
||||
<th>TTL</th>
|
||||
<th>Proxied</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="dns-records">
|
||||
<!-- DNS records will be inserted here -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Loading Indicator -->
|
||||
<div id="loading" class="text-center my-5">
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="mt-2">Loading...</p>
|
||||
</div>
|
||||
if !props.IsConfigured {
|
||||
@ConfigWarning()
|
||||
} else {
|
||||
@ConfigStatus(props.Config)
|
||||
@DNSRecordsSection(props.Records, props.CurrentIP)
|
||||
}
|
||||
@ConfigModal(props.Config, props.UpdateFreqs)
|
||||
@RecordModal(props.Config.Domain)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ConfigModal()
|
||||
@RecordModal()
|
||||
<!-- Toast container for notifications -->
|
||||
<div class="toast-container"></div>
|
||||
<script src="/assets/js/app.js"></script>
|
||||
}
|
||||
}
|
||||
|
||||
templ ConfigWarning() {
|
||||
<div class="alert alert-warning config-warning">
|
||||
<h4>Configuration Required</h4>
|
||||
<p>Please configure your Cloudflare API credentials to manage your DNS records.</p>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#configModal"
|
||||
>
|
||||
Configure Now
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ ConfigStatus(config ConfigData) {
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">Configuration</h5>
|
||||
<button
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#configModal"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<strong>Domain:</strong> <span>{ config.Domain }</span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<strong>Zone ID:</strong> <span>{ config.ZoneID }</span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<strong>IP Update Schedule:</strong>
|
||||
<span>{ formatUpdateSchedule(config.UpdatePeriod) }</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ DNSRecordsSection(records []DNSRecord, currentIP string) {
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">DNS Records</h5>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-sm btn-success me-2"
|
||||
hx-post="/update-all-records"
|
||||
hx-target="#dns-records-table"
|
||||
hx-confirm="Are you sure you want to update all A records to your current IP?"
|
||||
hx-indicator="#update-all-spinner"
|
||||
>
|
||||
<i class="bi bi-arrow-repeat"></i> Update All to Current IP
|
||||
<span id="update-all-spinner" class="htmx-indicator spinner-border spinner-border-sm ms-1"></span>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#recordModal"
|
||||
onclick="resetRecordForm()"
|
||||
>
|
||||
<i class="bi bi-plus-lg"></i> Add Record
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
@DNSRecordsTable(records, currentIP)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ DNSRecordsTable(records []DNSRecord, currentIP string) {
|
||||
<div id="dns-records-table" class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Name</th>
|
||||
<th>Content</th>
|
||||
<th>TTL</th>
|
||||
<th>Proxied</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
if len(records) == 0 {
|
||||
<tr>
|
||||
<td colspan="6" class="text-center">No DNS records found</td>
|
||||
</tr>
|
||||
} else {
|
||||
for _, record := range records {
|
||||
@DNSRecordRow(record, currentIP)
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ DNSRecordRow(record DNSRecord, currentIP string) {
|
||||
<tr>
|
||||
<td>{ record.Type }</td>
|
||||
<td>{ record.Name }</td>
|
||||
<td>
|
||||
{ record.Content }
|
||||
if record.Type == "A" {
|
||||
if record.Content == currentIP {
|
||||
<span class="badge bg-success update-badge">Current IP</span>
|
||||
} else {
|
||||
<span class="badge bg-warning update-badge">Outdated IP</span>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
if record.TTL == 1 {
|
||||
Auto
|
||||
} else {
|
||||
{ fmt.Sprintf("%ds", record.TTL) }
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
if record.Proxied {
|
||||
<i class="bi bi-check-lg text-success"></i>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-sm btn-outline-primary me-1"
|
||||
hx-get={ fmt.Sprintf("/edit-record/%s", record.ID) }
|
||||
hx-target="#record-modal-content"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#recordModal"
|
||||
>
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-outline-danger"
|
||||
hx-delete={ fmt.Sprintf("/records/%s", record.ID) }
|
||||
hx-target="closest tr"
|
||||
hx-swap="outerHTML"
|
||||
hx-confirm={ fmt.Sprintf("Are you sure you want to delete the record for \"%s\"?", record.Name) }
|
||||
>
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
// Helper function to format update schedule
|
||||
func formatUpdateSchedule(period string) string {
|
||||
switch period {
|
||||
case "*/1 * * * *":
|
||||
return "Every minute"
|
||||
case "*/5 * * * *":
|
||||
return "Every 5 minutes"
|
||||
case "*/30 * * * *":
|
||||
return "Every 30 minutes"
|
||||
case "0 * * * *":
|
||||
return "Hourly"
|
||||
case "0 */6 * * *":
|
||||
return "Every 6 hours"
|
||||
case "0 0 * * *":
|
||||
return "Daily"
|
||||
case "":
|
||||
return "Manual updates only"
|
||||
default:
|
||||
return period
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to extract subdomain name
|
||||
func getRecordName(fullName, domain string) string {
|
||||
if fullName == domain {
|
||||
return "@"
|
||||
}
|
||||
if strings.HasSuffix(fullName, "."+domain) {
|
||||
return fullName[:len(fullName)-len(domain)-1]
|
||||
}
|
||||
return fullName
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue