11import { conform , useForm } from "@conform-to/react" ;
22import { parse } from "@conform-to/zod" ;
3- import { BeakerIcon , StarIcon , RectangleStackIcon , TrashIcon } from "@heroicons/react/20/solid" ;
3+ import {
4+ BeakerIcon ,
5+ StarIcon ,
6+ RectangleStackIcon ,
7+ TrashIcon ,
8+ CheckCircleIcon ,
9+ } from "@heroicons/react/20/solid" ;
10+ import { AnimatePresence , motion } from "framer-motion" ;
411import { type ActionFunction , type LoaderFunctionArgs , json } from "@remix-run/server-runtime" ;
512import { useCallback , useEffect , useRef , useState , useMemo } from "react" ;
613import { typedjson , useTypedLoaderData } from "remix-typedjson" ;
@@ -355,6 +362,8 @@ function StandardTaskForm({
355362 paused : q . paused ,
356363 } ) ) ;
357364
365+ const [ showTemplateCreatedSuccessMessage , setShowTemplateCreatedSuccessMessage ] = useState ( false ) ;
366+
358367 const fetcher = useFetcher ( ) ;
359368 const [
360369 form ,
@@ -426,6 +435,7 @@ function StandardTaskForm({
426435 setTagsValue ( template . tags ?? [ ] ) ;
427436 setQueueValue ( template . queue ) ;
428437 } }
438+ showTemplateCreatedSuccessMessage = { showTemplateCreatedSuccessMessage }
429439 />
430440 < RecentRunsPopover
431441 runs = { runs }
@@ -741,6 +751,7 @@ function StandardTaskForm({
741751 } }
742752 getCurrentPayload = { ( ) => currentPayloadJson . current }
743753 getCurrentMetadata = { ( ) => currentMetadataJson . current }
754+ setShowCreatedSuccessMessage = { setShowTemplateCreatedSuccessMessage }
744755 />
745756 < Button
746757 type = "submit"
@@ -804,6 +815,8 @@ function ScheduledTaskForm({
804815 ) ;
805816 const [ tagsValue , setTagsValue ] = useState < string [ ] > ( lastRun ?. runTags ?? [ ] ) ;
806817
818+ const [ showTemplateCreatedSuccessMessage , setShowTemplateCreatedSuccessMessage ] = useState ( false ) ;
819+
807820 const queueItems = queues . map ( ( q ) => ( {
808821 value : q . type === "task" ? `task/${ q . name } ` : q . name ,
809822 label : q . name ,
@@ -888,6 +901,7 @@ function ScheduledTaskForm({
888901 setExternalIdValue ( template . scheduledTaskPayload ?. externalId ) ;
889902 setTimezoneValue ( template . scheduledTaskPayload ?. timezone ?? "UTC" ) ;
890903 } }
904+ showTemplateCreatedSuccessMessage = { showTemplateCreatedSuccessMessage }
891905 />
892906 < RecentRunsPopover
893907 runs = { runs }
@@ -1243,6 +1257,7 @@ function ScheduledTaskForm({
12431257 } }
12441258 getCurrentPayload = { ( ) => "" }
12451259 getCurrentMetadata = { ( ) => "" }
1260+ setShowCreatedSuccessMessage = { setShowTemplateCreatedSuccessMessage }
12461261 />
12471262 < Button
12481263 type = "submit"
@@ -1315,9 +1330,11 @@ function RecentRunsPopover<T extends StandardRun | ScheduledRun>({
13151330function RunTemplatesPopover ( {
13161331 templates,
13171332 onTemplateSelected,
1333+ showTemplateCreatedSuccessMessage,
13181334} : {
13191335 templates : RunTemplate [ ] ;
13201336 onTemplateSelected : ( run : RunTemplate ) => void ;
1337+ showTemplateCreatedSuccessMessage : boolean ;
13211338} ) {
13221339 const [ isPopoverOpen , setIsPopoverOpen ] = useState ( false ) ;
13231340 const [ isDeleteDialogOpen , setIsDeleteDialogOpen ] = useState ( false ) ;
@@ -1346,28 +1363,17 @@ function RunTemplatesPopover({
13461363 } ) ;
13471364
13481365 return (
1349- < >
1366+ < div className = "relative" >
13501367 < Popover open = { isPopoverOpen } onOpenChange = { setIsPopoverOpen } >
13511368 < PopoverTrigger asChild >
1352- { templates . length === 0 ? (
1353- < SimpleTooltip
1354- button = {
1355- < Button
1356- type = "button"
1357- variant = "tertiary/small"
1358- LeadingIcon = { StarIcon }
1359- disabled = { true }
1360- >
1361- Templates
1362- </ Button >
1363- }
1364- content = "No templates yet"
1365- />
1366- ) : (
1367- < Button type = "button" variant = "tertiary/small" LeadingIcon = { StarIcon } >
1368- Templates
1369- </ Button >
1370- ) }
1369+ < Button
1370+ type = "button"
1371+ variant = "tertiary/small"
1372+ LeadingIcon = { StarIcon }
1373+ disabled = { templates . length === 0 }
1374+ >
1375+ Templates
1376+ </ Button >
13711377 </ PopoverTrigger >
13721378 < PopoverContent className = "min-w-[279px] p-0" align = "end" sideOffset = { 6 } >
13731379 < div className = "max-h-80 overflow-y-auto" >
@@ -1417,6 +1423,43 @@ function RunTemplatesPopover({
14171423 </ PopoverContent >
14181424 </ Popover >
14191425
1426+ < AnimatePresence mode = "wait" >
1427+ { showTemplateCreatedSuccessMessage && (
1428+ < motion . div
1429+ key = "template-success-message"
1430+ initial = { {
1431+ opacity : 0 ,
1432+ scale : 0.8 ,
1433+ y : - 10 ,
1434+ } }
1435+ animate = { {
1436+ opacity : 1 ,
1437+ scale : 1 ,
1438+ y : 0 ,
1439+ } }
1440+ exit = { {
1441+ opacity : 0 ,
1442+ scale : 0.7 ,
1443+ y : - 10 ,
1444+ transition : {
1445+ duration : 0.15 ,
1446+ ease : "easeOut" ,
1447+ } ,
1448+ } }
1449+ transition = { {
1450+ type : "spring" ,
1451+ stiffness : 400 ,
1452+ damping : 25 ,
1453+ duration : 0.15 ,
1454+ } }
1455+ className = "absolute -left-1/2 top-full z-10 mt-1 flex min-w-max max-w-64 items-center gap-1 rounded border border-charcoal-700 bg-background-bright px-2 py-1 text-xs shadow-md outline-none before:absolute before:-top-2 before:left-1/2 before:-translate-x-1/2 before:border-4 before:border-transparent before:border-b-charcoal-700 before:content-[''] after:absolute after:-top-[7px] after:left-1/2 after:-translate-x-1/2 after:border-4 after:border-transparent after:border-b-background-bright after:content-['']"
1456+ >
1457+ < CheckCircleIcon className = "h-4 w-4 shrink-0 text-success" /> Template created
1458+ successfully
1459+ </ motion . div >
1460+ ) }
1461+ </ AnimatePresence >
1462+
14201463 < Dialog open = { isDeleteDialogOpen } onOpenChange = { setIsDeleteDialogOpen } >
14211464 < DialogContent className = "sm:max-w-sm" >
14221465 < DialogHeader > Delete template</ DialogHeader >
@@ -1444,14 +1487,15 @@ function RunTemplatesPopover({
14441487 </ div >
14451488 </ DialogContent >
14461489 </ Dialog >
1447- </ >
1490+ </ div >
14481491 ) ;
14491492}
14501493
14511494function CreateTemplateModal ( {
14521495 rawTestTaskFormData,
14531496 getCurrentPayload,
14541497 getCurrentMetadata,
1498+ setShowCreatedSuccessMessage,
14551499} : {
14561500 rawTestTaskFormData : {
14571501 environmentId : string ;
@@ -1472,6 +1516,7 @@ function CreateTemplateModal({
14721516 } ;
14731517 getCurrentPayload : ( ) => string ;
14741518 getCurrentMetadata : ( ) => string ;
1519+ setShowCreatedSuccessMessage : ( value : boolean ) => void ;
14751520} ) {
14761521 const submit = useSubmit ( ) ;
14771522 const [ isModalOpen , setIsModalOpen ] = useState ( false ) ;
@@ -1488,14 +1533,10 @@ function CreateTemplateModal({
14881533 lastSubmission . success === true
14891534 ) {
14901535 setIsModalOpen ( false ) ;
1491- toast . custom (
1492- ( t ) => (
1493- < ToastUI variant = "success" message = "Template created successfully" t = { t as string } />
1494- ) ,
1495- {
1496- duration : 2000 ,
1497- }
1498- ) ;
1536+ setShowCreatedSuccessMessage ( true ) ;
1537+ setTimeout ( ( ) => {
1538+ setShowCreatedSuccessMessage ( false ) ;
1539+ } , 2000 ) ;
14991540 }
15001541 } , [ lastSubmission ] ) ;
15011542
0 commit comments