import React, {useEffect, useMemo, useState} from 'react' import {Box, Card, Stack, Heading, Grid, Label, Text, Code, Button} from '@sanity/ui' import {useVersionedClient} from '../../versionedClient' import {Subscription} from 'rxjs' import {WidgetContainer} from '../../containers/WidgetContainer' import {DashboardWidgetContainer} from '../../components/DashboardWidgetContainer' import {type DashboardWidget} from '../../types' import {type App, type ProjectInfoProps, type ProjectData, UserApplication} from './types' function isUrl(url?: string) { return url && /^https?:\/\//.test(`${url}`) } function getGraphQLUrl(projectId: string, dataset: string) { return `https://${projectId}.api.sanity.io/v1/graphql/${dataset}/default` } function getGroqUrl(projectId: string, dataset: string) { return `https://${projectId}.api.sanity.io/v1/groq/${dataset}` } function getManageUrl(projectId: string) { return `https://manage.sanity.io/projects/${projectId}` } const NO_EXPERIMENTAL: DashboardWidget[] = [] const NO_DATA: ProjectData[] = [] export function ProjectInfo(props: ProjectInfoProps) { const {__experimental_before = NO_EXPERIMENTAL, data = NO_DATA} = props const [studioApps, setStudioApps] = useState() const [graphQLApi, setGraphQLApi] = useState() const versionedClient = useVersionedClient() const {projectId = 'unknown', dataset = 'unknown'} = versionedClient.config() useEffect(() => { const subscriptions: Subscription[] = [] subscriptions.push( versionedClient.observable .request({uri: '/user-applications', tag: 'dashboard.project-info'}) .subscribe({ next: (result) => setStudioApps(result.filter((app) => app.type === 'studio')), error: (error) => { console.error('Error while resolving user applications', error) setStudioApps({ error: 'Something went wrong while resolving user applications. See console.', }) }, }), ) // ping assumed graphql endpoint subscriptions.push( versionedClient.observable .request({ method: 'HEAD', uri: `/graphql/${dataset}/default`, tag: 'dashboard.project-info.graphql-api', }) .subscribe({ next: () => setGraphQLApi(getGraphQLUrl(projectId, dataset)), error: (error) => { if (error.statusCode === 404) { setGraphQLApi(undefined) } else { console.error('Error while looking for graphQLApi', error) setGraphQLApi({ error: 'Something went wrong while looking up graphQLApi. See console.', }) } }, }), ) return () => { subscriptions.forEach((s) => s.unsubscribe()) } }, [dataset, projectId, versionedClient, setGraphQLApi]) const assembleTableRows = useMemo(() => { let result: App[] = [ { title: 'Sanity project', rows: [ {title: 'Project ID', value: projectId}, {title: 'Dataset', value: dataset}, ], }, ] const apps: App[] = data.filter((item) => item.category === 'apps') // Handle studios ;(Array.isArray(studioApps) ? studioApps : []).forEach((app) => { apps.push({ title: app.title || 'Studio', value: app.urlType === 'internal' ? `https://${app.appHost}.sanity.studio` : app.appHost, }) }) if (apps.length > 0) { result = result.concat([{title: 'Apps', rows: apps}]) } // Handle APIs result = result.concat( [ { title: 'APIs', rows: [ {title: 'GROQ', value: getGroqUrl(projectId, dataset)}, { title: 'GraphQL', value: (typeof graphQLApi === 'object' ? 'Error' : graphQLApi) ?? 'Not deployed', }, ], }, ], data.filter((item) => item.category === 'apis'), ) // Handle whatever else there might be const otherStuff: Record = {} data.forEach((item) => { if (item.category && item.category !== 'apps' && item.category !== 'apis') { if (!otherStuff[item.category]) { otherStuff[item.category] = [] } otherStuff[item.category].push(item) } }) Object.keys(otherStuff).forEach((category) => { result.push({title: category, rows: otherStuff[category]}) }) return result }, [graphQLApi, studioApps, projectId, dataset, data]) return ( <> {__experimental_before.map((widgetConfig, idx) => ( ))} 0 ? 4 : 0}> } > Project info {assembleTableRows.map((item) => { if (!item || !item.rows) { return null } return ( {item.rows.map((row) => { return ( {row.title} {typeof row.value === 'object' && ( {row.value?.error} )} {typeof row.value === 'string' && ( <> {isUrl(row.value) ? ( {row.value} ) : ( {row.value} )} )} ) })} ) })} ) }