Fix editor state and operation handling in Laboratory + e2e tests (#6282)

Fixes

When opening a new tab or selecting one of the saved operations a wrong query was populated. It was always the default query or the one that's active. Meaning, you couldn't select and see the saved operation :)

When saving the operation, the submit button of the form was always disabled, even when the state of the form was valid.

e2e tests

Added tests for CRUD of collections and their operations.
The scenario where a user visits a shared link to an operation is also now tested.
This commit is contained in:
Kamil Kisiela 2025-01-09 09:59:17 +01:00 committed by GitHub
parent 469443bdc2
commit a7f9d50fb9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 350 additions and 38 deletions

View file

@ -0,0 +1,7 @@
---
'hive': patch
---
Fix editor state and operation handling in Laboratory.
When opening a new tab or selecting a saved operation, the editor incorrectly populated the query, defaulting to the active query. This made it impossible to view the selected operation. Additionally, the submit button for saving an operation was always disabled, even when the form was in a valid state.

View file

@ -234,6 +234,7 @@ module.exports = {
extends: 'plugin:cypress/recommended',
rules: {
'cypress/no-unnecessary-waiting': 'off',
'cypress/unsafe-to-chain-command': 'off',
},
},
],

View file

@ -0,0 +1,248 @@
import { laboratory } from '../support/testkit';
beforeEach(() => {
cy.clearAllLocalStorage().then(() => {
return cy.task('seedTarget').then(({ slug, refreshToken }: any) => {
cy.setCookie('sRefreshToken', refreshToken);
cy.visit(`/${slug}/laboratory`);
// To make sure the operation collections tab is opened
// It first opens the Documentation Explorer or GraphiQL Explorer,
// then opens the Operation Collections tab.
// It does that, because the Operation Collections tab could be already opened for some reason.
// This way it's guaranteed that the Operation Collections tab is opened.
cy.get('[aria-label*="Show Documentation Explorer"], [aria-label*="Show GraphiQL Explorer"]')
.first()
.click();
cy.get('[aria-label="Show Operation Collections"]').click();
});
});
});
const collections = {
/**
* Opens the modal to create a new collection and fills the form
*/
create(args: { name: string; description: string }) {
cy.get('button[data-cy="new-collection"]').click();
cy.get('div[data-cy="create-collection-modal"] input[name="name"]').type(args.name);
cy.get('div[data-cy="create-collection-modal"] input[name="description"]').type(
args.description,
);
cy.get('div[data-cy="create-collection-modal"] button[type="submit"]').click();
},
/**
* Clicks on a collection in the sidebar
*/
clickCollectionButton(name: string) {
cy.get('button[data-cy="collection-item-trigger"]').contains(name).click();
},
/**
* Saves the current operation as a new operation and assigns it to a collection
*/
saveCurrentOperationAs(args: { name: string; collectionName: string }) {
cy.get('[data-cy="save-operation"]').click();
cy.get('[data-cy="save-operation-as"]').click();
cy.get('div[data-cy="create-operation-modal"] input[name="name"]').type(args.name);
cy.get(
'div[data-cy="create-operation-modal"] button[data-cy="collection-select-trigger"]',
).click();
cy.get('div[data-cy="collection-select-item"]').contains(args.collectionName).click();
cy.get('div[data-cy="create-operation-modal"] button[type="submit"]').click();
},
/**
* Opens the menu for a specific operation, to access delete, copy link or edit buttons.
*/
openOperationMenu(name: string) {
return cy.get(`a[data-cy="operation-${name}"] ~ button`).click();
},
/**
* Opens the menu for a specific collection, to access delete or edit buttons.
*/
openCollectionMenu(name: string) {
return cy
.contains(`[data-cy="collection-item-trigger"]`, name)
.parent()
.get('[data-cy="collection-menu-trigger"]')
.click();
},
/**
* Returns the operation element
*/
getOperationButton(name: string) {
return cy.get<HTMLAnchorElement>(`a[data-cy="operation-${name}"]`);
},
/**
* Returns the collection element
*/
getCollectionButton(name: string) {
return cy.contains('[data-cy="collection-item"]', name);
},
};
describe('Laboratory > Collections', () => {
it('create a collection and an operation', () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});
collections.getOperationButton('operation-1').should('exist');
});
it(`edit collection's name`, () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});
collections.openCollectionMenu('collection-1');
// Click on the edit button and fill the form
cy.get('[data-cy="edit-collection"]').click();
cy.get('[data-cy="create-collection-modal"]').should('exist');
cy.get('[data-cy="create-collection-modal"] input[name="name"]')
.clear()
.type('collection-1-updated');
cy.get('[data-cy="create-collection-modal"] button[data-cy="confirm"]').click();
collections.getCollectionButton('collection-1-updated').should('exist');
collections.getOperationButton('operation-1').should('exist');
});
it('delete a collection', () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});
collections.getOperationButton('operation-1').should('exist');
collections.getCollectionButton('collection-1').should('exist');
collections.openCollectionMenu('collection-1');
// Click on the delete button and confirm the deletion
cy.get('[data-cy="delete-collection"]').click();
cy.get('[data-cy="delete-collection-modal"]').should('exist');
cy.get('[data-cy="delete-collection-modal"] button[data-cy="confirm"]').click();
collections.getOperationButton('operation-1').should('not.exist');
collections.getCollectionButton('collection-1').should('not.exist');
});
it(`edit operation's name`, () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});
collections.openOperationMenu('operation-1');
// Click on the edit button and fill the form
cy.get('[data-cy="edit-operation"]').click();
cy.get('[data-cy="edit-operation-modal"]').should('exist');
cy.get('[data-cy="edit-operation-modal"] input[name="name"]').type('operation-1-updated');
cy.get('[data-cy="edit-operation-modal"] button[data-cy="confirm"]').click();
collections.getOperationButton('operation-1').should('not.exist');
collections.getOperationButton('operation-1-updated').should('exist');
});
it('delete an operation', () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});
laboratory.openNewTab();
laboratory.updateEditorValue(`query op2 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-2',
collectionName: 'collection-1',
});
collections.openOperationMenu('operation-1');
// Click on the delete button and confirm the deletion
cy.get('[data-cy="delete-operation"]').click();
cy.get('[data-cy="delete-operation-modal"]').should('exist');
cy.get('[data-cy="delete-operation-modal"] button[data-cy="confirm"]').click();
collections.getOperationButton('operation-1').should('not.exist');
collections.getOperationButton('operation-2').should('exist');
});
it('visiting a copied operation link should open the operation', () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
collections.create({
name: 'collection-2',
description: 'Description 2',
});
collections.clickCollectionButton('collection-1');
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});
laboratory.openNewTab();
laboratory.updateEditorValue(`query op2 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-2',
collectionName: 'collection-2',
});
collections.openOperationMenu('operation-1');
// Stub the clipboard API to intercept the copied URL
cy.window().then(win => {
cy.stub(win.navigator.clipboard, 'writeText').as('copied');
});
cy.get('[data-cy="copy-operation-link"]').click();
cy.get<{
getCall(index: number): {
args: unknown[];
};
}>('@copied')
.should('have.been.calledOnce')
.then(stub => {
const copiedUrl = stub.getCall(0).args[0]; // Extract the copied URL
if (typeof copiedUrl !== 'string') {
throw new Error('The copied URL is not a string');
}
// Navigate to the copied URL
return cy.visit(copiedUrl);
});
laboratory.assertActiveTab('operation-1');
laboratory.getEditorValue().should('contain', 'op1');
});
});

