diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 846b4b48e..b4ec0cff5 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -199,7 +199,8 @@ module.exports = { tailwindcss: { callees: tailwindCallees, config: 'packages/web/app/tailwind.config.cjs', - whitelist: ['drag-none', 'graphiql-toolbar-icon', 'graphiql-toolbar-button'], + whitelist: ['drag-none'], + cssFiles: ['packages/web/app/src/index.css', 'node_modules/graphiql/dist/style.css'], }, }, }, diff --git a/package.json b/package.json index 7ef556a8a..b77d6d74e 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "slonik@30.4.4": "patches/slonik@30.4.4.patch", "@oclif/core@3.26.6": "patches/@oclif__core@3.26.6.patch", "oclif@4.13.6": "patches/oclif@4.13.6.patch", - "graphiql@3.3.2": "patches/graphiql@3.3.0.patch" + "@graphiql/react@1.0.0-alpha.3": "patches/@graphiql__react@1.0.0-alpha.3.patch" } } } diff --git a/packages/web/app/package.json b/packages/web/app/package.json index e3bbede18..65096de65 100644 --- a/packages/web/app/package.json +++ b/packages/web/app/package.json @@ -17,7 +17,7 @@ "@fastify/cors": "9.0.1", "@fastify/static": "7.0.4", "@fastify/vite": "6.0.7", - "@graphiql/react": "0.22.4", + "@graphiql/react": "1.0.0-alpha.3", "@graphiql/toolkit": "0.9.1", "@graphql-codegen/client-preset-swc-plugin": "0.2.0", "@graphql-tools/mock": "9.0.4", @@ -88,7 +88,7 @@ "fastify": "4.28.1", "formik": "2.4.6", "framer-motion": "11.3.28", - "graphiql": "3.3.2", + "graphiql": "4.0.0-alpha.4", "graphql": "16.9.0", "graphql-sse": "2.5.3", "immer": "10.1.1", diff --git a/packages/web/app/src/components/target/laboratory/create-operation-modal.tsx b/packages/web/app/src/components/target/laboratory/create-operation-modal.tsx index a5ca31cc7..3a1ceed5d 100644 --- a/packages/web/app/src/components/target/laboratory/create-operation-modal.tsx +++ b/packages/web/app/src/components/target/laboratory/create-operation-modal.tsx @@ -22,8 +22,10 @@ import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'; import { useToast } from '@/components/ui/use-toast'; import { graphql } from '@/gql'; -import { DocumentCollection } from '@/gql/graphql'; -import { useCollections } from '@/pages/target-laboratory'; +import { + DocumentCollectionOperation, + useCollections, +} from '@/lib/hooks/laboratory/use-collections'; import { useEditorContext } from '@graphiql/react'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -88,7 +90,7 @@ export type CreateOperationModalFormValues = z.infer void; - onSaveSuccess?: (operationId?: string) => void; + onSaveSuccess: (args: { id: string; name: string }) => void; organizationId: string; projectId: string; targetId: string; @@ -139,7 +141,10 @@ export function CreateOperationModal(props: { const error = response.error || response.data?.createOperationInDocumentCollection.error; if (!error) { - onSaveSuccess?.(result?.createOperationInDocumentCollection.ok?.operation.id); + const operation = result?.createOperationInDocumentCollection.ok?.operation; + if (operation) { + onSaveSuccess({ id: operation.id, name: operation.name }); + } form.reset(); close(); } else { @@ -166,11 +171,6 @@ export function CreateOperationModal(props: { ); } -type DocumentCollectionWithOutOperations = Omit< - DocumentCollection, - 'createdBy' | 'createdAt' | 'updatedAt' | 'operations' | 'pageInfo' ->; - export function CreateOperationModalContent(props: { isOpen: boolean; close: () => void; @@ -180,7 +180,7 @@ export function CreateOperationModalContent(props: { form: UseFormReturn; targetId: string; fetching: boolean; - collections: DocumentCollectionWithOutOperations[]; + collections: DocumentCollectionOperation[]; }): ReactElement { return ( @@ -195,52 +195,43 @@ export function CreateOperationModalContent(props: { { - return ( - - Operation Name - - - - - - ); - }} + render={({ field }) => ( + + Operation Name + + + + + + )} /> { - return ( - - Collection Description - - - - - - ); - }} + render={({ field }) => ( + + Collection Description + + + + + + )} /> diff --git a/packages/web/app/src/components/target/laboratory/edit-operation-modal.tsx b/packages/web/app/src/components/target/laboratory/edit-operation-modal.tsx index cca66c6da..79fe5f823 100644 --- a/packages/web/app/src/components/target/laboratory/edit-operation-modal.tsx +++ b/packages/web/app/src/components/target/laboratory/edit-operation-modal.tsx @@ -21,8 +21,9 @@ import { import { Input } from '@/components/ui/input'; import { useToast } from '@/components/ui/use-toast'; import { graphql } from '@/gql'; +import { useCollections } from '@/lib/hooks/laboratory/use-collections'; +import { useEditorContext } from '@graphiql/react'; import { zodResolver } from '@hookform/resolvers/zod'; -import { useCollections } from '../../../pages/target-laboratory'; const UpdateOperationNameMutation = graphql(` mutation UpdateOperation( @@ -78,6 +79,7 @@ export const EditOperationModal = (props: { projectId: props.projectId, targetId: props.targetId, }); + const { setTabState } = useEditorContext({ nonNull: true }); const [collection, operation] = useMemo(() => { for (const collection of collections) { @@ -115,6 +117,13 @@ export const EditOperationModal = (props: { const error = response.error || response.data?.updateOperationInDocumentCollection?.error; if (!error) { + // Update tab title + setTabState(state => ({ + ...state, + tabs: state.tabs.map(tab => + tab.id === props.operationId ? { ...tab, title: values.name } : tab, + ), + })); props.close(); toast({ title: 'Operation Updated', diff --git a/packages/web/app/src/index.css b/packages/web/app/src/index.css index 18106cb05..1ffe949cf 100644 --- a/packages/web/app/src/index.css +++ b/packages/web/app/src/index.css @@ -199,3 +199,7 @@ -webkit-appearance: none; } } + +.hive-badge-is-changed:after { + @apply absolute right-2 size-1.5 rounded-full border border-orange-600 bg-orange-400 content-['']; +} diff --git a/packages/web/app/src/lib/hooks/laboratory/use-collections.ts b/packages/web/app/src/lib/hooks/laboratory/use-collections.ts new file mode 100644 index 000000000..1a125dc89 --- /dev/null +++ b/packages/web/app/src/lib/hooks/laboratory/use-collections.ts @@ -0,0 +1,72 @@ +import { useEffect } from 'react'; +import { useQuery } from 'urql'; +import { graphql } from '@/gql'; +import { CollectionsQuery as _CollectionsQuery } from '@/gql/graphql'; +import { useNotifications } from '@/lib/hooks'; + +export const CollectionsQuery = graphql(` + query Collections($selector: TargetSelectorInput!) { + target(selector: $selector) { + id + documentCollections { + edges { + cursor + node { + id + name + description + operations(first: 100) { + edges { + node { + id + name + } + cursor + } + } + } + } + } + } + } +`); + +export type DocumentCollectionOperation = Exclude< + _CollectionsQuery['target'], + null | undefined +>['documentCollections']['edges'][number]['node']; + +const EMPTY_ARRAY: DocumentCollectionOperation[] = []; + +export function useCollections(props: { + organizationId: string; + projectId: string; + targetId: string; +}): { + fetching: boolean; + collections: DocumentCollectionOperation[]; +} { + const [{ data, error, fetching }] = useQuery({ + query: CollectionsQuery, + variables: { + selector: { + target: props.targetId, + organization: props.organizationId, + project: props.projectId, + }, + }, + }); + + const notify = useNotifications(); + + useEffect(() => { + if (error) { + notify(error.message, 'error'); + } + }, [error]); + + return { + collections: data?.target?.documentCollections.edges.map(v => v.node) || EMPTY_ARRAY, + fetching, + }; +} diff --git a/packages/web/app/src/lib/hooks/laboratory/use-current-operation.ts b/packages/web/app/src/lib/hooks/laboratory/use-current-operation.ts new file mode 100644 index 000000000..04d2f5297 --- /dev/null +++ b/packages/web/app/src/lib/hooks/laboratory/use-current-operation.ts @@ -0,0 +1,45 @@ +import { useQuery } from 'urql'; +import { graphql } from '@/gql'; +import { useOperationFromQueryString } from './useOperationFromQueryString'; + +const OperationQuery = graphql(` + query Operation($selector: TargetSelectorInput!, $id: ID!) { + target(selector: $selector) { + id + documentCollectionOperation(id: $id) { + id + name + query + headers + variables + updatedAt + collection { + id + name + } + } + } + } +`); + +export function useCurrentOperation(props: { + organizationId: string; + projectId: string; + targetId: string; +}) { + const operationIdFromSearch = useOperationFromQueryString(); + const [{ data }] = useQuery({ + query: OperationQuery, + variables: { + selector: { + target: props.targetId, + project: props.projectId, + organization: props.organizationId, + }, + id: operationIdFromSearch!, + }, + pause: !operationIdFromSearch, + }); + // if operationId is undefined `data` could contain previous state + return operationIdFromSearch ? data?.target?.documentCollectionOperation : null; +} diff --git a/packages/web/app/src/lib/hooks/laboratory/use-operation-collections-plugin.tsx b/packages/web/app/src/lib/hooks/laboratory/use-operation-collections-plugin.tsx new file mode 100644 index 000000000..77712b310 --- /dev/null +++ b/packages/web/app/src/lib/hooks/laboratory/use-operation-collections-plugin.tsx @@ -0,0 +1,499 @@ +import { useEffect, useMemo, useRef, useState } from 'react'; +import clsx from 'clsx'; +import { FolderIcon, FolderOpenIcon, SquareTerminalIcon } from 'lucide-react'; +import { useMutation } from 'urql'; +import { CreateCollectionModal } from '@/components/target/laboratory/create-collection-modal'; +import { DeleteCollectionModal } from '@/components/target/laboratory/delete-collection-modal'; +import { DeleteOperationModal } from '@/components/target/laboratory/delete-operation-modal'; +import { EditOperationModal } from '@/components/target/laboratory/edit-operation-modal'; +import { + Accordion, + AccordionContent, + AccordionHeader, + AccordionItem, + AccordionTriggerPrimitive, +} from '@/components/ui/accordion'; +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { PlusIcon } from '@/components/ui/icon'; +import { Link } from '@/components/ui/link'; +import { Spinner } from '@/components/ui/spinner'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; +import { graphql } from '@/gql'; +import { useClipboard, useNotifications, useToggle } from '@/lib/hooks'; +import { useOperationFromQueryString } from '@/lib/hooks/laboratory/useOperationFromQueryString'; +import { cn } from '@/lib/utils'; +import { GraphiQLPlugin, useEditorContext, usePluginContext } from '@graphiql/react'; +import { BookmarkFilledIcon, BookmarkIcon, DotsHorizontalIcon } from '@radix-ui/react-icons'; +import { useRouter } from '@tanstack/react-router'; +import { useCollections } from './use-collections'; +import { useCurrentOperation } from './use-current-operation'; +import { useSyncOperationState } from './use-sync-operation-state'; + +const CreateOperationMutation = graphql(` + mutation CreateOperation( + $selector: TargetSelectorInput! + $input: CreateDocumentCollectionOperationInput! + ) { + createOperationInDocumentCollection(selector: $selector, input: $input) { + error { + message + } + ok { + operation { + id + name + } + updatedTarget { + id + documentCollections { + edges { + cursor + node { + id + operations { + edges { + node { + id + } + cursor + } + } + } + } + } + } + } + } + } +`); + +const _tabBadgeClassName = clsx( + 'hive-badge-is-changed', + 'relative after:top-1/2 after:-translate-y-1/2 after:right-[.65rem] hover:after:hidden', + '[&_.graphiql-tab-close]:hidden [&:hover_.graphiql-tab-close]:block', +); + +export function useOperationCollectionsPlugin(props: { + canEdit: boolean; + canDelete: boolean; + organizationId: string; + projectId: string; + targetId: string; +}): GraphiQLPlugin { + return useMemo(() => { + function Content() { + const [isCollectionModalOpen, toggleCollectionModal] = useToggle(); + const { collections, fetching: loading } = useCollections({ + organizationId: props.organizationId, + projectId: props.projectId, + targetId: props.targetId, + }); + const [collectionId, setCollectionId] = useState(''); + const [isDeleteCollectionModalOpen, toggleDeleteCollectionModalOpen] = useToggle(); + const [isDeleteOperationModalOpen, toggleDeleteOperationModalOpen] = useToggle(); + const [operationToDeleteId, setOperationToDeleteId] = useState(null); + const [operationToEditId, setOperationToEditId] = useState(null); + const { clearOperation, savedOperation, setSavedOperation } = useSyncOperationState({ + organizationId: props.organizationId, + projectId: props.projectId, + targetId: props.targetId, + }); + const router = useRouter(); + const [accordionValue, setAccordionValue] = useState([]); + const containerRef = useRef(null); + const [isScrolled, setIsScrolled] = useState(false); + const copyToClipboard = useClipboard(); + + const currentOperation = useCurrentOperation({ + organizationId: props.organizationId, + projectId: props.projectId, + targetId: props.targetId, + }); + const { queryEditor, variableEditor, headerEditor, tabs, changeTab, addTab } = + useEditorContext({ + nonNull: true, + }); + + const hasAllEditors = !!(queryEditor && variableEditor && headerEditor); + const queryParamsOperationId = useOperationFromQueryString(); + const activeTab = tabs.find(tab => tab.id === queryParamsOperationId); + + const isSame = + !currentOperation || + !activeTab || + (currentOperation.query === activeTab.query && + currentOperation.variables === activeTab.variables && + currentOperation.headers === (activeTab.headers || '')); + + useEffect(() => { + if (!hasAllEditors || !currentOperation) { + const searchObj = router.latestLocation.search; + const operationString = + 'operationString' in searchObj && typeof searchObj.operationString === 'string' + ? searchObj.operationString + : null; + + // We provide an operation string when navigating to the laboratory from persisted documents + // in that case we want to show that operation within this tab. + if (operationString) { + queryEditor?.setValue(operationString); + variableEditor?.setValue(''); + headerEditor?.setValue(''); + } + + return; + } + + if (queryParamsOperationId) { + const tabIndex = tabs.findIndex(tab => tab.id === queryParamsOperationId); + + if (tabIndex !== -1) { + changeTab(tabIndex); + return; + } + // Set selected operation in editors + addTab({ + id: queryParamsOperationId, + query: (savedOperation || currentOperation).query, + variables: (savedOperation || currentOperation).variables, + headers: currentOperation.headers, + title: currentOperation.name, + }); + + if (!savedOperation) { + return; + } + + const oneWeek = 7 * 24 * 60 * 60 * 1000; + if (savedOperation.updatedAt + oneWeek < Date.now()) { + clearOperation(); + return; + } + + const currentOperationUpdatedAt = new Date(currentOperation.updatedAt).getTime(); + if (savedOperation.updatedAt > currentOperationUpdatedAt) { + queryEditor.setValue(savedOperation.query); + variableEditor.setValue(savedOperation.variables); + } + } + }, [hasAllEditors, queryParamsOperationId, currentOperation]); + + useEffect(() => { + // updateActiveTabValues({ className: isSame ? '' : tabBadgeClassName }); + if (!hasAllEditors || !currentOperation || isSame) { + return; + } + setSavedOperation({ + query: queryEditor.getValue() || '', + variables: variableEditor.getValue() || '', + }); + }, [queryEditor?.getValue(), variableEditor?.getValue()]); + + const shouldShowMenu = props.canEdit || props.canDelete; + + const initialSelectedCollection = + currentOperation?.id && + collections.find(c => + c.operations.edges.some(({ node }) => node.id === currentOperation.id), + )?.id; + + const [createOperationState, createOperation] = useMutation(CreateOperationMutation); + const notify = useNotifications(); + + const addOperation = async (e: { currentTarget: { dataset: DOMStringMap } }) => { + const collectionId = e.currentTarget.dataset.collectionId!; + + const result = await createOperation({ + input: { + collectionId, + name: 'New Operation', + query: '{\n \n}', + headers: '', + variables: '', + }, + selector: { + target: props.targetId, + organization: props.organizationId, + project: props.projectId, + }, + }); + if (result.error) { + notify("Couldn't create operation. Please try again later.", 'error'); + } + if (result.data?.createOperationInDocumentCollection.error) { + notify(result.data.createOperationInDocumentCollection.error.message, 'error'); + } + if (result.data?.createOperationInDocumentCollection.ok) { + void router.navigate({ + to: '/$organizationId/$projectId/$targetId/laboratory', + params: { + organizationId: props.organizationId, + projectId: props.projectId, + targetId: props.targetId, + }, + search: { + operation: result.data.createOperationInDocumentCollection.ok.operation.id, + }, + }); + } + }; + + useEffect(() => { + if (!initialSelectedCollection || isScrolled) return; + + setAccordionValue([initialSelectedCollection]); + setTimeout(() => { + const link = containerRef.current!.querySelector(`a[href$="${queryParamsOperationId}"]`); + link!.scrollIntoView(); + setIsScrolled(true); + }, 150); + }, [initialSelectedCollection]); + + const renderedCollections = collections.map(collection => ( + + + + + + {collection.name} + + {shouldShowMenu && ( + + + + + + + Add operation + + + { + setCollectionId(collection.id); + toggleCollectionModal(); + }} + > + Edit + + { + setCollectionId(collection.id); + toggleDeleteCollectionModalOpen(); + }} + className="text-red-500" + > + Delete + + + + )} + + + {collection.operations.edges.length ? ( + collection.operations.edges.map(({ node }) => ( +
+ + + {node.name} + + + + + + + { + const url = new URL(window.location.href); + await copyToClipboard( + `${url.origin}${url.pathname}?operation=${node.id}`, + ); + }} + > + Copy link to operation + + + {props.canEdit && ( + { + setOperationToEditId(node.id); + }} + > + Edit + + )} + {props.canDelete && ( + { + setOperationToDeleteId(node.id); + toggleDeleteOperationModalOpen(); + }} + className="text-red-500" + > + Delete + + )} + + +
+ )) + ) : ( + + )} +
+
+ )); + + return ( + <> +
+
Operations
+ + + + + + Create a new collection of GraphQL Operations + + +
+ {loading ? ( +
+ + Loading collections... +
+ ) : collections.length ? ( + + {renderedCollections} + + ) : ( +
+
+ +
There are no collections available.
+ {props.canEdit && ( + + )} +
+
+ )} + + + {operationToDeleteId && ( + + )} + {operationToEditId && ( + setOperationToEditId(null)} + /> + )} + + ); + } + + const plugin = { + title: 'Operation Collections', + content: Content, + icon: function Icon() { + const pluginContext = usePluginContext(); + const IconToUse = + pluginContext?.visiblePlugin === plugin ? BookmarkFilledIcon : BookmarkIcon; + return ; + }, + }; + + return plugin; + }, [props.canEdit, props.canDelete]); +} diff --git a/packages/web/app/src/lib/hooks/laboratory/use-sync-operation-state.ts b/packages/web/app/src/lib/hooks/laboratory/use-sync-operation-state.ts new file mode 100644 index 000000000..4af08ffc4 --- /dev/null +++ b/packages/web/app/src/lib/hooks/laboratory/use-sync-operation-state.ts @@ -0,0 +1,33 @@ +import { useCurrentOperation } from './use-current-operation'; + +export function useSyncOperationState(props: { + organizationId: string; + projectId: string; + targetId: string; +}): { + savedOperation: { query: string; variables: string; updatedAt: number } | null; + setSavedOperation: (value: { query: string; variables: string }) => void; + clearOperation: () => void; +} { + const currentOperation = useCurrentOperation({ + organizationId: props.organizationId, + projectId: props.projectId, + targetId: props.targetId, + }); + const storageKey = currentOperation ? `hive:operation-${currentOperation.id}` : null; + const savedOperationData = storageKey ? localStorage.getItem(storageKey) : null; + + return { + savedOperation: savedOperationData ? JSON.parse(savedOperationData) : null, + setSavedOperation(value: { query: string; variables: string }) { + if (storageKey) { + localStorage.setItem(storageKey, JSON.stringify({ ...value, updatedAt: Date.now() })); + } + }, + clearOperation() { + if (storageKey) { + localStorage.removeItem(storageKey); + } + }, + }; +} diff --git a/packages/web/app/src/lib/hooks/laboratory/useOperationFromQueryString.ts b/packages/web/app/src/lib/hooks/laboratory/useOperationFromQueryString.ts new file mode 100644 index 000000000..61566b9ca --- /dev/null +++ b/packages/web/app/src/lib/hooks/laboratory/useOperationFromQueryString.ts @@ -0,0 +1,9 @@ +import { useRouter } from '@tanstack/react-router'; + +export function useOperationFromQueryString() { + const router = useRouter(); + + const { search } = router.latestLocation; + + return 'operation' in search && typeof search.operation === 'string' ? search.operation : null; +} diff --git a/packages/web/app/src/lib/urql-cache.ts b/packages/web/app/src/lib/urql-cache.ts index 3da586fc5..4da1c6854 100644 --- a/packages/web/app/src/lib/urql-cache.ts +++ b/packages/web/app/src/lib/urql-cache.ts @@ -12,10 +12,10 @@ import type { DeleteCollectionMutationType } from '@/components/target/laborator import type { DeleteOperationMutationType } from '@/components/target/laboratory/delete-operation-modal'; import type { CreateAccessToken_CreateTokenMutation } from '@/components/target/settings/registry-access-token'; import { graphql } from '@/gql'; +import { CollectionsQuery } from '@/lib/hooks/laboratory/use-collections'; import type { CreateOrganizationMutation } from '@/pages/organization-new'; import type { DeleteOrganizationDocument } from '@/pages/organization-settings'; import type { DeleteProjectMutation } from '@/pages/project-settings'; -import { CollectionsQuery } from '@/pages/target-laboratory'; import { TokensDocument, type DeleteTargetMutation, diff --git a/packages/web/app/src/pages/dev.tsx b/packages/web/app/src/pages/dev.tsx index 2f2afd4d0..b26b4d394 100644 --- a/packages/web/app/src/pages/dev.tsx +++ b/packages/web/app/src/pages/dev.tsx @@ -1,9 +1,9 @@ import { GraphiQL } from 'graphiql'; -import { HiveLogo } from '@/components/ui/icon'; -import { createGraphiQLFetcher } from '@graphiql/toolkit'; -import 'graphiql/graphiql.css'; import { Helmet } from 'react-helmet-async'; +import { HiveLogo } from '@/components/ui/icon'; import { env } from '@/env/frontend'; +import { createGraphiQLFetcher } from '@graphiql/toolkit'; +import 'graphiql/style.css'; export function DevPage() { return ( diff --git a/packages/web/app/src/pages/target-laboratory.tsx b/packages/web/app/src/pages/target-laboratory.tsx index 5cb7d56b2..852179dc7 100644 --- a/packages/web/app/src/pages/target-laboratory.tsx +++ b/packages/web/app/src/pages/target-laboratory.tsx @@ -1,25 +1,13 @@ -import { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { ReactElement, useCallback, useMemo, useState } from 'react'; import { cx } from 'class-variance-authority'; import clsx from 'clsx'; import { GraphiQL } from 'graphiql'; import { buildSchema } from 'graphql'; -import { FolderIcon, FolderOpenIcon, SquareTerminalIcon } from 'lucide-react'; import { Helmet } from 'react-helmet-async'; import { useMutation, useQuery } from 'urql'; import { Page, TargetLayout } from '@/components/layouts/target'; import { ConnectLabModal } from '@/components/target/laboratory/connect-lab-modal'; -import { CreateCollectionModal } from '@/components/target/laboratory/create-collection-modal'; import { CreateOperationModal } from '@/components/target/laboratory/create-operation-modal'; -import { DeleteCollectionModal } from '@/components/target/laboratory/delete-collection-modal'; -import { DeleteOperationModal } from '@/components/target/laboratory/delete-operation-modal'; -import { EditOperationModal } from '@/components/target/laboratory/edit-operation-modal'; -import { - Accordion, - AccordionContent, - AccordionHeader, - AccordionItem, - AccordionTriggerPrimitive, -} from '@/components/ui/accordion'; import { Button } from '@/components/ui/button'; import { DocsLink } from '@/components/ui/docs-note'; import { @@ -29,42 +17,40 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; -import { PlusIcon, SaveIcon, ShareIcon } from '@/components/ui/icon'; -import { Link } from '@/components/ui/link'; +import { SaveIcon, ShareIcon } from '@/components/ui/icon'; import { Meta } from '@/components/ui/meta'; import { Subtitle, Title } from '@/components/ui/page'; import { QueryError } from '@/components/ui/query-error'; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import { ToggleGroup, ToggleGroupItem } from '@/components/v2/toggle-group'; import { graphql } from '@/gql'; import { TargetAccessScope } from '@/gql/graphql'; import { canAccessTarget } from '@/lib/access/target'; import { useClipboard, useNotifications, useToggle } from '@/lib/hooks'; +import { useCollections } from '@/lib/hooks/laboratory/use-collections'; +import { useCurrentOperation } from '@/lib/hooks/laboratory/use-current-operation'; +import { useOperationCollectionsPlugin } from '@/lib/hooks/laboratory/use-operation-collections-plugin'; +import { useSyncOperationState } from '@/lib/hooks/laboratory/use-sync-operation-state'; +import { useOperationFromQueryString } from '@/lib/hooks/laboratory/useOperationFromQueryString'; import { useResetState } from '@/lib/hooks/use-reset-state'; import { cn } from '@/lib/utils'; import { UnStyledButton as GraphiQLButton, - GraphiQLPlugin, + GraphiQLProviderProps, Tooltip as GraphiQLTooltip, useEditorContext, } from '@graphiql/react'; import { createGraphiQLFetcher, Fetcher, isAsyncIterable } from '@graphiql/toolkit'; -import { - BookmarkIcon, - DotsHorizontalIcon, - EnterFullScreenIcon, - ExitFullScreenIcon, -} from '@radix-ui/react-icons'; +import { EnterFullScreenIcon, ExitFullScreenIcon } from '@radix-ui/react-icons'; import { Repeater } from '@repeaterjs/repeater'; import { Link as RouterLink, useRouter } from '@tanstack/react-router'; -import 'graphiql/graphiql.css'; -import { Spinner } from '@/components/ui/spinner'; +import 'graphiql/style.css'; -function Share({ operation }: { operation: string | null }): ReactElement | null { +function Share(): ReactElement | null { const label = 'Share query'; const copyToClipboard = useClipboard(); + const operationFromQueryString = useOperationFromQueryString(); - if (!operation) return null; + if (!operationFromQueryString) return null; return ( @@ -81,585 +67,6 @@ function Share({ operation }: { operation: string | null }): ReactElement | null ); } -const OperationQuery = graphql(` - query Operation($selector: TargetSelectorInput!, $id: ID!) { - target(selector: $selector) { - id - documentCollectionOperation(id: $id) { - id - name - query - headers - variables - updatedAt - collection { - id - name - } - } - } - } -`); - -function useCurrentOperation(props: { - organizationId: string; - projectId: string; - targetId: string; -}) { - const router = useRouter(); - const operationIdFromSearch = - 'operation' in router.latestLocation.search && - typeof router.latestLocation.search.operation === 'string' - ? router.latestLocation.search.operation - : null; - const [{ data }] = useQuery({ - query: OperationQuery, - variables: { - selector: { - target: props.targetId, - project: props.projectId, - organization: props.organizationId, - }, - id: operationIdFromSearch!, - }, - pause: !operationIdFromSearch, - }); - // if operationId is undefined `data` could contain previous state - return operationIdFromSearch ? data?.target?.documentCollectionOperation : null; -} - -const CreateOperationMutation = graphql(` - mutation CreateOperation( - $selector: TargetSelectorInput! - $input: CreateDocumentCollectionOperationInput! - ) { - createOperationInDocumentCollection(selector: $selector, input: $input) { - error { - message - } - ok { - operation { - id - name - } - updatedTarget { - id - documentCollections { - edges { - cursor - node { - id - operations { - edges { - node { - id - } - cursor - } - } - } - } - } - } - } - } - } -`); - -const CollectionItem = (props: { - node: { id: string; name: string }; - toggleDeleteOperationModalOpen: () => void; - canDelete: boolean; - canEdit: boolean; - onDelete: (operationId: string) => void; - onEdit: (operationId: string) => void; - isChanged?: boolean; - organizationId: string; - projectId: string; - targetId: string; -}): ReactElement => { - const router = useRouter(); - const operationIdFromSearch = - 'operation' in router.latestLocation.search && - typeof router.latestLocation.search.operation === 'string' - ? router.latestLocation.search.operation - : null; - const copyToClipboard = useClipboard(); - - return ( -
- -
- - {props.node.name} -
- {props.isChanged && ( - - )} - - - - - - - { - const url = new URL(window.location.href); - await copyToClipboard(`${url.origin}${url.pathname}?operation=${props.node.id}`); - }} - > - Copy link to operation - - - {props.canEdit && ( - { - props.onEdit(props.node.id); - }} - > - Edit - - )} - {props.canDelete && ( - { - props.onDelete(props.node.id); - props.toggleDeleteOperationModalOpen(); - }} - className="text-red-500" - > - Delete - - )} - - -
- ); -}; - -export const CollectionsQuery = graphql(` - query Collections($selector: TargetSelectorInput!) { - target(selector: $selector) { - id - documentCollections { - edges { - cursor - node { - id - name - description - operations(first: 100) { - edges { - node { - id - name - } - cursor - } - } - } - } - } - } - } -`); - -export function useCollections(props: { - organizationId: string; - projectId: string; - targetId: string; -}) { - const [{ data, error, fetching }] = useQuery({ - query: CollectionsQuery, - variables: { - selector: { - target: props.targetId, - organization: props.organizationId, - project: props.projectId, - }, - }, - }); - - const notify = useNotifications(); - - useEffect(() => { - if (error) { - notify(error.message, 'error'); - } - }, [error]); - - return { - collections: data?.target?.documentCollections.edges.map(v => v.node) || [], - fetching, - }; -} - -function useOperationCollectionsPlugin(props: { - canEdit: boolean; - canDelete: boolean; - organizationId: string; - projectId: string; - targetId: string; -}): GraphiQLPlugin { - return useMemo(() => { - function Content() { - const [isCollectionModalOpen, toggleCollectionModal] = useToggle(); - const { collections, fetching: loading } = useCollections({ - organizationId: props.organizationId, - projectId: props.projectId, - targetId: props.targetId, - }); - const [collectionId, setCollectionId] = useState(''); - const [isDeleteCollectionModalOpen, toggleDeleteCollectionModalOpen] = useToggle(); - const [isDeleteOperationModalOpen, toggleDeleteOperationModalOpen] = useToggle(); - const [operationToDeleteId, setOperationToDeleteId] = useState(null); - const [operationToEditId, setOperationToEditId] = useState(null); - const { clearOperation, savedOperation, setSavedOperation } = useSyncOperationState({ - organizationId: props.organizationId, - projectId: props.projectId, - targetId: props.targetId, - }); - const router = useRouter(); - const [accordionValue, setAccordionValue] = useState([]); - const containerRef = useRef(null); - const [isScrolled, setIsScrolled] = useState(false); - - const currentOperation = useCurrentOperation({ - organizationId: props.organizationId, - projectId: props.projectId, - targetId: props.targetId, - }); - const editorContext = useEditorContext({ nonNull: true }); - - const hasAllEditors = !!( - editorContext.queryEditor && - editorContext.variableEditor && - editorContext.headerEditor - ); - - const isSame = - !!currentOperation && - currentOperation.query === editorContext.queryEditor?.getValue() && - currentOperation.variables === editorContext.variableEditor?.getValue() && - currentOperation.headers === editorContext.headerEditor?.getValue(); - - const queryParamsOperationId = - 'operation' in router.latestLocation.search && - typeof router.latestLocation.search.operation === 'string' - ? router.latestLocation.search.operation - : null; - - useEffect(() => { - if (!hasAllEditors || !currentOperation) { - const searchObj = router.latestLocation.search; - const operationString = - 'operationString' in searchObj && typeof searchObj.operationString === 'string' - ? searchObj.operationString - : null; - - // We provide an operation string when navigating to the laboratory from persisted documents - // in that case we want to show that operation within this tab. - if (operationString) { - editorContext.queryEditor?.setValue(operationString); - editorContext.variableEditor?.setValue(''); - editorContext.headerEditor?.setValue(''); - } - - return; - } - - if (queryParamsOperationId) { - // Set selected operation in editors - editorContext.queryEditor?.setValue(currentOperation.query); - editorContext.variableEditor?.setValue(currentOperation.variables ?? ''); - editorContext.headerEditor?.setValue(currentOperation.headers ?? ''); - - if (!savedOperation) { - return; - } - - const oneWeek = 7 * 24 * 60 * 60 * 1000; - if (savedOperation.updatedAt + oneWeek < Date.now()) { - clearOperation(); - return; - } - - const currentOperationUpdatedAt = new Date(currentOperation.updatedAt).getTime(); - if (savedOperation.updatedAt > currentOperationUpdatedAt) { - editorContext.queryEditor?.setValue(savedOperation.query); - editorContext.variableEditor?.setValue(savedOperation.variables); - } - } - }, [hasAllEditors, queryParamsOperationId, currentOperation]); - - useEffect(() => { - if (!hasAllEditors || !currentOperation || isSame) { - return; - } - setSavedOperation({ - query: editorContext.queryEditor?.getValue() ?? '', - variables: editorContext.variableEditor?.getValue() ?? '', - }); - }, [editorContext.queryEditor?.getValue(), editorContext.variableEditor?.getValue()]); - - const shouldShowMenu = props.canEdit || props.canDelete; - - const initialSelectedCollection = - currentOperation?.id && - collections?.find(c => - c.operations.edges.some(({ node }) => node.id === currentOperation.id), - )?.id; - - const [createOperationState, createOperation] = useMutation(CreateOperationMutation); - const notify = useNotifications(); - - const addOperation = async (e: { currentTarget: { dataset: DOMStringMap } }) => { - const collectionId = e.currentTarget.dataset.collectionId!; - - const result = await createOperation({ - input: { - collectionId, - name: 'New Operation', - query: '{\n \n}', - headers: '', - variables: '', - }, - selector: { - target: props.targetId, - organization: props.organizationId, - project: props.projectId, - }, - }); - if (result.error) { - notify("Couldn't create operation. Please try again later.", 'error'); - } - if (result.data?.createOperationInDocumentCollection.error) { - notify(result.data.createOperationInDocumentCollection.error.message, 'error'); - } - if (result.data?.createOperationInDocumentCollection.ok) { - void router.navigate({ - to: '/$organizationId/$projectId/$targetId/laboratory', - params: { - organizationId: props.organizationId, - projectId: props.projectId, - targetId: props.targetId, - }, - search: { - operation: result.data.createOperationInDocumentCollection.ok.operation.id, - }, - }); - } - }; - - useEffect(() => { - if (!initialSelectedCollection || isScrolled) return; - - setAccordionValue([initialSelectedCollection]); - setTimeout(() => { - const link = containerRef.current!.querySelector(`a[href$="${queryParamsOperationId}"]`); - link!.scrollIntoView(); - setIsScrolled(true); - }, 150); - }, [initialSelectedCollection]); - - return ( - <> -
- Operations - - - - - - Create a new collection of GraphQL Operations - - -
- {loading ? ( -
- - Loading collections... -
- ) : collections?.length ? ( - - {collections.map(collection => ( - - - - - - {collection.name} - - {shouldShowMenu ? ( - - - - - - - Add operation - - - { - setCollectionId(collection.id); - toggleCollectionModal(); - }} - > - Edit - - { - setCollectionId(collection.id); - toggleDeleteCollectionModalOpen(); - }} - className="text-red-500" - > - Delete - - - - ) : null} - - - {collection.operations.edges.length ? ( - collection.operations.edges.map(({ node }) => ( - - )) - ) : ( - - )} - - - ))} - - ) : ( -
-
- -
There are no collections available.
- {props.canEdit ? ( - - ) : null} -
-
- )} - - - {operationToDeleteId && ( - - )} - {operationToEditId && ( - setOperationToEditId(null)} - /> - )} - - ); - } - - return { - title: 'Operation Collections', - icon: BookmarkIcon, - content: Content, - }; - }, [props.canEdit, props.canDelete]); -} - const UpdateOperationMutation = graphql(` mutation UpdateOperation( $selector: TargetSelectorInput! @@ -682,45 +89,6 @@ const UpdateOperationMutation = graphql(` } `); -function useSyncOperationState(props: { - organizationId: string; - projectId: string; - targetId: string; -}): { - savedOperation: { query: string; variables: string; updatedAt: number } | null; - setSavedOperation: (value: { query: string; variables: string }) => void; - clearOperation: () => void; -} { - const currentOperation = useCurrentOperation({ - organizationId: props.organizationId, - projectId: props.projectId, - targetId: props.targetId, - }); - const storageKey = currentOperation ? `hive:operation-${currentOperation?.id}` : null; - const savedOperationData = storageKey ? localStorage.getItem(storageKey) : null; - const operation = savedOperationData ? JSON.parse(savedOperationData) : null; - - const setSavedOperation = (value: { query: string; variables: string }) => { - if (!storageKey) { - return; - } - localStorage.setItem(storageKey, JSON.stringify({ ...value, updatedAt: Date.now() })); - }; - - const clearOperation = () => { - if (!storageKey) { - return; - } - localStorage.removeItem(storageKey); - }; - - return { - savedOperation: operation, - setSavedOperation, - clearOperation, - }; -} - function Save(props: { organizationId: string; projectId: string; @@ -740,15 +108,20 @@ function Save(props: { targetId: props.targetId, }); const [, mutateUpdate] = useMutation(UpdateOperationMutation); - const { queryEditor, variableEditor, headerEditor } = useEditorContext()!; + const { queryEditor, variableEditor, headerEditor, updateActiveTabValues } = useEditorContext()!; const { clearOperation } = useSyncOperationState({ organizationId: props.organizationId, projectId: props.projectId, targetId: props.targetId, }); + const operationFromQueryString = useOperationFromQueryString(); + const onSaveSuccess = useCallback( - (operationId?: string) => { - if (operationId) { + ({ id, name }: { id: string; name: string }) => { + if (id) { + if (!operationFromQueryString) { + updateActiveTabValues({ id, title: name }); + } void router.navigate({ to: '/$organizationId/$projectId/$targetId/laboratory', params: { @@ -756,9 +129,7 @@ function Save(props: { projectId: props.projectId, targetId: props.targetId, }, - search: { - operation: operationId, - }, + search: { operation: id }, }); } clearOperation(); @@ -777,10 +148,13 @@ function Save(props: { - - {!isSame && ( - + @@ -791,7 +165,7 @@ function Save(props: { { + onClick={() => { queryEditor?.setValue(currentOperation.query); clearOperation(); }} @@ -901,6 +275,17 @@ function LaboratoryPageContent(props: { const [isFullScreen, setIsFullScreen] = useState(false); const currentOrganization = query.data?.organization?.organization; + const { collections } = useCollections({ + organizationId: props.organizationId, + projectId: props.projectId, + targetId: props.targetId, + }); + const userOperations = useMemo(() => { + const operations = collections.flatMap(collection => + collection.operations.edges.map(o => o.node.id), + ); + return new Set(operations); + }, [collections]); const operationCollectionsPlugin = useOperationCollectionsPlugin({ canEdit: canAccessTarget(TargetAccessScope.Settings, currentOrganization?.me ?? null), @@ -910,36 +295,25 @@ function LaboratoryPageContent(props: { targetId: props.targetId, }); - const schema = useMemo(() => { - if (!query.data?.target?.latestSchemaVersion?.sdl) { - return null; - } - return buildSchema(query.data.target.latestSchemaVersion.sdl); - }, [query.data?.target?.latestSchemaVersion?.sdl]); + const sdl = query.data?.target?.latestSchemaVersion?.sdl; + const schema = useMemo(() => (sdl ? buildSchema(sdl) : null), [sdl]); const [actualSelectedApiEndpoint, setEndpointType] = useApiTabValueState( query.data?.target?.graphqlEndpointUrl ?? null, ); - const mockEndpoint = useMemo(() => { - if (globalThis.window) { - return `${location.origin}/api/lab/${props.organizationId}/${props.projectId}/${props.targetId}`; - } - - return ''; - }, [props.organizationId, props.projectId, props.targetId]); + const mockEndpoint = `${location.origin}/api/lab/${props.organizationId}/${props.projectId}/${props.targetId}`; const fetcher = useMemo(() => { return async (params, opts) => { - const fetcher = createGraphiQLFetcher({ - url: - (actualSelectedApiEndpoint === 'linkedApi' - ? query.data?.target?.graphqlEndpointUrl - : undefined) ?? mockEndpoint, - fetch, - }); + const url = + (actualSelectedApiEndpoint === 'linkedApi' + ? query.data?.target?.graphqlEndpointUrl + : undefined) ?? mockEndpoint; - const result = await fetcher(params, opts); + const _fetcher = createGraphiQLFetcher({ url, fetch }); + + const result = await _fetcher(params, opts); // We only want to expose the error message, not the whole stack trace. if (isAsyncIterable(result)) { @@ -953,13 +327,9 @@ function LaboratoryPageContent(props: { await push(value); } stop(); - } catch (err: unknown) { + } catch (err) { const error = new Error(err instanceof Error ? err.message : 'Unexpected error.'); - Object.defineProperty(error, 'stack', { - get() { - return undefined; - }, - }); + delete error.stack; stop(error); } }); @@ -973,13 +343,24 @@ function LaboratoryPageContent(props: { return ; } - const searchObj = router.latestLocation.search; - const operation = - 'operation' in searchObj && typeof searchObj.operation === 'string' - ? searchObj.operation - : null; + const FullScreenIcon = isFullScreen ? ExitFullScreenIcon : EnterFullScreenIcon; - const FullScreenComponent = isFullScreen ? ExitFullScreenIcon : EnterFullScreenIcon; + const handleTabChange = useCallback>( + ({ tabs, activeTabIndex }) => { + const activeTab = tabs.find((_, index) => index === activeTabIndex)!; + // Set search params while clicking on tab + void router.navigate({ + to: '/$organizationId/$projectId/$targetId/laboratory', + params: { + organizationId: props.organizationId, + projectId: props.projectId, + targetId: props.targetId, + }, + search: userOperations.has(activeTab.id) ? { operation: activeTab.id } : {}, + }); + }, + [userOperations], + ); return ( - - - + + + + + {({ prettify }) => ( + <> + + + {prettify} + + )} + + )} - {currentOperation?.id ? ( - <> - {currentOperation.collection.name} {'>'}{' '} - {currentOperation.name} - - ) : ( - 'New Operation' - )} - - ); -} diff --git a/packages/web/app/src/stories/create-operation-modal.stories.tsx b/packages/web/app/src/stories/create-operation-modal.stories.tsx index fa3a26f7f..596d46674 100644 --- a/packages/web/app/src/stories/create-operation-modal.stories.tsx +++ b/packages/web/app/src/stories/create-operation-modal.stories.tsx @@ -73,18 +73,21 @@ Default.args = { isOpen: true, close: () => {}, collections: [ + // @ts-expect-error -- Tuval: these types are invalid { id: '1', name: 'Collection 1', __typename: 'DocumentCollection', description: 'Collection 1 description', }, + // @ts-expect-error -- Tuval: these types are invalid { id: '2', name: 'Collection 2', __typename: 'DocumentCollection', description: 'Collection 2 description', }, + // @ts-expect-error -- Tuval: these types are invalid { id: '3', name: 'Collection 3', diff --git a/patches/@graphiql__react@1.0.0-alpha.3.patch b/patches/@graphiql__react@1.0.0-alpha.3.patch new file mode 100644 index 000000000..8e94659e1 --- /dev/null +++ b/patches/@graphiql__react@1.0.0-alpha.3.patch @@ -0,0 +1,140 @@ +diff --git a/dist/index.mjs b/dist/index.mjs +index 567480ba5ccc30619db2eb8e6da8d618ddb5e891..c49c573893a26897062cda2af9896bc69881db2a 100644 +--- a/dist/index.mjs ++++ b/dist/index.mjs +@@ -3056,14 +3056,16 @@ function useSetEditorValues({ + ); + } + function createTab({ ++ id, ++ title, + query = null, + variables = null, + headers = null +-} = {}) { ++}) { + return { +- id: guid(), ++ id: id || guid(), + hash: hashFromTabContents({ query, variables, headers }), +- title: query && fuzzyExtractOperationName(query) || DEFAULT_TITLE, ++ title: title || query && fuzzyExtractOperationName(query) || DEFAULT_TITLE, + query, + variables, + headers, +@@ -3081,8 +3083,7 @@ function setPropertiesInActiveTab(state, partialTab) { + const newTab = { ...tab, ...partialTab }; + return { + ...newTab, +- hash: hashFromTabContents(newTab), +- title: newTab.operationName || (newTab.query ? fuzzyExtractOperationName(newTab.query) : void 0) || DEFAULT_TITLE ++ hash: hashFromTabContents(newTab) + }; + }) + }; +@@ -3304,25 +3305,31 @@ function EditorContextProvider(props) { + responseEditor, + defaultHeaders + }); +- const addTab = useCallback(() => { +- setTabState((current) => { +- const updatedValues = synchronizeActiveTabValues(current); +- const updated = { +- tabs: [...updatedValues.tabs, createTab({ headers: defaultHeaders })], +- activeTabIndex: updatedValues.tabs.length +- }; +- storeTabs(updated); +- setEditorValues(updated.tabs[updated.activeTabIndex]); +- onTabChange == null ? void 0 : onTabChange(updated); +- return updated; +- }); +- }, [ +- defaultHeaders, +- onTabChange, +- setEditorValues, +- storeTabs, +- synchronizeActiveTabValues +- ]); ++ const addTab = useCallback( ++ (_tabState) => { ++ setTabState((current) => { ++ const updatedValues = synchronizeActiveTabValues(current); ++ const updated = { ++ tabs: [ ++ ...updatedValues.tabs, ++ createTab({ ..._tabState, headers: defaultHeaders }) ++ ], ++ activeTabIndex: updatedValues.tabs.length ++ }; ++ storeTabs(updated); ++ setEditorValues(updated.tabs[updated.activeTabIndex]); ++ onTabChange == null ? void 0 : onTabChange(updated); ++ return updated; ++ }); ++ }, ++ [ ++ defaultHeaders, ++ onTabChange, ++ setEditorValues, ++ storeTabs, ++ synchronizeActiveTabValues ++ ] ++ ); + const changeTab = useCallback( + (index) => { + setTabState((current) => { +@@ -3418,6 +3425,7 @@ function EditorContextProvider(props) { + const value = useMemo( + () => ({ + ...tabState, ++ setTabState, + addTab, + changeTab, + moveTab, +diff --git a/dist/types/editor/context.d.ts b/dist/types/editor/context.d.ts +index 199db8a294f8132d46470498870adbdf9fdc83af..d8901fe0d50db17db36a502dcf69d5f69efb84a1 100644 +--- a/dist/types/editor/context.d.ts ++++ b/dist/types/editor/context.d.ts +@@ -1,6 +1,6 @@ + import { DocumentNode, FragmentDefinitionNode, OperationDefinitionNode, ValidationRule } from 'graphql'; + import { VariableToType } from 'graphql-language-service'; +-import { ReactNode } from 'react'; ++import { Dispatch, ReactNode, SetStateAction } from 'react'; + import { TabDefinition, TabsState, TabState } from './tabs'; + import { CodeMirrorEditor } from './types'; + export declare type CodeMirrorEditorWithOperationFacts = CodeMirrorEditor & { +@@ -10,10 +10,11 @@ export declare type CodeMirrorEditorWithOperationFacts = CodeMirrorEditor & { + variableToType: VariableToType | null; + }; + export declare type EditorContextType = TabsState & { ++ setTabState: Dispatch>; + /** + * Add a new tab. + */ +- addTab(): void; ++ addTab(tabState?: Pick): void; + /** + * Switch to a different tab. + * @param index The index of the tab that should be switched to. +@@ -38,7 +39,7 @@ export declare type EditorContextType = TabsState & { + * @param partialTab A partial tab state object that will override the + * current values. The properties `id`, `hash` and `title` cannot be changed. + */ +- updateActiveTabValues(partialTab: Partial>): void; ++ updateActiveTabValues(partialTab: Partial>): void; + /** + * The CodeMirror editor instance for the headers editor. + */ +diff --git a/dist/types/editor/tabs.d.ts b/dist/types/editor/tabs.d.ts +index 28704a9c1c6e22fa75986de8591759e13035c8c5..5204d2b25198f89da9bba70804656f02799c7df6 100644 +--- a/dist/types/editor/tabs.d.ts ++++ b/dist/types/editor/tabs.d.ts +@@ -90,7 +90,7 @@ export declare function useSetEditorValues({ queryEditor, variableEditor, header + headers?: string | null | undefined; + response: string | null; + }) => void; +-export declare function createTab({ query, variables, headers, }?: Partial): TabState; ++export declare function createTab({ id, title, query, variables, headers, }: Partial>): TabState; + export declare function setPropertiesInActiveTab(state: TabsState, partialTab: Partial>): TabsState; + export declare function fuzzyExtractOperationName(str: string): string | null; + export declare function clearHeadersFromTabs(storage: StorageAPI | null): void; diff --git a/patches/graphiql@3.3.0.patch b/patches/graphiql@3.3.0.patch deleted file mode 100644 index 92dac402c..000000000 --- a/patches/graphiql@3.3.0.patch +++ /dev/null @@ -1,25 +0,0 @@ -# move prettify button to the end, we can't use `` because `usePrettifyEditors` needs to access `EditorContextProvider` -# -diff --git a/esm/components/GraphiQL.js b/esm/components/GraphiQL.js -index adf5b7dfc4d292391c5f3c20d7082984529062d9..e8d32614459dd0e9ee484ce278b8ce4f3a9e7d35 100644 ---- a/esm/components/GraphiQL.js -+++ b/esm/components/GraphiQL.js -@@ -139,14 +139,10 @@ export function GraphiQLInterface(props) { - var toolbar = children.find(function (child) { - return isChildComponentType(child, GraphiQL.Toolbar); - }) || (React.createElement(React.Fragment, null, -- React.createElement(ToolbarButton, { onClick: prettify, label: "Prettify query (Shift-Ctrl-P)" }, -- React.createElement(PrettifyIcon, { className: "graphiql-toolbar-icon", "aria-hidden": "true" })), -- React.createElement(ToolbarButton, { onClick: merge, label: "Merge fragments into query (Shift-Ctrl-M)" }, -- React.createElement(MergeIcon, { className: "graphiql-toolbar-icon", "aria-hidden": "true" })), -- React.createElement(ToolbarButton, { onClick: copy, label: "Copy query (Shift-Ctrl-C)" }, -- React.createElement(CopyIcon, { className: "graphiql-toolbar-icon", "aria-hidden": "true" })), (_c = props.toolbar) === null || _c === void 0 ? void 0 : -- _c.additionalContent, -- ((_d = props.toolbar) === null || _d === void 0 ? void 0 : _d.additionalComponent) && (React.createElement(props.toolbar.additionalComponent, null)))); -+ (_c = props.toolbar) === null || _c === void 0 ? void 0 : _c.additionalContent, -+ ((_d = props.toolbar) === null || _d === void 0 ? void 0 : _d.additionalComponent) && (React.createElement(props.toolbar.additionalComponent, null)), -+ React.createElement(ToolbarButton, { onClick: prettify, label: "Prettify query (Shift-Ctrl-P)" }, React.createElement(PrettifyIcon, { className: "graphiql-toolbar-icon", "aria-hidden": "true" })) -+ )); - var footer = children.find(function (child) { - return isChildComponentType(child, GraphiQL.Footer); - }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 68745b0d2..7eca4235e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ patchedDependencies: '@apollo/federation@0.38.1': hash: rjgakkkphrejw6qrtph4ar24zq path: patches/@apollo__federation@0.38.1.patch + '@graphiql/react@1.0.0-alpha.3': + hash: gnbo5nw2wgehkfq2yrmuhrx4im + path: patches/@graphiql__react@1.0.0-alpha.3.patch '@graphql-eslint/eslint-plugin@3.20.1': hash: n437g5o7zq7pnxdxldn52uql2q path: patches/@graphql-eslint__eslint-plugin@3.20.1.patch @@ -26,9 +29,6 @@ patchedDependencies: got@14.4.2: hash: b6pwqmrs3qqykctltsasvrfwti path: patches/got@14.4.2.patch - graphiql@3.3.2: - hash: p4mc7pxwsatzeupmv5hnqi5t6q - path: patches/graphiql@3.3.0.patch mjml-core@4.14.0: hash: zxxsxbqejjmcwuzpigutzzq6wa path: patches/mjml-core@4.14.0.patch @@ -1309,7 +1309,7 @@ importers: devDependencies: '@graphql-inspector/core': specifier: 5.1.0-alpha-20231208113249-34700c8a - version: 5.1.0-alpha-20231208113249-34700c8a(graphql@16.9.0) + version: 5.1.0-alpha-20231208113249-34700c8a(graphql@17.0.0-alpha.7) '@hive/service-common': specifier: workspace:* version: link:../service-common @@ -1638,8 +1638,8 @@ importers: specifier: 6.0.7 version: 6.0.7(@types/node@20.16.1)(less@4.2.0)(terser@5.31.1) '@graphiql/react': - specifier: 0.22.4 - version: 0.22.4(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 1.0.0-alpha.3 + version: 1.0.0-alpha.3(patch_hash=gnbo5nw2wgehkfq2yrmuhrx4im)(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@graphiql/toolkit': specifier: 0.9.1 version: 0.9.1(@types/node@20.16.1)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0) @@ -1851,8 +1851,8 @@ importers: specifier: 11.3.28 version: 11.3.28(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) graphiql: - specifier: 3.3.2 - version: 3.3.2(patch_hash=p4mc7pxwsatzeupmv5hnqi5t6q)(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 4.0.0-alpha.4 + version: 4.0.0-alpha.4(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) graphql: specifier: 16.9.0 version: 16.9.0 @@ -4192,13 +4192,22 @@ packages: graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 typescript: ^5.0.0 - '@graphiql/react@0.22.4': - resolution: {integrity: sha512-FsupNjAUJ17qhdyCjKo150wpNH7gr0ScAm/Rmk7VHP4Mh0Osid+1bKLPtXEOjGI+InuTPSKhJw3Zbm8dD3+o1A==} + '@graphiql/react@1.0.0-alpha.3': + resolution: {integrity: sha512-9WPfC7I9xO1qC/dKaYwVe3UbPJvdjU+fxoUW2Id0mIljkD7LXnVUnzBQMB1SY4JrRJX3I0nQPbHXzKvAYSpnjw==} peerDependencies: - graphql: ^15.5.0 || ^16.0.0 + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2 react: ^16.8.0 || ^17 || ^18 react-dom: ^16.8.0 || ^17 || ^18 + '@graphiql/toolkit@0.10.0': + resolution: {integrity: sha512-tVWVYL4AKrkBr4f4Vw4/EV1NjstVYg3TGnatFVe6TdBW4kBeATBz5jyGJju/Oq2JrrrQ2LNXfhCDwfdjSlKyHg==} + peerDependencies: + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2 + graphql-ws: '>= 4.5.0' + peerDependenciesMeta: + graphql-ws: + optional: true + '@graphiql/toolkit@0.9.1': resolution: {integrity: sha512-LVt9pdk0830so50ZnU2Znb2rclcoWznG8r8asqAENzV0U1FM1kuY0sdPpc/rBc9MmmNgnB6A+WZzDhq6dbhTHA==} peerDependencies: @@ -5055,24 +5064,6 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@motionone/animation@10.15.1': - resolution: {integrity: sha512-mZcJxLjHor+bhcPuIFErMDNyrdb2vJur8lSfMCsuCB4UyV8ILZLvK+t+pg56erv8ud9xQGK/1OGPt10agPrCyQ==} - - '@motionone/dom@10.12.0': - resolution: {integrity: sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==} - - '@motionone/easing@10.15.1': - resolution: {integrity: sha512-6hIHBSV+ZVehf9dcKZLT7p5PEKHGhDwky2k8RKkmOvUoYP3S+dXsKupyZpqx5apjd9f+php4vXk4LuS+ADsrWw==} - - '@motionone/generators@10.15.1': - resolution: {integrity: sha512-67HLsvHJbw6cIbLA/o+gsm7h+6D4Sn7AUrB/GPxvujse1cGZ38F5H7DzoH7PhX+sjvtDnt2IhFYF2Zp1QTMKWQ==} - - '@motionone/types@10.15.1': - resolution: {integrity: sha512-iIUd/EgUsRZGrvW0jqdst8st7zKTzS9EsKkP+6c6n4MPZoQHwiHuVtTQLD6Kp0bsBLhNzKIBlHXponn/SDT4hA==} - - '@motionone/utils@10.15.1': - resolution: {integrity: sha512-p0YncgU+iklvYr/Dq4NobTRdAPv9PveRDUXabPEeOjBLSO/1FNB2phNTZxOxpi1/GZwYpAoECEa0Wam+nsmhSw==} - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2': resolution: {integrity: sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==} cpu: [arm64] @@ -9246,12 +9237,12 @@ packages: code-block-writer@13.0.1: resolution: {integrity: sha512-c5or4P6erEA69TxaxTNcHUNcIn+oyxSRTOWV+pSYF+z4epXqNvwvJ70XPGjPNgue83oAFAPBRQYwpAJ/Hpe/Sg==} - codemirror-graphql@2.0.12: - resolution: {integrity: sha512-5UCqhWzck1jClCmRewFb8aSiabnAqiaRfsvIPfmbf6WJvOb8oiefJeHilclPPiZBzY8v/Et6EBMtOeKnWCoyng==} + codemirror-graphql@2.1.0: + resolution: {integrity: sha512-Lm5augEJOd+7L6HXzBDmx/n7ViL8P/Dt0ba21X0JLeaMMEWtcG1SOvIdeI35St9ADOGdu/eMOg7aciX/RnWDFA==} peerDependencies: '@codemirror/language': 6.0.0 codemirror: ^5.65.3 - graphql: ^15.5.0 || ^16.0.0 + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2 codemirror@5.65.9: resolution: {integrity: sha512-19Jox5sAKpusTDgqgKB5dawPpQcY+ipQK7xoEI+MVucEF9qqFaXpeqY1KaoyGBso/wHQoDa4HMMxMjdsS3Zzzw==} @@ -9726,6 +9717,9 @@ packages: dayjs@1.11.7: resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==} + debounce-promise@3.1.2: + resolution: {integrity: sha512-rZHcgBkbYavBeD9ej6sP56XfG53d51CD4dnaw989YX/nZ/ZJfgRx/9ePKmTNiUiyQvh4mtrMoS3OAWW+yoYtpg==} + debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -10812,6 +10806,17 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + framer-motion@10.18.0: + resolution: {integrity: sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + framer-motion@11.3.28: resolution: {integrity: sha512-dqhoawipEAjqdv32zbv72sOMJZjol7dROWn7t/FOq23WXJ40O4OUybgnO2ldnuS+3YquSn8xO/KKRavZ+TBVOQ==} peerDependencies: @@ -10826,15 +10831,6 @@ packages: react-dom: optional: true - framer-motion@6.5.1: - resolution: {integrity: sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==} - peerDependencies: - react: '>=16.8 || ^17.0.0 || ^18.0.0' - react-dom: '>=16.8 || ^17.0.0 || ^18.0.0' - - framesync@6.0.1: - resolution: {integrity: sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==} - fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -10975,6 +10971,10 @@ packages: get-tsconfig@4.7.5: resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} + get-value@3.0.1: + resolution: {integrity: sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==} + engines: {node: '>=6.0'} + getos@3.2.1: resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} @@ -11106,10 +11106,10 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - graphiql@3.3.2: - resolution: {integrity: sha512-LJ8Q6UM3kUzTXvybud9a4sj/QBEVHwHWd5Oc3OjLp9DQiKjqVY/2P/Q3RdPQD/MihwaO+6eC69R4MYnPQGd2Hw==} + graphiql@4.0.0-alpha.4: + resolution: {integrity: sha512-mMjUJKqNSuHGDBC6JE3CprtBniB3iaGN7Ifisrd6ucmpH7biqA1uIbz1LgzCeQdtndCTHADLJu6dCGOWAcgP9w==} peerDependencies: - graphql: ^15.5.0 || ^16.0.0 + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2 react: ^16.8.0 || ^17 || ^18 react-dom: ^16.8.0 || ^17 || ^18 @@ -11174,11 +11174,11 @@ packages: peerDependencies: graphql: ^15.5.0 || ^16.0.0 - graphql-language-service@5.2.1: - resolution: {integrity: sha512-8ewD6otGO43vg2TiEGjoLz3CweTwfaf4ZnqfNREqZXS2JSJGXtsRBOMMknCxMfFVh4x14ql3jyDrXcyAAtbmkQ==} + graphql-language-service@5.3.0: + resolution: {integrity: sha512-gCQIIy7lM9CB1KPLEb+DNZLczA9zuTLEOJE2hEQZTFYInogdmMDRa6RAkvM4LL0LcgcS+3uPs6KtHlcjCqRbUg==} hasBin: true peerDependencies: - graphql: ^15.5.0 || ^16.0.0 + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2 graphql-modules@2.3.0: resolution: {integrity: sha512-CcrjUjMYHy3zelnffldhR3h6t4ndCVJEzdqBAv/mp4ZGEA/izirOKZB2lnRwpXNqOtVwIz2O/E1Cg/UH8dFNaQ==} @@ -11248,6 +11248,10 @@ packages: resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + graphql@17.0.0-alpha.7: + resolution: {integrity: sha512-kdteHez9s0lfNAGntSwnDBpxSl09sBWEFxFRPS/Z8K1nCD4FZ2wVGwXuj5dvrTKcqOA+O8ujAJ3CiY/jXhs14g==} + engines: {node: ^16.19.0 || ^18.14.0 || >=19.7.0} + gray-matter@4.0.3: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} @@ -11355,9 +11359,6 @@ packages: help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} - hey-listen@1.0.8: - resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} - highlight-words-core@1.2.2: resolution: {integrity: sha512-BXUKIkUuh6cmmxzi5OIbUJxrG8OAk2MqoL1DtO3Wo9D2faJg2ph5ntyuQeLqaHJmzER6H5tllCDA9ZnNe9BVGg==} @@ -13911,9 +13912,6 @@ packages: resolution: {integrity: sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==} engines: {node: '>=10'} - popmotion@11.0.3: - resolution: {integrity: sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==} - postcss-calc@10.0.0: resolution: {integrity: sha512-OmjhudoNTP0QleZCwl1i6NeBwN+5MZbY5ersLZz69mjJiDVv/p57RjRuKDkHeDWr4T+S97wQfsqRTNoDHB2e3g==} engines: {node: ^18.12 || ^20.9 || >=22.0} @@ -15486,9 +15484,6 @@ packages: style-to-object@1.0.5: resolution: {integrity: sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ==} - style-value-types@5.0.0: - resolution: {integrity: sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==} - styled-jsx@5.1.1: resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} @@ -17106,10 +17101,10 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0) - '@aws-sdk/client-sts': 3.596.0 + '@aws-sdk/client-sso-oidc': 3.596.0 + '@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0) '@aws-sdk/core': 3.592.0 - '@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0) + '@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -17214,13 +17209,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0)': + '@aws-sdk/client-sso-oidc@3.596.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.596.0 + '@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0) '@aws-sdk/core': 3.592.0 - '@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0) + '@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -17257,7 +17252,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso-oidc@3.632.0(@aws-sdk/client-sts@3.632.0)': @@ -17391,13 +17385,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.596.0': + '@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0) + '@aws-sdk/client-sso-oidc': 3.596.0 '@aws-sdk/core': 3.592.0 - '@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0) + '@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -17434,6 +17428,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/client-sts@3.632.0': @@ -17542,14 +17537,14 @@ snapshots: '@smithy/util-stream': 3.1.3 tslib: 2.6.3 - '@aws-sdk/credential-provider-ini@3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0)': + '@aws-sdk/credential-provider-ini@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))': dependencies: - '@aws-sdk/client-sts': 3.596.0 + '@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0) '@aws-sdk/credential-provider-env': 3.587.0 '@aws-sdk/credential-provider-http': 3.596.0 '@aws-sdk/credential-provider-process': 3.587.0 - '@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0)) - '@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.596.0) + '@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.596.0) + '@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.1.4 '@smithy/property-provider': 3.1.3 @@ -17578,14 +17573,14 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-node@3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0)': + '@aws-sdk/credential-provider-node@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))': dependencies: '@aws-sdk/credential-provider-env': 3.587.0 '@aws-sdk/credential-provider-http': 3.596.0 - '@aws-sdk/credential-provider-ini': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0) + '@aws-sdk/credential-provider-ini': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)) '@aws-sdk/credential-provider-process': 3.587.0 - '@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0)) - '@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.596.0) + '@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.596.0) + '@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.1.4 '@smithy/property-provider': 3.1.3 @@ -17632,10 +17627,10 @@ snapshots: '@smithy/types': 3.3.0 tslib: 2.6.3 - '@aws-sdk/credential-provider-sso@3.592.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))': + '@aws-sdk/credential-provider-sso@3.592.0(@aws-sdk/client-sso-oidc@3.596.0)': dependencies: '@aws-sdk/client-sso': 3.592.0 - '@aws-sdk/token-providers': 3.587.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0)) + '@aws-sdk/token-providers': 3.587.0(@aws-sdk/client-sso-oidc@3.596.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 @@ -17658,9 +17653,9 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.596.0)': + '@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))': dependencies: - '@aws-sdk/client-sts': 3.596.0 + '@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.1.3 '@smithy/types': 3.3.0 @@ -17825,9 +17820,9 @@ snapshots: '@smithy/types': 3.3.0 tslib: 2.6.3 - '@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))': + '@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.596.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0) + '@aws-sdk/client-sso-oidc': 3.596.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 @@ -19699,7 +19694,7 @@ snapshots: '@escape.tech/graphql-armor-types@0.6.0': dependencies: - graphql: 16.9.0 + graphql: link:../graphiql/node_modules/graphql optional: true '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0(patch_hash=fjbpfrtrjd6idngyeqxnwopfva))': @@ -19870,9 +19865,9 @@ snapshots: graphql: 16.9.0 typescript: 5.5.4 - '@graphiql/react@0.22.4(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@graphiql/react@1.0.0-alpha.3(patch_hash=gnbo5nw2wgehkfq2yrmuhrx4im)(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@graphiql/toolkit': 0.9.1(@types/node@20.16.1)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0) + '@graphiql/toolkit': 0.10.0(@types/node@20.16.1)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0) '@headlessui/react': 1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dialog': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dropdown-menu': 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -19881,11 +19876,12 @@ snapshots: '@types/codemirror': 5.60.15 clsx: 1.2.1 codemirror: 5.65.9 - codemirror-graphql: 2.0.12(@codemirror/language@6.10.2)(codemirror@5.65.9)(graphql@16.9.0) + codemirror-graphql: 2.1.0(@codemirror/language@6.10.2)(codemirror@5.65.9)(graphql@16.9.0) copy-to-clipboard: 3.3.3 - framer-motion: 6.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + framer-motion: 10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + get-value: 3.0.1 graphql: 16.9.0 - graphql-language-service: 5.2.1(graphql@16.9.0) + graphql-language-service: 5.3.0(graphql@16.9.0) markdown-it: 14.1.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -19897,6 +19893,16 @@ snapshots: - '@types/react-dom' - graphql-ws + '@graphiql/toolkit@0.10.0(@types/node@20.16.1)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)': + dependencies: + '@n1ru4l/push-pull-async-iterable-iterator': 3.2.0 + graphql: 16.9.0 + meros: 1.2.1(@types/node@20.16.1) + optionalDependencies: + graphql-ws: 5.16.0(graphql@16.9.0) + transitivePeerDependencies: + - '@types/node' + '@graphiql/toolkit@0.9.1(@types/node@20.16.1)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)': dependencies: '@n1ru4l/push-pull-async-iterable-iterator': 3.2.0 @@ -20255,6 +20261,13 @@ snapshots: object-inspect: 1.12.3 tslib: 2.6.2 + '@graphql-inspector/core@5.1.0-alpha-20231208113249-34700c8a(graphql@17.0.0-alpha.7)': + dependencies: + dependency-graph: 0.11.0 + graphql: 17.0.0-alpha.7 + object-inspect: 1.12.3 + tslib: 2.6.2 + '@graphql-inspector/coverage-command@5.0.3(@graphql-inspector/config@4.0.2(graphql@16.9.0))(@graphql-inspector/loaders@4.0.3(@babel/core@7.22.9)(@graphql-inspector/config@4.0.2(graphql@16.9.0))(graphql@16.9.0))(graphql@16.9.0)(yargs@17.7.2)': dependencies: '@graphql-inspector/commands': 4.0.3(@graphql-inspector/config@4.0.2(graphql@16.9.0))(@graphql-inspector/loaders@4.0.3(@babel/core@7.22.9)(@graphql-inspector/config@4.0.2(graphql@16.9.0))(graphql@16.9.0))(graphql@16.9.0)(yargs@17.7.2) @@ -21390,41 +21403,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@motionone/animation@10.15.1': - dependencies: - '@motionone/easing': 10.15.1 - '@motionone/types': 10.15.1 - '@motionone/utils': 10.15.1 - tslib: 2.6.3 - - '@motionone/dom@10.12.0': - dependencies: - '@motionone/animation': 10.15.1 - '@motionone/generators': 10.15.1 - '@motionone/types': 10.15.1 - '@motionone/utils': 10.15.1 - hey-listen: 1.0.8 - tslib: 2.6.3 - - '@motionone/easing@10.15.1': - dependencies: - '@motionone/utils': 10.15.1 - tslib: 2.6.3 - - '@motionone/generators@10.15.1': - dependencies: - '@motionone/types': 10.15.1 - '@motionone/utils': 10.15.1 - tslib: 2.6.3 - - '@motionone/types@10.15.1': {} - - '@motionone/utils@10.15.1': - dependencies: - '@motionone/types': 10.15.1 - hey-listen: 1.0.8 - tslib: 2.6.3 - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2': optional: true @@ -26653,13 +26631,13 @@ snapshots: code-block-writer@13.0.1: {} - codemirror-graphql@2.0.12(@codemirror/language@6.10.2)(codemirror@5.65.9)(graphql@16.9.0): + codemirror-graphql@2.1.0(@codemirror/language@6.10.2)(codemirror@5.65.9)(graphql@16.9.0): dependencies: '@codemirror/language': 6.10.2 '@types/codemirror': 0.0.90 codemirror: 5.65.9 graphql: 16.9.0 - graphql-language-service: 5.2.1(graphql@16.9.0) + graphql-language-service: 5.3.0(graphql@16.9.0) codemirror@5.65.9: {} @@ -27213,6 +27191,8 @@ snapshots: dayjs@1.11.7: {} + debounce-promise@3.1.2: {} + debounce@1.2.1: {} debug@2.6.9: @@ -28631,6 +28611,14 @@ snapshots: fraction.js@4.3.7: {} + framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + tslib: 2.6.3 + optionalDependencies: + '@emotion/is-prop-valid': 0.8.8 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + framer-motion@11.3.28(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: tslib: 2.6.3 @@ -28639,23 +28627,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - framer-motion@6.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@motionone/dom': 10.12.0 - framesync: 6.0.1 - hey-listen: 1.0.8 - popmotion: 11.0.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - style-value-types: 5.0.0 - tslib: 2.6.3 - optionalDependencies: - '@emotion/is-prop-valid': 0.8.8 - - framesync@6.0.1: - dependencies: - tslib: 2.6.3 - fresh@0.5.2: {} fromentries@1.3.2: {} @@ -28805,6 +28776,10 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-value@3.0.1: + dependencies: + isobject: 3.0.1 + getos@3.2.1: dependencies: async: 3.2.4 @@ -28999,13 +28974,10 @@ snapshots: graphemer@1.4.0: {} - graphiql@3.3.2(patch_hash=p4mc7pxwsatzeupmv5hnqi5t6q)(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + graphiql@4.0.0-alpha.4(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@graphiql/react': 0.22.4(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@graphiql/toolkit': 0.9.1(@types/node@20.16.1)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0) + '@graphiql/react': 1.0.0-alpha.3(patch_hash=gnbo5nw2wgehkfq2yrmuhrx4im)(@codemirror/language@6.10.2)(@types/node@20.16.1)(@types/react-dom@18.3.0)(@types/react@18.3.3)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) graphql: 16.9.0 - graphql-language-service: 5.2.1(graphql@16.9.0) - markdown-it: 14.1.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: @@ -29136,8 +29108,9 @@ snapshots: - encoding - utf-8-validate - graphql-language-service@5.2.1(graphql@16.9.0): + graphql-language-service@5.3.0(graphql@16.9.0): dependencies: + debounce-promise: 3.1.2 graphql: 16.9.0 nullthrows: 1.1.1 vscode-languageserver-types: 3.17.2 @@ -29224,6 +29197,8 @@ snapshots: graphql@16.9.0: {} + graphql@17.0.0-alpha.7: {} + gray-matter@4.0.3: dependencies: js-yaml: 3.14.1 @@ -29411,8 +29386,6 @@ snapshots: help-me@5.0.0: {} - hey-listen@1.0.8: {} - highlight-words-core@1.2.2: {} hoist-non-react-statics@3.3.2: @@ -30579,7 +30552,7 @@ snapshots: markdown-it@14.1.0: dependencies: argparse: 2.0.1 - entities: 4.4.0 + entities: 4.5.0 linkify-it: 5.0.0 mdurl: 2.0.0 punycode.js: 2.3.1 @@ -32710,13 +32683,6 @@ snapshots: dependencies: '@babel/runtime': 7.24.7 - popmotion@11.0.3: - dependencies: - framesync: 6.0.1 - hey-listen: 1.0.8 - style-value-types: 5.0.0 - tslib: 2.6.3 - postcss-calc@10.0.0(postcss@8.4.41): dependencies: postcss: 8.4.41 @@ -34449,11 +34415,6 @@ snapshots: dependencies: inline-style-parser: 0.2.2 - style-value-types@5.0.0: - dependencies: - hey-listen: 1.0.8 - tslib: 2.6.3 - styled-jsx@5.1.1(@babel/core@7.22.9)(react@18.3.1): dependencies: client-only: 0.0.1