Files
shields/frontend/components/suggestion-and-search.js
Marcin Mielnicki eeb78ccf15 Badge suggestion feature fix (#3331)
* Display suggested badges

* E2e test for badge suggestion

* Suggest resource returns example with pattern

* Do not require preview in MarkupModalContent

* Skip integration test for suggestion

* Unmodifiable path in customizer

* Use suggested link

* Allow to change suggested badges

* Enable skipped test

* Enable skipped test

* Code refactoring

* Code refactoring

* Code refactoring

* Code refactoring

* Code refactoring

* Code refactoring

* Unused code removed

* Unused code removed

* getExampleWithServiceByPattern helper added

* BadgeExamples uses examples instead of services definitions

* Revert "getExampleWithServiceByPattern helper added"

This reverts commit 80839fd705.

* style removed from example

* example.exact replaced with preview.buildFromExample

* keywords are required again

* Code refactoring

* More e2e tests for suggestion feature

* Code refactoring

* Build add with a base url

* showActualParams -> isPrefilled

* A new schema for BadgeExamples

* Link moved to queryParams

* Updated documentation for the suggest reponse format

* Link moved to queryParams - another test updated

* Revert "Link moved to queryParams - another test updated"

This reverts commit b5f811bb07.

* Revert "Link moved to queryParams"

This reverts commit 3b54c6d2b4.

* Disable changes in path in suggested badges

* 'link' element documentation restored
2019-04-29 18:38:27 +02:00

113 lines
2.7 KiB
JavaScript

import React from 'react'
import PropTypes from 'prop-types'
import fetchPonyfill from 'fetch-ponyfill'
import debounce from 'lodash.debounce'
import BadgeExamples from './badge-examples'
import { BlockInput } from './common'
export default class SuggestionAndSearch extends React.Component {
static propTypes = {
queryChanged: PropTypes.func.isRequired,
onBadgeClick: PropTypes.func.isRequired,
baseUrl: PropTypes.string.isRequired,
}
constructor(props) {
super(props)
this.queryChangedDebounced = debounce(props.queryChanged, 50, {
leading: true,
})
}
state = {
isUrl: false,
inProgress: false,
projectUrl: null,
suggestions: [],
}
queryChanged(query) {
const isUrl = query.startsWith('https://') || query.startsWith('http://')
this.setState({
isUrl,
projectUrl: isUrl ? query : null,
})
this.queryChangedDebounced(query)
}
getSuggestions() {
this.setState({ inProgress: true }, async () => {
const { baseUrl } = this.props
const { projectUrl } = this.state
const url = `${baseUrl}/$suggest/v1?url=${encodeURIComponent(projectUrl)}`
const fetch = window.fetch || fetchPonyfill
const res = await fetch(url)
let suggestions
try {
const json = await res.json()
// This doesn't validate the response. The default value here prevents
// a crash if the server returns {"err":"Disallowed"}.
suggestions = json.suggestions || []
} catch (e) {
suggestions = []
}
this.setState({ inProgress: false, suggestions })
})
}
renderSuggestions() {
const { baseUrl } = this.props
let { suggestions } = this.state
if (suggestions.length === 0) {
return null
}
suggestions = suggestions.map(
({ title, link, example, preview, documentation }) => ({
title,
link,
example,
preview: { ...preview, buildFromExample: true },
documentation,
})
)
return (
<BadgeExamples
baseUrl={baseUrl}
examples={suggestions}
onClick={this.props.onBadgeClick}
/>
)
}
render() {
return (
<section>
<form action="javascript:void 0" autoComplete="off">
<BlockInput
autoFocus
autofill="off"
onChange={event => this.queryChanged(event.target.value)}
placeholder="search / project URL"
/>
<br />
<button
disabled={this.state.inProgress}
hidden={!this.state.isUrl}
onClick={event => this.getSuggestions(event.target.value)}
>
Suggest badges
</button>
</form>
{this.renderSuggestions()}
</section>
)
}
}