View file

@ -34,7 +34,7 @@ function setEditorScript(script: string) {
setMonacoEditorContents('preflight-script-editor', script);
}
describe('Preflight Script', () => {
describe('Laboratory > Preflight Script', () => {
it('mini script editor is read only', () => {
cy.dataCy('toggle-preflight-script').click();
// Wait loading disappears

View file

@ -38,6 +38,40 @@ export function createProject(projectSlug: string) {
cy.get('form[data-cy="create-project-form"] [data-cy="submit"]').click();
}
export const laboratory = {
/**
* Updates the value of the graphiql editor
*/
updateEditorValue(value: string) {
cy.get('.graphiql-query-editor .cm-s-graphiql').then($editor => {
const editor = ($editor[0] as any).CodeMirror; // Access the CodeMirror instance
editor.setValue(value);
});
},
/**
* Returns the value of the graphiql editor as Chainable<string>
*/
getEditorValue() {
return cy.get('.graphiql-query-editor .cm-s-graphiql').then<string>($editor => {
const editor = ($editor[0] as any).CodeMirror; // Access the CodeMirror instance
return editor.getValue();
});
},
openNewTab() {
cy.get('button[aria-label="New tab"]').click();
// tab's title should be "untitled" as it's a default name
cy.contains('button[aria-controls="graphiql-session"]', 'untitled').should('exist');
},
/**
* Asserts that the tab with the given name is active
*/
assertActiveTab(name: string) {
cy.contains('li.graphiql-tab-active > button[aria-controls="graphiql-session"]', name).should(
'exist',
);
},
};
export function dedent(strings: TemplateStringsArray, ...values: unknown[]): string {
// Took from https://github.com/dmnd/dedent
// Couldn't use the package because I had some issues with moduleResolution.

View file

@ -235,7 +235,10 @@ export function CreateCollectionModalContent(props: {
}) {
return (
<Dialog open={props.isOpen} onOpenChange={props.toggleModalOpen}>
<DialogContent className="container w-4/5 max-w-[600px] md:w-3/5">
<DialogContent
className="container w-4/5 max-w-[600px] md:w-3/5"
data-cy="create-collection-modal"
>
{!props.fetching && (
<Form {...props.form}>
<form className="space-y-8" onSubmit={props.form.handleSubmit(props.onSubmit)}>

View file

@ -190,7 +190,10 @@ export function CreateOperationModalContent(props: {
props.form.reset();
}}
>
<DialogContent className="container w-4/5 max-w-[600px] md:w-3/5">
<DialogContent
className="container w-4/5 max-w-[600px] md:w-3/5"
data-cy="create-operation-modal"
>
{!props.fetching && (
<Form {...props.form}>
<form className="space-y-8" onSubmit={props.form.handleSubmit(props.onSubmit)}>
@ -224,13 +227,13 @@ export function CreateOperationModalContent(props: {
</FormLabel>
<FormControl>
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger>
<SelectTrigger data-cy="collection-select-trigger">
{props.collections.find(c => c.id === field.value)?.name ??
'Select a Collection'}
</SelectTrigger>
<SelectContent className="w-[--radix-select-trigger-width]">
{props.collections.map(c => (
<SelectItem key={c.id} value={c.id}>
<SelectItem key={c.id} value={c.id} data-cy="collection-select-item">
{c.name}
<div className="mt-1 line-clamp-1 text-xs opacity-50">
{c.description}
@ -263,12 +266,7 @@ export function CreateOperationModalContent(props: {
size="lg"
className="w-full justify-center"
variant="primary"
disabled={
props.form.formState.isSubmitting ||
!props.form.formState.isValid ||
!props.form.getValues('collectionId')
}
data-cy="confirm"
disabled={props.form.formState.isSubmitting || !props.form.formState.isValid}
>
Add Operation
</Button>

View file

@ -90,7 +90,7 @@ export function DeleteCollectionModalContent(props: {
}) {
return (
<Dialog open={props.isOpen} onOpenChange={props.toggleModalOpen}>
<DialogContent className="w-4/5 max-w-[520px] md:w-3/5">
<DialogContent className="w-4/5 max-w-[520px] md:w-3/5" data-cy="delete-collection-modal">
<DialogHeader>
<DialogTitle>Delete Collection</DialogTitle>
<DialogDescription>Are you sure you wish to delete this collection?</DialogDescription>
@ -108,7 +108,7 @@ export function DeleteCollectionModalContent(props: {
>
Cancel
</Button>
<Button variant="destructive" onClick={props.handleDelete}>
<Button variant="destructive" data-cy="confirm" onClick={props.handleDelete}>
Delete
</Button>
</DialogFooter>

View file

@ -99,7 +99,7 @@ export function DeleteOperationModalContent(props: {
}): ReactElement {
return (
<Dialog open={props.isOpen} onOpenChange={props.toggleModalOpen}>
<DialogContent className="w-4/5 max-w-[520px] md:w-3/5">
<DialogContent className="w-4/5 max-w-[520px] md:w-3/5" data-cy="delete-operation-modal">
<DialogHeader>
<DialogTitle>Delete Operation</DialogTitle>
<DialogDescription>Do you really want to delete this operation?</DialogDescription>
@ -117,7 +117,7 @@ export function DeleteOperationModalContent(props: {
>
Cancel
</Button>
<Button variant="destructive" onClick={props.handleDelete}>
<Button variant="destructive" data-cy="confirm" onClick={props.handleDelete}>
Delete
</Button>
</DialogFooter>

View file

@ -167,7 +167,10 @@ export const EditOperationModalContent = (props: {
props.form.reset();
}}
>
<DialogContent className="container w-4/5 max-w-[600px] md:w-3/5">
<DialogContent
className="container w-4/5 max-w-[600px] md:w-3/5"
data-cy="edit-operation-modal"
>
{!props.fetching && (
<Form {...props.form}>
<form className="space-y-8" onSubmit={props.form.handleSubmit(props.onSubmit)}>

View file

@ -308,19 +308,27 @@ export function Content() {
const renderedCollections = collections.map(collection => (
<AccordionItem key={collection.id} value={collection.id} className="border-b-0">
<AccordionHeader className="flex items-center justify-between">
<AccordionTriggerPrimitive className="group flex w-full items-center gap-x-3 rounded p-2 text-left font-medium text-white hover:bg-gray-100/10">
<AccordionHeader className="flex items-center justify-between" data-cy="collection-item">
<AccordionTriggerPrimitive
className="group flex w-full items-center gap-x-3 rounded p-2 text-left font-medium text-white hover:bg-gray-100/10"
data-cy="collection-item-trigger"
>
<FolderIcon className="size-4 group-data-[state=open]:hidden" />
<FolderOpenIcon className="size-4 group-data-[state=closed]:hidden" />
{collection.name}
</AccordionTriggerPrimitive>
{shouldShowMenu && (
<DropdownMenu>
<DropdownMenuTrigger aria-label="More" className="graphiql-toolbar-button">
<DropdownMenuTrigger
aria-label="More"
className="graphiql-toolbar-button"
data-cy="collection-menu-trigger"
>
<DotsHorizontalIcon />
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem
data-cy="add-operation-to-collection"
onClick={addOperation}
disabled={createOperationState.fetching}
data-collection-id={collection.id}
@ -329,6 +337,7 @@ export function Content() {
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
data-cy="edit-collection"
onClick={() => {
setCollectionId(collection.id);
toggleCollectionModal();
@ -337,6 +346,7 @@ export function Content() {
Edit
</DropdownMenuItem>
<DropdownMenuItem
data-cy="delete-collection"
onClick={() => {
setCollectionId(collection.id);
toggleDeleteCollectionModalOpen();
@ -361,6 +371,7 @@ export function Content() {
targetSlug,
}}
search={{ operation: node.id }}
data-cy={`operation-${node.name}`}
className={cn(
'flex w-full items-center gap-x-3 rounded p-2 font-normal text-white/50 hover:bg-gray-100/10 hover:text-white hover:no-underline',
node.id === queryParamsOperationId && [
@ -381,6 +392,7 @@ export function Content() {
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem
data-cy="copy-operation-link"
onClick={async () => {
const url = new URL(window.location.href);
await copyToClipboard(`${url.origin}${url.pathname}?operation=${node.id}`);
@ -391,6 +403,7 @@ export function Content() {
<DropdownMenuSeparator />
{canEdit && (
<DropdownMenuItem
data-cy="edit-operation"
onClick={() => {
setOperationToEditId(node.id);
}}
@ -400,6 +413,7 @@ export function Content() {
)}
{canDelete && (
<DropdownMenuItem
data-cy="delete-operation"
onClick={() => {
setOperationToDeleteId(node.id);
toggleDeleteOperationModalOpen();
@ -440,6 +454,7 @@ export function Content() {
<Button
variant="orangeLink"
size="icon-sm"
data-cy="new-collection"
className={clsx(
'flex w-auto items-center gap-1',
'min-w-0', // trick to make work truncate

View file

@ -164,6 +164,7 @@ function Save(props: {
<GraphiQLTooltip label={label}>
<DropdownMenuTrigger asChild>
<GraphiQLButton
data-cy="save-operation"
className={cn(
'graphiql-toolbar-button',
currentOperation && !isSame && 'hive-badge-is-changed relative after:top-1',
@ -226,6 +227,7 @@ function Save(props: {
Save
</DropdownMenuItem>
<DropdownMenuItem
data-cy="save-operation-as"
onClick={async () => {
if (!collections.length) {
notify('Please create a collection first.', 'error');

View file

@ -224,8 +224,8 @@ index 8ca339a2ba2031f0c1e22f1d099fa9a571492107..1cf3e8c620dc2c3ad4cfc42e2feeb4ca
+ ...updatedValues.tabs,
+ createTab({
+ ..._tabState,
+ headers: defaultHeaders,
+ query: defaultQuery ?? DEFAULT_QUERY
+ headers: _tabState?.headers ?? defaultHeaders,
+ query: _tabState?.query ?? (defaultQuery ?? DEFAULT_QUERY)
+ })
+ ],
+ activeTabIndex: updatedValues.tabs.length

View file

@ -21,7 +21,7 @@ patchedDependencies:
hash: wz23vdqq6qtsz64wb433afnvou
path: patches/@fastify__vite.patch
'@graphiql/react':
hash: bru5she67j343rpipomank3vn4
hash: cxjlr4qnvqgvcsnnl2map34diy
path: patches/@graphiql__react.patch
'@graphql-eslint/eslint-plugin@3.20.1':
hash: n437g5o7zq7pnxdxldn52uql2q
@ -1681,10 +1681,10 @@ importers:
version: 6.0.6(patch_hash=wz23vdqq6qtsz64wb433afnvou)(@types/node@22.10.3)(less@4.2.0)(lightningcss@1.28.2)(terser@5.37.0)
'@graphiql/plugin-explorer':
specifier: 4.0.0-alpha.2
version: 4.0.0-alpha.2(@graphiql/react@1.0.0-alpha.4(patch_hash=bru5she67j343rpipomank3vn4)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
version: 4.0.0-alpha.2(@graphiql/react@1.0.0-alpha.4(patch_hash=cxjlr4qnvqgvcsnnl2map34diy)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@graphiql/react':
specifier: 1.0.0-alpha.4
version: 1.0.0-alpha.4(patch_hash=bru5she67j343rpipomank3vn4)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
version: 1.0.0-alpha.4(patch_hash=cxjlr4qnvqgvcsnnl2map34diy)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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@22.10.3)(graphql-ws@5.16.1(graphql@16.9.0))(graphql@16.9.0)
@ -3901,6 +3901,7 @@ packages:
'@fastify/vite@6.0.6':
resolution: {integrity: sha512-FsWJC92murm5tjeTezTTvMLyZido/ZWy0wYWpVkh/bDe1gAUAabYLB7Vp8hokXGsRE/mOpqYVsRDAKENY2qPUQ==}
bundledDependencies: []
'@floating-ui/core@1.2.6':
resolution: {integrity: sha512-EvYTiXet5XqweYGClEmpu3BoxmsQ4hkj3QaYA6qEnigCWffTP3vNRwBReTdrwDwo7OoJ3wM8Uoe9Uk4n+d4hfg==}
@ -16502,8 +16503,8 @@ 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-sso-oidc@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/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/middleware-host-header': 3.577.0
@ -16610,11 +16611,11 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/client-sso-oidc@3.596.0':
'@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@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-sso-oidc@3.596.0)
'@aws-sdk/client-sts': 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/middleware-host-header': 3.577.0
@ -16653,6 +16654,7 @@ snapshots:
'@smithy/util-utf8': 3.0.0
tslib: 2.8.1
transitivePeerDependencies:
- '@aws-sdk/client-sts'
- aws-crt
'@aws-sdk/client-sso-oidc@3.723.0(@aws-sdk/client-sts@3.723.0)':
@ -16786,11 +16788,11 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)':
'@aws-sdk/client-sts@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-sso-oidc': 3.596.0(@aws-sdk/client-sts@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/middleware-host-header': 3.577.0
@ -16829,7 +16831,6 @@ snapshots:
'@smithy/util-utf8': 3.0.0
tslib: 2.8.1
transitivePeerDependencies:
- '@aws-sdk/client-sso-oidc'
- aws-crt
'@aws-sdk/client-sts@3.723.0':
@ -16943,7 +16944,7 @@ snapshots:
'@aws-sdk/credential-provider-ini@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0)':
dependencies:
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/client-sts': 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
@ -17062,7 +17063,7 @@ snapshots:
'@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.596.0)':
dependencies:
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/client-sts': 3.596.0
'@aws-sdk/types': 3.577.0
'@smithy/property-provider': 3.1.11
'@smithy/types': 3.7.2
@ -17237,7 +17238,7 @@ snapshots:
'@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-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/types': 3.577.0
'@smithy/property-provider': 3.1.11
'@smithy/shared-ini-file-loader': 3.1.12
@ -18644,15 +18645,15 @@ snapshots:
graphql: 16.9.0
typescript: 5.7.3
'@graphiql/plugin-explorer@4.0.0-alpha.2(@graphiql/react@1.0.0-alpha.4(patch_hash=bru5she67j343rpipomank3vn4)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
'@graphiql/plugin-explorer@4.0.0-alpha.2(@graphiql/react@1.0.0-alpha.4(patch_hash=cxjlr4qnvqgvcsnnl2map34diy)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@graphiql/react': 1.0.0-alpha.4(patch_hash=bru5she67j343rpipomank3vn4)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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.4(patch_hash=cxjlr4qnvqgvcsnnl2map34diy)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
graphiql-explorer: 0.9.0(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
graphql: 16.9.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
'@graphiql/react@1.0.0-alpha.4(patch_hash=bru5she67j343rpipomank3vn4)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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.4(patch_hash=cxjlr4qnvqgvcsnnl2map34diy)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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.10.0(@types/node@22.10.3)(graphql-ws@5.16.1(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)
@ -27704,7 +27705,7 @@ snapshots:
graphiql@4.0.0-alpha.5(patch_hash=yjzkcog7ut7wshk4npre67txki)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@graphiql/react': 1.0.0-alpha.4(patch_hash=bru5she67j343rpipomank3vn4)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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.4(patch_hash=cxjlr4qnvqgvcsnnl2map34diy)(@codemirror/language@6.10.2)(@types/node@22.10.3)(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(graphql-ws@5.16.1(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
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)