Skip to content

Commit

Permalink
fix: create a new util to manage historyStore out of query history co…
Browse files Browse the repository at this point in the history
…mponent
  • Loading branch information
harshithpabbati committed Jun 27, 2021
1 parent 04fad79 commit 45bfb06
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 141 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-mirrors-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'graphiql': minor
---

fix: history can now be saved even when query history panel is not opened
8 changes: 6 additions & 2 deletions packages/graphiql/src/components/GraphiQL.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import type {
Unsubscribable,
FetcherResultPayload,
} from '@graphiql/toolkit';
import HistoryStore from '../utility/HistoryStore';

const DEFAULT_DOC_EXPLORER_WIDTH = 350;

Expand Down Expand Up @@ -185,6 +186,7 @@ export class GraphiQL extends React.Component<GraphiQLProps, GraphiQLState> {
variableEditorComponent: Maybe<VariableEditor>;
headerEditorComponent: Maybe<HeaderEditor>;
_queryHistory: Maybe<QueryHistory>;
_historyStore: Maybe<HistoryStore>;
editorBarComponent: Maybe<HTMLDivElement>;
queryEditorComponent: Maybe<QueryEditor>;
resultViewerElement: Maybe<HTMLElement>;
Expand All @@ -200,6 +202,8 @@ export class GraphiQL extends React.Component<GraphiQLProps, GraphiQLState> {
// Cache the storage instance
this._storage = new StorageAPI(props.storage);

this._historyStore = new HistoryStore(this._storage);

// Disable setState when the component is not mounted
this.componentIsMounted = false;

Expand Down Expand Up @@ -1061,8 +1065,8 @@ export class GraphiQL extends React.Component<GraphiQLProps, GraphiQLState> {
});
this._storage.set('operationName', operationName as string);

if (this._queryHistory) {
this._queryHistory.updateHistory(
if (this._historyStore) {
this._historyStore.updateHistory(
editedQuery,
variables,
headers,
Expand Down
179 changes: 40 additions & 139 deletions packages/graphiql/src/components/QueryHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,15 @@
* LICENSE file in the root directory of this source tree.
*/

import { parse } from 'graphql';
import React from 'react';
import QueryStore, { QueryStoreItem } from '../utility/QueryStore';
import { QueryStoreItem } from '../utility/QueryStore';
import HistoryQuery, {
HandleEditLabelFn,
HandleToggleFavoriteFn,
HandleSelectQueryFn,
HandleToggleFavoriteFn,
} from './HistoryQuery';
import StorageAPI from '../utility/StorageAPI';

const MAX_QUERY_SIZE = 100000;
const MAX_HISTORY_LENGTH = 20;

const shouldSaveQuery = (
query?: string,
variables?: string,
headers?: string,
lastQuerySaved?: QueryStoreItem,
) => {
if (!query) {
return false;
}

try {
parse(query);
} catch (e) {
return false;
}

// Don't try to save giant queries
if (query.length > MAX_QUERY_SIZE) {
return false;
}
if (!lastQuerySaved) {
return true;
}
if (JSON.stringify(query) === JSON.stringify(lastQuerySaved.query)) {
if (
JSON.stringify(variables) === JSON.stringify(lastQuerySaved.variables)
) {
if (JSON.stringify(headers) === JSON.stringify(lastQuerySaved.headers)) {
return false;
}
if (headers && !lastQuerySaved.headers) {
return false;
}
}
if (variables && !lastQuerySaved.variables) {
return false;
}
}
return true;
};
import HistoryStore from '../utility/HistoryStore';

type QueryHistoryProps = {
query?: string;
Expand All @@ -77,129 +33,74 @@ export class QueryHistory extends React.Component<
QueryHistoryProps,
QueryHistoryState
> {
historyStore: QueryStore;
favoriteStore: QueryStore;
historyStore: HistoryStore;

constructor(props: QueryHistoryProps) {
super(props);
this.historyStore = new QueryStore(
'queries',
props.storage,
MAX_HISTORY_LENGTH,
);
// favorites are not automatically deleted, so there's no need for a max length
this.favoriteStore = new QueryStore('favorites', props.storage, null);
const historyQueries = this.historyStore.fetchAll();
const favoriteQueries = this.favoriteStore.fetchAll();
const queries = historyQueries.concat(favoriteQueries);
this.historyStore = new HistoryStore(this.props.storage);
const queries = this.historyStore.queries;
this.state = { queries };
}

render() {
const queries = this.state.queries.slice().reverse();
const queryNodes = queries.map((query, i) => {
return (
<HistoryQuery
handleEditLabel={this.editLabel}
handleToggleFavorite={this.toggleFavorite}
key={`${i}:${query.label || query.query}`}
onSelect={this.props.onSelectQuery}
{...query}
/>
);
});
return (
<section aria-label="History">
<div className="history-title-bar">
<div className="history-title">{'History'}</div>
<div className="doc-explorer-rhs">{this.props.children}</div>
</div>
<ul className="history-contents">{queryNodes}</ul>
</section>
);
}

// Public API
updateHistory = (
query?: string,
variables?: string,
headers?: string,
operationName?: string,
) => {
if (
shouldSaveQuery(
query,
variables,
headers,
this.historyStore.fetchRecent(),
)
) {
this.historyStore.push({
query,
variables,
headers,
operationName,
});
const historyQueries = this.historyStore.items;
const favoriteQueries = this.favoriteStore.items;
const queries = historyQueries.concat(favoriteQueries);
this.setState({
queries,
});
}
};

// Public API
toggleFavorite: HandleToggleFavoriteFn = (
onHandleEditLabel: HandleEditLabelFn = (
query,
variables,
headers,
operationName,
label,
favorite,
) => {
const item: QueryStoreItem = {
this.historyStore.editLabel(
query,
variables,
headers,
operationName,
label,
};
if (!this.favoriteStore.contains(item)) {
item.favorite = true;
this.favoriteStore.push(item);
} else if (favorite) {
item.favorite = false;
this.favoriteStore.delete(item);
}
this.setState({
queries: [...this.historyStore.items, ...this.favoriteStore.items],
});
favorite,
);
this.setState({ queries: this.historyStore.queries });
};

// Public API
editLabel: HandleEditLabelFn = (
onToggleFavorite: HandleToggleFavoriteFn = (
query,
variables,
headers,
operationName,
label,
favorite,
) => {
const item = {
this.historyStore.toggleFavorite(
query,
variables,
headers,
operationName,
label,
};
if (favorite) {
this.favoriteStore.edit({ ...item, favorite });
} else {
this.historyStore.edit(item);
}
this.setState({
queries: [...this.historyStore.items, ...this.favoriteStore.items],
});
favorite,
);
this.setState({ queries: this.historyStore.queries });
};

render() {
const queries = this.state.queries.slice().reverse();
const queryNodes = queries.map((query, i) => {
return (
<HistoryQuery
handleEditLabel={this.onHandleEditLabel}
handleToggleFavorite={this.onToggleFavorite}
key={`${i}:${query.label || query.query}`}
onSelect={this.props.onSelectQuery}
{...query}
/>
);
});
return (
<section aria-label="History">
<div className="history-title-bar">
<div className="history-title">{'History'}</div>
<div className="doc-explorer-rhs">{this.props.children}</div>
</div>
<ul className="history-contents">{queryNodes}</ul>
</section>
);
}
}
Loading

0 comments on commit 45bfb06

Please sign in to comment.