diff --git a/src/api/clearlyDefined.js b/src/api/clearlyDefined.js index 8da2f9e1..490d4941 100644 --- a/src/api/clearlyDefined.js +++ b/src/api/clearlyDefined.js @@ -17,6 +17,7 @@ export const BROWSE = 'browse' export const ORIGINS_GITHUB = 'origins/github' export const ORIGINS_NPM = 'origins/npm' export const ORIGINS_NUGET = 'origins/nuget' +export const ORIGINS_CONDA = 'origins/conda' export const ORIGINS_CRATE = 'origins/crate' export const ORIGINS_MAVEN = 'origins/maven' export const ORIGINS_PYPI = 'origins/pypi' @@ -25,9 +26,12 @@ export const ORIGINS_DEBIAN = 'origins/deb' export const ORIGINS_COMPOSER = 'origins/composer' export const ORIGINS_POD = 'origins/pod' export const ORIGINS = { + "anaconda-main": { conda: ORIGINS_CONDA, condasource: ORIGINS_CONDA }, + "anaconda-r": { conda: ORIGINS_CONDA, condasource: ORIGINS_CONDA }, github: { git: ORIGINS_GITHUB }, npmjs: { npm: ORIGINS_NPM }, nuget: { nuget: ORIGINS_NUGET }, + "conda-forge": { conda: ORIGINS_CONDA, condasource: ORIGINS_CONDA }, cratesio: { crate: ORIGINS_CRATE }, mavencentral: { maven: ORIGINS_MAVEN, sourcearchive: ORIGINS_MAVEN }, pypi: { pypi: ORIGINS_PYPI }, @@ -188,6 +192,14 @@ export function getRubyGemsRevisions(token, path) { return get(url(`${ORIGINS_RUBYGEMS}/${path}/revisions`), token) } +export function getCondaSearch(token, path) { + return get(url(`${ORIGINS_CONDA}/${path}`), token) +} + +export function getCondaRevisions(token, path) { + return get(url(`${ORIGINS_CONDA}/${path}/revisions`), token) +} + export function getCrateSearch(token, path) { return get(url(`${ORIGINS_CRATE}/${path}`), token) } diff --git a/src/components/DefinitionEntry.js b/src/components/DefinitionEntry.js index c4bd4646..c6b96731 100644 --- a/src/components/DefinitionEntry.js +++ b/src/components/DefinitionEntry.js @@ -11,6 +11,7 @@ import git from '../images/Git-Logo-2Color.png' import npm from '../images/n-large.png' import pypi from '../images/pypi.png' import gem from '../images/gem.png' +import conda from '../images/conda.svg' import cargo from '../images/cargo.png' import nuget from '../images/nuget.svg' import debian from '../images/debian.png' @@ -49,7 +50,7 @@ class DefinitionEntry extends React.Component { static defaultProps = {} isSourceComponent(component) { - return ['github', 'sourcearchive', 'debsrc'].includes(component.provider) + return ['github', 'sourcearchive', 'debsrc', 'condasource'].includes(component.provider) } fieldChange(field, equality = isEqual, transform = a => a) { @@ -453,6 +454,7 @@ class DefinitionEntry extends React.Component { getImage(definition) { if (definition.coordinates.type === 'git') return git if (definition.coordinates.type === 'npm') return npm + if (definition.coordinates.type === 'conda') return conda if (definition.coordinates.type === 'crate') return cargo if (definition.coordinates.type === 'pypi') return pypi if (definition.coordinates.type === 'gem') return gem diff --git a/src/components/FilterBar.js b/src/components/FilterBar.js index f3c28585..8fd535f3 100644 --- a/src/components/FilterBar.js +++ b/src/components/FilterBar.js @@ -10,6 +10,7 @@ import maven from '../images/maven.png' import nuget from '../images/nuget.png' import pod from '../images/pod.png' import git from '../images/Git-Logo-2Color.png' +import conda from '../images/conda.svg' import crate from '../images/cargo.png' import gem from '../images/gem.png' import pypi from '../images/pypi.png' @@ -23,6 +24,7 @@ const types = { maven: maven, nuget: nuget, git: git, + conda: conda, crate: crate, pod: pod, deb: debian, diff --git a/src/components/HarvestQueueList.js b/src/components/HarvestQueueList.js index a2f62ae4..47af160c 100644 --- a/src/components/HarvestQueueList.js +++ b/src/components/HarvestQueueList.js @@ -11,6 +11,7 @@ import { NpmVersionPicker, MavenVersionPicker, PyPiVersionPicker, + CondaVersionPicker, CrateVersionPicker, DebianVersionPicker, NuGetVersionPicker, @@ -25,6 +26,9 @@ import npm from '../images/n-large.png' import pypi from '../images/pypi.png' import debian from '../images/debian.png' import gem from '../images/gem.png' +import anaconda_main from '../images/anaconda-main.svg' +import anaconda_r from '../images/anaconda-r.png' +import conda_forge from '../images/conda-forge.png' import cargo from '../images/cargo.png' import maven from '../images/maven.png' import nuget from '../images/nuget.png' @@ -84,6 +88,15 @@ class HarvestQueueList extends React.Component { onChange={this.commitChanged.bind(this, request)} /> )} + {request.provider === 'anaconda-main' && ( + + )} + {request.provider === 'anaconda-r' && ( + + )} + {request.provider === 'cratesio' && ( + + )} {request.provider === 'npmjs' && ( )} @@ -96,6 +109,9 @@ class HarvestQueueList extends React.Component { {request.provider === 'rubygems' && ( )} + {request.provider === 'conda-forge' && ( + + )} {request.provider === 'cratesio' && ( )} @@ -150,6 +166,9 @@ class HarvestQueueList extends React.Component { if (request.provider === 'npmjs') return npm if (request.provider === 'pypi') return pypi if (request.provider === 'rubygems') return gem + if (request.provider === 'anaconda-main') return anaconda_main + if (request.provider === 'anaconda-r') return anaconda_r + if (request.provider === 'conda-forge') return conda_forge if (request.provider === 'cratesio') return cargo if (request.provider === 'mavencentral') return maven if (request.provider === 'nuget') return nuget diff --git a/src/components/Navigation/Pages/PageHarvest/PageHarvest.js b/src/components/Navigation/Pages/PageHarvest/PageHarvest.js index 0cf346e1..c7c5edfd 100644 --- a/src/components/Navigation/Pages/PageHarvest/PageHarvest.js +++ b/src/components/Navigation/Pages/PageHarvest/PageHarvest.js @@ -12,6 +12,7 @@ import { NpmSelector, MavenSelector, NuGetSelector, + CondaSelector, CrateSelector, DebianSelector, ComposerSelector, @@ -114,11 +115,14 @@ class PageHarvest extends Component { {this.renderProviderButtons()} + {activeProvider.value === 'anaconda-main' && } + {activeProvider.value === 'anaconda-r' && } {activeProvider.value === 'github' && } {activeProvider.value === 'mavencentral' && } {activeProvider.value === 'npmjs' && } {activeProvider.value === 'nuget' && } {activeProvider.value === 'cratesio' && } + {activeProvider.value === 'conda-forge' && } {activeProvider.value === 'packagist' && } {activeProvider.value === 'pypi' && } {activeProvider.value === 'rubygems' && } diff --git a/src/components/Navigation/Pages/PageStats/PageStats.js b/src/components/Navigation/Pages/PageStats/PageStats.js index 599db4f4..8d6f1e91 100644 --- a/src/components/Navigation/Pages/PageStats/PageStats.js +++ b/src/components/Navigation/Pages/PageStats/PageStats.js @@ -13,6 +13,7 @@ import maven from '../../../../images/maven.png' import nuget from '../../../../images/nuget.png' import pod from '../../../../images/pod.png' import git from '../../../../images/Git-Logo-2Color.png' +import conda from '../../../../images/conda.svg' import crate from '../../../../images/cargo.png' import composer from '../../../../images/packagist.png' import gem from '../../../../images/gem.png' @@ -34,6 +35,8 @@ const types = { maven: maven, nuget: nuget, git: git, + conda: conda, + condasource: conda, crate: crate, deb: debian, debsrc: debian, diff --git a/src/components/Navigation/Ui/ComponentButtons.js b/src/components/Navigation/Ui/ComponentButtons.js index acf9a479..3c16fad9 100644 --- a/src/components/Navigation/Ui/ComponentButtons.js +++ b/src/components/Navigation/Ui/ComponentButtons.js @@ -32,7 +32,7 @@ class ComponentButtons extends Component { } isSourceComponent(component) { - return ['github', 'sourcearchive', 'debsrc'].includes(component.provider) + return ['github', 'sourcearchive', 'debsrc', 'condasource'].includes(component.provider) } _isProviderSupported(component) { @@ -152,7 +152,7 @@ class ComponentButtons extends Component { )} {!isDefinitionEmpty && onInspect && ( - diff --git a/src/components/Navigation/Ui/ComponentDetailsButtons.js b/src/components/Navigation/Ui/ComponentDetailsButtons.js index d1040625..f7378c6c 100644 --- a/src/components/Navigation/Ui/ComponentDetailsButtons.js +++ b/src/components/Navigation/Ui/ComponentDetailsButtons.js @@ -14,7 +14,7 @@ class ComponentDetailsButtons extends Component { } isSourceComponent(component) { - return ['github', 'sourcearchive', 'debsrc'].includes(component.provider) + return ['github', 'sourcearchive', 'debsrc', 'condasource'].includes(component.provider) } openSourceForComponent = definition => { diff --git a/src/components/Providers/Selectors/CondaSelector.js b/src/components/Providers/Selectors/CondaSelector.js new file mode 100644 index 00000000..1ff25750 --- /dev/null +++ b/src/components/Providers/Selectors/CondaSelector.js @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation and others. Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { getCondaSearch } from '../../../api/clearlyDefined' +import { AsyncTypeahead } from 'react-bootstrap-typeahead' +import searchSvg from '../../../images/icons/searchSvg.svg' + +export default class CondaSelector extends Component { + static propTypes = { + onChange: PropTypes.func + } + + constructor(props) { + super(props) + this.state = { isLoading: false, options: [], focus: false } + 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: 'conda', provider: this.props.provider, name: value.id }, 'package') + } + + async getOptions(value) { + try { + this.setState({ ...this.state, isLoading: true }) + const options = await getCondaSearch(this.props.token, `${value}/${this.props.provider}`) + 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/Providers/VersionPickers/CondaVersionPicker.js b/src/components/Providers/VersionPickers/CondaVersionPicker.js new file mode 100644 index 00000000..e265d81d --- /dev/null +++ b/src/components/Providers/VersionPickers/CondaVersionPicker.js @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation and others. Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { getCondaRevisions } from '../../../api/clearlyDefined' +import Autocomplete from '../../Navigation/Ui/Autocomplete' + +export default class CondaVersionPicker extends Component { + static propTypes = { + onChange: PropTypes.func, + request: PropTypes.object.isRequired, + defaultInputValue: PropTypes.string + } + + constructor(props) { + super(props) + this.state = { customValues: [], options: [] } + this.onChange = this.onChange.bind(this) + this.filter = this.filter.bind(this) + } + + componentDidMount() { + this.getOptions('') + } + + async getOptions(value) { + try { + const { name, provider } = this.props.request + const options = await getCondaRevisions(this.props.token, `${name}/${provider}`) + 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 } = this.state + const list = customValues.concat(options) + return ( + + ) + } +} diff --git a/src/components/index.js b/src/components/index.js index d4bd0136..42f3994e 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -2,92 +2,96 @@ // SPDX-License-Identifier: MIT export { default as App } -from './App' + from './App' export { default as Clearly } -from './Clearly' + from './Clearly' export { default as ComponentList } -from './ComponentList' + from './ComponentList' export { default as ContributePrompt } -from './ContributePrompt' + from './ContributePrompt' export { default as CopyUrlButton } -from './CopyUrlButton' + from './CopyUrlButton' +export { default as CondaSelector } + from './Providers/Selectors/CondaSelector' +export { default as CondaVersionPicker } + from './Providers/VersionPickers/CondaVersionPicker' export { default as CrateSelector } -from './Providers/Selectors/CrateSelector' + from './Providers/Selectors/CrateSelector' export { default as CrateVersionPicker } -from './Providers/VersionPickers/CrateVersionPicker' + from './Providers/VersionPickers/CrateVersionPicker' export { default as DebianSelector } -from './Providers/Selectors/DebianSelector' + from './Providers/Selectors/DebianSelector' export { default as DebianVersionPicker } -from './Providers/VersionPickers/DebianVersionPicker' + from './Providers/VersionPickers/DebianVersionPicker' export { default as ComposerSelector } -from './Providers/Selectors/ComposerSelector' + from './Providers/Selectors/ComposerSelector' export { default as ComposerVersionPicker } -from './Providers/VersionPickers/ComposerVersionPicker' + from './Providers/VersionPickers/ComposerVersionPicker' export { default as DefinitionEntry } -from './DefinitionEntry' + from './DefinitionEntry' export { default as FieldGroup } -from './FieldGroup' + from './FieldGroup' export { default as FileCountRenderer } -from './FileCountRenderer' + from './FileCountRenderer' export { default as FilterBar } -from './FilterBar' + from './FilterBar' export { default as Footer } -from './Footer' + from './Footer' export { default as GitHubCommitPicker } -from './Providers/VersionPickers/GitHubCommitPicker' + from './Providers/VersionPickers/GitHubCommitPicker' export { default as GitHubSelector } -from './Providers/Selectors/GitHubSelector' + from './Providers/Selectors/GitHubSelector' export { default as HarvestQueueList } -from './HarvestQueueList' + from './HarvestQueueList' export { default as Header } -from './Header' + from './Header' export { default as InfiniteList } -from './InfiniteList' + from './InfiniteList' export { default as InlineEditor } -from './InlineEditor' + from './InlineEditor' export { default as ModalEditor } -from './ModalEditor' + from './ModalEditor' export { default as SourcePicker } -from './SourcePicker' + from './SourcePicker' export { default as MavenSelector } -from './Providers/Selectors/MavenSelector' + from './Providers/Selectors/MavenSelector' export { default as MavenVersionPicker } -from './Providers/VersionPickers/MavenVersionPicker' + from './Providers/VersionPickers/MavenVersionPicker' export { default as NotificationList } -from './NotificationList' + from './NotificationList' export { default as NpmSelector } -from './Providers/Selectors/NpmSelector' + from './Providers/Selectors/NpmSelector' export { default as NpmVersionPicker } -from './Providers/VersionPickers/NpmVersionPicker' + from './Providers/VersionPickers/NpmVersionPicker' export { default as NuGetSelector } -from './Providers/Selectors/NuGetSelector' + from './Providers/Selectors/NuGetSelector' export { default as NuGetVersionPicker } -from './Providers/VersionPickers/NuGetVersionPicker' + from './Providers/VersionPickers/NuGetVersionPicker' export { default as PyPiSelector } -from './Providers/Selectors/PyPiSelector' + from './Providers/Selectors/PyPiSelector' export { default as PyPiVersionPicker } -from './Providers/VersionPickers/PyPiVersionPicker' + from './Providers/VersionPickers/PyPiVersionPicker' export { default as RubyGemsSelector } -from './Providers/Selectors/RubyGemsSelector' + from './Providers/Selectors/RubyGemsSelector' export { default as RubyGemsVersionPicker } -from './Providers/VersionPickers/RubyGemsVersionPicker' + from './Providers/VersionPickers/RubyGemsVersionPicker' export { default as CocoaPodsSelector } -from './Providers/Selectors/CocoaPodsSelector' + from './Providers/Selectors/CocoaPodsSelector' export { default as CocoaPodsVersionPicker } -from './Providers/VersionPickers/CocoaPodsVersionPicker' + from './Providers/VersionPickers/CocoaPodsVersionPicker' export { default as PageAbout } -from './PageAbout' + from './PageAbout' export { default as RehydrationProvider } -from './RehydrationProvider' + from './RehydrationProvider' export { default as RowEntityList } -from './RowEntityList' + from './RowEntityList' export { default as Section } -from './Section' + from './Section' export { default as SocialIcons } -from './SocialIcons' + from './SocialIcons' export { default as SpdxPicker } -from './SpdxPicker' + from './SpdxPicker' export { default as TwoLineEntry } -from './TwoLineEntry' + from './TwoLineEntry' export { default as QuickEditModel } -from './QuickEditModel' + from './QuickEditModel' diff --git a/src/images/anaconda-main.svg b/src/images/anaconda-main.svg new file mode 100644 index 00000000..aea6b8cc --- /dev/null +++ b/src/images/anaconda-main.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/anaconda-r.png b/src/images/anaconda-r.png new file mode 100644 index 00000000..2f720fd5 Binary files /dev/null and b/src/images/anaconda-r.png differ diff --git a/src/images/conda-forge.png b/src/images/conda-forge.png new file mode 100644 index 00000000..25619488 Binary files /dev/null and b/src/images/conda-forge.png differ diff --git a/src/images/conda.svg b/src/images/conda.svg new file mode 100644 index 00000000..3ad2de74 --- /dev/null +++ b/src/images/conda.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/utils/contribution.js b/src/utils/contribution.js index e2c79631..821eeaba 100644 --- a/src/utils/contribution.js +++ b/src/utils/contribution.js @@ -15,6 +15,9 @@ import github from '../images/GitHub-Mark-120px-plus.png' import npm from '../images/n-large.png' import pypi from '../images/pypi.png' import gem from '../images/gem.png' +import anaconda_r from '../images/anaconda-r.png' +import anaconda_main from '../images/anaconda-main.svg' +import conda_forge from '../images/conda-forge.png' import cargo from '../images/cargo.png' import nuget from '../images/nuget.svg' import debian from '../images/debian.png' @@ -198,7 +201,7 @@ export default class Contribution { static getPercentage = (count, total) => Math.round(((count || 0) / total) * 100) - static isSourceComponent = component => ['github', 'sourcearchive', 'debsrc'].includes(component.provider) + static isSourceComponent = component => ['github', 'sourcearchive', 'debsrc', 'condasource'].includes(component.provider) /** * Get image of definition based on the provider @@ -208,6 +211,10 @@ export default class Contribution { */ static getImage(item) { switch (item.coordinates.provider) { + case 'anaconda-main': + return anaconda_main + case 'anaconda-r': + return anaconda_r case 'github': return github case 'npmjs': @@ -216,6 +223,8 @@ export default class Contribution { return pypi case 'rubygems': return gem + case 'conda-forge': + return conda_forge case 'cratesio': return cargo case 'packagist': diff --git a/src/utils/utils.js b/src/utils/utils.js index 30c0b923..fabc02f3 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,11 +1,14 @@ // Copyright (c) Microsoft Corporation and others. Licensed under the MIT license. // SPDX-License-Identifier: MIT +import anacondaMainImage from '../images/anaconda-main.svg' +import anacondaRImage from '../images/anaconda-r.png' import deepDiff from 'deep-diff' import npmImage from '../images/n-large.png' import mavenImage from '../images/maven.png' import nugetImage from '../images/nuget.svg' import podImage from '../images/pod.png' import gitImage from '../images/Git-Logo-2Color.png' +import condaForgeImage from '../images/conda-forge.png' import crateImage from '../images/cargo.png' import gemImage from '../images/gem.png' import pypiImage from '../images/pypi.png' @@ -108,6 +111,8 @@ const curateFilters = [ const types = [ { value: 'composer', label: 'Composer', provider: 'packagist' }, { value: 'pod', label: 'Pod', provider: 'cocoapods' }, + { value: 'conda', label: 'Conda', provider: 'conda-forge' }, + { value: 'condasource', label: 'Conda', provider: 'conda-forge' }, { value: 'crate', label: 'Crate', provider: 'cratesio' }, { value: 'git', label: 'Git', provider: 'github' }, { value: 'maven', label: 'Maven', provider: 'mavencentral' }, @@ -121,6 +126,8 @@ const types = [ ] const providers = [ + { value: 'anaconda-main', label: 'Anaconda /main', image: anacondaMainImage, type: 'conda' }, + { value: 'anaconda-r', label: 'Anaconda /r', image: anacondaRImage, type: 'conda' }, { value: 'npmjs', label: 'NpmJS', image: npmImage, type: 'npm' }, { value: 'github', label: 'GitHub', image: gitImage, type: 'git' }, { value: 'mavencentral', label: 'MavenCentral', image: mavenImage, type: 'maven' }, @@ -128,6 +135,7 @@ const providers = [ { value: 'pypi', label: 'PyPI', image: pypiImage, type: 'pypi' }, { value: 'rubygems', label: 'RubyGems', image: gemImage, type: 'gem' }, { value: 'cocoapods', label: 'CocoaPods', image: podImage, type: 'pod' }, + { value: 'conda-forge', label: 'Conda-Forge', image: condaForgeImage, type: 'conda' }, { value: 'cratesio', label: 'Crates.io', image: crateImage, type: 'crate' }, { value: 'debian', label: 'Debian', image: debianImage, type: 'deb' }, { value: 'packagist', label: 'Packagist', image: composerImage, type: 'composer' }