Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow GraphiQL apps control over closing tabs #3563

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

klippx
Copy link

@klippx klippx commented Mar 19, 2024

Allow GraphiQL apps control over closing tabs

This feature is about closing tabs.

Current functionality:

  • When closing a tab, it just happens, the tab is removed and all state is gone

Requested functionality

  • Grant possibility to give control to the user (i.e. the app that mounts the GraphiQL component) if they are OK with closing a particular tab
  • This could for instance be an dialogue "Are you sure you want to close the tab?"

In our case, we are working on a Collection plugin that you can click to read saved queries / variables / headers from a DB, and this opens it in a new tab. So we need to sync tabState with the list of Collection items. And if a user starts to change a Collection item, we want to warn the user that changes will be lost.

It is the same as if the user selected a file in a code editor, started to change it, and then tries to close the tab.

Mock screenshots

Screenshot 2024-03-19 at 16 32 30

Screenshot 2024-03-19 at 16 32 41

Copy link

changeset-bot bot commented Mar 19, 2024

🦋 Changeset detected

Latest commit: 5b37ed0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
graphiql Minor
@graphiql/react Minor
@graphiql/plugin-code-exporter Major
@graphiql/plugin-explorer Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

codecov bot commented Mar 19, 2024

Codecov Report

Attention: Patch coverage is 66.66667% with 6 lines in your changes are missing coverage. Please review.

Project coverage is 55.33%. Comparing base (29e99a8) to head (fbb81ad).

❗ Current head fbb81ad differs from pull request most recent head 5b37ed0. Consider uploading reports for the commit 5b37ed0 to get more accurate results

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3563      +/-   ##
==========================================
- Coverage   55.33%   55.33%   -0.01%     
==========================================
  Files         115      115              
  Lines        5349     5355       +6     
  Branches     1450     1452       +2     
==========================================
+ Hits         2960     2963       +3     
- Misses       1963     1964       +1     
- Partials      426      428       +2     
Files Coverage Δ
packages/graphiql-react/src/provider.tsx 100.00% <ø> (ø)
packages/graphiql/src/components/GraphiQL.tsx 69.65% <100.00%> (+0.94%) ⬆️
packages/graphiql-react/src/editor/context.tsx 70.33% <64.70%> (-3.06%) ⬇️

... and 1 file with indirect coverage changes

if (editorContext.activeTabIndex === index) {
executionContext.stop();
onClick={async () => {
if (
Copy link
Member

@acao acao Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should move all of this into closeTab itself, even what was directly in the handler here before, making it async. i see no reason to let this be an implementation detail for sdk users, as if the context they are using has this logic they would expect this as as an internal detail of the method if it's exposed to the user yeah?

  const closeTab = useCallback<EditorContextType['closeTab']>(
    async index => {
      if (await closeTabConfirmation(index)) {
      // this could be a breaking change for users who are already stopping 
      // execution manually like graphiql does, however stopping execution twice should not
      // cause any errors?
        if (index === tabState.activeTabIndex) {
          stop();
        }
        setTabState(current => {
          const updated = {
            tabs: current.tabs.filter((_tab, i) => index !== i),
            activeTabIndex: Math.max(current.activeTabIndex - 1, 0),
          };
          storeTabs(updated);
          setEditorValues(updated.tabs[updated.activeTabIndex]);
          onTabChange?.(updated);
          return updated;
        });
      }
    },
    [
      onTabChange,
      setEditorValues,
      storeTabs,
      closeTabConfirmation,
      tabState.activeTabIndex,
    ],
  );

and then here in graphiql:

 <Tab.Close
    onClick={async () => editorContext.closeTab(index)}
/>

so then sdk users have this in const { openTab, closeTab } = useEditorContext()

Copy link
Member

@acao acao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is awesome, and makes a lot of sense! i'm glad you're able to achieve this with your app. just the one change,,I hope that's ok!

@klippx
Copy link
Author

klippx commented Mar 20, 2024

this is awesome, and makes a lot of sense! i'm glad you're able to achieve this with your app. just the one change,,I hope that's ok!

Absolutely, I don't mind a little boy scouting, looks much cleaner now overall. I think this looks good to go now.

PS:

i'm glad you're able to achieve this with your app.

Yea, it totally works - but... Since the plugin is handling its own state management and its own data fetching, it is a bit tricky, since I need the top level component that mounts <GraphiQL /> to essentially get the confirmation from a component further down the component tree. I got it to work using event emitters and listeners, which I think is not React-kosher but still fine, since I don't want to lift state further up, that price is much higher to pay since I want my plugin to manage its own state.

  • Just sharing my solution FYI, like I said I am fine with this.

@klippx klippx requested a review from acao March 22, 2024 14:10
@klippx
Copy link
Author

klippx commented Mar 22, 2024

@acao Are we good to go?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants