fix review findings

This commit is contained in:
Eduard Heimbuch
2020-03-02 14:13:51 +01:00
parent d15ef12c1c
commit e110033e3b
31 changed files with 167 additions and 200 deletions

View File

@@ -1,3 +0,0 @@
// @create-index
export { MenuContext, storeMenuCollapsed, isMenuCollapsed } from "./MenuContext";

View File

@@ -67,7 +67,6 @@ export * from "./navigation";
export * from "./repos"; export * from "./repos";
export * from "./table"; export * from "./table";
export * from "./toast"; export * from "./toast";
export * from "./contexts";
export { export {
File, File,

View File

@@ -7,32 +7,39 @@ type Props = {
children: ReactElement[]; children: ReactElement[];
collapsed?: boolean; collapsed?: boolean;
onCollapse?: (newStatus: boolean) => void; onCollapse?: (newStatus: boolean) => void;
scrollTransitionAt?: number;
}; };
type StylingProps = { type CollapsedProps = {
scrollPositionY: number;
collapsed: boolean; collapsed: boolean;
}; };
const SectionContainer = styled.div` type PositionProps = CollapsedProps & {
position: ${(props: StylingProps) => (props.scrollPositionY > 210 && window.innerWidth > 770 ? "fixed" : "inherit")}; scrollPositionY: number;
top: ${(props: StylingProps) => props.scrollPositionY > 210 && window.innerWidth > 770 && "4.5rem"}; scrollTransitionAt: number;
width: ${(props: StylingProps) => (props.collapsed ? "5.5rem" : "20.5rem")}; };
const SectionContainer = styled.div<PositionProps>`
position: ${props =>
props.scrollPositionY > props.scrollTransitionAt && window.innerWidth > 770 ? "fixed" : "inherit"};
top: ${props => props.scrollPositionY > props.scrollTransitionAt && window.innerWidth > 770 && "2rem"};
width: ${props => (props.collapsed ? "5.5rem" : "20.5rem")};
`; `;
const SmallButton = styled(Button)` const SmallButton = styled(Button)<CollapsedProps>`
padding-left: 1rem; padding-left: 1rem;
padding-right: 1rem; padding-right: 1rem;
margin-right: ${(props: CollapsedProps) => (props.collapsed ? "0" : "0.5rem")};
height: 1.5rem; height: 1.5rem;
`; `;
const MenuLabel = styled.p` const MenuLabel = styled.p<CollapsedProps>`
min-height: 2.5rem; min-height: 2.5rem;
display: flex; display: flex;
justify-content: ${(props: { collapsed: boolean }) => (props.collapsed ? "center" : "space-between")}; justify-content: ${props => (props.collapsed ? "center" : "left")};
`; `;
const Section: FC<Props> = ({ label, children, collapsed, onCollapse }) => { const Section: FC<Props> = ({ label, children, collapsed, onCollapse, scrollTransitionAt }) => {
const [scrollPositionY, setScrollPositionY] = useState(0); const [scrollPositionY, setScrollPositionY] = useState(0);
useEffect(() => { useEffect(() => {
@@ -49,14 +56,23 @@ const Section: FC<Props> = ({ label, children, collapsed, onCollapse }) => {
const arrowIcon = collapsed ? <i className="fas fa-caret-down" /> : <i className="fas fa-caret-right" />; const arrowIcon = collapsed ? <i className="fas fa-caret-down" /> : <i className="fas fa-caret-right" />;
return ( return (
<SectionContainer collapsed={collapsed ? collapsed : false} scrollPositionY={onCollapse ? scrollPositionY : 0}> <SectionContainer
collapsed={collapsed ? collapsed : false}
scrollPositionY={onCollapse ? scrollPositionY : 0}
scrollTransitionAt={scrollTransitionAt ? scrollTransitionAt : 250}
>
<MenuLabel className="menu-label" collapsed={collapsed ? collapsed : false}> <MenuLabel className="menu-label" collapsed={collapsed ? collapsed : false}>
{collapsed ? "" : label}
{onCollapse && ( {onCollapse && (
<SmallButton color="info" className="is-medium" action={() => onCollapse(!collapsed)}> <SmallButton
color="info"
className="is-medium"
action={() => onCollapse(!collapsed)}
collapsed={collapsed ? collapsed : false}
>
{arrowIcon} {arrowIcon}
</SmallButton> </SmallButton>
)} )}
{collapsed ? "" : label}
</MenuLabel> </MenuLabel>
<ul className="menu-list">{childrenWithProps}</ul> <ul className="menu-list">{childrenWithProps}</ul>
</SectionContainer> </SectionContainer>

View File

@@ -1,6 +1,7 @@
import React, { ReactNode } from "react"; import React, { FC, ReactElement, useContext } from "react";
import { Link, Route } from "react-router-dom"; import { Link, Route } from "react-router-dom";
import classNames from "classnames"; import classNames from "classnames";
import { MenuContext } from "./MenuContext";
type Props = { type Props = {
to: string; to: string;
@@ -8,57 +9,57 @@ type Props = {
label: string; label: string;
activeOnlyWhenExact?: boolean; activeOnlyWhenExact?: boolean;
activeWhenMatch?: (route: any) => boolean; activeWhenMatch?: (route: any) => boolean;
children?: ReactNode; children?: ReactElement[];
collapsed?: boolean; collapsed?: boolean;
title?: string; title?: string;
}; };
class SubNavigation extends React.Component<Props> { const SubNavigation: FC<Props> = ({
static defaultProps = { to,
activeOnlyWhenExact: false icon,
label,
activeOnlyWhenExact,
activeWhenMatch,
children,
collapsed,
title
}) => {
const menuContext = useContext(MenuContext);
const isActive = (route: any) => {
return route.match || activeWhenMatch && activeWhenMatch(route);
}; };
isActive(route: any) { const renderLink = (route: any) => {
const { activeWhenMatch } = this.props;
return route.match || (activeWhenMatch && activeWhenMatch(route));
}
renderLink = (route: any) => {
const { to, icon, label, collapsed, title } = this.props;
let defaultIcon = "fas fa-cog"; let defaultIcon = "fas fa-cog";
if (icon) { if (icon) {
defaultIcon = icon; defaultIcon = icon;
} }
let children = null; let childrenList = null;
if (this.isActive(route)) { if (isActive(route)) {
children = <ul className="sub-menu">{this.props.children}</ul>; if (menuContext.menuCollapsed) {
menuContext.setMenuCollapsed(false);
}
childrenList = <ul className="sub-menu">{children}</ul>;
} }
return ( return (
<li title={collapsed ? title : undefined}> <li title={collapsed ? title : undefined}>
<Link <Link className={classNames(isActive(route) ? "is-active" : "", collapsed ? "has-text-centered" : "")} to={to}>
className={classNames(this.isActive(route) ? "is-active" : "", collapsed ? "has-text-centered" : "")}
to={to}
>
<i className={classNames(defaultIcon, "fa-fw")} /> {collapsed ? "" : label} <i className={classNames(defaultIcon, "fa-fw")} /> {collapsed ? "" : label}
</Link> </Link>
{children} {childrenList}
</li> </li>
); );
}; };
render() { // removes last part of url
const { to, activeOnlyWhenExact } = this.props; const parents = to.split("/");
parents.splice(-1, 1);
const parent = parents.join("/");
// removes last part of url return <Route path={parent} exact={activeOnlyWhenExact} children={renderLink} />;
const parents = to.split("/"); };
parents.splice(-1, 1);
const parent = parents.join("/");
return <Route path={parent} exact={activeOnlyWhenExact} children={this.renderLink} />;
}
}
export default SubNavigation; export default SubNavigation;

View File

@@ -7,3 +7,4 @@ export { default as SubNavigation } from "./SubNavigation";
export { default as PrimaryNavigation } from "./PrimaryNavigation"; export { default as PrimaryNavigation } from "./PrimaryNavigation";
export { default as PrimaryNavigationLink } from "./PrimaryNavigationLink"; export { default as PrimaryNavigationLink } from "./PrimaryNavigationLink";
export { default as Section } from "./Section"; export { default as Section } from "./Section";
export { MenuContext, storeMenuCollapsed, isMenuCollapsed } from "./MenuContext";

View File

@@ -101,12 +101,12 @@ class DiffFile extends React.Component<Props, State> {
} }
}; };
toggleSideBySide = (callback: (collapsed: boolean) => void) => { toggleSideBySide = (callback: () => void) => {
this.setState( this.setState(
state => ({ state => ({
sideBySide: !state.sideBySide sideBySide: !state.sideBySide
}), }),
() => callback(true) () => callback()
); );
}; };

View File

@@ -1,7 +1,7 @@
{ {
"admin": { "admin": {
"menu": { "menu": {
"navigationLabel": "Administrations Navigation", "navigationLabel": "Administration",
"informationNavLink": "Informationen", "informationNavLink": "Informationen",
"settingsNavLink": "Einstellungen", "settingsNavLink": "Einstellungen",
"generalNavLink": "Generell" "generalNavLink": "Generell"

View File

@@ -61,7 +61,7 @@
"previous": "Zurück" "previous": "Zurück"
}, },
"profile": { "profile": {
"navigationLabel": "Profil Navigation", "navigationLabel": "Profil",
"informationNavLink": "Information", "informationNavLink": "Information",
"changePasswordNavLink": "Passwort ändern", "changePasswordNavLink": "Passwort ändern",
"settingsNavLink": "Einstellungen", "settingsNavLink": "Einstellungen",

View File

@@ -1,6 +1,6 @@
{ {
"config": { "config": {
"navigationLabel": "Administrations Navigation", "navigationLabel": "Administration",
"title": "Globale Einstellungen", "title": "Globale Einstellungen",
"errorTitle": "Fehler", "errorTitle": "Fehler",
"errorSubtitle": "Unbekannter Einstellungen Fehler", "errorSubtitle": "Unbekannter Einstellungen Fehler",

View File

@@ -18,7 +18,7 @@
"errorTitle": "Fehler", "errorTitle": "Fehler",
"errorSubtitle": "Unbekannter Gruppen Fehler", "errorSubtitle": "Unbekannter Gruppen Fehler",
"menu": { "menu": {
"navigationLabel": "Gruppen Navigation", "navigationLabel": "Gruppen",
"informationNavLink": "Informationen", "informationNavLink": "Informationen",
"settingsNavLink": "Einstellungen", "settingsNavLink": "Einstellungen",
"generalNavLink": "Generell", "generalNavLink": "Generell",

View File

@@ -28,7 +28,7 @@
"errorTitle": "Fehler", "errorTitle": "Fehler",
"errorSubtitle": "Unbekannter Repository Fehler", "errorSubtitle": "Unbekannter Repository Fehler",
"menu": { "menu": {
"navigationLabel": "Repository Navigation", "navigationLabel": "Repository",
"informationNavLink": "Informationen", "informationNavLink": "Informationen",
"branchesNavLink": "Branches", "branchesNavLink": "Branches",
"sourcesNavLink": "Code", "sourcesNavLink": "Code",

View File

@@ -32,7 +32,7 @@
"errorTitle": "Fehler", "errorTitle": "Fehler",
"errorSubtitle": "Unbekannter Benutzer Fehler", "errorSubtitle": "Unbekannter Benutzer Fehler",
"menu": { "menu": {
"navigationLabel": "Benutzer Navigation", "navigationLabel": "Benutzer",
"informationNavLink": "Informationen", "informationNavLink": "Informationen",
"settingsNavLink": "Einstellungen", "settingsNavLink": "Einstellungen",
"generalNavLink": "Generell", "generalNavLink": "Generell",

View File

@@ -1,7 +1,7 @@
{ {
"admin": { "admin": {
"menu": { "menu": {
"navigationLabel": "Administration Navigation", "navigationLabel": "Administration",
"informationNavLink": "Information", "informationNavLink": "Information",
"settingsNavLink": "Settings", "settingsNavLink": "Settings",
"generalNavLink": "General" "generalNavLink": "General"

View File

@@ -62,7 +62,7 @@
"previous": "Previous" "previous": "Previous"
}, },
"profile": { "profile": {
"navigationLabel": "Profile Navigation", "navigationLabel": "Profile",
"informationNavLink": "Information", "informationNavLink": "Information",
"changePasswordNavLink": "Change password", "changePasswordNavLink": "Change password",
"settingsNavLink": "Settings", "settingsNavLink": "Settings",

View File

@@ -1,6 +1,6 @@
{ {
"config": { "config": {
"navigationLabel": "Administration Navigation", "navigationLabel": "Administration",
"title": "Global Configuration", "title": "Global Configuration",
"errorTitle": "Error", "errorTitle": "Error",
"errorSubtitle": "Unknown Config Error", "errorSubtitle": "Unknown Config Error",

View File

@@ -18,7 +18,7 @@
"errorTitle": "Error", "errorTitle": "Error",
"errorSubtitle": "Unknown group error", "errorSubtitle": "Unknown group error",
"menu": { "menu": {
"navigationLabel": "Group Navigation", "navigationLabel": "Group",
"informationNavLink": "Information", "informationNavLink": "Information",
"settingsNavLink": "Settings", "settingsNavLink": "Settings",
"generalNavLink": "General", "generalNavLink": "General",

View File

@@ -28,7 +28,7 @@
"errorTitle": "Error", "errorTitle": "Error",
"errorSubtitle": "Unknown repository error", "errorSubtitle": "Unknown repository error",
"menu": { "menu": {
"navigationLabel": "Repository Navigation", "navigationLabel": "Repository",
"informationNavLink": "Information", "informationNavLink": "Information",
"branchesNavLink": "Branches", "branchesNavLink": "Branches",
"sourcesNavLink": "Code", "sourcesNavLink": "Code",

View File

@@ -32,7 +32,7 @@
"errorTitle": "Error", "errorTitle": "Error",
"errorSubtitle": "Unknown user error", "errorSubtitle": "Unknown user error",
"menu": { "menu": {
"navigationLabel": "User Navigation", "navigationLabel": "User",
"informationNavLink": "Information", "informationNavLink": "Information",
"settingsNavLink": "Settings", "settingsNavLink": "Settings",
"generalNavLink": "General", "generalNavLink": "General",

View File

@@ -1,7 +1,7 @@
{ {
"admin": { "admin": {
"menu": { "menu": {
"navigationLabel": "Menú de administración", "navigationLabel": "Administración",
"informationNavLink": "Información", "informationNavLink": "Información",
"settingsNavLink": "Ajustes", "settingsNavLink": "Ajustes",
"generalNavLink": "General" "generalNavLink": "General"

View File

@@ -62,7 +62,7 @@
"previous": "Anterior" "previous": "Anterior"
}, },
"profile": { "profile": {
"navigationLabel": "Menú de sección", "navigationLabel": "Sección",
"informationNavLink": "Información", "informationNavLink": "Información",
"changePasswordNavLink": "Cambiar contraseña", "changePasswordNavLink": "Cambiar contraseña",
"settingsNavLink": "Ajustes", "settingsNavLink": "Ajustes",

View File

@@ -1,6 +1,6 @@
{ {
"config": { "config": {
"navigationLabel": "Menú de administración", "navigationLabel": "Administración",
"title": "Configuración global", "title": "Configuración global",
"errorTitle": "Error", "errorTitle": "Error",
"errorSubtitle": "Error de configuración desconocido", "errorSubtitle": "Error de configuración desconocido",

View File

@@ -18,7 +18,7 @@
"errorTitle": "Error", "errorTitle": "Error",
"errorSubtitle": "Error de grupo desconocido", "errorSubtitle": "Error de grupo desconocido",
"menu": { "menu": {
"navigationLabel": "Menú de grupo", "navigationLabel": "Grupo",
"informationNavLink": "Información", "informationNavLink": "Información",
"settingsNavLink": "Ajustes", "settingsNavLink": "Ajustes",
"generalNavLink": "General", "generalNavLink": "General",

View File

@@ -28,7 +28,7 @@
"errorTitle": "Error", "errorTitle": "Error",
"errorSubtitle": "Error de repositorio desconocido", "errorSubtitle": "Error de repositorio desconocido",
"menu": { "menu": {
"navigationLabel": "Menú de repositorio", "navigationLabel": "Repositorio",
"informationNavLink": "Información", "informationNavLink": "Información",
"branchesNavLink": "Ramas", "branchesNavLink": "Ramas",
"sourcesNavLink": "Código", "sourcesNavLink": "Código",

View File

@@ -32,7 +32,7 @@
"errorTitle": "Error", "errorTitle": "Error",
"errorSubtitle": "Error de usuario desconocido", "errorSubtitle": "Error de usuario desconocido",
"menu": { "menu": {
"navigationLabel": "Menú de usuario", "navigationLabel": "Usuario",
"informationNavLink": "Información", "informationNavLink": "Información",
"settingsNavLink": "Ajustes", "settingsNavLink": "Ajustes",
"generalNavLink": "General", "generalNavLink": "General",

View File

@@ -12,7 +12,8 @@ import {
Section, Section,
SubNavigation, SubNavigation,
isMenuCollapsed, isMenuCollapsed,
MenuContext MenuContext,
storeMenuCollapsed
} from "@scm-manager/ui-components"; } from "@scm-manager/ui-components";
import { getAvailablePluginsLink, getInstalledPluginsLink, getLinks } from "../../modules/indexResource"; import { getAvailablePluginsLink, getInstalledPluginsLink, getLinks } from "../../modules/indexResource";
import AdminDetails from "./AdminDetails"; import AdminDetails from "./AdminDetails";
@@ -21,7 +22,6 @@ import GlobalConfig from "./GlobalConfig";
import RepositoryRoles from "../roles/containers/RepositoryRoles"; import RepositoryRoles from "../roles/containers/RepositoryRoles";
import SingleRepositoryRole from "../roles/containers/SingleRepositoryRole"; import SingleRepositoryRole from "../roles/containers/SingleRepositoryRole";
import CreateRepositoryRole from "../roles/containers/CreateRepositoryRole"; import CreateRepositoryRole from "../roles/containers/CreateRepositoryRole";
import { storeMenuCollapsed } from "@scm-manager/ui-components/src";
type Props = RouteComponentProps & type Props = RouteComponentProps &
WithTranslation & { WithTranslation & {
@@ -32,7 +32,6 @@ type Props = RouteComponentProps &
type State = { type State = {
menuCollapsed: boolean; menuCollapsed: boolean;
setMenuCollapsed: (collapsed: boolean) => void;
}; };
class Admin extends React.Component<Props, State> { class Admin extends React.Component<Props, State> {
@@ -40,21 +39,10 @@ class Admin extends React.Component<Props, State> {
super(props); super(props);
this.state = { this.state = {
menuCollapsed: isMenuCollapsed(), menuCollapsed: isMenuCollapsed()
setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed })
}; };
} }
componentDidUpdate() {
if (this.state.menuCollapsed && this.isCollapseForbidden()) {
this.setState({ menuCollapsed: false });
}
}
isCollapseForbidden = () => {
return this.props.location.pathname.includes("/settings/") || this.props.location.pathname.includes("/plugins/");
};
onCollapseAdminMenu = (collapsed: boolean) => { onCollapseAdminMenu = (collapsed: boolean) => {
this.setState({ menuCollapsed: collapsed }, () => storeMenuCollapsed(collapsed)); this.setState({ menuCollapsed: collapsed }, () => storeMenuCollapsed(collapsed));
}; };
@@ -90,7 +78,9 @@ class Admin extends React.Component<Props, State> {
}; };
return ( return (
<MenuContext.Provider value={this.state}> <MenuContext.Provider
value={{ menuCollapsed, setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed }) }}
>
<Page> <Page>
<div className="columns"> <div className="columns">
<div className="column"> <div className="column">
@@ -136,8 +126,9 @@ class Admin extends React.Component<Props, State> {
<Navigation> <Navigation>
<Section <Section
label={t("admin.menu.navigationLabel")} label={t("admin.menu.navigationLabel")}
onCollapse={this.isCollapseForbidden() ? undefined : () => this.onCollapseAdminMenu(!menuCollapsed)} onCollapse={() => this.onCollapseAdminMenu(!menuCollapsed)}
collapsed={menuCollapsed} collapsed={menuCollapsed}
scrollTransitionAt={220}
> >
<NavLink <NavLink
to={`${url}/info`} to={`${url}/info`}

View File

@@ -30,7 +30,6 @@ type Props = RouteComponentProps &
type State = { type State = {
menuCollapsed: boolean; menuCollapsed: boolean;
setMenuCollapsed: (collapsed: boolean) => void;
}; };
class Profile extends React.Component<Props, State> { class Profile extends React.Component<Props, State> {
@@ -38,21 +37,10 @@ class Profile extends React.Component<Props, State> {
super(props); super(props);
this.state = { this.state = {
menuCollapsed: isMenuCollapsed(), menuCollapsed: isMenuCollapsed()
setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed })
}; };
} }
componentDidUpdate() {
if (this.state.menuCollapsed && this.isCollapseForbidden()) {
this.setState({ menuCollapsed: false });
}
}
isCollapseForbidden = () => {
return this.props.location.pathname.includes("/settings/");
};
onCollapseProfileMenu = (collapsed: boolean) => { onCollapseProfileMenu = (collapsed: boolean) => {
this.setState({ menuCollapsed: collapsed }, () => storeMenuCollapsed(collapsed)); this.setState({ menuCollapsed: collapsed }, () => storeMenuCollapsed(collapsed));
}; };
@@ -93,7 +81,9 @@ class Profile extends React.Component<Props, State> {
}; };
return ( return (
<MenuContext.Provider value={this.state}> <MenuContext.Provider
value={{ menuCollapsed, setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed }) }}
>
<Page title={me.displayName}> <Page title={me.displayName}>
<div className="columns"> <div className="columns">
<div className="column"> <div className="column">
@@ -105,7 +95,7 @@ class Profile extends React.Component<Props, State> {
<Navigation> <Navigation>
<Section <Section
label={t("profile.navigationLabel")} label={t("profile.navigationLabel")}
onCollapse={this.isCollapseForbidden() ? undefined : () => this.onCollapseProfileMenu(!menuCollapsed)} onCollapse={() => this.onCollapseProfileMenu(!menuCollapsed)}
collapsed={menuCollapsed} collapsed={menuCollapsed}
> >
<NavLink <NavLink

View File

@@ -37,7 +37,6 @@ type Props = RouteComponentProps &
type State = { type State = {
menuCollapsed: boolean; menuCollapsed: boolean;
setMenuCollapsed: (collapsed: boolean) => void;
}; };
class SingleGroup extends React.Component<Props, State> { class SingleGroup extends React.Component<Props, State> {
@@ -45,8 +44,7 @@ class SingleGroup extends React.Component<Props, State> {
super(props); super(props);
this.state = { this.state = {
menuCollapsed: isMenuCollapsed(), menuCollapsed: isMenuCollapsed()
setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed })
}; };
} }
@@ -54,16 +52,6 @@ class SingleGroup extends React.Component<Props, State> {
this.props.fetchGroupByName(this.props.groupLink, this.props.name); this.props.fetchGroupByName(this.props.groupLink, this.props.name);
} }
componentDidUpdate() {
if (this.state.menuCollapsed && this.isCollapseForbidden()) {
this.setState({ menuCollapsed: false });
}
}
isCollapseForbidden = () => {
return this.props.location.pathname.includes("/settings/");
};
onCollapseGroupMenu = (collapsed: boolean) => { onCollapseGroupMenu = (collapsed: boolean) => {
this.setState({ menuCollapsed: collapsed }, () => storeMenuCollapsed(collapsed)); this.setState({ menuCollapsed: collapsed }, () => storeMenuCollapsed(collapsed));
}; };
@@ -99,7 +87,9 @@ class SingleGroup extends React.Component<Props, State> {
}; };
return ( return (
<MenuContext.Provider value={this.state}> <MenuContext.Provider
value={{ menuCollapsed, setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed }) }}
>
<Page title={group.name}> <Page title={group.name}>
<div className="columns"> <div className="columns">
<div className="column"> <div className="column">
@@ -116,7 +106,7 @@ class SingleGroup extends React.Component<Props, State> {
<Navigation> <Navigation>
<Section <Section
label={t("singleGroup.menu.navigationLabel")} label={t("singleGroup.menu.navigationLabel")}
onCollapse={this.isCollapseForbidden() ? undefined : () => this.onCollapseGroupMenu(!menuCollapsed)} onCollapse={() => this.onCollapseGroupMenu(!menuCollapsed)}
collapsed={menuCollapsed} collapsed={menuCollapsed}
> >
<NavLink <NavLink

View File

@@ -42,7 +42,7 @@ class Changesets extends React.Component<Props> {
fetchChangesets(repository, branch, page); fetchChangesets(repository, branch, page);
} }
shouldComponentUpdate(nextProps: Readonly<Props>, nextState: Readonly<{}>, nextContext: any): boolean { shouldComponentUpdate(nextProps: Readonly<Props>): boolean {
return this.props.changesets !== nextProps.changesets; return this.props.changesets !== nextProps.changesets;
} }

View File

@@ -47,7 +47,6 @@ type Props = RouteComponentProps &
type State = { type State = {
menuCollapsed: boolean; menuCollapsed: boolean;
setMenuCollapsed: (collapsed: boolean) => void;
}; };
class RepositoryRoot extends React.Component<Props, State> { class RepositoryRoot extends React.Component<Props, State> {
@@ -55,8 +54,7 @@ class RepositoryRoot extends React.Component<Props, State> {
super(props); super(props);
this.state = { this.state = {
menuCollapsed: isMenuCollapsed(), menuCollapsed: isMenuCollapsed()
setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed })
}; };
} }
@@ -65,16 +63,6 @@ class RepositoryRoot extends React.Component<Props, State> {
fetchRepoByName(repoLink, namespace, name); fetchRepoByName(repoLink, namespace, name);
} }
componentDidUpdate() {
if (this.state.menuCollapsed && this.isCollapseForbidden()) {
this.setState({ menuCollapsed: false });
}
}
isCollapseForbidden = () => {
return this.props.location.pathname.includes("/settings/");
};
stripEndingSlash = (url: string) => { stripEndingSlash = (url: string) => {
if (url.endsWith("/")) { if (url.endsWith("/")) {
return url.substring(0, url.length - 1); return url.substring(0, url.length - 1);
@@ -138,7 +126,7 @@ class RepositoryRoot extends React.Component<Props, State> {
const url = this.matchedUrl(); const url = this.matchedUrl();
const extensionProps: any = { const extensionProps = {
repository, repository,
url, url,
indexLinks, indexLinks,
@@ -154,10 +142,15 @@ class RepositoryRoot extends React.Component<Props, State> {
} }
return ( return (
<Page title={repository.namespace + "/" + repository.name}> <MenuContext.Provider
<div className="columns"> value={{
<div className="column"> menuCollapsed,
<MenuContext.Provider value={this.state}> setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed })
}}
>
<Page title={repository.namespace + "/" + repository.name}>
<div className="columns">
<div className="column">
<Switch> <Switch>
<Redirect exact from={this.props.match.url} to={redirectedUrl} /> <Redirect exact from={this.props.match.url} to={redirectedUrl} />
@@ -206,59 +199,58 @@ class RepositoryRoot extends React.Component<Props, State> {
<Route path={`${url}/branches/create`} render={() => <CreateBranch repository={repository} />} /> <Route path={`${url}/branches/create`} render={() => <CreateBranch repository={repository} />} />
<ExtensionPoint name="repository.route" props={extensionProps} renderAll={true} /> <ExtensionPoint name="repository.route" props={extensionProps} renderAll={true} />
</Switch> </Switch>
</MenuContext.Provider> </div>
</div> <div className={menuCollapsed ? "column is-1" : "column is-3"}>
<div className={menuCollapsed ? "column is-1" : "column is-3"}> <Navigation>
<Navigation> <Section
<Section label={t("repositoryRoot.menu.navigationLabel")}
label={t("repositoryRoot.menu.navigationLabel")} onCollapse={() => this.onCollapseRepositoryMenu(!menuCollapsed)}
onCollapse={ collapsed={menuCollapsed}
this.isCollapseForbidden() ? undefined : () => this.onCollapseRepositoryMenu(!menuCollapsed) scrollTransitionAt={250}
}
collapsed={menuCollapsed}
>
<ExtensionPoint name="repository.navigation.topLevel" props={extensionProps} renderAll={true} />
<NavLink
to={`${url}/info`}
icon="fas fa-info-circle"
label={t("repositoryRoot.menu.informationNavLink")}
title={t("repositoryRoot.menu.informationNavLink")}
/>
<RepositoryNavLink
repository={repository}
linkName="branches"
to={`${url}/branches/`}
icon="fas fa-code-branch"
label={t("repositoryRoot.menu.branchesNavLink")}
activeWhenMatch={this.matchesBranches}
activeOnlyWhenExact={false}
title={t("repositoryRoot.menu.branchesNavLink")}
/>
<RepositoryNavLink
repository={repository}
linkName={this.getCodeLinkname()}
to={this.evaluateDestinationForCodeLink()}
icon="fas fa-code"
label={t("repositoryRoot.menu.sourcesNavLink")}
activeWhenMatch={this.matchesCode}
activeOnlyWhenExact={false}
title={t("repositoryRoot.menu.sourcesNavLink")}
/>
<ExtensionPoint name="repository.navigation" props={extensionProps} renderAll={true} />
<SubNavigation
to={`${url}/settings/general`}
label={t("repositoryRoot.menu.settingsNavLink")}
title={t("repositoryRoot.menu.settingsNavLink")}
> >
<EditRepoNavLink repository={repository} editUrl={`${url}/settings/general`} /> <ExtensionPoint name="repository.navigation.topLevel" props={extensionProps} renderAll={true} />
<PermissionsNavLink permissionUrl={`${url}/settings/permissions`} repository={repository} /> <NavLink
<ExtensionPoint name="repository.setting" props={extensionProps} renderAll={true} /> to={`${url}/info`}
</SubNavigation> icon="fas fa-info-circle"
</Section> label={t("repositoryRoot.menu.informationNavLink")}
</Navigation> title={t("repositoryRoot.menu.informationNavLink")}
/>
<RepositoryNavLink
repository={repository}
linkName="branches"
to={`${url}/branches/`}
icon="fas fa-code-branch"
label={t("repositoryRoot.menu.branchesNavLink")}
activeWhenMatch={this.matchesBranches}
activeOnlyWhenExact={false}
title={t("repositoryRoot.menu.branchesNavLink")}
/>
<RepositoryNavLink
repository={repository}
linkName={this.getCodeLinkname()}
to={this.evaluateDestinationForCodeLink()}
icon="fas fa-code"
label={t("repositoryRoot.menu.sourcesNavLink")}
activeWhenMatch={this.matchesCode}
activeOnlyWhenExact={false}
title={t("repositoryRoot.menu.sourcesNavLink")}
/>
<ExtensionPoint name="repository.navigation" props={extensionProps} renderAll={true} />
<SubNavigation
to={`${url}/settings/general`}
label={t("repositoryRoot.menu.settingsNavLink")}
title={t("repositoryRoot.menu.settingsNavLink")}
>
<EditRepoNavLink repository={repository} editUrl={`${url}/settings/general`} />
<PermissionsNavLink permissionUrl={`${url}/settings/permissions`} repository={repository} />
<ExtensionPoint name="repository.setting" props={extensionProps} renderAll={true} />
</SubNavigation>
</Section>
</Navigation>
</div>
</div> </div>
</div> </Page>
</Page> </MenuContext.Provider>
); );
} }
} }

View File

@@ -38,7 +38,6 @@ type Props = RouteComponentProps &
type State = { type State = {
menuCollapsed: boolean; menuCollapsed: boolean;
setMenuCollapsed: (collapsed: boolean) => void;
}; };
class SingleUser extends React.Component<Props, State> { class SingleUser extends React.Component<Props, State> {
@@ -46,8 +45,7 @@ class SingleUser extends React.Component<Props, State> {
super(props); super(props);
this.state = { this.state = {
menuCollapsed: isMenuCollapsed(), menuCollapsed: isMenuCollapsed()
setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed })
}; };
} }
@@ -55,12 +53,6 @@ class SingleUser extends React.Component<Props, State> {
this.props.fetchUserByName(this.props.usersLink, this.props.name); this.props.fetchUserByName(this.props.usersLink, this.props.name);
} }
componentDidUpdate() {
if (this.state.menuCollapsed && this.isCollapseForbidden()) {
this.setState({ menuCollapsed: false });
}
}
stripEndingSlash = (url: string) => { stripEndingSlash = (url: string) => {
if (url.endsWith("/")) { if (url.endsWith("/")) {
return url.substring(0, url.length - 2); return url.substring(0, url.length - 2);
@@ -68,10 +60,6 @@ class SingleUser extends React.Component<Props, State> {
return url; return url;
}; };
isCollapseForbidden = () => {
return this.props.location.pathname.includes("/settings/");
};
onCollapseUserMenu = (collapsed: boolean) => { onCollapseUserMenu = (collapsed: boolean) => {
this.setState({ menuCollapsed: collapsed }, () => storeMenuCollapsed(collapsed)); this.setState({ menuCollapsed: collapsed }, () => storeMenuCollapsed(collapsed));
}; };
@@ -100,7 +88,9 @@ class SingleUser extends React.Component<Props, State> {
}; };
return ( return (
<MenuContext.Provider value={this.state}> <MenuContext.Provider
value={{ menuCollapsed, setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed }) }}
>
<Page title={user.displayName}> <Page title={user.displayName}>
<div className="columns"> <div className="columns">
<div className="column"> <div className="column">
@@ -117,7 +107,7 @@ class SingleUser extends React.Component<Props, State> {
<Navigation> <Navigation>
<Section <Section
label={t("singleUser.menu.navigationLabel")} label={t("singleUser.menu.navigationLabel")}
onCollapse={this.isCollapseForbidden() ? undefined : () => this.onCollapseUserMenu(!menuCollapsed)} onCollapse={() => this.onCollapseUserMenu(!menuCollapsed)}
collapsed={menuCollapsed} collapsed={menuCollapsed}
> >
<NavLink <NavLink