Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fixes and Plugin Versions content #231

Merged
merged 14 commits into from
Aug 6, 2021
23 changes: 11 additions & 12 deletions src/components/Developers/components/Instructions/Instructions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const Instructions = () => (
<h1 className="instructions-header">
Get Started - 4 Simple Steps
{' '}
<a className="instructions-source" href="http://bit.ly/2KghHdY">[source]</a>
<a className="instructions-source" href="https://github.com/FNNDSC/cookiecutter-chrisapp/wiki/Quickstart">[source]</a>
</h1>
<div className="instructions-steps">
<div className="instructions-step">
Expand Down Expand Up @@ -44,7 +44,7 @@ const Instructions = () => (
<ul>
<li>
<a
href="http://bit.ly/2Iih52m"
href="https://github.com/FNNDSC/cookiecutter-chrisapp/wiki/Quickstart#1-prerequisites"
rel="noopener noreferrer"
target="_blank"
>
Expand All @@ -53,7 +53,7 @@ const Instructions = () => (
</li>
<li>
<a
href="http://bit.ly/2KghHdY"
href="https://github.com/FNNDSC/cookiecutter-chrisapp/wiki/Quickstart"
rel="noopener noreferrer"
target="_blank"
>
Expand Down Expand Up @@ -133,7 +133,7 @@ const Instructions = () => (
<h3>
Create a new automated build and repository on your
{' '}
<a href="https://dockr.ly/2K2pnRF">Docker Hub</a>
<a href="https://hub.docker.com/">Docker Hub</a>
{' '}
account.
</h3>
Expand All @@ -151,7 +151,7 @@ const Instructions = () => (
<h3>
For more information on Automated Builds, visit the
{' '}
<a href="https://dockr.ly/2tmNDDz">Docker build documentation</a>
<a href="https://docs.docker.com/docker-hub/builds/">Docker build documentation</a>
.
</h3>
<h3>
Expand All @@ -169,7 +169,7 @@ const Instructions = () => (
<h3>
Look at this
{' '}
<a href="http://bit.ly/2yzbRzF">
<a href="https://github.com/FNNDSC/pl-simplefsapp">
simple
<strong>fs</strong>
{' '}
Expand All @@ -178,7 +178,7 @@ const Instructions = () => (
{' '}
or this
{' '}
<a href="http://bit.ly/2KbHosS">
<a href="https://github.com/FNNDSC/pl-simpledsapp">
simple
<strong>ds</strong>
{' '}
Expand All @@ -199,12 +199,11 @@ const Instructions = () => (
Once you
&apos;
ve developed and properly tested your plugin app
consult the
consult the wiki to learn
{' '}
<a href="http://bit.ly/2ltTJ0w">wiki</a>
{' '}
to learn how to register it to
ChRIS.
<a href="https://github.com/FNNDSC/cookiecutter-chrisapp/wiki/Register-a-new-plugin-app-with-the-ChRIS-store-API">
how to register it to ChRIS.
</a>
</h3>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Navbar/components/Search/Search.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const Search = ({
onChange={onChange}
autoComplete="off"
onKeyDown={(e) => {
if (e.key === 'Enter' && value.length >= 3 && !autoCompleteData.length) {
if (e.key === 'Enter' && value.length >= 3) {
onSearch(value, 'ENTER');
setShowAutoComplete(false);
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Notification/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const Notification = ({ position, variant, message, onClose, closeable, t

Notification.propTypes = {
position: PropTypes.string.isRequired,
message: PropTypes.string.isRequired,
message: PropTypes.string,
variant: PropTypes.string,
closeable: PropTypes.bool,
onClose: PropTypes.func,
Expand Down
142 changes: 77 additions & 65 deletions src/components/Plugin/Plugin.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Badge, Grid, GridItem, Split, SplitItem, Button } from '@patternfly/react-core';
import { StarIcon } from '@patternfly/react-icons';
import PropTypes from 'prop-types';
import Client from '@fnndsc/chrisstoreapi';
import Client, { Plugin } from '@fnndsc/chrisstoreapi';

import LoadingPlugin from './components/LoadingPlugin/LoadingPlugin';
import PluginBody from './components/PluginBody/PluginBody';
Expand All @@ -15,46 +15,62 @@ import HttpApiCallError from '../../errors/HttpApiCallError';

import './Plugin.css';

export class Plugin extends Component {
/**
* View a plugin by plugin ID.
*/
export class PluginView extends Component {
constructor(props) {
super(props);

this.mounted = false;

const { pluginData, isFavorite } = props;
this.state = {
pluginData,
pluginData: undefined,
star: undefined,
loading: true,
star: isFavorite || undefined,
errors: [],
};

const storeURL = process.env.REACT_APP_STORE_URL;
const auth = { token: props.store.get('authToken') };
this.client = new Client(storeURL, auth);

this.fetchPluginData = this.fetchPluginData.bind(this);
}

/**
* Fetch a plugin by ID, from URL params.
* Then fetch other plugins which have the same name as versions.
* Set stars if user is logged in.
*/
async componentDidMount() {
let { pluginData } = this.state;

if (!pluginData) {
pluginData = await this.fetchPluginData();
}

this.setState({ pluginData, loading: false });
if (this.isLoggedIn()) {
this.fetchIsPluginStarred(pluginData);
// eslint-disable-next-line react/destructuring-assignment
const { pluginId } = this.props.match.params;
try {
const plugin = await this.fetchPlugin(pluginId);
const versions = await this.fetchPluginVersions(plugin.data.name);

let star;
if (this.isLoggedIn())
star = await this.fetchIsPluginStarred(plugin.data);

this.setState({
loading: false,
pluginData: {
...plugin.data,
url: plugin.url,
versions
},
star,
});
} catch (error) {
this.setState((prev) => ({
loading: false,
errors: [ ...prev.errors, error ]
}));
}
}

showNotifications = (error) => {
let { errors } = this.state;
errors = [ ...errors, error.message ]
this.setState({
errors
})
this.setState((prev) => ({
errors: [ ...prev.errors, error ]
}));
}

// eslint-disable-next-line react/destructuring-assignment
Expand All @@ -65,9 +81,13 @@ export class Plugin extends Component {

onStarClicked = () => {
if (this.isLoggedIn()) {
return this.isFavorite() ? this.unfavPlugin() : this.favPlugin();
if (this.isFavorite())
this.unfavPlugin();
else
this.favPlugin();
}
return Promise.resolve();
else
this.showNotifications(new Error('Login required to favorite this plugin.'))
}

favPlugin = async () => {
Expand Down Expand Up @@ -119,27 +139,35 @@ export class Plugin extends Component {
return <StarIcon name={name} className={className} onClick={this.onStarClicked} />;
}

async fetchPluginData() {
/**
* Fetch a plugin by ID
* @param {string} pluginId
* @returns {Promise} Plugin
*/
async fetchPlugin(pluginId) {
// eslint-disable-next-line react/destructuring-assignment
const { pluginId } = this.props.match.params;
return this.client.getPlugin(parseInt(pluginId, 10));
}

try {
const plugin = await this.client.getPlugin(parseInt(pluginId, 10));
return { ...plugin.data, url: plugin.url };
} catch (e) {
this.showNotifications(new HttpApiCallError(e));
return e
}
/**
* Fetch all versions of a plugin by name.
* @param {string} name Plugin name
* @returns Promise => void
*/
async fetchPluginVersions(name) {
const versions = await this.client.getPlugins({ limit: 10e6, name_exact: name });
const firstplg = await this.client.getPlugin(parseInt(versions.data[0].id, 10));
return [
{ ...versions.data[0], url: firstplg.url },
...versions.data.slice(1)
]
}

async fetchIsPluginStarred({ name }) {
try {
const response = await this.client.getPluginStars({ plugin_name: name });
if (response.data.length > 0)
this.setState({ star: response.data[0] });
} catch(error) {
this.showNotifications(new HttpApiCallError(error));
}
const response = await this.client.getPluginStars({ plugin_name: name });
if (response.data.length > 0)
return response.data[0];
return undefined;
}

render() {
Expand Down Expand Up @@ -216,7 +244,6 @@ export class Plugin extends Component {
);
}

const { className } = this.props;
return (
<>
{
Expand All @@ -234,7 +261,7 @@ export class Plugin extends Component {
/>
))
}
<div className={`plugin ${className}`}>
<div className="plugin">
{container}
</div>
</>
Expand All @@ -244,36 +271,21 @@ export class Plugin extends Component {
}

Plugin.propTypes = {
store: PropTypes.objectOf(PropTypes.object),
match: PropTypes.shape({
params: PropTypes.shape({
plugin: PropTypes.string,
}),
}),
pluginData: PropTypes.shape({
plugin: PropTypes.string,
pluginURL: PropTypes.string,
authorURL: PropTypes.string,
title: PropTypes.string,
id: PropTypes.number,
description: PropTypes.string,
dock_image: PropTypes.string,
modification_date: PropTypes.string,
authors: PropTypes.arrayOf(PropTypes.string),
version: PropTypes.string,
}),
className: PropTypes.string,
store: PropTypes.objectOf(PropTypes.object),
})
})
};

Plugin.defaultProps = {
store: new Map(),
match: {
params: {
plugin: undefined,
},
},
pluginData: null,
className: '',
store: new Map(),
}
}
};

export default ChrisStore.withStore(Plugin);
export default ChrisStore.withStore(PluginView);
Loading