-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add DNS management UI #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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
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
💡 Minor Suggestions
🚨 Critical Issues
|
There was a problem hiding this 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 = ""; |
There was a problem hiding this comment.
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.
| error.value = ""; | |
| error.value = ""; |
|
|
||
| loading.value = true; | ||
| error.value = ""; | ||
|
|
There was a problem hiding this comment.
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.
| error.value = ""; |
|
|
||
| loading.value = true; | ||
| error.value = ""; | ||
|
|
There was a problem hiding this comment.
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.
| error.value = ""; |
| if (!dnsStore.selectedZone) return; | ||
|
|
||
| saving.value = true; | ||
|
|
There was a problem hiding this comment.
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.
| dnsStore.error = ""; | |
| saving.value = true; |
| }; | ||
|
|
||
| const handleCreateZone = async () => { | ||
| saving.value = true; |
There was a problem hiding this comment.
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.
| saving.value = true; | |
| error.value = ""; | |
| saving.value = true; |
| const handleSaveRecord = async () => { | ||
| if (!selectedZone.value) return; | ||
|
|
||
| saving.value = true; |
There was a problem hiding this comment.
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.
| saving.value = true; | |
| error.value = ""; | |
| saving.value = true; |
|
|
||
| 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, | ||
| })), | ||
| }; |
There was a problem hiding this comment.
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.
| 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>
Deploying flatrun-ui with
|
| 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 |
There was a problem hiding this 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> |
There was a problem hiding this comment.
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.
| <option :value="1">Auto</option> | |
| <option :value="0">Auto (Managed by Provider)</option> |