diff --git a/scm-ui-components/packages/ui-components/src/CardColumn.js b/scm-ui-components/packages/ui-components/src/CardColumn.js index e1eb65255a..65710c7be2 100644 --- a/scm-ui-components/packages/ui-components/src/CardColumn.js +++ b/scm-ui-components/packages/ui-components/src/CardColumn.js @@ -25,12 +25,17 @@ const styles = { }, content: { display: "flex", - flexGrow: 1 + flexGrow: 1, + alignItems: "center", + justifyContent: "space-between" }, footer: { display: "flex", marginTop: "auto", paddingBottom: "1.5rem" + }, + noBottomMargin: { + marginBottom: "0 !important" } }; @@ -38,9 +43,11 @@ type Props = { title: string, description: string, avatar: React.Node, + contentRight?: React.Node, footerLeft: React.Node, footerRight: React.Node, link: string, + // context props classes: any }; @@ -55,7 +62,15 @@ class CardColumn extends React.Component { }; render() { - const { avatar, title, description, footerLeft, footerRight, classes } = this.props; + const { + avatar, + title, + description, + contentRight, + footerLeft, + footerRight, + classes + } = this.props; const link = this.createLink(); return ( <> @@ -64,16 +79,29 @@ class CardColumn extends React.Component {
{avatar}
-
+
-
+

{title}

{description}

+ {contentRight && contentRight}
-
+
{footerLeft}
{footerRight}
diff --git a/scm-ui/src/admin/containers/Admin.js b/scm-ui/src/admin/containers/Admin.js index 58e37a0a7c..22c6184548 100644 --- a/scm-ui/src/admin/containers/Admin.js +++ b/scm-ui/src/admin/containers/Admin.js @@ -1,14 +1,24 @@ // @flow import React from "react"; import { translate } from "react-i18next"; -import {Redirect, Route, Switch} from "react-router-dom"; +import { Redirect, Route, Switch } from "react-router-dom"; import { ExtensionPoint } from "@scm-manager/ui-extensions"; import type { History } from "history"; import { connect } from "react-redux"; import { compose } from "redux"; import type { Links } from "@scm-manager/ui-types"; -import { Page, Navigation, NavLink, Section, SubNavigation } from "@scm-manager/ui-components"; -import { getLinks } from "../../modules/indexResource"; +import { + Page, + Navigation, + NavLink, + Section, + SubNavigation +} from "@scm-manager/ui-components"; +import { + getLinks, + getAvailablePluginsLink, + getInstalledPluginsLink +} from "../../modules/indexResource"; import AdminDetails from "./AdminDetails"; import PluginsOverview from "../plugins/containers/PluginsOverview"; import GlobalConfig from "./GlobalConfig"; @@ -18,6 +28,8 @@ import CreateRepositoryRole from "../roles/containers/CreateRepositoryRole"; type Props = { links: Links, + availablePluginsLink: string, + installedPluginsLink: string, // context objects t: string => string, @@ -28,7 +40,7 @@ type Props = { class Admin extends React.Component { stripEndingSlash = (url: string) => { if (url.endsWith("/")) { - if(url.includes("role")) { + if (url.includes("role")) { return url.substring(0, url.length - 2); } return url.substring(0, url.length - 1); @@ -47,7 +59,7 @@ class Admin extends React.Component { }; render() { - const { links, t } = this.props; + const { links, availablePluginsLink, installedPluginsLink, t } = this.props; const url = this.matchedUrl(); const extensionProps = { @@ -62,34 +74,54 @@ class Admin extends React.Component { - - + + ( - + )} /> ( - + )} /> ( - + )} /> ( - + )} /> { ( - + )} /> ( - - )} + render={() => } /> { icon="fas fa-info-circle" label={t("admin.menu.informationNavLink")} /> - { - links.plugins && - - - {/* Activate this again after available plugins page is created */} - {/**/} - - } + {(availablePluginsLink || installedPluginsLink) && ( + + {installedPluginsLink && ( + + )} + {availablePluginsLink && ( + + )} + + )} { const mapStateToProps = (state: any) => { const links = getLinks(state); + const availablePluginsLink = getAvailablePluginsLink(state); + const installedPluginsLink = getInstalledPluginsLink(state); return { - links + links, + availablePluginsLink, + installedPluginsLink }; }; diff --git a/scm-ui/src/admin/plugins/components/PluginEntry.js b/scm-ui/src/admin/plugins/components/PluginEntry.js index a8cdaad915..3693c2e284 100644 --- a/scm-ui/src/admin/plugins/components/PluginEntry.js +++ b/scm-ui/src/admin/plugins/components/PluginEntry.js @@ -1,11 +1,21 @@ //@flow import React from "react"; +import injectSheet from "react-jss"; import type { Plugin } from "@scm-manager/ui-types"; import { CardColumn } from "@scm-manager/ui-components"; import PluginAvatar from "./PluginAvatar"; type Props = { - plugin: Plugin + plugin: Plugin, + + // context props + classes: any +}; + +const styles = { + link: { + pointerEvents: "all" + } }; class PluginEntry extends React.Component { @@ -13,6 +23,17 @@ class PluginEntry extends React.Component { return ; }; + createContentRight = (plugin: Plugin) => { + const { classes } = this.props; + if (plugin._links && plugin._links.install && plugin._links.install.href) { + return ( + + + + ); + } + }; + createFooterLeft = (plugin: Plugin) => { return {plugin.author}; }; @@ -24,6 +45,7 @@ class PluginEntry extends React.Component { render() { const { plugin } = this.props; const avatar = this.createAvatar(plugin); + const contentRight = this.createContentRight(plugin); const footerLeft = this.createFooterLeft(plugin); const footerRight = this.createFooterRight(plugin); @@ -34,6 +56,7 @@ class PluginEntry extends React.Component { avatar={avatar} title={plugin.name} description={plugin.description} + contentRight={contentRight} footerLeft={footerLeft} footerRight={footerRight} /> @@ -41,4 +64,4 @@ class PluginEntry extends React.Component { } } -export default PluginEntry; +export default injectSheet(styles)(PluginEntry); diff --git a/scm-ui/src/admin/plugins/containers/PluginsOverview.js b/scm-ui/src/admin/plugins/containers/PluginsOverview.js index 7a3fc7ec4a..5a8a46f884 100644 --- a/scm-ui/src/admin/plugins/containers/PluginsOverview.js +++ b/scm-ui/src/admin/plugins/containers/PluginsOverview.js @@ -18,7 +18,10 @@ import { isFetchPluginsPending } from "../modules/plugins"; import PluginsList from "../components/PluginsList"; -import { getPluginsLink } from "../../../modules/indexResource"; +import { + getAvailablePluginsLink, + getInstalledPluginsLink +} from "../../../modules/indexResource"; type Props = { loading: boolean, @@ -26,7 +29,8 @@ type Props = { collection: PluginCollection, baseUrl: string, installed: boolean, - pluginsLink: string, + availablePluginsLink: string, + installedPluginsLink: string, // context objects t: string => string, @@ -37,8 +41,27 @@ type Props = { class PluginsOverview extends React.Component { componentDidMount() { - const { fetchPluginsByLink, pluginsLink } = this.props; - fetchPluginsByLink(pluginsLink); + const { + installed, + fetchPluginsByLink, + availablePluginsLink, + installedPluginsLink + } = this.props; + fetchPluginsByLink(installed ? installedPluginsLink : availablePluginsLink); + } + + componentDidUpdate(prevProps) { + const { + installed, + fetchPluginsByLink, + availablePluginsLink, + installedPluginsLink + } = this.props; + if (prevProps.installed !== installed) { + fetchPluginsByLink( + installed ? installedPluginsLink : availablePluginsLink + ); + } } render() { @@ -81,13 +104,15 @@ const mapStateToProps = state => { const collection = getPluginCollection(state); const loading = isFetchPluginsPending(state); const error = getFetchPluginsFailure(state); - const pluginsLink = getPluginsLink(state); + const availablePluginsLink = getAvailablePluginsLink(state); + const installedPluginsLink = getInstalledPluginsLink(state); return { collection, loading, error, - pluginsLink + availablePluginsLink, + installedPluginsLink }; }; diff --git a/scm-ui/src/modules/indexResource.js b/scm-ui/src/modules/indexResource.js index 9bfa620674..aa8ebad5a2 100644 --- a/scm-ui/src/modules/indexResource.js +++ b/scm-ui/src/modules/indexResource.js @@ -116,8 +116,12 @@ export function getUiPluginsLink(state: Object) { return getLink(state, "uiPlugins"); } -export function getPluginsLink(state: Object) { - return getLink(state, "plugins"); +export function getAvailablePluginsLink(state: Object) { + return getLink(state, "availablePlugins"); +} + +export function getInstalledPluginsLink(state: Object) { + return getLink(state, "installedPlugins"); } export function getMeLink(state: Object) {