the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add loading state to context menu modals

+30 -6
+8 -2
apps/web/src/components/contextmenu/AddEnvironmentVariableModal/AddEnvironmentVariableModal.tsx
··· 1 - import { useEffect } from "react"; 1 + import { useEffect, useState } from "react"; 2 2 import { createPortal } from "react-dom"; 3 3 import { useForm } from "react-hook-form"; 4 4 import { z } from "zod"; ··· 23 23 onClose, 24 24 sandboxId, 25 25 }: AddEnvironmentVariableModalProps) { 26 + const [isLoading, setIsLoading] = useState(false); 26 27 const { mutateAsync } = useAddVariableMutation(); 27 28 const { 28 29 register, ··· 63 64 }; 64 65 65 66 const onSubmit = async (data: FormValues) => { 67 + setIsLoading(true); 66 68 await mutateAsync({ 67 69 sandboxId, 68 70 name: data.name, 69 71 value: data.value, 70 72 }); 73 + setIsLoading(false); 71 74 reset(); 72 75 onClose(); 73 76 }; ··· 149 152 <div className="modal-footer"> 150 153 <button 151 154 type="submit" 152 - className="btn btn-primary w-35 font-semibold" 155 + className="btn btn-primary w-45 font-semibold" 153 156 > 157 + {isLoading && ( 158 + <span className="loading loading-spinner loading-xs mr-1.5"></span> 159 + )} 154 160 Add Variable 155 161 </button> 156 162 </div>
+8 -2
apps/web/src/components/contextmenu/AddFileModal/AddFileModal.tsx
··· 1 - import { useEffect } from "react"; 1 + import { useEffect, useState } from "react"; 2 2 import { createPortal } from "react-dom"; 3 3 import { useForm } from "react-hook-form"; 4 4 import { z } from "zod"; ··· 19 19 }; 20 20 21 21 function AddFileModal({ isOpen, onClose, sandboxId }: AddFileModalProps) { 22 + const [isLoading, setIsLoading] = useState(false); 22 23 const { mutateAsync } = useAddFileMutation(); 23 24 const { 24 25 register, ··· 59 60 }; 60 61 61 62 const onSubmit = async (data: FormValues) => { 63 + setIsLoading(true); 62 64 await mutateAsync({ 63 65 sandboxId, 64 66 path: data.path, 65 67 content: data.content, 66 68 }); 69 + setIsLoading(false); 67 70 reset(); 68 71 onClose(); 69 72 }; ··· 143 146 <div className="modal-footer"> 144 147 <button 145 148 type="submit" 146 - className="btn btn-primary w-35 font-semibold" 149 + className="btn btn-primary w-36 font-semibold" 147 150 > 151 + {isLoading && ( 152 + <span className="loading loading-spinner loading-xs mr-1.5"></span> 153 + )} 148 154 Add File 149 155 </button> 150 156 </div>
+7 -1
apps/web/src/components/contextmenu/AddSecretModal/AddSecretModal.tsx
··· 1 - import { useEffect } from "react"; 1 + import { useEffect, useState } from "react"; 2 2 import { createPortal } from "react-dom"; 3 3 import { useForm } from "react-hook-form"; 4 4 import { z } from "zod"; ··· 19 19 }; 20 20 21 21 function AddSecretModal({ isOpen, onClose, sandboxId }: AddSecretModalProps) { 22 + const [isLoading, setIsLoading] = useState(false); 22 23 const { mutateAsync } = useAddSecretMutation(); 23 24 const { 24 25 register, ··· 59 60 }; 60 61 61 62 const onSubmit = async (data: FormValues) => { 63 + setIsLoading(true); 62 64 await mutateAsync({ 63 65 sandboxId, 64 66 name: data.name, 65 67 value: data.value, 66 68 }); 69 + setIsLoading(false); 67 70 reset(); 68 71 onClose(); 69 72 }; ··· 144 147 </div> 145 148 <div className="modal-footer"> 146 149 <button type="submit" className="btn btn-primary"> 150 + {isLoading && ( 151 + <span className="loading loading-spinner loading-xs mr-1.5"></span> 152 + )} 147 153 Add Secret 148 154 </button> 149 155 </div>
+7 -1
apps/web/src/components/contextmenu/AddVolumeModal/AddVolumeModal.tsx
··· 1 - import { useEffect } from "react"; 1 + import { useEffect, useState } from "react"; 2 2 import { createPortal } from "react-dom"; 3 3 import { useForm } from "react-hook-form"; 4 4 import { z } from "zod"; ··· 19 19 }; 20 20 21 21 function AddVolumeModal({ isOpen, onClose, sandboxId }: AddVolumeModalProps) { 22 + const [isLoading, setIsLoading] = useState(false); 22 23 const { mutateAsync } = useAddVolumeMutation(); 23 24 const { 24 25 register, ··· 59 60 }; 60 61 61 62 const onSubmit = async (data: FormValues) => { 63 + setIsLoading(true); 62 64 await mutateAsync({ 63 65 sandboxId, 64 66 name: data.name, 65 67 path: data.path, 66 68 }); 69 + setIsLoading(false); 67 70 reset(); 68 71 onClose(); 69 72 }; ··· 150 153 </div> 151 154 <div className="modal-footer"> 152 155 <button type="submit" className="btn btn-primary font-semibold"> 156 + {isLoading && ( 157 + <span className="loading loading-spinner loading-xs mr-1.5"></span> 158 + )} 153 159 Add Volume 154 160 </button> 155 161 </div>