Skip to content

Conversation

@nfebe
Copy link
Contributor

@nfebe nfebe commented Jan 14, 2026

  • Add DNS section to sidebar navigation
  • Add DnsZonesView for PowerDNS zone/record management
  • Add DnsExternalView for external DNS providers
  • Add API clients for PowerDNS and external DNS providers
  • Add DNS store for state management
  • Add routes for /dns/zones and /dns/external

@sourceant
Copy link

sourceant bot commented Jan 14, 2026

Code Review Summary

✨ This pull request introduces comprehensive DNS management capabilities, including support for external DNS providers (like Cloudflare, AWS Route 53, DigitalOcean) and a self-hosted PowerDNS server. The changes involve new navigation links, routing definitions, API interfaces, a Pinia store for external DNS, and two new Vue components for the respective DNS management UIs. The implementation generally follows good Vue practices for state and component management.

🚀 Key Improvements

  • Introduction of external DNS provider integration, offering flexibility.
  • Ability to host an authoritative DNS server with PowerDNS directly on the infrastructure.
  • Well-structured Pinia store (dns.ts) for managing external DNS state and interactions.
  • Clear separation of concerns between external and internal DNS management UIs.

💡 Minor Suggestions

  • Improve clarity of 'Auto' TTL value in the external DNS record form.
  • Add input validation for TTL values in the PowerDNS record form to prevent invalid entries.
  • Consider a more dynamic approach for provider icons instead of hardcoded mappings.

🚨 Critical Issues

  • Significant duplication of CSS styles and common UI component structures across DnsExternalView.vue and DnsZonesView.vue which impacts maintainability and consistency.

Copy link

@sourceant sourceant bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review complete. See the overview comment for a summary.

if (!selectedProvider.value || !credentialsValid.value) return null;

loading.value = true;
error.value = "";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is good practice to clear previous errors at the beginning of an asynchronous action to prevent stale error messages from being displayed to the user if the new attempt fails silently or with a different error. This ensures the user always sees feedback relevant to their latest action.

Suggested change
error.value = "";
error.value = "";


loading.value = true;
error.value = "";

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to createRecord, clear any existing error messages before attempting an update operation to ensure the UI provides up-to-date feedback.

Suggested change
error.value = "";


loading.value = true;
error.value = "";

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure previous error messages are cleared before attempting a delete operation. This prevents confusion if a previous action failed and a new delete attempt is made.

Suggested change
error.value = "";

if (!dnsStore.selectedZone) return;

saving.value = true;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clear any existing error messages from the store before attempting to save a new or updated record. This ensures that only errors pertinent to the current save operation are displayed, improving user feedback.

Suggested change
dnsStore.error = "";
saving.value = true;

};

const handleCreateZone = async () => {
saving.value = true;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clear any existing error messages from the view before attempting to create a new DNS zone. This prevents displaying stale error feedback to the user.

Suggested change
saving.value = true;
error.value = "";
saving.value = true;

const handleSaveRecord = async () => {
if (!selectedZone.value) return;

saving.value = true;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clear any existing error messages from the view before attempting to save a new or updated DNS record. This prevents displaying stale error feedback to the user.

Suggested change
saving.value = true;
error.value = "";
saving.value = true;

Comment on lines +669 to +662

saving.value = true;
error.value = "";

try {
const contents = recordForm.value.content
.split("\n")
.map((c) => c.trim())
.filter((c) => c);

const rrset: PowerDNSRRSet = {
name: recordForm.value.name.endsWith(".")
? recordForm.value.name
: `${recordForm.value.name}.${selectedZone.value.name}`,
type: recordForm.value.type,
ttl: recordForm.value.ttl,
changetype: showEditRecordModal.value ? "REPLACE" : "REPLACE",
records: contents.map((content) => ({
content,
disabled: false,
})),
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PowerDNS API for updating records (updateRecords) expects MX and SRV record priorities to be part of the content string, not a separate field. Currently, the recordForm.priority value is captured but ignored when constructing the rrset for the API call, leading to a functional bug where priority is not applied. This correction ensures the priority is correctly formatted into the content string for these record types.

For example, an MX record content should be 10 mail.example.com, where 10 is the priority.

Suggested change
saving.value = true;
error.value = "";
try {
const contents = recordForm.value.content
.split("\n")
.map((c) => c.trim())
.filter((c) => c);
const rrset: PowerDNSRRSet = {
name: recordForm.value.name.endsWith(".")
? recordForm.value.name
: `${recordForm.value.name}.${selectedZone.value.name}`,
type: recordForm.value.type,
ttl: recordForm.value.ttl,
changetype: showEditRecordModal.value ? "REPLACE" : "REPLACE",
records: contents.map((content) => ({
content,
disabled: false,
})),
};
const formattedContents = contents.map((content) => {
if (['MX', 'SRV'].includes(recordForm.value.type) && recordForm.value.priority !== undefined && recordForm.value.priority !== null) {
return `${recordForm.value.priority} ${content}`;
}
return content;
});
const rrset: PowerDNSRRSet = {
name: recordForm.value.name.endsWith(".")
? recordForm.value.name
: `${recordForm.value.name}.${selectedZone.value.name}`,
type: recordForm.value.type,
ttl: recordForm.value.ttl,
changetype: "REPLACE",
records: formattedContents.map((content) => ({
content,
disabled: false,
})),
};

- Add DNS section to sidebar navigation
- Add DnsZonesView for PowerDNS zone/record management
- Add DnsExternalView for external DNS providers
- Add API clients for PowerDNS and external DNS providers
- Add DNS store for state management
- Add routes for /dns/zones and /dns/external

Signed-off-by: nfebe <fenn25.fn@gmail.com>
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jan 14, 2026

Deploying flatrun-ui with  Cloudflare Pages  Cloudflare Pages

Latest commit: 72e5a36
Status: ✅  Deploy successful!
Preview URL: https://e0c6f5bf.flatrun-ui.pages.dev
Branch Preview URL: https://feat-dns-ui.flatrun-ui.pages.dev

View logs

Copy link

@sourceant sourceant bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review complete. See the overview comment for a summary.

<div class="form-group">
<label for="record-ttl">TTL</label>
<select id="record-ttl" v-model.number="recordForm.ttl">
<option :value="1">Auto</option>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value 1 for the "Auto" TTL option might be ambiguous without clear documentation or API context. Consider using 0 if it's the standard for "automatic" TTL or providing a more descriptive label to clarify what "Auto" means in this context (e.g., "Managed by Provider"). Ensure the backend API correctly interprets this 'Auto' value.

Suggested change
<option :value="1">Auto</option>
<option :value="0">Auto (Managed by Provider)</option>

@flatrun flatrun deleted a comment from openhands-ai bot Jan 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants