import { nanoid } from 'nanoid' import { useEffect, useState } from 'react' import { type Subscription } from 'rxjs' import { Box, Button, Card, Container, Dialog, Flex, Grid, Spinner, Stack, studioTheme, Switch, Text, TextInput, ThemeProvider, ToastProvider, useToast, } from '@sanity/ui' import { FormField, useColorScheme } from 'sanity' import DeployItem from './deploy-item' import { useClient } from './hook/useClient' import type { SanityDeploySchema } from './types' import deployIcon from './netlify-icon' const initialDeploy = { name: '', siteId: '', buildHook: '', branch: '', accessToken: '', onlyShowProductionDeploys: true, disableDeleteAction: false, } const NetlifyDeploy = () => { const WEBHOOK_TYPE = 'webhook_deploy' const WEBHOOK_QUERY = `*[_type == "${WEBHOOK_TYPE}"] | order(_createdAt)` const client = useClient() const { scheme } = useColorScheme() const [isLoading, setIsLoading] = useState(true) const [isSubmitting, setIsSubmitting] = useState(false) const [isFormOpen, setIsFormOpen] = useState(false) const [deploys, setDeploys] = useState([]) const [pendingDeploy, setpendingDeploy] = useState(initialDeploy) const toast = useToast() const onSubmit = async () => { client .create({ // Explicitly define an _id inside the netlify path to make sure it's not publicly accessible // This will protect users' tokens & project info. Read more: https://www.sanity.io/docs/ids _id: `netlify.${nanoid()}`, _type: WEBHOOK_TYPE, name: pendingDeploy.name, siteId: pendingDeploy.siteId, buildHook: pendingDeploy.buildHook, branch: pendingDeploy.branch, accessToken: pendingDeploy.accessToken, onlyShowProductionDeploys: pendingDeploy.onlyShowProductionDeploys, disableDeleteAction: pendingDeploy.disableDeleteAction, }) .then(() => { toast.push({ status: 'success', title: 'Success!', description: `Created Deployment: ${pendingDeploy.name}`, }) setIsFormOpen(false) setIsSubmitting(false) setpendingDeploy(initialDeploy) // Reset the pending webhook state }) } // Fetch all existing webhooks and listen for newly created useEffect(() => { let webhookSubscription: Subscription client.fetch(WEBHOOK_QUERY).then((w) => { setDeploys(w) setIsLoading(false) webhookSubscription = client .listen(WEBHOOK_QUERY, {}, { includeResult: true }) .subscribe({ next: (res) => { if (res.type === 'mutation') { const wasCreated = res.mutations.some((item) => Object.prototype.hasOwnProperty.call(item, 'create') ) const wasPatched = res.mutations.some((item) => Object.prototype.hasOwnProperty.call(item, 'patch') ) const wasDeleted = res.mutations.some((item) => Object.prototype.hasOwnProperty.call(item, 'delete') ) const filterDeploy = (deploy: SanityDeploySchema) => deploy._id !== res.documentId const updateDeploy = (deploy: SanityDeploySchema) => deploy._id === res.documentId ? (res.result as SanityDeploySchema) : deploy if (wasCreated) { setDeploys((prevState) => { if (res.result) { return [...prevState, res.result] } return prevState }) } if (wasPatched) { setDeploys((prevState) => { const updatedDeploys = prevState.map(updateDeploy) return updatedDeploys }) } if (wasDeleted) { setDeploys((prevState) => prevState.filter(filterDeploy)) } } }, }) }) return () => { if (webhookSubscription) { webhookSubscription.unsubscribe() } } }, [WEBHOOK_QUERY, client]) return ( {deployIcon()} Netlify Deployments