DNS ui changes (#4417)

* DNS ui changes
This commit is contained in:
Neal Shah authored and GitHub committed 2026-10-30 21:16:25 -04:00
1 parent 4881264c88
commit 2a3c181657
5 files changed
+74 -10

No files matched your search

+11 -3
View File
@@ -39,11 +39,11 @@ Why the domain isn't active yet, when that's known.
The DNS records to set at the domain's DNS provider. Each record is an object with these attributes:
- `type` (String): `CNAME` or `TXT`.
- `type` (String): `CNAME`, `TXT` or `A`.
- `name` (String): the record's name.
- `value` (String): the record's value.
- `purpose` (String): `routing` for the record that sends traffic to the website, `ownership` for the record that proves the user owns the domain, or `certificate` for a record that speeds up issuing the HTTPS certificate.
- `required` (Boolean): `true` for the `routing` and `ownership` records, which the user has to set. A `certificate` record is optional.
- `purpose` (String): `routing` for the record that sends traffic to the website, `ownership` for the record that proves the user owns the domain, `certificate` for a record that speeds up issuing the HTTPS certificate, or `redirect` for the `A` record that forwards a root domain to its `www.` hostname.
- `required` (Boolean): `true` for the `routing`, `ownership` and `redirect` records, which the user has to set. A `certificate` record is optional.
#### `createdAt` (Number)
@@ -52,3 +52,11 @@ When the domain was added, in milliseconds since the Unix epoch.
#### `activatedAt` (Number | null)
When the domain became active, in milliseconds since the Unix epoch, or `null` if it isn't active.
#### `dnsProvider` (String, optional)
Who hosts the DNS of a root domain: `route53`, `godaddy` or `other`. Puter looks this up when a root domain is added, and only includes it in that response. Route 53 and GoDaddy can't point a root domain at another host name, so a root domain on either is added as its `www.` hostname (see `redirectFrom`).
#### `redirectFrom` (String, optional)
The root domain that forwards to this `www.` hostname. A root domain hosted on Route 53 or GoDaddy is added as its `www.` hostname, and the user can switch any other root domain to `www.` in the dialog. The `records` then include an `A` record that forwards the root domain.
+42 -4
View File
@@ -136,7 +136,9 @@ async function UIWindowAttachCustomDomain (options) {
<thead><tr><th>${i18n('custom_domain_record_type')}</th><th>${i18n('name')}</th><th>${i18n('custom_domain_record_value')}</th></tr></thead>
<tbody></tbody>
</table>
<p class="app-feedback-note custom-domain-redirect" style="display:none;"></p>
<p class="app-feedback-note custom-domain-apex" style="display:none;">${i18n('custom_domain_apex_hint')}</p>
<button type="button" class="app-feedback-btn custom-domain-use-www" style="display:none;">${i18n('custom_domain_no_root_alias')}</button>
<p class="app-feedback-error" role="alert" style="display:none;"></p>
<div class="app-feedback-actions">
<button type="button" class="app-feedback-btn custom-domain-check">${i18n('custom_domain_check_status')}</button>
@@ -371,7 +373,12 @@ async function UIWindowAttachCustomDomain (options) {
if ( domain.statusDetail && domain.status !== 'active' ) {
$status.append($('<span class="custom-domain-status-detail"></span>').text(domain.statusDetail));
}
const $redirect = $overlay.find('.custom-domain-redirect').toggle(!!domain.redirectFrom);
if ( domain.redirectFrom ) {
$redirect.html(i18n('custom_domain_redirect_note', [domain.redirectFrom, domain.hostname]));
}
$overlay.find('.custom-domain-apex').toggle(domain.isApex === true);
$overlay.find('.custom-domain-use-www').toggle(domain.isApex === true && domain.status !== 'active');
const $tbody = $overlay.find('.custom-domain-records tbody').empty();
for ( const record of domain.records ?? [] ) {
@@ -382,9 +389,12 @@ async function UIWindowAttachCustomDomain (options) {
<td><code class="custom-domain-copy"></code></td>
</tr>
`);
const type = domain.isApex && record.purpose === 'routing'
? text('custom_domain_record_type_apex')
: record.type;
$tr.find('.custom-domain-record-type').text(record.required
? record.type
: `${record.type} ${i18n('custom_domain_optional', [], false)}`);
? type
: `${type} ${text('custom_domain_optional')}`);
const [$name, $value] = $tr.find('code').toArray().map((el) => $(el));
$name.text(record.name);
$value.text(record.value);
@@ -405,8 +415,17 @@ async function UIWindowAttachCustomDomain (options) {
return;
}
// A domain that is no longer pending comes back with only its
// routing record; keep the full set shown when it was added.
chosen = { ...res.data, records: res.data.records?.length > 1 ? res.data.records : chosen.records };
// routing record, and a GET never repeats the provider or the
// redirect; keep what was shown when it was added.
const redirect = chosen.records.filter((r) => r.purpose === 'redirect');
const fresh = (res.data.records?.length > 1 ? res.data.records : chosen.records)
.filter((r) => r.purpose !== 'redirect');
chosen = {
...res.data,
dnsProvider: chosen.dnsProvider,
redirectFrom: chosen.redirectFrom,
records: [...fresh.slice(0, 1), ...redirect, ...fresh.slice(1)],
};
renderRecords(chosen);
} catch ( e ) {
console.error('custom-domain: status check failed', e);
@@ -415,6 +434,25 @@ async function UIWindowAttachCustomDomain (options) {
setBusy(false);
}
});
// Same row, so the month already paid covers the www hostname.
$overlay.find('.custom-domain-use-www').on('click', async () => {
if ( busy || ! chosen ) return;
setBusy(true);
try {
const res = await api('POST', `/${encodeURIComponent(chosen.uuid)}/use-www`);
if ( ! res.ok ) {
showError('records', errorFor(res));
return;
}
chosen = res.data;
renderRecords(chosen);
} catch ( e ) {
console.error('custom-domain: switch to www failed', e);
showError('records', text('custom_domain_error_generic'));
} finally {
setBusy(false);
}
});
$overlay.find('.custom-domain-done').on('click', () => {
if ( ! busy ) close();
});
+10
View File
@@ -2124,6 +2124,16 @@ input.myapps-group-name:focus {
border-top: 1px solid var(--afb-border);
vertical-align: top;
}
.custom-domain-redirect strong {
color: var(--afb-fg);
word-break: break-all;
}
.custom-domain-use-www {
display: block;
width: 100%;
margin-top: 10px;
font-size: 13px;
}
.custom-domain-copy {
display: block;
word-break: break-all;
+4 -1
View File
@@ -160,7 +160,7 @@ const en = {
current_password: 'Current Password',
custom_domain_add: 'Add Domain',
custom_domain_add_new: 'Add a New Domain',
custom_domain_apex_hint: 'This is a root domain. Your DNS provider needs to support CNAME flattening, ALIAS, or ANAME records for it. If it doesn\'t, connect www instead and forward the root domain to it.',
custom_domain_apex_hint: 'This is a root domain, so your DNS provider needs to support a CNAME, ALIAS or ANAME record at the root (sometimes called CNAME flattening).',
custom_domain_claim_c2a: 'Someone else added this domain but never connected it. If it\'s yours, add this record at your DNS provider, then verify. The domain moves to your account.',
custom_domain_claim_not_found: 'The record isn\'t visible yet. DNS changes can take a few minutes; try again shortly.',
custom_domain_check_status: 'Check Status',
@@ -181,7 +181,10 @@ const en = {
custom_domain_none_yet: 'You don\'t have any custom domains yet.',
custom_domain_optional: '(optional)',
custom_domain_price_note: 'Each domain costs %% per month. example.com and www.example.com count as two domains.',
custom_domain_no_root_alias: 'My DNS provider doesn\'t support CNAME, ALIAS or ANAME at the root',
custom_domain_record_type: 'Type',
custom_domain_record_type_apex: 'CNAME / ALIAS / ANAME',
custom_domain_redirect_note: 'Your website is served on %strong%. The A record forwards visitors from %strong% to it.',
custom_domain_record_value: 'Value',
custom_domain_records_c2a: 'Add these records at your DNS provider. The domain starts working a few minutes after they\'re in place.',
custom_domain_requested_by: 'Requested by %strong%',
+7 -2
View File
@@ -15,10 +15,11 @@
* A DNS record the user sets at their DNS provider for a custom domain.
*
* @typedef {Object} CustomDomainRecord
* @property {'CNAME' | 'TXT'} type Record type.
* @property {'CNAME' | 'TXT' | 'A'} type Record type.
* @property {string} name Record name (host).
* @property {string} value Record value.
* @property {'routing' | 'ownership' | 'certificate'} purpose What the record is for.
* @property {'routing' | 'ownership' | 'certificate' | 'redirect'} purpose What the record is
* for. `redirect` is the A record that forwards a root domain to its `www.` hostname.
* @property {boolean} required `true` for records the user has to set (routing and
* ownership); certificate records only speed issuance up.
*/
@@ -38,6 +39,10 @@
* @property {CustomDomainRecord[]} records DNS records to set.
* @property {number} createdAt When the domain was added, in milliseconds since the epoch.
* @property {number | null} activatedAt When the domain went active, if it has.
* @property {'route53' | 'godaddy' | 'other'} [dnsProvider] Who hosts the DNS of a root
* domain, when Puter looked it up while adding it.
* @property {string} [redirectFrom] The root domain forwarded to this `www.` hostname, when
* the root domain couldn't be served directly.
*/
export {};