Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions packages/host/app/components/operator-mode/publish-realm-modal.gts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import {
import { not } from '@cardstack/boxel-ui/helpers';
import { IconX, Warning as WarningIcon } from '@cardstack/boxel-ui/icons';

import { ensureTrailingSlash } from '@cardstack/runtime-common';
import { getPublishedRealmDomainOverrides } from '@cardstack/runtime-common/constants';

import ModalContainer from '@cardstack/host/components/modal-container';
import PrivateDependencyViolationComponent from '@cardstack/host/components/operator-mode/private-dependency-violation';
import WithLoadedRealm from '@cardstack/host/components/with-loaded-realm';
Expand Down Expand Up @@ -221,6 +224,65 @@ export default class PublishRealmModal extends Component<Signature> {
return config.publishedRealmBoxelSiteDomain;
}

// TODO: Remove with CS-9061 once published realm domain overrides are removed.
private getPublishedRealmOverrideUrl(
publishedRealmURL: string | null,
): string | null {
let overrideDomain = getPublishedRealmDomainOverrides(
config.publishedRealmDomainOverrides,
)[ensureTrailingSlash(this.currentRealmURL)];
if (!overrideDomain) {
return null;
}

if (!publishedRealmURL) {
return null;
}

let overriddenURL = new URL(publishedRealmURL);
overriddenURL.host = overrideDomain;
Comment on lines +242 to +243

Choose a reason for hiding this comment

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

P2 Badge Parse override host before assigning to URL.host

The override value is fed directly into URL.host, but overrides can come from env JSON and the server-side parser explicitly accepts full URLs (e.g. https://whitepaper.boxel.ai). If the override includes a scheme, overriddenURL.host = overrideDomain produces a malformed URL like https://https/, which then shows a broken URL in the modal and causes publish requests to fail for those overrides. Consider parsing/normalizing the override string to hostname/port (or stripping scheme) before assigning it to host.

Useful? React with 👍 / 👎.

return ensureTrailingSlash(overriddenURL.toString());
}

get customSubdomainOverrideUrl() {
let publishedRealmURL =
this.claimedDomainPublishedUrl ??
this.buildPublishedRealmUrl(
`${this.customSubdomainDisplay}.${this.customSubdomainBase}`,
);
return this.getPublishedRealmOverrideUrl(publishedRealmURL);
}

get shouldShowCustomSubdomainOverride() {
return (
!!this.customSubdomainOverrideUrl &&
this.realm.canWrite(this.currentRealmURL)
);
}

get isCustomSubdomainOverrideSelected() {
if (!this.customSubdomainOverrideUrl) {
return false;
}
return this.selectedPublishedRealmURLs.includes(
this.customSubdomainOverrideUrl,
);
}

get isCustomSubdomainOverridePublished() {
if (!this.customSubdomainOverrideUrl) {
return false;
}
return this.hostModeService.isPublished(this.customSubdomainOverrideUrl);
}

get customSubdomainOverrideLastPublishedTime() {
if (!this.customSubdomainOverrideUrl) {
return null;
}
return this.getFormattedLastPublishedTime(this.customSubdomainOverrideUrl);
}

get customSubdomainDisplay() {
if (this.claimedDomain) {
return this.claimedDomain.subdomain;
Expand Down Expand Up @@ -458,6 +520,20 @@ export default class PublishRealmModal extends Component<Signature> {
}
}

@action
toggleCustomSubdomainOverride(event: Event) {
const overrideUrl = this.customSubdomainOverrideUrl;
if (!overrideUrl) {
return;
}
const input = event.target as HTMLInputElement;
if (input.checked) {
this.addPublishedRealmUrl(overrideUrl);
} else {
this.removePublishedRealmUrl(overrideUrl);
}
}

private addPublishedRealmUrl(url: string) {
if (!this.selectedPublishedRealmURLs.includes(url)) {
this.selectedPublishedRealmURLs = [
Expand Down Expand Up @@ -619,6 +695,13 @@ export default class PublishRealmModal extends Component<Signature> {
return this.getPublishErrorForUrl(this.claimedDomainPublishedUrl);
}

get publishErrorForCustomSubdomainOverride() {
if (!this.customSubdomainOverrideUrl) {
return null;
}
return this.getPublishErrorForUrl(this.customSubdomainOverrideUrl);
}

ensureInitialSelectionsTask = restartableTask(
async (claim: ClaimedDomain | null = null) => {
await this.realm.ensureRealmMeta(this.currentRealmURL);
Expand Down Expand Up @@ -1027,6 +1110,99 @@ export default class PublishRealmModal extends Component<Signature> {
</div>
{{/if}}
</div>

{{#if this.shouldShowCustomSubdomainOverride}}
{{#let this.customSubdomainOverrideUrl as |overrideUrl|}}
{{#if overrideUrl}}
<div class='domain-option'>
<input
type='checkbox'
id='custom-subdomain-override-checkbox'
class='domain-checkbox'
checked={{this.isCustomSubdomainOverrideSelected}}
{{on 'change' this.toggleCustomSubdomainOverride}}
data-test-custom-subdomain-override-checkbox
disabled={{this.isUnpublishingAnyRealms}}
/>
<label
class='option-title'
for='custom-subdomain-override-checkbox'
>Custom Domain Override</label>
<div class='domain-details'>
<WithLoadedRealm
@realmURL={{this.currentRealmURL}}
as |realm|
>
<RealmIcon @realmInfo={{realm.info}} class='realm-icon' />
</WithLoadedRealm>
<div class='domain-url-container'>
<span class='domain-url'>{{overrideUrl}}</span>
{{#if this.isCustomSubdomainOverridePublished}}
<div class='domain-info'>
{{#if this.customSubdomainOverrideLastPublishedTime}}
<span class='last-published-at'>Published
{{this.customSubdomainOverrideLastPublishedTime}}</span>
{{/if}}
<BoxelButton
@kind='text-only'
@size='extra-small'
@disabled={{this.isUnpublishingRealm overrideUrl}}
class='unpublish-button'
{{on 'click' (fn @handleUnpublish overrideUrl)}}
data-test-unpublish-custom-subdomain-override-button
>
{{#if (this.isUnpublishingRealm overrideUrl)}}
<LoadingIndicator />
Unpublishing…
{{else}}
<Undo2
width='11'
height='11'
class='unpublish-icon'
/>
Unpublish
{{/if}}
</BoxelButton>
</div>
{{else}}
<span class='not-published-yet'>Not published yet</span>
{{/if}}
</div>
</div>
{{#if this.isCustomSubdomainOverridePublished}}
<BoxelButton
@as='anchor'
@kind='secondary-light'
@size='small'
@href={{overrideUrl}}
@disabled={{this.isUnpublishingAnyRealms}}
class='action'
target='_blank'
rel='noopener noreferrer'
data-test-open-custom-subdomain-override-button
>
<ExternalLink
width='16'
height='16'
class='button-icon'
/>
Open Site
</BoxelButton>
{{/if}}
{{#if this.publishErrorForCustomSubdomainOverride}}
<div
class='domain-publish-error'
data-test-domain-publish-error={{overrideUrl}}
>
<span
class='error-text'
>{{this.publishErrorForCustomSubdomainOverride}}</span>
</div>
{{/if}}
</div>
{{/if}}
{{/let}}
{{/if}}
</div>
</:content>

Expand Down
1 change: 1 addition & 0 deletions packages/host/app/config/environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ declare const config: {
};
publishedRealmBoxelSpaceDomain: string;
publishedRealmBoxelSiteDomain: string;
publishedRealmDomainOverrides: string;
defaultSystemCardId: string;
cardSizeLimitBytes: number;
};
Loading