Skip to content

Commit 16656c4

Browse files
authored
Support editing the subdomain to point to the latest release using the tag (#2796)
* Support for tag * fake data * find the is_latest
1 parent ae08353 commit 16656c4

6 files changed

Lines changed: 138 additions & 10 deletions

File tree

fake-snippets-api/lib/db/seed.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2381,6 +2381,12 @@ exports.TestComponent = TestComponent;
23812381
transpilation_error: null,
23822382
})
23832383

2384+
db.addPackageDomain({
2385+
points_to: "package_release",
2386+
package_release_id: glbModelReleaseId,
2387+
fully_qualified_domain_name: "custom-3d-model.tscircuit.app",
2388+
})
2389+
23842390
// Update the package to link to the release
23852391
db.updatePackage(glbModelPackage.package_id, {
23862392
latest_package_release_id: glbModelReleaseId,

fake-snippets-api/routes/api/package_domains/update.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ export default withRouteSpec({
1010
package_domain_id: z.string(),
1111
default_main_component_path: z.string().nullable().optional(),
1212
fully_qualified_domain_name: z.string().nullable().optional(),
13+
points_to: z
14+
.enum([
15+
"package_release",
16+
"package_build",
17+
"package_release_with_tag",
18+
"package",
19+
])
20+
.optional(),
21+
package_release_id: z.string().optional(),
22+
package_build_id: z.string().optional(),
23+
package_id: z.string().optional(),
24+
tag: z.string().optional(),
1325
}),
1426
jsonResponse: z.object({
1527
ok: z.boolean(),
@@ -20,6 +32,11 @@ export default withRouteSpec({
2032
package_domain_id,
2133
default_main_component_path,
2234
fully_qualified_domain_name,
35+
points_to,
36+
package_release_id,
37+
package_build_id,
38+
package_id,
39+
tag,
2340
} = req.jsonBody
2441

2542
const existingDomain = ctx.db.getPackageDomainById(package_domain_id)
@@ -51,6 +68,70 @@ export default withRouteSpec({
5168
}
5269
}
5370

71+
// Validate the points_to constraint if points_to is being updated
72+
if (points_to !== undefined) {
73+
if (points_to === "package_release") {
74+
if (!package_release_id) {
75+
return ctx.error(400, {
76+
error_code: "missing_package_release_id",
77+
message:
78+
"package_release_id is required when points_to is 'package_release'",
79+
})
80+
}
81+
if (package_build_id || tag || package_id) {
82+
return ctx.error(400, {
83+
error_code: "invalid_params",
84+
message:
85+
"package_build_id, tag, and package_id must not be provided when points_to is 'package_release'",
86+
})
87+
}
88+
} else if (points_to === "package_build") {
89+
if (!package_build_id) {
90+
return ctx.error(400, {
91+
error_code: "missing_package_build_id",
92+
message:
93+
"package_build_id is required when points_to is 'package_build'",
94+
})
95+
}
96+
if (package_release_id || tag || package_id) {
97+
return ctx.error(400, {
98+
error_code: "invalid_params",
99+
message:
100+
"package_release_id, tag, and package_id must not be provided when points_to is 'package_build'",
101+
})
102+
}
103+
} else if (points_to === "package_release_with_tag") {
104+
if (!package_release_id || !tag) {
105+
return ctx.error(400, {
106+
error_code: "missing_params",
107+
message:
108+
"package_release_id and tag are required when points_to is 'package_release_with_tag'",
109+
})
110+
}
111+
if (package_build_id || package_id) {
112+
return ctx.error(400, {
113+
error_code: "invalid_params",
114+
message:
115+
"package_build_id and package_id must not be provided when points_to is 'package_release_with_tag'",
116+
})
117+
}
118+
} else if (points_to === "package") {
119+
if (!package_id) {
120+
return ctx.error(400, {
121+
error_code: "missing_package_id",
122+
message: "package_id is required when points_to is 'package'",
123+
})
124+
}
125+
if (package_release_id || package_build_id || tag) {
126+
return ctx.error(400, {
127+
error_code: "invalid_params",
128+
message:
129+
"package_release_id, package_build_id, and tag must not be provided when points_to is 'package'",
130+
})
131+
}
132+
}
133+
}
134+
54135
const updateValues: Record<string, unknown> = {}
55136

56137
if (default_main_component_path !== undefined) {
@@ -61,6 +142,15 @@ export default withRouteSpec({
61142
updateValues.fully_qualified_domain_name = fully_qualified_domain_name
62143
}
63144

145+
if (points_to !== undefined) {
146+
updateValues.points_to = points_to
147+
// Clear all pointer fields and set the appropriate ones
148+
updateValues.package_release_id = package_release_id ?? null
149+
updateValues.package_build_id = package_build_id ?? null
150+
updateValues.package_id = package_id ?? null
151+
updateValues.tag = tag ?? null
152+
}
153+
64154
if (Object.keys(updateValues).length === 0) {
65155
return ctx.json({
66156
ok: true,

src/components/dialogs/edit-subdomain-dialog.tsx

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,31 @@ export const EditSubdomainDialog = ({
3737
packageId,
3838
currentPointsTo,
3939
currentPackageReleaseId,
40+
currentTag,
4041
}: {
4142
open: boolean
4243
onOpenChange: (open: boolean) => void
4344
packageDomainId: string
4445
currentFqdn: string
4546
targetInfo?: { badgeLabel: string; description: string } | null
4647
packageId?: string | null
47-
currentPointsTo?: "package" | "package_release" | string | null
48+
currentPointsTo?:
49+
| "package"
50+
| "package_release"
51+
| "package_release_with_tag"
52+
| string
53+
| null
4854
currentPackageReleaseId?: string | null
55+
currentTag?: string | null
4956
}) => {
5057
const [subdomain, setSubdomain] = useState(extractSubdomain(currentFqdn))
58+
const isCurrentlyLatest =
59+
currentPointsTo === "package" ||
60+
(currentPointsTo === "package_release_with_tag" && currentTag === "latest")
5161
const [targetType, setTargetType] = useState<"latest" | "release">(
52-
currentPointsTo === "package_release" ? "release" : "latest",
62+
isCurrentlyLatest || currentPointsTo !== "package_release"
63+
? "latest"
64+
: "release",
5365
)
5466
const [selectedReleaseId, setSelectedReleaseId] = useState(
5567
currentPackageReleaseId || "",
@@ -59,16 +71,23 @@ export const EditSubdomainDialog = ({
5971
const { data: releases = [] } = usePackageReleasesByPackageId(
6072
packageId ?? null,
6173
)
74+
const latestRelease = releases.find((r) => r.is_latest) ?? releases[0]
6275

6376
useEffect(() => {
6477
if (open) {
6578
setSubdomain(extractSubdomain(currentFqdn))
79+
const isLatest =
80+
currentPointsTo === "package" ||
81+
(currentPointsTo === "package_release_with_tag" &&
82+
currentTag === "latest")
6683
setTargetType(
67-
currentPointsTo === "package_release" ? "release" : "latest",
84+
!isLatest && currentPointsTo === "package_release"
85+
? "release"
86+
: "latest",
6887
)
6988
setSelectedReleaseId(currentPackageReleaseId || "")
7089
}
71-
}, [open, currentFqdn, currentPointsTo, currentPackageReleaseId])
90+
}, [open, currentFqdn, currentPointsTo, currentPackageReleaseId, currentTag])
7291

7392
const releaseOptions = useMemo(
7493
() =>
@@ -91,13 +110,18 @@ export const EditSubdomainDialog = ({
91110
const domainChanged = newFqdn !== currentFqdn
92111
const targetChanged =
93112
targetType === "latest"
94-
? currentPointsTo !== "package"
113+
? !(
114+
currentPointsTo === "package_release_with_tag" &&
115+
currentTag === "latest"
116+
)
95117
: currentPointsTo !== "package_release" ||
96118
currentPackageReleaseId !== selectedReleaseId
97119

98120
const hasChanged = domainChanged || targetChanged
99121
const isDomainValid = normalizedSubdomain.length > 0
100-
const isTargetValid = targetType === "latest" || Boolean(selectedReleaseId)
122+
const isTargetValid =
123+
(targetType === "latest" && Boolean(latestRelease)) ||
124+
(targetType === "release" && Boolean(selectedReleaseId))
101125

102126
const handleSave = () => {
103127
if (!isDomainValid || !isTargetValid || !hasChanged) return
@@ -108,9 +132,9 @@ export const EditSubdomainDialog = ({
108132
fully_qualified_domain_name: newFqdn,
109133
...(targetType === "latest"
110134
? {
111-
points_to: "package" as const,
112-
package_id: packageId || null,
113-
package_release_id: null,
135+
points_to: "package_release_with_tag" as const,
136+
tag: "latest",
137+
package_release_id: latestRelease?.package_release_id ?? null,
114138
}
115139
: {
116140
points_to: "package_release" as const,

src/components/package-settings/PackageDomainsList.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ export function PackageDomainsList({
172172
packageId={packageId}
173173
currentPointsTo={editingDomain.points_to}
174174
currentPackageReleaseId={editingDomain.package_release_id}
175+
currentTag={editingDomain.tag}
175176
/>
176177
)}
177178

src/components/preview/ReleaseDeploymentDetails.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ export function ReleaseDeploymentDetails({
459459
packageId={pkg.package_id}
460460
currentPointsTo={editingDomain.points_to}
461461
currentPackageReleaseId={editingDomain.package_release_id}
462+
currentTag={editingDomain.tag}
462463
/>
463464
)}
464465
</div>

src/hooks/use-package-domains.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,15 @@ export const useUpdatePackageDomain = () => {
156156
mutationFn: async (params: {
157157
package_domain_id: string
158158
fully_qualified_domain_name?: string | null
159-
points_to?: "package_release" | "package"
159+
points_to?:
160+
| "package_release"
161+
| "package_build"
162+
| "package_release_with_tag"
163+
| "package"
160164
package_release_id?: string | null
165+
package_build_id?: string | null
161166
package_id?: string | null
167+
tag?: string | null
162168
}) => {
163169
const { data } = await axios.post("/package_domains/update", params)
164170
return data.package_domain as PublicPackageDomain

0 commit comments

Comments
 (0)