@@ -21,6 +21,7 @@ import {
21
21
} from "@webstudio-is/icons" ;
22
22
import { CollapsibleDomainSection } from "./collapsible-domain-section" ;
23
23
import {
24
+ Fragment ,
24
25
startTransition ,
25
26
useEffect ,
26
27
useOptimistic ,
@@ -34,12 +35,13 @@ import { useStore } from "@nanostores/react";
34
35
import { $publisherHost } from "~/shared/nano-states" ;
35
36
import { extractCname } from "./cname" ;
36
37
import { useEffectEvent } from "~/shared/hook-utils/effect-event" ;
37
- import DomainCheckbox from "./domain-checkbox" ;
38
+ import { DomainCheckbox } from "./domain-checkbox" ;
38
39
import { CopyToClipboard } from "~/builder/shared/copy-to-clipboard" ;
39
40
import { RelativeTime } from "~/builder/shared/relative-time" ;
40
41
41
42
export type Domain = Project [ "domainsVirtual" ] [ number ] ;
42
- type DomainStatus = Project [ "domainsVirtual" ] [ number ] [ "status" ] ;
43
+
44
+ type DomainStatus = Domain [ "status" ] ;
43
45
44
46
const InputEllipsis = styled ( InputField , {
45
47
"&>input" : {
@@ -164,23 +166,28 @@ const StatusIcon = (props: { projectDomain: Domain; isLoading: boolean }) => {
164
166
) ;
165
167
} ;
166
168
167
- const DomainItem = ( props : {
169
+ const DomainItem = ( {
170
+ initiallyOpen,
171
+ projectDomain,
172
+ project,
173
+ refresh,
174
+ } : {
168
175
initiallyOpen : boolean ;
169
176
projectDomain : Domain ;
170
- refresh : ( ) => Promise < void > ;
171
177
project : Project ;
178
+ refresh : ( ) => Promise < void > ;
172
179
} ) => {
173
180
const timeSinceLastUpdateMs =
174
- Date . now ( ) - new Date ( props . projectDomain . updatedAt ) . getTime ( ) ;
181
+ Date . now ( ) - new Date ( projectDomain . updatedAt ) . getTime ( ) ;
175
182
176
183
const DAY_IN_MS = 24 * 60 * 60 * 1000 ;
177
184
178
- const status = props . projectDomain . verified
179
- ? ( `VERIFIED_${ props . projectDomain . status } ` as `VERIFIED_${DomainStatus } `)
185
+ const status = projectDomain . verified
186
+ ? ( `VERIFIED_${ projectDomain . status } ` as `VERIFIED_${DomainStatus } `)
180
187
: `UNVERIFIED` ;
181
188
182
189
const [ isStatusLoading , setIsStatusLoading ] = useState (
183
- props . initiallyOpen ||
190
+ initiallyOpen ||
184
191
status === "VERIFIED_ACTIVE" ||
185
192
timeSinceLastUpdateMs > DAY_IN_MS
186
193
? false
@@ -195,16 +202,16 @@ const DomainItem = (props: {
195
202
const handleRemoveDomain = async ( ) => {
196
203
setIsRemoveInProgress ( true ) ;
197
204
const result = await nativeClient . domain . remove . mutate ( {
198
- projectId : props . projectDomain . projectId ,
199
- domainId : props . projectDomain . domainId ,
205
+ projectId : projectDomain . projectId ,
206
+ domainId : projectDomain . domainId ,
200
207
} ) ;
201
208
202
209
if ( result . success === false ) {
203
210
toast . error ( result . error ) ;
204
211
return ;
205
212
}
206
213
207
- await props . refresh ( ) ;
214
+ await refresh ( ) ;
208
215
} ;
209
216
210
217
const [ verifyError , setVerifyError ] = useState < string | undefined > ( undefined ) ;
@@ -214,16 +221,16 @@ const DomainItem = (props: {
214
221
setIsCheckStateInProgress ( true ) ;
215
222
216
223
const verifyResult = await nativeClient . domain . verify . mutate ( {
217
- projectId : props . projectDomain . projectId ,
218
- domainId : props . projectDomain . domainId ,
224
+ projectId : projectDomain . projectId ,
225
+ domainId : projectDomain . domainId ,
219
226
} ) ;
220
227
221
228
if ( verifyResult . success === false ) {
222
229
setVerifyError ( verifyResult . error ) ;
223
230
return ;
224
231
}
225
232
226
- await props . refresh ( ) ;
233
+ await refresh ( ) ;
227
234
} ) ;
228
235
229
236
const [ updateStatusError , setUpdateStatusError ] = useState <
@@ -235,8 +242,8 @@ const DomainItem = (props: {
235
242
setIsCheckStateInProgress ( true ) ;
236
243
237
244
const updateStatusResult = await nativeClient . domain . updateStatus . mutate ( {
238
- projectId : props . projectDomain . projectId ,
239
- domain : props . projectDomain . domain ,
245
+ projectId : projectDomain . projectId ,
246
+ domain : projectDomain . domain ,
240
247
} ) ;
241
248
242
249
setIsStatusLoading ( false ) ;
@@ -246,7 +253,7 @@ const DomainItem = (props: {
246
253
return ;
247
254
}
248
255
249
- await props . refresh ( ) ;
256
+ await refresh ( ) ;
250
257
} ) ;
251
258
252
259
const onceRef = useRef ( false ) ;
@@ -272,67 +279,60 @@ const DomainItem = (props: {
272
279
} ) ;
273
280
} , [ status , handleVerify , handleUpdateStatus , isStatusLoading ] ) ;
274
281
275
- const publisherHost = useStore ( $publisherHost ) ;
276
- const cnameEntryName = extractCname ( props . projectDomain . domain ) ;
277
- const cnameEntryValue = `${ props . projectDomain . cname } .customers.${ publisherHost } ` ;
278
-
279
- const txtEntryName =
280
- cnameEntryName === "@"
281
- ? "_webstudio_is"
282
- : `_webstudio_is.${ cnameEntryName } ` ;
283
-
284
- const domainStatus = getStatus ( props . projectDomain ) ;
285
-
286
- const cnameRecord = {
287
- type : "CNAME" ,
288
- host : cnameEntryName ,
289
- value : cnameEntryValue ,
290
- ttl : 300 ,
291
- } as const ;
292
-
293
- const txtRecord = {
294
- type : "TXT" ,
295
- host : txtEntryName ,
296
- value : props . projectDomain . expectedTxtRecord ,
297
- ttl : 300 ,
298
- } as const ;
299
-
300
- const dnsRecords = [ cnameRecord , txtRecord ] ;
282
+ const domainStatus = getStatus ( projectDomain ) ;
301
283
302
284
const { isVerifiedActive, text } = getStatusText ( {
303
- projectDomain : props . projectDomain ,
285
+ projectDomain,
304
286
isLoading : false ,
305
287
} ) ;
306
288
289
+ const publisherHost = useStore ( $publisherHost ) ;
290
+ const cname = extractCname ( projectDomain . domain ) ;
291
+ const dnsRecords = [
292
+ {
293
+ type : "CNAME" ,
294
+ host : cname ,
295
+ value : `${ projectDomain . cname } .customers.${ publisherHost } ` ,
296
+ ttl : 300 ,
297
+ } as const ,
298
+ {
299
+ type : "TXT" ,
300
+ host : cname === "@" ? "_webstudio_is" : `_webstudio_is.${ cname } ` ,
301
+ value : projectDomain . expectedTxtRecord ,
302
+ ttl : 300 ,
303
+ } as const ,
304
+ ] ;
305
+
307
306
return (
308
307
< CollapsibleDomainSection
309
308
prefix = {
310
309
< DomainCheckbox
311
- buildId = { props . projectDomain . latestBuildVirtual ?. buildId }
310
+ buildId = { projectDomain . latestBuildVirtual ?. buildId }
312
311
defaultChecked = {
313
- props . projectDomain . latestBuildVirtual ?. buildId != null &&
314
- props . projectDomain . latestBuildVirtual ?. buildId ===
315
- props . project . latestBuildVirtual ?. buildId
312
+ projectDomain . latestBuildVirtual ?. buildId != null &&
313
+ projectDomain . latestBuildVirtual ?. buildId ===
314
+ project . latestBuildVirtual ?. buildId
316
315
}
317
- domain = { props . projectDomain . domain }
316
+ domain = { projectDomain . domain }
318
317
disabled = { domainStatus !== "VERIFIED_ACTIVE" }
319
318
/>
320
319
}
321
- initiallyOpen = { props . initiallyOpen }
322
- title = { props . projectDomain . domain }
320
+ initiallyOpen = { initiallyOpen }
321
+ title = { projectDomain . domain }
323
322
suffix = {
324
323
< Grid flow = "column" >
325
324
< StatusIcon
326
325
isLoading = { isStatusLoading }
327
- projectDomain = { props . projectDomain }
326
+ projectDomain = { projectDomain }
328
327
/>
329
328
330
- < Tooltip content = { `Proceed to ${ props . projectDomain . domain } ` } >
329
+ < Tooltip content = { `Proceed to ${ projectDomain . domain } ` } >
331
330
< IconButton
331
+ type = "button"
332
332
tabIndex = { - 1 }
333
333
disabled = { status !== "VERIFIED_ACTIVE" }
334
334
onClick = { ( event ) => {
335
- const url = new URL ( `https://${ props . projectDomain . domain } ` ) ;
335
+ const url = new URL ( `https://${ projectDomain . domain } ` ) ;
336
336
window . open ( url . href , "_blank" ) ;
337
337
event . preventDefault ( ) ;
338
338
} }
@@ -423,67 +423,45 @@ const DomainItem = (props: {
423
423
424
424
< Grid
425
425
gap = { 2 }
426
- css = { {
427
- gridTemplateColumns : `${ theme . spacing [ 18 ] } 1fr 1fr` ,
428
- } }
426
+ css = { { gridTemplateColumns : `${ theme . spacing [ 18 ] } 1fr 1fr` } }
429
427
>
430
- < Text color = "subtle" variant = { "titles" } >
428
+ < Text color = "subtle" variant = "titles" >
431
429
TYPE
432
430
</ Text >
433
- < Text color = "subtle" variant = { "titles" } >
431
+ < Text color = "subtle" variant = "titles" >
434
432
NAME
435
433
</ Text >
436
- < Text color = "subtle" variant = { "titles" } >
434
+ < Text color = "subtle" variant = "titles" >
437
435
VALUE
438
436
</ Text >
439
437
440
- < InputEllipsis readOnly value = "CNAME" />
441
- < InputEllipsis
442
- readOnly
443
- value = { cnameRecord . host }
444
- suffix = {
445
- < CopyToClipboard text = { cnameRecord . host } >
446
- < NestedInputButton type = "button" >
447
- < CopyIcon />
448
- </ NestedInputButton >
449
- </ CopyToClipboard >
450
- }
451
- />
452
- < InputEllipsis
453
- readOnly
454
- value = { cnameRecord . value }
455
- suffix = {
456
- < CopyToClipboard text = { cnameRecord . value } >
457
- < NestedInputButton type = "button" >
458
- < CopyIcon />
459
- </ NestedInputButton >
460
- </ CopyToClipboard >
461
- }
462
- />
463
-
464
- < InputEllipsis readOnly value = "TXT" />
465
- < InputEllipsis
466
- readOnly
467
- value = { txtRecord . host }
468
- suffix = {
469
- < CopyToClipboard text = { txtRecord . host } >
470
- < NestedInputButton type = "button" >
471
- < CopyIcon />
472
- </ NestedInputButton >
473
- </ CopyToClipboard >
474
- }
475
- />
476
- < InputEllipsis
477
- readOnly
478
- value = { txtRecord . value }
479
- suffix = {
480
- < CopyToClipboard text = { txtRecord . value } >
481
- < NestedInputButton type = "button" >
482
- < CopyIcon />
483
- </ NestedInputButton >
484
- </ CopyToClipboard >
485
- }
486
- />
438
+ { dnsRecords . map ( ( record , index ) => (
439
+ < Fragment key = { index } >
440
+ < InputEllipsis readOnly value = { record . type } />
441
+ < InputEllipsis
442
+ readOnly
443
+ value = { record . host }
444
+ suffix = {
445
+ < CopyToClipboard text = { record . host } >
446
+ < NestedInputButton type = "button" >
447
+ < CopyIcon />
448
+ </ NestedInputButton >
449
+ </ CopyToClipboard >
450
+ }
451
+ />
452
+ < InputEllipsis
453
+ readOnly
454
+ value = { record . value }
455
+ suffix = {
456
+ < CopyToClipboard text = { record . value } >
457
+ < NestedInputButton type = "button" >
458
+ < CopyIcon />
459
+ </ NestedInputButton >
460
+ </ CopyToClipboard >
461
+ }
462
+ />
463
+ </ Fragment >
464
+ ) ) }
487
465
</ Grid >
488
466
489
467
< Grid
@@ -500,7 +478,7 @@ const DomainItem = (props: {
500
478
501
479
< Entri
502
480
dnsRecords = { dnsRecords }
503
- domain = { props . projectDomain . domain }
481
+ domain = { projectDomain . domain }
504
482
onClose = { ( ) => {
505
483
// Sometimes Entri modal dialog hangs even if it's successful,
506
484
// until they fix that, we'll just refresh the status here on every onClose event
0 commit comments