Skip to content

Commit

Permalink
feat(configure): add the Configure widget (#2698)
Browse files Browse the repository at this point in the history
* feat(configure): add the configure connector
* chore: use jsHelper.make in tests
* chore: format
* refactor: add configure widget instead
* test: use workaround method instead
* refactor: remove connectConfigure
* chore: fix imports
* chore: use searchParameters key
* chore: use searchParameters directly after all
* chore(doc): support for unnnamed parameters in widgets
* chore(doc): support for externals
* chore: incorporate feedback
  • Loading branch information
Haroenv authored and bobylito committed Mar 5, 2018
1 parent 0a63a1d commit 94daabc
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 18 deletions.
4 changes: 2 additions & 2 deletions docgen/layouts/mixins/documentationjs/type.pug
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ mixin type(t, relatedTypes)
if t.name !== 'Object' && t.name !== 'Array' && t.name[0] === t.name[0].toUpperCase()
- const symbol = relatedTypes && relatedTypes.find(t2 => t2 && t.name === t2.name) || {};
- const isExternal = symbol.kind === 'external'
if isExternal
if symbol.name && isExternal
- const firstSee = symbol.tags.find(t => t.title === 'see') || {};
a.typed-link(href=firstSee.description, target='_blank')=t.name
else
else if symbol.name
a.typed-link(href=`${navPath}#struct-${t.name}`)=t.name
else
| !{t.name}
42 changes: 40 additions & 2 deletions docgen/layouts/mixins/documentationjs/widget-usage.pug
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ mixin widgetUsage(fnSymbol)
span.cm-variable search
| =
span.cm-def instantsearch
| (
span.cm-comment /* parameters */
| (
span.cm-comment /* parameters */
| );
br
br
Expand Down Expand Up @@ -45,3 +45,41 @@ mixin widgetUsage(fnSymbol)
| (
span.cm-variable widget
| );
else
.heading
| Usage
pre.CodeMirror.cm-s-mdn-like
code
span.cm-keyword const
span.cm-variable search
| =
span.cm-def instantsearch
| (
span.cm-comment /* parameters */
| );
br
br
span.cm-keyword const
span.cm-def widget
span.cm-operator =
span.cm-variable instantsearch
| .
span.cm-variable widgets
| .
span.cm-variable=fnSymbol.name
| (!{' \n'}
for property in fnSymbol.params
span.cm-property=` ${property.name}`
| :
span.cm-def
+type(property.type, fnSymbol.relatedTypes)
| , !{'\n'}
| );
|
br
span.cm-variable search
|.
span.cm-property addWidget
| (
span.cm-variable widget
| );
28 changes: 23 additions & 5 deletions docgen/layouts/widget.pug
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,29 @@ block content
a.anchor(href=`${navPath}#usage`)
+widgetUsage(jsdoc)

h2#structure Options
a.anchor(href=`${navPath}#structure`)
each t in jsdoc.relatedTypes
if t
+struct(t, jsdoc.relatedTypes)
if jsdoc.params && jsdoc.params.length === 1 && jsdoc.params[0].name === '$0'
if jsdoc.relatedTypes && jsdoc.relatedTypes.length > 0
h2#structure Options
a.anchor(href=`${navPath}#structure`)
each t in jsdoc.relatedTypes
if t
+struct(t, jsdoc.relatedTypes)
else if jsdoc.params
h2#structure Options
a.anchor(href=`${navPath}#structure`)
ul.struct-def
each property in jsdoc.params
li.type(id=`struct-${property.name}`)
strong=property.name
a.anchor(href=`${navPath}#param-${property.name}`)
code
+type(property.type, jsdoc.relatedTypes)
if tag && tag.default
div.default-value
| Default value:
code=tag.default
+description(property.description)

if jsdoc.examples && jsdoc.examples.length > 0
h2#example Example
a.anchor(href=`${navPath}#example`)
Expand Down
21 changes: 16 additions & 5 deletions docgen/plugins/documentationjs-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,23 @@ function findRelatedTypes(functionSymbol, symbols) {
const typeSymbol = find(symbols, {name: unnamedParameterType});
types = [...types, typeSymbol, ...findRelatedTypes(typeSymbol, symbols)]
} else {
const currentTypeName = p.name;
const isCustomType = currentTypeName && currentTypeName !== 'Object' && currentTypeName[0] === currentTypeName[0].toUpperCase();
if (isCustomType) {
const typeSymbol = find(symbols, {name: currentTypeName});
if(!typeSymbol) console.warn('Undefined type: ', currentTypeName);
if (isCustomType(p.name)) {
const typeSymbol = find(symbols, {name: p.name});
if(!typeSymbol) console.warn('Undefined type: ', p.name);
else {
types = [...types, typeSymbol];
// iterate over each property to get their types
forEach(typeSymbol.properties, p => findParamsTypes({name: p.type.name, type: p.type}));
}
} else if(isCustomType(p.type.name)){
const typeSymbol = find(symbols, {name: p.type.name});
if(!typeSymbol) console.warn('Undefined type: ', p.type.name);
else {
types = [...types, typeSymbol];
// iterate over each property to get their types
if(typeSymbol.properties)
forEach(typeSymbol.properties, p2 => findParamsTypes({name: p2.type.name, type: p2.type}));
}
}
}
};
Expand All @@ -206,3 +213,7 @@ function findRelatedTypes(functionSymbol, symbols) {

return uniqBy(types, 'name');
}

function isCustomType(name) {
return name && name !== 'Object' && name[0] === name[0].toUpperCase();
}
10 changes: 6 additions & 4 deletions src/lib/main.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/** @module module:instantsearch */
/**
* @external SearchParameters
* @see https://community.algolia.com/algoliasearch-helper-js/reference.html#searchparameters
*/

// required for browsers not supporting Object.freeze (helper requirement)
import '../shams/Object.freeze.js';

Expand All @@ -15,6 +12,11 @@ import version from './version.js';
import * as connectors from '../connectors/index.js';
import * as widgets from '../widgets/index.js';

/**
* @external SearchParameters
* @see https://www.algolia.com/doc/api-reference/search-api-parameters/
*/

/**
* @typedef {Object} UrlSyncOptions
* @property {Object} [mapping] Object used to define replacement query
Expand Down
85 changes: 85 additions & 0 deletions src/widgets/configure/__tests__/configure-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { SearchParameters } from 'algoliasearch-helper';
import configure from '../configure';

describe('configure', () => {
it('throws when you pass it a non-plain object', () => {
[
() => configure(new Date()),
() => configure(() => {}),
() => configure(/ok/),
].forEach(widget => expect(widget).toThrowError(/Usage/));
});

it('Applies searchParameters if nothing in configuration yet', () => {
const widget = configure({ analytics: true });
const config = widget.getConfiguration(SearchParameters.make({}));
expect(config).toEqual({
analytics: true,
});
});

it('Applies searchParameters if nothing conflicting configuration', () => {
const widget = configure({ analytics: true });
const config = widget.getConfiguration(
SearchParameters.make({ query: 'testing' })
);
expect(config).toEqual({
analytics: true,
});
});

it('Applies searchParameters with a higher priority', () => {
const widget = configure({ analytics: true });
{
const config = widget.getConfiguration(
SearchParameters.make({ analytics: false })
);
expect(config).toEqual({
analytics: true,
});
}
{
const config = widget.getConfiguration(
SearchParameters.make({ analytics: false, extra: true })
);
expect(config).toEqual({
analytics: true,
});
}
});

it('disposes all of the state set by configure', () => {
const widget = configure({ analytics: true });

const nextState = widget.dispose({
state: SearchParameters.make({
analytics: true,
somethingElse: false,
}),
});

expect(nextState).toEqual(
SearchParameters.make({
somethingElse: false,
})
);
});

it('disposes all of the state set by configure in case of a conflict', () => {
const widget = configure({ analytics: true });

const nextState = widget.dispose({
state: SearchParameters.make({
// even though it's different, it will be deleted
analytics: false,
somethingElse: false,
}),
});

expect(nextState).toEqual(
SearchParameters.make({
somethingElse: false,
})
);
});
});
51 changes: 51 additions & 0 deletions src/widgets/configure/configure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import isPlainObject from 'lodash/isPlainObject';
const usage = `Usage:
search.addWidget(
instantsearch.widgets.configure({
// any searchParameter
})
);
Full documentation available at https://community.algolia.com/instantsearch.js/v2/widgets/configure.html
`;

/**
* The **configure** widget is a headless widget that let you configure the
* settings of your search using the parameters described by the
* [general Algolia documentation](https://www.algolia.com/doc/api-reference/search-api-parameters/)
*
* This widget has no visible UI, so you should only use it for search parameters
* users shouldn't expect to change.
*
* @type {WidgetFactory}
* @category filter
* @param {SearchParameters} searchParameters The Configure widget options are search parameters
* @returns {Object} A new Configure widget instance.
* @example
* search.addWidget(
* instantsearch.widgets.configure({
* analytics: true,
* ruleContexts: ['desktop', 'cool-users'],
* distinct: 3,
* })
* );
*/
export default function configure(searchParameters = {}) {
if (!isPlainObject(searchParameters)) {
throw new Error(usage);
}
return {
getConfiguration() {
return searchParameters;
},
init() {},
dispose({ state }) {
return state.mutateMe(mutableState => {
// widgetParams are assumed 'controlled',
// so they override whatever other widgets give the state
Object.keys(searchParameters).forEach(key => {
delete mutableState[key];
});
});
},
};
}
1 change: 1 addition & 0 deletions src/widgets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

export { default as clearAll } from '../widgets/clear-all/clear-all.js';
export { default as configure } from '../widgets/configure/configure.js';
export {
default as currentRefinedValues,
} from '../widgets/current-refined-values/current-refined-values.js';
Expand Down

0 comments on commit 94daabc

Please sign in to comment.