From 25d9d001b03c664e83ff09d1c9bf3bed6e231973 Mon Sep 17 00:00:00 2001 From: Qing Tomlinson Date: Tue, 5 Apr 2022 14:04:36 -0700 Subject: [PATCH] Support cocoapods search on harvest page Task: https://github.com/clearlydefined/website/issues/963 --- src/api/clearlyDefined.js | 12 ++- src/components/CocoaPodsSelector.js | 66 +++++++++++++ src/components/CocoaPodsVersionPicker.js | 95 +++++++++++++++++++ src/components/HarvestQueueList.js | 12 ++- .../Pages/PageHarvest/PageHarvest.js | 2 + src/components/index.js | 4 + 6 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 src/components/CocoaPodsSelector.js create mode 100644 src/components/CocoaPodsVersionPicker.js diff --git a/src/api/clearlyDefined.js b/src/api/clearlyDefined.js index 4e355323d..8da2f9e11 100644 --- a/src/api/clearlyDefined.js +++ b/src/api/clearlyDefined.js @@ -23,6 +23,7 @@ export const ORIGINS_PYPI = 'origins/pypi' export const ORIGINS_RUBYGEMS = 'origins/rubygems' export const ORIGINS_DEBIAN = 'origins/deb' export const ORIGINS_COMPOSER = 'origins/composer' +export const ORIGINS_POD = 'origins/pod' export const ORIGINS = { github: { git: ORIGINS_GITHUB }, npmjs: { npm: ORIGINS_NPM }, @@ -32,7 +33,8 @@ export const ORIGINS = { pypi: { pypi: ORIGINS_PYPI }, rubygems: { gem: ORIGINS_RUBYGEMS }, debian: { deb: ORIGINS_DEBIAN, debsrc: ORIGINS_DEBIAN }, - packagist: { composer: ORIGINS_COMPOSER } + packagist: { composer: ORIGINS_COMPOSER }, + cocoapods: { pod: ORIGINS_POD } } export function getHarvestResults(token, entity) { @@ -218,6 +220,14 @@ export function getComposerRevisions(token, path) { return get(url(`${ORIGINS_COMPOSER}/${path}/revisions`), token) } +export function getCocoaPodsSearch(token, path) { + return get(url(`${ORIGINS_POD}/${path}`), token) +} + +export function getCocoaPodsRevisions(token, path) { + return get(url(`${ORIGINS_POD}/${path}/revisions`), token) +} + export function getRevisions(token, path, type, provider) { const origin = _.get(ORIGINS, `${provider}.${type}`) return get(url(`${origin}/${path}/revisions`), token) diff --git a/src/components/CocoaPodsSelector.js b/src/components/CocoaPodsSelector.js new file mode 100644 index 000000000..ca1bb6f31 --- /dev/null +++ b/src/components/CocoaPodsSelector.js @@ -0,0 +1,66 @@ +// (c) Copyright 2022, SAP SE and ClearlyDefined contributors. Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { getCocoaPodsSearch } from '../api/clearlyDefined' +import { AsyncTypeahead } from 'react-bootstrap-typeahead' +import searchSvg from '../images/icons/searchSvg.svg' +import 'react-bootstrap-typeahead/css/Typeahead.css' + +export default class CocoaPodsSelector extends Component { + static propTypes = { + onChange: PropTypes.func + } + + constructor(props) { + super(props) + this.state = { isLoading: false, options: [], focus: true } + this.getOptions = this.getOptions.bind(this) + this.onChange = this.onChange.bind(this) + } + + onChange(values) { + const { onChange } = this.props + const value = values.length === 0 ? null : values[0] + value && onChange && onChange({ type: 'pod', provider: 'cocoapods', name: value.id }, 'package') + } + + async getOptions(value) { + try { + this.setState({ ...this.state, isLoading: true }) + const options = await getCocoaPodsSearch(this.props.token, value) + this.setState({ ...this.state, options, isLoading: false }) + } catch (error) { + this.setState({ ...this.state, options: [], isLoading: false }) + } + } + + render() { + const { options, isLoading, focus } = this.state + return ( +
+
+ search +
+ this.setState({ ...this.state, focus: true })} + onBlur={() => this.setState({ ...this.state, focus: false })} + clearButton + highlightOnlyResult + emptyLabel="" + selectHintOnEnter + isLoading={isLoading} + onSearch={this.getOptions} + /> +
+ ) + } +} diff --git a/src/components/CocoaPodsVersionPicker.js b/src/components/CocoaPodsVersionPicker.js new file mode 100644 index 000000000..1a6fc24ac --- /dev/null +++ b/src/components/CocoaPodsVersionPicker.js @@ -0,0 +1,95 @@ +// (c) Copyright 2022, SAP SE and ClearlyDefined contributors. Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { getCocoaPodsRevisions } from '../api/clearlyDefined' +import Autocomplete from './Navigation/Ui/Autocomplete' +import searchSvg from '../images/icons/searchSvg.svg' + +export default class CocoaPodsVersionPicker extends Component { + static propTypes = { + onChange: PropTypes.func, + request: PropTypes.object.isRequired, + defaultInputValue: PropTypes.string + } + + constructor(props) { + super(props) + this.state = { + customValues: [], + options: [], + focus: false, + selected: props.request.revision ? [props.request.revision] : [] + } + this.onChange = this.onChange.bind(this) + this.filter = this.filter.bind(this) + } + + componentDidMount() { + this.getOptions('') + } + + componentWillReceiveProps(nextProps) { + this.setState({ ...this.state, selected: nextProps.request.revision ? [nextProps.request.revision] : [] }) + } + + async getOptions(value) { + try { + const { name } = this.props.request + const options = await getCocoaPodsRevisions(this.props.token, name) + this.setState({ ...this.state, options }) + } catch (error) { + this.setState({ ...this.state, options: [] }) + } + } + + onChange(values) { + const { onChange } = this.props + if (!onChange) return + let value = values.length === 0 ? null : values[0] + if (!value) return onChange(value) + if (value.customOption) { + value = value.label + this.setState({ ...this.state, customValues: [...this.state.customValues, value] }) + } + onChange(value) + } + + filter(option, props) { + if (this.props.request.revision) return true + return option.toLowerCase().indexOf(props.text.toLowerCase()) !== -1 + } + + render() { + const { defaultInputValue } = this.props + const { customValues, options, selected, focus } = this.state + const list = customValues.concat(options) + return ( +
+
+ search +
{' '} + this.setState({ ...this.state, focus: true })} + onBlur={() => this.setState({ ...this.state, focus: false })} + positionFixed + clearButton + allowNew + newSelectionPrefix="Version:" + emptyLabel="" + filterBy={this.filter} + selectHintOnEnter + /> +
+ ) + } +} diff --git a/src/components/HarvestQueueList.js b/src/components/HarvestQueueList.js index 539a78539..a2f62ae43 100644 --- a/src/components/HarvestQueueList.js +++ b/src/components/HarvestQueueList.js @@ -15,7 +15,8 @@ import { DebianVersionPicker, NuGetVersionPicker, RubyGemsVersionPicker, - ComposerVersionPicker + ComposerVersionPicker, + CocoaPodsVersionPicker } from './' import { getGitHubRevisions } from '../api/clearlyDefined' import { clone } from 'lodash' @@ -28,6 +29,7 @@ import cargo from '../images/cargo.png' import maven from '../images/maven.png' import nuget from '../images/nuget.png' import composer from '../images/packagist.png' +import pod from '../images/pod.png' class HarvestQueueList extends React.Component { static propTypes = { @@ -39,7 +41,7 @@ class HarvestQueueList extends React.Component { } static defaultProps = { - loadMoreRows: () => {} + loadMoreRows: () => { } } constructor(props) { @@ -106,6 +108,9 @@ class HarvestQueueList extends React.Component { {request.provider === 'packagist' && ( )} + {request.provider === 'cocoapods' && ( + + )} ) @@ -150,6 +155,7 @@ class HarvestQueueList extends React.Component { if (request.provider === 'nuget') return nuget if (request.provider === 'debian') return debian if (request.provider === 'packagist') return composer + if (request.provider === 'cocoapods') return pod return null } @@ -161,7 +167,7 @@ class HarvestQueueList extends React.Component { renderRow({ index, key, style }) { const { list } = this.props const request = list[index] - const clickHandler = () => {} + const clickHandler = () => { } return (
} {activeProvider.value === 'rubygems' && } {activeProvider.value === 'debian' && } + {activeProvider.value === 'cocoapods' && } {this.renderActionButton()} diff --git a/src/components/index.js b/src/components/index.js index aab3984c6..7f192105c 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -71,6 +71,10 @@ export { default as RubyGemsSelector } from './RubyGemsSelector' export { default as RubyGemsVersionPicker } from './RubyGemsVersionPicker' +export { default as CocoaPodsSelector } +from './CocoaPodsSelector' +export { default as CocoaPodsVersionPicker } +from './CocoaPodsVersionPicker' export { default as PageAbout } from './PageAbout' export { default as RehydrationProvider }