Added token modal after creating site

This commit is contained in:
2026-04-06 18:22:25 +02:00
parent 38fcdbf391
commit a95c76ce7e
3 changed files with 114 additions and 5 deletions
@@ -24,7 +24,7 @@ func NewUpdateSiteHandler(envCfg *envconfig.EnvConfig, siteRepo repository.SiteR
return &UpdateSiteHandler{EnvCfg: envCfg, SiteRepo: siteRepo}
}
func (h *UpdateSiteHandler) PostUpdate(c fiber.Ctx) error {
func (h *UpdateSiteHandler) PostDeploy(c fiber.Ctx) error {
siteId := c.Query("site")
if siteId == "" {
return c.Status(400).JSON(models.APIError{
+1 -1
View File
@@ -24,7 +24,7 @@ func Register(app *fiber.App, cfg *config.Config, envCfg *envconfig.EnvConfig, d
api := app.Group("/api/v1", middleware.APIHostGuard(envCfg.DashboardHost))
api.Get("/health", handlers.HealthCheck)
api.Post("/update", updateSiteHandler.PostUpdate)
api.Post("/deploy", updateSiteHandler.PostDeploy)
api.Get("/sites", siteHandler.GetSites)
api.Get("/sites/:id", siteHandler.GetSite)
+112 -3
View File
@@ -6,9 +6,18 @@ import { Button } from '@/components/ui/button';
import { Switch } from '@/components/ui/switch';
import { Separator } from '@/components/ui/separator';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Plus, Zap } from 'lucide-react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Plus, Zap, Copy, Check, AlertTriangle } from 'lucide-react';
import { cn } from '@/lib/utils';
import { useCreateSite } from '../../hooks/api/useCreateSite';
import { useNavigate } from 'react-router';
const GIT_SERVERS = [
{
@@ -55,6 +64,7 @@ const parseRepoUrl = (url: string) => {
};
const NewSite = () => {
const navigate = useNavigate();
const [name, setName] = useState('');
const [repoUrl, setRepoUrl] = useState('');
const [gitServer, setGitServer] = useState('');
@@ -64,6 +74,11 @@ const NewSite = () => {
const [domain, setDomain] = useState('');
const [spa, setSpa] = useState(false);
const [urlError, setUrlError] = useState('');
const [showTokenModal, setShowTokenModal] = useState(false);
const [deployToken, setDeployToken] = useState('');
const [createdSiteId, setCreatedSiteId] = useState('');
const [copiedToken, setCopiedToken] = useState(false);
const [copiedCurl, setCopiedCurl] = useState(false);
const createNewSite = useCreateSite();
const handleQuickImport = () => {
@@ -90,7 +105,6 @@ const NewSite = () => {
};
const handleSubmit = async () => {
console.log({ name, gitServer, owner, repository, branch, domain, spa });
const data = await createNewSite.mutateAsync({
name,
git_server: gitServer,
@@ -103,9 +117,32 @@ const NewSite = () => {
not_found_file: '',
index_file: '',
});
console.log('Created site:', data);
setCreatedSiteId(data.site.id);
setDeployToken(data.raw_deploy_token);
setShowTokenModal(true);
};
const handleCopy = async (text: string, type: 'token' | 'curl') => {
await navigator.clipboard.writeText(text);
if (type === 'token') {
setCopiedToken(true);
setTimeout(() => setCopiedToken(false), 2000);
} else {
setCopiedCurl(true);
setTimeout(() => setCopiedCurl(false), 2000);
}
};
const handleModalClose = () => {
setShowTokenModal(false);
navigate(`/sites/${createdSiteId}`);
};
const curlExample = `curl -X POST \\
"${window.location.origin}/api/v1/deploy?site=${createdSiteId}" \\
-H "Authorization: Bearer ${deployToken}"`;
const isValid = name && gitServer && owner && repository && branch && domain;
return (
@@ -278,6 +315,78 @@ const NewSite = () => {
</div>
</div>
</div>
<Dialog open={showTokenModal} onOpenChange={setShowTokenModal}>
<DialogContent
className="sm:max-w-lg"
onInteractOutside={(e) => e.preventDefault()}
>
<DialogHeader>
<DialogTitle className="text-lg">Site Created Successfully</DialogTitle>
<DialogDescription>
Your site has been created. Use the deploy token below to trigger
deployments via the API.
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="flex items-start gap-2 rounded-lg border border-amber-500/30 bg-amber-500/10 p-3">
<AlertTriangle className="w-4 h-4 text-amber-500 mt-0.5 shrink-0" />
<p className="text-sm text-amber-500">
Make sure to copy your deploy token now. You won't be able to see it
again.
</p>
</div>
<div className="space-y-2">
<Label>Deploy Token</Label>
<div className="flex gap-2">
<Input readOnly value={deployToken} className="font-mono text-sm" />
<Button
variant="outline"
size="icon"
onClick={() => handleCopy(deployToken, 'token')}
>
{copiedToken ? (
<Check className="w-4 h-4 text-success" />
) : (
<Copy className="w-4 h-4" />
)}
</Button>
</div>
</div>
<div className="space-y-2">
<Label>Usage</Label>
<p className="text-sm text-muted-foreground">
Trigger a deployment by sending a POST request to the deploy
endpoint with your token in the Authorization header:
</p>
<div className="relative">
<pre className="rounded-lg border bg-muted p-3 text-sm font-mono overflow-x-auto whitespace-pre-wrap break-all">
{curlExample}
</pre>
<Button
variant="ghost"
size="icon"
className="absolute top-2 right-2 h-7 w-7"
onClick={() => handleCopy(curlExample, 'curl')}
>
{copiedCurl ? (
<Check className="w-3.5 h-3.5 text-success" />
) : (
<Copy className="w-3.5 h-3.5" />
)}
</Button>
</div>
</div>
</div>
<DialogFooter>
<Button onClick={handleModalClose}>I've saved my token</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</Page>
);
};