-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
WIP: feat: Add migration context to enable GraphiQL refactoring #1380
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,10 @@ import { | |
introspectionQueryName, | ||
introspectionQuerySansSubscriptions, | ||
} from '../utility/introspectionQueries'; | ||
import { | ||
MigrationContextProvider, | ||
MigrationContext, | ||
} from 'src/state/MigrationContext'; | ||
|
||
const DEFAULT_DOC_EXPLORER_WIDTH = 350; | ||
|
||
|
@@ -63,7 +67,7 @@ if (majorVersion < 16) { | |
} | ||
|
||
declare namespace global { | ||
export let g: GraphiQL; | ||
export let g: GraphiQLInternals; | ||
} | ||
|
||
export type Maybe<T> = T | null | undefined; | ||
|
@@ -134,21 +138,70 @@ type GraphiQLState = { | |
* | ||
* @see https://github.com/graphql/graphiql#usage | ||
*/ | ||
export class GraphiQL extends React.Component<GraphiQLProps, GraphiQLState> { | ||
/** | ||
* Static Methods | ||
*/ | ||
static formatResult(result: any) { | ||
return JSON.stringify(result, null, 2); | ||
} | ||
export const GraphiQL: React.FC<GraphiQLProps> & | ||
GraphiQLStaticProperties = props => { | ||
return ( | ||
<MigrationContextProvider> | ||
<GraphiQLInternals {...props} /> | ||
</MigrationContextProvider> | ||
); | ||
}; | ||
|
||
static formatError(rawError: Error) { | ||
const result = Array.isArray(rawError) | ||
? rawError.map(formatSingleError) | ||
: formatSingleError(rawError); | ||
return JSON.stringify(result, null, 2); | ||
} | ||
interface GraphiQLStaticProperties { | ||
formatResult: (result: any) => string; | ||
formatError: (rawError: Error) => string; | ||
Logo: typeof GraphiQLLogo; | ||
Toolbar: typeof GraphiQLToolbar; | ||
Footer: typeof GraphiQLFooter; | ||
QueryEditor: typeof QueryEditor; | ||
VariableEditor: typeof VariableEditor; | ||
ResultViewer: typeof ResultViewer; | ||
Button: typeof ToolbarButton; | ||
ToolbarButton: typeof ToolbarButton; | ||
Group: typeof ToolbarGroup; | ||
Menu: typeof ToolbarMenu; | ||
MenuItem: typeof ToolbarMenuItem; | ||
} | ||
Comment on lines
+150
to
+164
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotta be a better way to do this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we're about to drop this interface for 1.0.0 so don't worry about it too much: |
||
|
||
GraphiQL.formatResult = (result: any) => { | ||
return JSON.stringify(result, null, 2); | ||
}; | ||
|
||
GraphiQL.formatError = (rawError: Error) => { | ||
const result = Array.isArray(rawError) | ||
? rawError.map(formatSingleError) | ||
: formatSingleError(rawError); | ||
return JSON.stringify(result, null, 2); | ||
}; | ||
|
||
// Export main windows/panes to be used separately if desired. | ||
GraphiQL.Logo = GraphiQLLogo; | ||
GraphiQL.Toolbar = GraphiQLToolbar; | ||
GraphiQL.Footer = GraphiQLFooter; | ||
GraphiQL.QueryEditor = QueryEditor; | ||
GraphiQL.VariableEditor = VariableEditor; | ||
GraphiQL.ResultViewer = ResultViewer; | ||
|
||
// Add a button to the Toolbar. | ||
GraphiQL.Button = ToolbarButton; | ||
GraphiQL.ToolbarButton = ToolbarButton; // Don't break existing API. | ||
|
||
// Add a group of buttons to the Toolbar | ||
GraphiQL.Group = ToolbarGroup; | ||
|
||
// Add a menu of items to the Toolbar. | ||
GraphiQL.Menu = ToolbarMenu; | ||
GraphiQL.MenuItem = ToolbarMenuItem; | ||
|
||
// Add a select-option input to the Toolbar. | ||
// GraphiQL.Select = ToolbarSelect; | ||
// GraphiQL.SelectOption = ToolbarSelectOption; | ||
|
||
/** | ||
* GraphiQL implementation details, intended to only be used via | ||
* the GraphiQL component | ||
*/ | ||
class GraphiQLInternals extends React.Component<GraphiQLProps, GraphiQLState> { | ||
// Ensure only the last executed editor query is rendered. | ||
_editorQueryID = 0; | ||
_storage: StorageAPI; | ||
|
@@ -583,29 +636,6 @@ export class GraphiQL extends React.Component<GraphiQLProps, GraphiQLState> { | |
); | ||
} | ||
|
||
// Export main windows/panes to be used separately if desired. | ||
static Logo = GraphiQLLogo; | ||
static Toolbar = GraphiQLToolbar; | ||
static Footer = GraphiQLFooter; | ||
static QueryEditor = QueryEditor; | ||
static VariableEditor = VariableEditor; | ||
static ResultViewer = ResultViewer; | ||
|
||
// Add a button to the Toolbar. | ||
static Button = ToolbarButton; | ||
static ToolbarButton = ToolbarButton; // Don't break existing API. | ||
|
||
// Add a group of buttons to the Toolbar | ||
static Group = ToolbarGroup; | ||
|
||
// Add a menu of items to the Toolbar. | ||
static Menu = ToolbarMenu; | ||
static MenuItem = ToolbarMenuItem; | ||
|
||
// Add a select-option input to the Toolbar. | ||
// static Select = ToolbarSelect; | ||
// static SelectOption = ToolbarSelectOption; | ||
|
||
/** | ||
* Get the query editor CodeMirror instance. | ||
* | ||
|
@@ -1266,6 +1296,8 @@ export class GraphiQL extends React.Component<GraphiQLProps, GraphiQLState> { | |
}; | ||
} | ||
|
||
GraphiQLInternals.contextType = MigrationContext; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the magic that enables There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh yes, i remember it used to work this way with the old context API too, amazing how little the class component interface changed |
||
|
||
// // Configure the UI by providing this Component as a child of GraphiQL. | ||
function GraphiQLLogo<TProps>(props: PropsWithChildren<TProps>) { | ||
return ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -113,7 +113,7 @@ export const schemaReducer: SchemaReducer = ( | |
*/ | ||
|
||
export type SchemaProviderProps = { | ||
config: SchemaConfig; | ||
config?: SchemaConfig; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This already provided a default so it seems it'd be fine to have as optional. |
||
schemaLoader?: typeof defaultSchemaLoader; | ||
children?: any; | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { | ||
SchemaContext, | ||
SchemaProvider, | ||
SchemaProviderProps, | ||
} from './GraphiQLSchemaProvider'; | ||
import React, { useContext, useRef } from 'react'; | ||
|
||
export const MigrationContext = React.createContext({}); | ||
|
||
// To add a new context... | ||
|
||
const AggregateContext: React.FC = ({ children }) => { | ||
const schemaContext = useContext(SchemaContext); // 1. consume the context via useContext | ||
const contexts = useRef({ schema: schemaContext }); // 2. add it to the migration's aggregate context | ||
|
||
return ( | ||
<MigrationContext.Provider value={contexts.current}> | ||
{children} | ||
</MigrationContext.Provider> | ||
); | ||
}; | ||
|
||
export const MigrationContextProvider: React.FC<SchemaProviderProps> = ({ | ||
// 3. Union its props here | ||
children, | ||
...props | ||
}) => { | ||
return ( | ||
// 4. Wrap it around this section | ||
<SchemaProvider {...props}> | ||
<AggregateContext>{children}</AggregateContext> | ||
</SchemaProvider> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this and the changes that follow are a bit ugly. I'm trying to preserve the api without requiring an extra wrapper which required some... creativity.