Skip to content

Commit

Permalink
Search in Doc Explorer
Browse files Browse the repository at this point in the history
  • Loading branch information
asiandrummer committed Jan 21, 2016
1 parent 6894c9c commit 0a92996
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 3 deletions.
27 changes: 27 additions & 0 deletions css/doc-explorer.css
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,30 @@
#graphiql-container .arg:last-child:after {
content: '';
}

#graphiql-container .doc-alert-text {
color: #F00F00;
font-family: 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace;
font-size: 13px;
}

#graphiql-container .search-box-outer {
border: 1px solid #d3d6db;
box-sizing: border-box;
display: inline-block;
font-size: 12px;
height: 24px;
margin-bottom: 12px;
padding: 3px 8px 5px;
vertical-align: middle;
width: 100%;
}

#graphiql-container .search-box-input {
border: 0;
font-size: 12px;
margin: 0;
outline: 0;
padding: 0;
width: 100%;
}
139 changes: 136 additions & 3 deletions src/components/DocExplorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,36 @@ export class DocExplorer extends React.Component {
constructor() {
super();

this.state = { navStack: [] };
this.state = {
navStack: [],
searchValue: null
};
}

_onToggleBtnClick = () => {
this.setState({ expanded: !this.state.expanded });
}

_onNavBackClick = () => {
this.setState({ navStack: this.state.navStack.slice(0, -1) });
this.setState({
navStack: this.state.navStack.slice(0, -1),
searchValue: null
});
}

_onClickTypeOrField = typeOrField => {
this.showDoc(typeOrField);
}

_onSearch = event => {
this.setState({ searchValue: event.target.value });
}

shouldComponentUpdate(nextProps, nextState) {
return (
this.props.schema !== nextProps.schema ||
this.state.navStack !== nextState.navStack
this.state.navStack !== nextState.navStack ||
this.state.searchValue !== nextState.searchValue
);
}

Expand Down Expand Up @@ -103,12 +114,21 @@ export class DocExplorer extends React.Component {
field={typeOrField}
onClickType={this._onClickTypeOrField}
/>;
} else if (this.state.searchValue) {
title = 'Search Results';
content = <SearchDoc
searchValue={this.state.searchValue}
schema={schema}
onClickType={this._onClickTypeOrField}
onClickField={this._onClickTypeOrField}
/>;
} else if (schema) {
title = 'Documentation Explorer';
content =
<SchemaDoc
schema={schema}
onClickType={this._onClickTypeOrField}
onSearch={this._onSearch}
/>;
}

Expand Down Expand Up @@ -141,13 +161,126 @@ export class DocExplorer extends React.Component {
</div>
</div>
<div className="doc-explorer-contents">
{!typeOrField &&
<label className="search-box-outer">
<input className="search-box-input"
onKeyUp={event => this._onSearch(event)}
type="text"
placeholder="Search the schema ..." />
</label>
}
{this.props.schema ? content : spinnerDiv}
</div>
</div>
);
}
}

// Render Search Results
class SearchDoc extends React.Component {
shouldComponentUpdate(nextProps) {
return (this.props.schema !== nextProps.schema) ||
(this.props.searchValue !== nextProps.searchValue);
}

render() {
const searchValue = this.props.searchValue;
const schema = this.props.schema;
const onClickType = this.props.onClickType;
const onClickField = this.props.onClickField;

const typeMap = schema.getTypeMap();

let matchedTypes = [];
let matchedFields = [];
let matchedArgs = [];

Object.keys(typeMap).forEach(typeName => {
const type = typeMap[typeName];
let matchedOn = [];
if (typeName.indexOf(searchValue) !== -1) {
matchedOn.push('Type Name');
}

if (matchedOn.length) {
matchedTypes.push(
<div className="doc-category-item">
<TypeLink type={type} onClick={onClickType} />
</div>
);
}

if (type.getFields) {
let fields = type.getFields();
Object.keys(fields).forEach(fieldName => {
let field = fields[fieldName];
if (fieldName.indexOf(searchValue) !== -1) {
matchedFields.push(
<div className="doc-category-item">
<a className="field-name"
onClick={event => onClickField(field, type, event)}>
{field.name}
</a>
{' on '}
<TypeLink type={type} onClick={onClickType} />
</div>
);
} else if (field.args && field.args.length) {
let matches = field.args.filter(arg => {
return arg.name.indexOf(searchValue) !== -1;
});
matchedFields.push(
<div className="doc-category-item">
<a className="field-name"
onClick={event => onClickField(field, type, event)}>
{field.name}
</a>
{'('}
<span>
{matches.map(arg =>
<span className="arg" key={arg.name}>
<span className="arg-name">{arg.name}</span>
{': '}
<TypeLink type={arg.type} onClick={onClickType} />
</span>
)}
</span>
{')'}
{' on '}
<TypeLink type={type} onClick={onClickType} />
</div>
);
}
});
}
});

if (matchedTypes.length === 0 &&
matchedFields.length === 0 &&
matchedArgs.length === 0) {
return (
<span className="doc-alert-text">
No results found.
</span>
);
}

return (
<div>
<div className="doc-category">
{(matchedTypes.length > 0 || matchedFields.length > 0) &&
<div className="doc-category-title">
search results
</div>
}
{matchedTypes}
{matchedFields}
</div>
</div>
);
}
}

// Render the top level Schema
class SchemaDoc extends React.Component {
shouldComponentUpdate(nextProps) {
Expand Down

0 comments on commit 0a92996

Please sign in to comment.