Merged in feature/consolidate_code_section (pull request #381)

Feature/consolidate code section
This commit is contained in:
Sebastian Sdorra
2020-01-15 11:46:57 +00:00
110 changed files with 1182 additions and 1187 deletions

View File

@@ -1,7 +1,15 @@
import React, { FormEvent } from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { Branch, Repository, Link } from "@scm-manager/ui-types";
import { apiClient, BranchSelector, ErrorPage, Loading, Subtitle, Level, SubmitButton } from "@scm-manager/ui-components";
import {
apiClient,
BranchSelector,
ErrorPage,
Loading,
Subtitle,
Level,
SubmitButton
} from "@scm-manager/ui-components";
type Props = WithTranslation & {
repository: Repository;
@@ -13,7 +21,7 @@ type State = {
submitPending: boolean;
error?: Error;
branches: Branch[];
selectedBranchName?: string;
selectedBranchName: string;
defaultBranchChanged: boolean;
disabled: boolean;
};
@@ -29,6 +37,7 @@ class RepositoryConfig extends React.Component<Props, State> {
loadingDefaultBranch: true,
submitPending: false,
branches: [],
selectedBranchName: "",
defaultBranchChanged: false,
disabled: true
};
@@ -87,16 +96,16 @@ class RepositoryConfig extends React.Component<Props, State> {
if (!branch) {
this.setState({
...this.state,
selectedBranchName: undefined,
selectedBranchName: "",
defaultBranchChanged: false
});
} else {
this.setState({
...this.state,
selectedBranchName: branch.name,
defaultBranchChanged: false
});
return;
}
this.setState({
...this.state,
selectedBranchName: branch.name,
defaultBranchChanged: false
});
};
submit = (event: FormEvent) => {
@@ -164,7 +173,7 @@ class RepositoryConfig extends React.Component<Props, State> {
<BranchSelector
label={t("scm-git-plugin.repo-config.default-branch")}
branches={this.state.branches}
selected={this.branchSelected}
onSelectBranch={this.branchSelected}
selectedBranch={this.state.selectedBranchName}
disabled={disabled}
/>

View File

@@ -8,9 +8,6 @@ import { Links, Link } from "@scm-manager/ui-types";
type Props = RouteComponentProps & {
authenticated?: boolean;
links: Links;
//context objects
history: History;
};
type State = {

View File

@@ -1,4 +1,5 @@
module.exports = api => {
api.cache.using(() => process.env.NODE_ENV || "production");
return {
presets: [
require("@babel/preset-env"),

View File

@@ -19,6 +19,7 @@
<properties>
<build.script>build</build.script>
<skipTests>false</skipTests>
<skipTypecheck>false</skipTypecheck>
<sonar.language>typescript</sonar.language>
<sonar.sources>ui-extensions/src,ui-components/src,ui-webapp/src</sonar.sources>
<sonar.test.exclusions>**/*.test.js,src/tests/**</sonar.test.exclusions>
@@ -60,6 +61,7 @@
<goal>run</goal>
</goals>
<configuration>
<skip>${skipTypecheck}</skip>
<script>typecheck</script>
</configuration>
</execution>

View File

@@ -1,4 +1,4 @@
import React from "react";
import React, { FC } from "react";
import classNames from "classnames";
import styled from "styled-components";
import { Branch } from "@scm-manager/ui-types";
@@ -6,16 +6,12 @@ import DropDown from "./forms/DropDown";
type Props = {
branches: Branch[];
selected: (branch?: Branch) => void;
onSelectBranch: (branch: Branch | undefined) => void;
selectedBranch?: string;
label: string;
disabled?: boolean;
};
type State = {
selectedBranch?: Branch;
};
const ZeroflexFieldLabel = styled.div`
flex-basis: inherit;
flex-grow: 0;
@@ -29,66 +25,31 @@ const NoBottomMarginField = styled.div`
margin-bottom: 0 !important;
`;
export default class BranchSelector extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {};
}
componentDidMount() {
const { branches } = this.props;
if (branches) {
const selectedBranch = branches.find(branch => branch.name === this.props.selectedBranch);
this.setState({
selectedBranch
});
}
}
render() {
const { branches, label, disabled } = this.props;
if (branches) {
return (
<div className={classNames("field", "is-horizontal")}>
<ZeroflexFieldLabel className={classNames("field-label", "is-normal")}>
<label className={classNames("label", "is-size-6")}>{label}</label>
</ZeroflexFieldLabel>
<div className="field-body">
<NoBottomMarginField className={classNames("field", "is-narrow")}>
<MinWidthControl className="control">
<DropDown
className="is-fullwidth"
options={branches.map(b => b.name)}
optionSelected={this.branchSelected}
disabled={!!disabled}
preselectedOption={this.state.selectedBranch ? this.state.selectedBranch.name : ""}
/>
</MinWidthControl>
</NoBottomMarginField>
</div>
const BranchSelector: FC<Props> = ({ branches, onSelectBranch, selectedBranch, label, disabled }) => {
if (branches) {
return (
<div className={classNames("field", "is-horizontal")}>
<ZeroflexFieldLabel className={classNames("field-label", "is-normal")}>
<label className={classNames("label", "is-size-6")}>{label}</label>
</ZeroflexFieldLabel>
<div className="field-body">
<NoBottomMarginField className={classNames("field", "is-narrow")}>
<MinWidthControl className="control">
<DropDown
className="is-fullwidth"
options={branches.map(b => b.name)}
optionSelected={branch => onSelectBranch(branches.filter(b => b.name === branch)[0])}
disabled={!!disabled}
preselectedOption={selectedBranch && selectedBranch}
/>
</MinWidthControl>
</NoBottomMarginField>
</div>
);
} else {
return null;
}
</div>
);
} else {
return null;
}
};
branchSelected = (branchName: string) => {
const { branches, selected } = this.props;
if (!branchName) {
this.setState({
selectedBranch: undefined
});
selected(undefined);
return;
}
const branch = branches.find(b => b.name === branchName);
selected(branch);
this.setState({
selectedBranch: branch
});
};
}
export default BranchSelector;

View File

@@ -5,7 +5,7 @@ import { Link } from "react-router-dom";
type Props = {
title: string;
description: string;
description?: string;
avatar: ReactNode;
contentRight?: ReactNode;
footerLeft: ReactNode;

View File

@@ -9,10 +9,6 @@ type Props = RouteComponentProps & {
showCreateButton: boolean;
link: string;
label?: string;
// context props
history: History;
location: any;
};
class OverviewPageActions extends React.Component<Props> {

View File

@@ -13,10 +13,15 @@ type Props = {
class DropDown extends React.Component<Props> {
render() {
const { options, optionValues, preselectedOption, className, disabled } = this.props;
if (preselectedOption && !options.includes(preselectedOption)) {
options.unshift(preselectedOption);
}
return (
<div className={classNames(className, "select", disabled ? "disabled" : "")}>
<select value={preselectedOption ? preselectedOption : ""} onChange={this.change} disabled={disabled}>
<option key="" />
<option key={preselectedOption} />
{options.map((option, index) => {
return (
<option key={option} value={optionValues && optionValues[index] ? optionValues[index] : option}>

View File

@@ -6,11 +6,11 @@ export type Description = {
};
export function createChangesetLink(repository: Repository, changeset: Changeset) {
return `/repo/${repository.namespace}/${repository.name}/changeset/${changeset.id}`;
return `/repo/${repository.namespace}/${repository.name}/code/changeset/${changeset.id}`;
}
export function createSourcesLink(repository: Repository, changeset: Changeset) {
return `/repo/${repository.namespace}/${repository.name}/sources/${changeset.id}`;
return `/repo/${repository.namespace}/${repository.name}/code/sources/${changeset.id}`;
}
export function parseDescription(description?: string): Description {

View File

@@ -5,8 +5,7 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const isDevelopment = process.env.NODE_ENV !== "production";
const isDevelopment = process.env.NODE_ENV === "development";
const root = path.resolve(process.cwd(), "scm-ui");
module.exports = [

View File

@@ -30,8 +30,7 @@
"navigationLabel": "Repository Navigation",
"informationNavLink": "Informationen",
"branchesNavLink": "Branches",
"historyNavLink": "Commits",
"sourcesNavLink": "Sources",
"sourcesNavLink": "Code",
"settingsNavLink": "Einstellungen",
"generalNavLink": "Generell",
"permissionsNavLink": "Berechtigungen"
@@ -69,6 +68,11 @@
"sources": "Sources",
"defaultTag": "Default"
},
"code": {
"sources": "Sources",
"commits": "Commits",
"branchSelector": "Branches"
},
"changesets": {
"errorTitle": "Fehler",
"errorSubtitle": "Changesets konnten nicht abgerufen werden",

View File

@@ -30,8 +30,7 @@
"navigationLabel": "Repository Navigation",
"informationNavLink": "Information",
"branchesNavLink": "Branches",
"historyNavLink": "Commits",
"sourcesNavLink": "Sources",
"sourcesNavLink": "Code",
"settingsNavLink": "Settings",
"generalNavLink": "General",
"permissionsNavLink": "Permissions"
@@ -69,6 +68,11 @@
"sources": "Sources",
"defaultTag": "Default"
},
"code": {
"sources": "Sources",
"commits": "Commits",
"branchSelector": "Branches"
},
"changesets": {
"errorTitle": "Error",
"errorSubtitle": "Could not fetch changesets",

View File

@@ -30,8 +30,7 @@
"navigationLabel": "Menú de repositorio",
"informationNavLink": "Información",
"branchesNavLink": "Ramas",
"historyNavLink": "Commits",
"sourcesNavLink": "Fuentes",
"sourcesNavLink": "Código",
"settingsNavLink": "Ajustes",
"generalNavLink": "General",
"permissionsNavLink": "Permisos"
@@ -69,6 +68,11 @@
"sources": "Fuentes",
"defaultTag": "Por defecto"
},
"code": {
"sources": "Sources",
"commits": "Commits",
"branchSelector": "Branches"
},
"changesets": {
"errorTitle": "Error",
"errorSubtitle": "No se han podido recuperar los changesets",

View File

@@ -1,7 +1,7 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { NamespaceStrategies, Config } from "@scm-manager/ui-types";
import { Level, SubmitButton, Notification } from "@scm-manager/ui-components";
import { Config, NamespaceStrategies } from "@scm-manager/ui-types";
import { Level, Notification, SubmitButton } from "@scm-manager/ui-components";
import ProxySettings from "./ProxySettings";
import GeneralSettings from "./GeneralSettings";
import BaseUrlSettings from "./BaseUrlSettings";

View File

@@ -1,6 +1,6 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { Checkbox, InputField, Subtitle, AddEntryToTableField } from "@scm-manager/ui-components";
import { AddEntryToTableField, Checkbox, InputField, Subtitle } from "@scm-manager/ui-components";
import ProxyExcludesTable from "../table/ProxyExcludesTable";
type Props = WithTranslation & {

View File

@@ -1,5 +1,5 @@
import React from "react";
import { RemoveEntryOfTableButton, LabelWithHelpIcon } from "@scm-manager/ui-components";
import { LabelWithHelpIcon, RemoveEntryOfTableButton } from "@scm-manager/ui-components";
type Props = {
items: string[];
@@ -13,27 +13,27 @@ type Props = {
class ArrayConfigTable extends React.Component<Props> {
render() {
const { label, disabled, removeLabel, items, helpText } = this.props;
if(items.length > 0) {
if (items.length > 0) {
return (
<>
<LabelWithHelpIcon label={label} helpText={helpText}/>
<LabelWithHelpIcon label={label} helpText={helpText} />
<table className="table is-hoverable is-fullwidth">
<tbody>
{items.map(item => {
return (
<tr key={item}>
<td>{item}</td>
<td>
<RemoveEntryOfTableButton
entryname={item}
removeEntry={this.removeEntry}
disabled={disabled}
label={removeLabel}
/>
</td>
</tr>
);
})}
{items.map(item => {
return (
<tr key={item}>
<td>{item}</td>
<td>
<RemoveEntryOfTableButton
entryname={item}
removeEntry={this.removeEntry}
disabled={disabled}
label={removeLabel}
/>
</td>
</tr>
);
})}
</tbody>
</table>
</>

View File

@@ -6,8 +6,8 @@ import { Redirect, Route, Switch } from "react-router-dom";
import { History } from "history";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Links } from "@scm-manager/ui-types";
import { Page, Navigation, NavLink, Section, SubNavigation } from "@scm-manager/ui-components";
import { getLinks, getAvailablePluginsLink, getInstalledPluginsLink } from "../../modules/indexResource";
import { Navigation, NavLink, Page, Section, SubNavigation } from "@scm-manager/ui-components";
import { getAvailablePluginsLink, getInstalledPluginsLink, getLinks } from "../../modules/indexResource";
import AdminDetails from "./AdminDetails";
import PluginsOverview from "../plugins/containers/PluginsOverview";
import GlobalConfig from "./GlobalConfig";
@@ -147,7 +147,4 @@ const mapStateToProps = (state: any) => {
};
};
export default compose(
connect(mapStateToProps),
withTranslation("admin")
)(Admin);
export default compose(connect(mapStateToProps), withTranslation("admin"))(Admin);

View File

@@ -2,17 +2,17 @@ import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Config, NamespaceStrategies } from "@scm-manager/ui-types";
import { Title, Loading, ErrorNotification } from "@scm-manager/ui-components";
import { ErrorNotification, Loading, Title } from "@scm-manager/ui-components";
import { getConfigLink } from "../../modules/indexResource";
import {
fetchConfig,
getFetchConfigFailure,
isFetchConfigPending,
getConfig,
modifyConfig,
isModifyConfigPending,
getConfigUpdatePermission,
getFetchConfigFailure,
getModifyConfigFailure,
isFetchConfigPending,
isModifyConfigPending,
modifyConfig,
modifyConfigReset
} from "../modules/config";
import ConfigForm from "../components/form/ConfigForm";
@@ -22,6 +22,7 @@ import {
getNamespaceStrategies,
isFetchNamespaceStrategiesPending
} from "../modules/namespaceStrategies";
import { compose } from "redux";
type Props = WithTranslation & {
loading: boolean;
@@ -137,7 +138,7 @@ class GlobalConfig extends React.Component<Props, State> {
};
}
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchConfig: (link: string) => {
dispatch(fetchConfig(link));
@@ -154,7 +155,7 @@ const mapDispatchToProps = dispatch => {
};
};
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const loading =
isFetchConfigPending(state) || isModifyConfigPending(state) || isFetchNamespaceStrategiesPending(state);
const error =
@@ -175,7 +176,4 @@ const mapStateToProps = state => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("config")(GlobalConfig));
export default compose(connect(mapStateToProps, mapDispatchToProps), withTranslation("config"))(GlobalConfig);

View File

@@ -4,22 +4,22 @@ import fetchMock from "fetch-mock";
import reducer, {
FETCH_CONFIG,
FETCH_CONFIG_FAILURE,
FETCH_CONFIG_PENDING,
FETCH_CONFIG_SUCCESS,
FETCH_CONFIG_FAILURE,
MODIFY_CONFIG,
MODIFY_CONFIG_PENDING,
MODIFY_CONFIG_SUCCESS,
MODIFY_CONFIG_FAILURE,
fetchConfig,
fetchConfigSuccess,
getFetchConfigFailure,
isFetchConfigPending,
modifyConfig,
isModifyConfigPending,
getModifyConfigFailure,
getConfig,
getConfigUpdatePermission
getConfigUpdatePermission,
getFetchConfigFailure,
getModifyConfigFailure,
isFetchConfigPending,
isModifyConfigPending,
MODIFY_CONFIG,
MODIFY_CONFIG_FAILURE,
MODIFY_CONFIG_PENDING,
MODIFY_CONFIG_SUCCESS,
modifyConfig
} from "./config";
const CONFIG_URL = "/config";

View File

@@ -1,10 +1,9 @@
import { apiClient } from "@scm-manager/ui-components";
import * as types from "../../modules/types";
import { Action } from "@scm-manager/ui-types";
import { Action, Config } from "@scm-manager/ui-types";
import { isPending } from "../../modules/pending";
import { getFailure } from "../../modules/failure";
import { Dispatch } from "redux";
import { Config } from "@scm-manager/ui-types";
export const FETCH_CONFIG = "scm/config/FETCH_CONFIG";
export const FETCH_CONFIG_PENDING = `${FETCH_CONFIG}_${types.PENDING_SUFFIX}`;

View File

@@ -2,17 +2,17 @@ import fetchMock from "fetch-mock";
import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import {
default as reducer,
FETCH_NAMESPACESTRATEGIES_TYPES,
FETCH_NAMESPACESTRATEGIES_TYPES_FAILURE,
FETCH_NAMESPACESTRATEGIES_TYPES_PENDING,
FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS,
fetchNamespaceStrategiesIfNeeded,
fetchNamespaceStrategiesSuccess,
shouldFetchNamespaceStrategies,
default as reducer,
getFetchNamespaceStrategiesFailure,
getNamespaceStrategies,
isFetchNamespaceStrategiesPending,
getFetchNamespaceStrategiesFailure
shouldFetchNamespaceStrategies
} from "./namespaceStrategies";
import { MODIFY_CONFIG_SUCCESS } from "./config";

View File

@@ -4,13 +4,13 @@ import { WithTranslation, withTranslation } from "react-i18next";
import { compose } from "redux";
import { PendingPlugins, PluginCollection } from "@scm-manager/ui-types";
import {
Button,
ButtonGroup,
ErrorNotification,
Loading,
Notification,
Subtitle,
Title,
Button
Title
} from "@scm-manager/ui-components";
import {
fetchPendingPlugins,
@@ -31,6 +31,7 @@ import PluginBottomActions from "../components/PluginBottomActions";
import ExecutePendingActionModal from "../components/ExecutePendingActionModal";
import CancelPendingActionModal from "../components/CancelPendingActionModal";
import UpdateAllActionModal from "../components/UpdateAllActionModal";
import { Plugin } from "@scm-manager/ui-types/src";
type Props = WithTranslation & {
loading: boolean;
@@ -68,7 +69,7 @@ class PluginsOverview extends React.Component<Props, State> {
this.fetchPlugins();
}
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: Props) {
const { installed } = this.props;
if (prevProps.installed !== installed) {
this.fetchPlugins();
@@ -90,7 +91,7 @@ class PluginsOverview extends React.Component<Props, State> {
}
};
renderHeader = (actions: React.Node) => {
renderHeader = (actions: React.ReactNode) => {
const { installed, t } = this.props;
return (
<div className="columns">
@@ -103,7 +104,7 @@ class PluginsOverview extends React.Component<Props, State> {
);
};
renderFooter = (actions: React.Node) => {
renderFooter = (actions: React.ReactNode) => {
if (actions) {
return <PluginBottomActions>{actions}</PluginBottomActions>;
}
@@ -173,7 +174,7 @@ class PluginsOverview extends React.Component<Props, State> {
computeUpdateAllSize = () => {
const { collection, t } = this.props;
const outdatedPlugins = collection._embedded.plugins.filter(p => p._links.update).length;
const outdatedPlugins = collection._embedded.plugins.filter((p: Plugin) => p._links.update).length;
return t("plugins.outdatedPlugins", {
count: outdatedPlugins
});
@@ -256,7 +257,7 @@ class PluginsOverview extends React.Component<Props, State> {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const collection = getPluginCollection(state);
const loading = isFetchPluginsPending(state);
const error = getFetchPluginsFailure(state);
@@ -276,7 +277,7 @@ const mapStateToProps = state => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchPluginsByLink: (link: string) => {
dispatch(fetchPluginsByLink(link));
@@ -287,10 +288,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default compose(
withTranslation("admin"),
connect(
mapStateToProps,
mapDispatchToProps
)
)(PluginsOverview);
export default compose(withTranslation("admin"), connect(mapStateToProps, mapDispatchToProps))(PluginsOverview);

View File

@@ -2,25 +2,25 @@ import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import reducer, {
FETCH_PLUGINS,
FETCH_PLUGINS_PENDING,
FETCH_PLUGINS_SUCCESS,
FETCH_PLUGINS_FAILURE,
FETCH_PLUGIN,
FETCH_PLUGIN_FAILURE,
FETCH_PLUGIN_PENDING,
FETCH_PLUGIN_SUCCESS,
FETCH_PLUGIN_FAILURE,
fetchPluginsByLink,
fetchPluginsSuccess,
getPluginCollection,
isFetchPluginsPending,
getFetchPluginsFailure,
FETCH_PLUGINS,
FETCH_PLUGINS_FAILURE,
FETCH_PLUGINS_PENDING,
FETCH_PLUGINS_SUCCESS,
fetchPluginByLink,
fetchPluginByName,
fetchPluginsByLink,
fetchPluginsSuccess,
fetchPluginSuccess,
getFetchPluginFailure,
getFetchPluginsFailure,
getPlugin,
getPluginCollection,
isFetchPluginPending,
getFetchPluginFailure
isFetchPluginsPending
} from "./plugins";
import { Plugin, PluginCollection } from "@scm-manager/ui-types";

View File

@@ -2,7 +2,7 @@ import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { RepositoryRole } from "@scm-manager/ui-types";
import { Level, Button } from "@scm-manager/ui-components";
import { Button, Level } from "@scm-manager/ui-components";
import PermissionRoleDetailsTable from "./PermissionRoleDetailsTable";
type Props = WithTranslation & {

View File

@@ -1,5 +1,6 @@
import React from "react";
import { connect } from "react-redux";
import { compose } from "redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { RepositoryRole } from "@scm-manager/ui-types";
@@ -38,13 +39,13 @@ class CreateRepositoryRole extends React.Component<Props> {
<>
<Title title={t("repositoryRole.title")} />
<Subtitle subtitle={t("repositoryRole.createSubtitle")} />
<RepositoryRoleForm submitForm={role => this.createRepositoryRole(role)} />
<RepositoryRoleForm submitForm={(role: RepositoryRole) => this.createRepositoryRole(role)} />
</>
);
}
}
const mapStateToProps = (state) => {
const mapStateToProps = (state: any) => {
const loading = isFetchVerbsPending(state);
const error = getFetchVerbsFailure(state) || getCreateRoleFailure(state);
const verbsLink = getRepositoryVerbsLink(state);
@@ -58,7 +59,7 @@ const mapStateToProps = (state) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
addRole: (link: string, role: RepositoryRole, callback?: () => void) => {
dispatch(createRole(link, role, callback));
@@ -66,7 +67,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("admin")(CreateRepositoryRole));
export default compose(connect(mapStateToProps, mapDispatchToProps), withTranslation("admin"))(CreateRepositoryRole);

View File

@@ -1,10 +1,11 @@
import React from "react";
import { connect } from "react-redux";
import { compose } from "redux";
import { withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { RepositoryRole } from "@scm-manager/ui-types";
import { Level, DeleteButton, confirmAlert, ErrorNotification } from "@scm-manager/ui-components";
import { confirmAlert, DeleteButton, ErrorNotification, Level } from "@scm-manager/ui-components";
import { deleteRole, getDeleteRoleFailure, isDeleteRolePending } from "../modules/roles";
type Props = WithTranslation & {
@@ -72,7 +73,7 @@ class DeleteRepositoryRole extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const loading = isDeleteRolePending(state, ownProps.role.name);
const error = getDeleteRoleFailure(state, ownProps.role.name);
return {
@@ -81,7 +82,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
deleteRole: (role: RepositoryRole, callback?: () => void) => {
dispatch(deleteRole(role, callback));
@@ -89,7 +90,8 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(withTranslation("admin")(DeleteRepositoryRole)));
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withRouter,
withTranslation("admin")
)(DeleteRepositoryRole);

View File

@@ -3,10 +3,11 @@ import RepositoryRoleForm from "./RepositoryRoleForm";
import { connect } from "react-redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { getModifyRoleFailure, isModifyRolePending, modifyRole } from "../modules/roles";
import { ErrorNotification, Subtitle, Loading } from "@scm-manager/ui-components";
import { ErrorNotification, Loading, Subtitle } from "@scm-manager/ui-components";
import { RepositoryRole } from "@scm-manager/ui-types";
import { History } from "history";
import DeleteRepositoryRole from "./DeleteRepositoryRole";
import { compose } from "redux";
type Props = WithTranslation & {
disabled: boolean;
@@ -43,14 +44,17 @@ class EditRepositoryRole extends React.Component<Props> {
return (
<>
<Subtitle subtitle={t("repositoryRole.editSubtitle")} />
<RepositoryRoleForm role={this.props.role} submitForm={role => this.updateRepositoryRole(role)} />
<RepositoryRoleForm
role={this.props.role}
submitForm={(role: RepositoryRole) => this.updateRepositoryRole(role)}
/>
<DeleteRepositoryRole role={this.props.role} />
</>
);
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const loading = isModifyRolePending(state, ownProps.role.name);
const error = getModifyRoleFailure(state, ownProps.role.name);
@@ -60,7 +64,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
updateRole: (role: RepositoryRole, callback?: () => void) => {
dispatch(modifyRole(role, callback));
@@ -68,7 +72,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("admin")(EditRepositoryRole));
export default compose(connect(mapStateToProps, mapDispatchToProps), withTranslation("admin"))(EditRepositoryRole);

View File

@@ -6,6 +6,7 @@ import { InputField, Level, SubmitButton } from "@scm-manager/ui-components";
import { getRepositoryRolesLink, getRepositoryVerbsLink } from "../../../modules/indexResource";
import { fetchAvailableVerbs, getFetchVerbsFailure, getVerbsFromState, isFetchVerbsPending } from "../modules/roles";
import PermissionsWrapper from "../../../permissions/components/PermissionsWrapper";
import { compose } from "redux";
type Props = WithTranslation & {
role?: RepositoryRole;
@@ -120,7 +121,7 @@ class RepositoryRoleForm extends React.Component<Props, State> {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const loading = isFetchVerbsPending(state);
const error = getFetchVerbsFailure(state);
const verbsLink = getRepositoryVerbsLink(state);
@@ -136,7 +137,7 @@ const mapStateToProps = state => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchAvailableVerbs: (link: string) => {
dispatch(fetchAvailableVerbs(link));
@@ -144,7 +145,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("admin")(RepositoryRoleForm));
export default compose(connect(mapStateToProps, mapDispatchToProps), withTranslation("admin"))(RepositoryRoleForm);

View File

@@ -1,38 +1,35 @@
import React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { RouteComponentProps, withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { RepositoryRole, PagedCollection } from "@scm-manager/ui-types";
import { Title, Subtitle, Loading, Notification, LinkPaginator, urls, CreateButton } from "@scm-manager/ui-components";
import { PagedCollection, RepositoryRole } from "@scm-manager/ui-types";
import { CreateButton, LinkPaginator, Loading, Notification, Subtitle, Title, urls } from "@scm-manager/ui-components";
import {
fetchRolesByPage,
getFetchRolesFailure,
getRolesFromState,
selectListAsCollection,
isPermittedToCreateRoles,
isFetchRolesPending,
getFetchRolesFailure
isPermittedToCreateRoles,
selectListAsCollection
} from "../modules/roles";
import PermissionRoleTable from "../components/PermissionRoleTable";
import { getRepositoryRolesLink } from "../../../modules/indexResource";
type Props = WithTranslation & {
baseUrl: string;
roles: RepositoryRole[];
loading: boolean;
error: Error;
canAddRoles: boolean;
list: PagedCollection;
page: number;
rolesLink: string;
type Props = RouteComponentProps &
WithTranslation & {
baseUrl: string;
roles: RepositoryRole[];
loading: boolean;
error: Error;
canAddRoles: boolean;
list: PagedCollection;
page: number;
rolesLink: string;
// context objects
history: History;
location: any;
// dispatch functions
fetchRolesByPage: (link: string, page: number) => void;
};
// dispatch functions
fetchRolesByPage: (link: string, page: number) => void;
};
class RepositoryRoles extends React.Component<Props> {
componentDidMount() {
@@ -89,7 +86,7 @@ class RepositoryRoles extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { match } = ownProps;
const roles = getRolesFromState(state);
const loading = isFetchRolesPending(state);
@@ -110,7 +107,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchRolesByPage: (link: string, page: number) => {
dispatch(fetchRolesByPage(link, page));
@@ -118,9 +115,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("admin")(RepositoryRoles))
);
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(withTranslation("admin")(RepositoryRoles)));

View File

@@ -5,11 +5,12 @@ import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { RepositoryRole } from "@scm-manager/ui-types";
import { Loading, ErrorPage, Title } from "@scm-manager/ui-components";
import { ErrorPage, Loading, Title } from "@scm-manager/ui-components";
import { getRepositoryRolesLink } from "../../../modules/indexResource";
import { fetchRoleByName, getFetchRoleFailure, getRoleByName, isFetchRolePending } from "../modules/roles";
import PermissionRoleDetail from "../components/PermissionRoleDetails";
import EditRepositoryRole from "./EditRepositoryRole";
import { compose } from "redux";
type Props = WithTranslation & {
roleName: string;
@@ -78,7 +79,7 @@ class SingleRepositoryRole extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const roleName = ownProps.match.params.role;
const role = getRoleByName(state, roleName);
const loading = isFetchRolePending(state, roleName);
@@ -93,7 +94,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchRoleByName: (link: string, name: string) => {
dispatch(fetchRoleByName(link, name));
@@ -101,9 +102,8 @@ const mapDispatchToProps = dispatch => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("admin")(SingleRepositoryRole))
);
export default compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps),
withTranslation("admin")
)(SingleRepositoryRole);

View File

@@ -3,49 +3,49 @@ import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import reducer, {
FETCH_ROLES,
FETCH_ROLES_PENDING,
FETCH_ROLES_SUCCESS,
FETCH_ROLES_FAILURE,
FETCH_ROLE,
FETCH_ROLE_PENDING,
FETCH_ROLE_SUCCESS,
FETCH_ROLE_FAILURE,
CREATE_ROLE,
CREATE_ROLE_FAILURE,
CREATE_ROLE_PENDING,
CREATE_ROLE_SUCCESS,
CREATE_ROLE_FAILURE,
MODIFY_ROLE,
MODIFY_ROLE_PENDING,
MODIFY_ROLE_SUCCESS,
MODIFY_ROLE_FAILURE,
createRole,
DELETE_ROLE,
DELETE_ROLE_FAILURE,
DELETE_ROLE_PENDING,
DELETE_ROLE_SUCCESS,
DELETE_ROLE_FAILURE,
fetchRoles,
getFetchRolesFailure,
getRolesFromState,
isFetchRolesPending,
fetchRolesSuccess,
deleteRole,
deleteRoleSuccess,
FETCH_ROLE,
FETCH_ROLE_FAILURE,
FETCH_ROLE_PENDING,
FETCH_ROLE_SUCCESS,
FETCH_ROLES,
FETCH_ROLES_FAILURE,
FETCH_ROLES_PENDING,
FETCH_ROLES_SUCCESS,
fetchRoleByLink,
fetchRoleByName,
fetchRoles,
fetchRolesSuccess,
fetchRoleSuccess,
isFetchRolePending,
getFetchRoleFailure,
createRole,
isCreateRolePending,
getCreateRoleFailure,
getRoleByName,
modifyRole,
isModifyRolePending,
getModifyRoleFailure,
deleteRole,
isDeleteRolePending,
deleteRoleSuccess,
getDeleteRoleFailure,
selectListAsCollection,
isPermittedToCreateRoles
getFetchRoleFailure,
getFetchRolesFailure,
getModifyRoleFailure,
getRoleByName,
getRolesFromState,
isCreateRolePending,
isDeleteRolePending,
isFetchRolePending,
isFetchRolesPending,
isModifyRolePending,
isPermittedToCreateRoles,
MODIFY_ROLE,
MODIFY_ROLE_FAILURE,
MODIFY_ROLE_PENDING,
MODIFY_ROLE_SUCCESS,
modifyRole,
selectListAsCollection
} from "./roles";
const role1 = {

View File

@@ -1,7 +1,7 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import styled from "styled-components";
import { Image, ErrorNotification, InputField, SubmitButton, UnauthorizedError } from "@scm-manager/ui-components";
import { ErrorNotification, Image, InputField, SubmitButton, UnauthorizedError } from "@scm-manager/ui-components";
type Props = WithTranslation & {
error?: Error;

View File

@@ -1,6 +1,7 @@
import React, { Component } from "react";
import Main from "./Main";
import { connect } from "react-redux";
import { compose } from "redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { withRouter } from "react-router-dom";
import { fetchMe, getFetchMeFailure, getMe, isAuthenticated, isFetchMePending } from "../modules/auth";
@@ -61,7 +62,7 @@ const mapDispatchToProps = (dispatch: any) => {
};
};
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const authenticated = isAuthenticated(state);
const me = getMe(state);
const loading = isFetchMePending(state) || isFetchIndexResourcesPending(state);
@@ -78,9 +79,4 @@ const mapStateToProps = state => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("commons")(App))
);
export default compose(withRouter, connect(mapStateToProps, mapDispatchToProps), withTranslation("commons"))(App);

View File

@@ -2,9 +2,9 @@ import React from "react";
import {
ErrorNotification,
InputField,
Level,
Notification,
PasswordConfirmation,
Level,
SubmitButton
} from "@scm-manager/ui-components";
import { WithTranslation, withTranslation } from "react-i18next";

View File

@@ -1,9 +1,10 @@
import React, { Component } from "react";
import App from "./App";
import { connect } from "react-redux";
import { compose } from "redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { withRouter } from "react-router-dom";
import { Loading, ErrorBoundary } from "@scm-manager/ui-components";
import { ErrorBoundary, Loading } from "@scm-manager/ui-components";
import {
fetchIndexResources,
getFetchIndexResourcesFailure,
@@ -74,7 +75,7 @@ const mapDispatchToProps = (dispatch: any) => {
};
};
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const loading = isFetchIndexResourcesPending(state);
const error = getFetchIndexResourcesFailure(state);
const indexResources = getLinks(state);
@@ -85,9 +86,4 @@ const mapStateToProps = state => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("commons")(Index))
);
export default compose(withRouter, connect(mapStateToProps, mapDispatchToProps), withTranslation("commons"))(Index);

View File

@@ -62,7 +62,7 @@ class Login extends React.Component<Props> {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const authenticated = isAuthenticated(state);
const loading = isLoginPending(state);
const error = getLoginFailure(state);
@@ -77,16 +77,10 @@ const mapStateToProps = state => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
login: (loginLink: string, username: string, password: string) => dispatch(login(loginLink, username, password))
};
};
export default compose(
withRouter,
connect(
mapStateToProps,
mapDispatchToProps
)
)(Login);
export default compose(withRouter, connect(mapStateToProps, mapDispatchToProps))(Login);

View File

@@ -3,8 +3,8 @@ import { connect } from "react-redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { Redirect } from "react-router-dom";
import { logout, isAuthenticated, isLogoutPending, getLogoutFailure, isRedirecting } from "../modules/auth";
import { Loading, ErrorPage } from "@scm-manager/ui-components";
import { getLogoutFailure, isAuthenticated, isLogoutPending, isRedirecting, logout } from "../modules/auth";
import { ErrorPage, Loading } from "@scm-manager/ui-components";
import { getLogoutLink } from "../modules/indexResource";
type Props = WithTranslation & {
@@ -35,7 +35,7 @@ class Logout extends React.Component<Props> {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const authenticated = isAuthenticated(state);
const loading = isLogoutPending(state);
const redirecting = isRedirecting(state);
@@ -50,13 +50,10 @@ const mapStateToProps = state => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
logout: (link: string) => dispatch(logout(link))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("commons")(Logout));
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("commons")(Logout));

View File

@@ -5,7 +5,7 @@ import { compose } from "redux";
import { connect } from "react-redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { Me } from "@scm-manager/ui-types";
import { ErrorPage, Page, Navigation, SubNavigation, Section, NavLink } from "@scm-manager/ui-components";
import { ErrorPage, Navigation, NavLink, Page, Section, SubNavigation } from "@scm-manager/ui-components";
import ChangeUserPassword from "./ChangeUserPassword";
import ProfileInfo from "./ProfileInfo";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
@@ -78,14 +78,10 @@ class Profile extends React.Component<Props, State> {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
return {
me: getMe(state)
};
};
export default compose(
withTranslation("commons"),
connect(mapStateToProps),
withRouter
)(Profile);
export default compose(withTranslation("commons"), connect(mapStateToProps), withRouter)(Profile);

View File

@@ -1,7 +1,7 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { Me } from "@scm-manager/ui-types";
import { MailLink, AvatarWrapper, AvatarImage } from "@scm-manager/ui-components";
import { AvatarImage, AvatarWrapper, MailLink } from "@scm-manager/ui-components";
type Props = WithTranslation & {
me: Me;

View File

@@ -7,13 +7,10 @@ import * as ReactDOM from "react-dom";
import * as ReactRouterDom from "react-router-dom";
import * as Redux from "redux";
import * as ReactRedux from "react-redux";
import SytleComponentsDefault from "styled-components";
import * as SytleComponents from "styled-components";
import SytleComponentsDefault, * as SytleComponents from "styled-components";
import * as ReactI18Next from "react-i18next";
import ClassNamesDefault from "classnames";
import * as ClassNames from "classnames";
import QueryStringDefault from "query-string";
import * as QueryString from "query-string";
import ClassNamesDefault, * as ClassNames from "classnames";
import QueryStringDefault, * as QueryString from "query-string";
import * as UIExtensions from "@scm-manager/ui-extensions";
import * as UIComponents from "@scm-manager/ui-components";
import { urls } from "@scm-manager/ui-components";

View File

@@ -1,6 +1,6 @@
import thunk from "redux-thunk";
import logger from "redux-logger";
import { createStore, compose, applyMiddleware, combineReducers } from "redux";
import { applyMiddleware, combineReducers, compose, createStore } from "redux";
import users from "./users/modules/users";
import repos from "./repos/modules/repos";
import repositoryTypes from "./repos/modules/repositoryTypes";

View File

@@ -2,14 +2,14 @@ import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { Group, SelectValue } from "@scm-manager/ui-types";
import {
Subtitle,
AutocompleteAddEntryToTableField,
MemberNameTagGroup,
Checkbox,
InputField,
SubmitButton,
Textarea,
Level,
Checkbox
MemberNameTagGroup,
SubmitButton,
Subtitle,
Textarea
} from "@scm-manager/ui-components";
import * as validator from "./groupValidation";

View File

@@ -2,7 +2,7 @@ import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import styled from "styled-components";
import { Group } from "@scm-manager/ui-types";
import { DateFromNow, Checkbox } from "@scm-manager/ui-components";
import { Checkbox, DateFromNow } from "@scm-manager/ui-components";
import GroupMember from "./GroupMember";
type Props = WithTranslation & {

View File

@@ -1,11 +1,12 @@
import React from "react";
import { connect } from "react-redux";
import { compose } from "redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { Group } from "@scm-manager/ui-types";
import { DisplayedUser, Group } from "@scm-manager/ui-types";
import { Page } from "@scm-manager/ui-components";
import { getGroupsLink, getUserAutoCompleteLink } from "../../modules/indexResource";
import { createGroup, isCreateGroupPending, getCreateGroupFailure, createGroupReset } from "../modules/groups";
import { createGroup, createGroupReset, getCreateGroupFailure, isCreateGroupPending } from "../modules/groups";
import GroupForm from "../components/GroupForm";
import { apiClient } from "@scm-manager/ui-components/src";
@@ -45,7 +46,7 @@ class CreateGroup extends React.Component<Props> {
.get(url + inputValue)
.then(response => response.json())
.then(json => {
return json.map(element => {
return json.map((element: DisplayedUser) => {
return {
value: element,
label: `${element.displayName} (${element.id})`
@@ -61,7 +62,7 @@ class CreateGroup extends React.Component<Props> {
};
}
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
createGroup: (link: string, group: Group, callback?: () => void) => dispatch(createGroup(link, group, callback)),
resetForm: () => {
@@ -70,7 +71,7 @@ const mapDispatchToProps = dispatch => {
};
};
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const loading = isCreateGroupPending(state);
const error = getCreateGroupFailure(state);
const createLink = getGroupsLink(state);
@@ -83,7 +84,4 @@ const mapStateToProps = state => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("groups")(CreateGroup));
export default compose(connect(mapStateToProps, mapDispatchToProps), withTranslation("groups"))(CreateGroup);

View File

@@ -1,10 +1,11 @@
import React from "react";
import { connect } from "react-redux";
import { compose } from "redux";
import { withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { Group } from "@scm-manager/ui-types";
import { Level, DeleteButton, confirmAlert, ErrorNotification } from "@scm-manager/ui-components";
import { confirmAlert, DeleteButton, ErrorNotification, Level } from "@scm-manager/ui-components";
import { deleteGroup, getDeleteGroupFailure, isDeleteGroupPending } from "../modules/groups";
type Props = WithTranslation & {
@@ -72,7 +73,7 @@ export class DeleteGroup extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const loading = isDeleteGroupPending(state, ownProps.group.name);
const error = getDeleteGroupFailure(state, ownProps.group.name);
return {
@@ -81,7 +82,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
deleteGroup: (group: Group, callback?: () => void) => {
dispatch(deleteGroup(group, callback));
@@ -89,7 +90,8 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(withTranslation("groups")(DeleteGroup)));
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withRouter,
withTranslation("groups")
)(DeleteGroup);

View File

@@ -1,14 +1,15 @@
import React from "react";
import { connect } from "react-redux";
import GroupForm from "../components/GroupForm";
import { modifyGroup, getModifyGroupFailure, isModifyGroupPending, modifyGroupReset } from "../modules/groups";
import { getModifyGroupFailure, isModifyGroupPending, modifyGroup, modifyGroupReset } from "../modules/groups";
import { History } from "history";
import { withRouter } from "react-router-dom";
import { Group } from "@scm-manager/ui-types";
import { DisplayedUser, Group } from "@scm-manager/ui-types";
import { ErrorNotification } from "@scm-manager/ui-components";
import { getUserAutoCompleteLink } from "../../modules/indexResource";
import DeleteGroup from "./DeleteGroup";
import { apiClient } from "@scm-manager/ui-components/src";
import { compose } from "redux";
type Props = {
group: Group;
@@ -41,7 +42,7 @@ class EditGroup extends React.Component<Props> {
.get(url + inputValue)
.then(response => response.json())
.then(json => {
return json.map(element => {
return json.map((element: DisplayedUser) => {
return {
value: element,
label: `${element.displayName} (${element.id})`
@@ -69,7 +70,7 @@ class EditGroup extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const loading = isModifyGroupPending(state, ownProps.group.name);
const error = getModifyGroupFailure(state, ownProps.group.name);
const autocompleteLink = getUserAutoCompleteLink(state);
@@ -80,7 +81,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
modifyGroup: (group: Group, callback?: () => void) => {
dispatch(modifyGroup(group, callback));
@@ -91,7 +92,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(EditGroup));
export default compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(EditGroup);

View File

@@ -1,44 +1,42 @@
import React from "react";
import { connect } from "react-redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { RouteComponentProps } from "react-router-dom";
import { History } from "history";
import { Group, PagedCollection } from "@scm-manager/ui-types";
import {
CreateButton,
LinkPaginator,
Notification,
OverviewPageActions,
Page,
PageActions,
OverviewPageActions,
Notification,
LinkPaginator,
urls,
CreateButton
urls
} from "@scm-manager/ui-components";
import { getGroupsLink } from "../../modules/indexResource";
import {
fetchGroupsByPage,
getFetchGroupsFailure,
getGroupsFromState,
isFetchGroupsPending,
getFetchGroupsFailure,
isPermittedToCreateGroups,
selectListAsCollection
} from "../modules/groups";
import { GroupTable } from "./../components/table";
type Props = WithTranslation & {
groups: Group[];
loading: boolean;
error: Error;
canAddGroups: boolean;
list: PagedCollection;
page: number;
groupLink: string;
type Props = RouteComponentProps &
WithTranslation & {
groups: Group[];
loading: boolean;
error: Error;
canAddGroups: boolean;
list: PagedCollection;
page: number;
groupLink: string;
// context objects
history: History;
location: any;
// dispatch functions
fetchGroupsByPage: (link: string, page: number, filter?: string) => void;
};
// dispatch functions
fetchGroupsByPage: (link: string, page: number, filter?: string) => void;
};
class Groups extends React.Component<Props> {
componentDidMount() {
@@ -100,7 +98,7 @@ class Groups extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { match } = ownProps;
const groups = getGroupsFromState(state);
const loading = isFetchGroupsPending(state);
@@ -121,7 +119,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchGroupsByPage: (link: string, page: number, filter?: string) => {
dispatch(fetchGroupsByPage(link, page, filter));
@@ -129,7 +127,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("groups")(Groups));
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("groups")(Groups));

View File

@@ -5,9 +5,9 @@ import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Group } from "@scm-manager/ui-types";
import { Page, ErrorPage, Loading, Navigation, SubNavigation, Section, NavLink } from "@scm-manager/ui-components";
import { ErrorPage, Loading, Navigation, NavLink, Page, Section, SubNavigation } from "@scm-manager/ui-components";
import { getGroupsLink } from "../../modules/indexResource";
import { fetchGroupByName, getGroupByName, isFetchGroupPending, getFetchGroupFailure } from "../modules/groups";
import { fetchGroupByName, getFetchGroupFailure, getGroupByName, isFetchGroupPending } from "../modules/groups";
import { Details } from "./../components/table";
import { EditGroupNavLink, SetPermissionsNavLink } from "./../components/navLinks";
import EditGroup from "./EditGroup";
@@ -94,7 +94,7 @@ class SingleGroup extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const name = ownProps.match.params.name;
const group = getGroupByName(state, name);
const loading = isFetchGroupPending(state, name);
@@ -110,7 +110,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchGroupByName: (link: string, name: string) => {
dispatch(fetchGroupByName(link, name));
@@ -118,7 +118,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("groups")(SingleGroup));
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("groups")(SingleGroup));

View File

@@ -3,48 +3,49 @@ import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import reducer, {
fetchGroups,
FETCH_GROUPS,
FETCH_GROUPS_PENDING,
FETCH_GROUPS_SUCCESS,
FETCH_GROUPS_FAILURE,
fetchGroupsSuccess,
isPermittedToCreateGroups,
getGroupsFromState,
getFetchGroupsFailure,
isFetchGroupsPending,
selectListAsCollection,
fetchGroupByLink,
fetchGroupByName,
FETCH_GROUP_PENDING,
FETCH_GROUP_SUCCESS,
FETCH_GROUP_FAILURE,
fetchGroupSuccess,
getFetchGroupFailure,
FETCH_GROUP,
isFetchGroupPending,
getGroupByName,
createGroup,
CREATE_GROUP_SUCCESS,
CREATE_GROUP_PENDING,
CREATE_GROUP_FAILURE,
isCreateGroupPending,
CREATE_GROUP,
getCreateGroupFailure,
deleteGroup,
CREATE_GROUP_FAILURE,
CREATE_GROUP_PENDING,
CREATE_GROUP_SUCCESS,
createGroup,
DELETE_GROUP,
DELETE_GROUP_FAILURE,
DELETE_GROUP_PENDING,
DELETE_GROUP_SUCCESS,
DELETE_GROUP_FAILURE,
DELETE_GROUP,
deleteGroup,
deleteGroupSuccess,
isDeleteGroupPending,
FETCH_GROUP,
FETCH_GROUP_FAILURE,
FETCH_GROUP_PENDING,
FETCH_GROUP_SUCCESS,
FETCH_GROUPS,
FETCH_GROUPS_FAILURE,
FETCH_GROUPS_PENDING,
FETCH_GROUPS_SUCCESS,
fetchGroupByLink,
fetchGroupByName,
fetchGroups,
fetchGroupsSuccess,
fetchGroupSuccess,
getCreateGroupFailure,
getCreateGroupLink,
getDeleteGroupFailure,
modifyGroup,
getFetchGroupFailure,
getFetchGroupsFailure,
getGroupByName,
getGroupsFromState,
isCreateGroupPending,
isDeleteGroupPending,
isFetchGroupPending,
isFetchGroupsPending,
isPermittedToCreateGroups,
MODIFY_GROUP_FAILURE,
MODIFY_GROUP_PENDING,
MODIFY_GROUP_SUCCESS,
MODIFY_GROUP_FAILURE,
getCreateGroupLink
modifyGroup,
selectListAsCollection
} from "./groups";
const GROUPS_URL = "/api/v2/groups";
const URL_HUMAN_GROUP = "http://localhost:8081/api/v2/groups/humanGroup";
const URL = "/groups";

View File

@@ -3,7 +3,7 @@ import { isPending } from "../../modules/pending";
import { getFailure } from "../../modules/failure";
import * as types from "../../modules/types";
import { combineReducers, Dispatch } from "redux";
import { Action, PagedCollection, Group } from "@scm-manager/ui-types";
import { Action, Group, PagedCollection } from "@scm-manager/ui-types";
export const FETCH_GROUPS = "scm/groups/FETCH_GROUPS";
export const FETCH_GROUPS_PENDING = `${FETCH_GROUPS}_${types.PENDING_SUFFIX}`;

View File

@@ -2,29 +2,29 @@ import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import reducer, {
FETCH_INDEXRESOURCES,
FETCH_INDEXRESOURCES_FAILURE,
FETCH_INDEXRESOURCES_PENDING,
FETCH_INDEXRESOURCES_SUCCESS,
FETCH_INDEXRESOURCES_FAILURE,
fetchIndexResources,
fetchIndexResourcesSuccess,
FETCH_INDEXRESOURCES,
isFetchIndexResourcesPending,
getFetchIndexResourcesFailure,
getUiPluginsLink,
getMeLink,
getLogoutLink,
getLoginLink,
getUsersLink,
getConfigLink,
getRepositoriesLink,
getHgConfigLink,
getFetchIndexResourcesFailure,
getGitConfigLink,
getSvnConfigLink,
getLinks,
getGroupAutoCompleteLink,
getGroupsLink,
getHgConfigLink,
getLinkCollection,
getLinks,
getLoginLink,
getLogoutLink,
getMeLink,
getRepositoriesLink,
getSvnConfigLink,
getUiPluginsLink,
getUserAutoCompleteLink,
getGroupAutoCompleteLink
getUsersLink,
isFetchIndexResourcesPending
} from "./indexResource";
const indexResourcesUnauthenticated = {

View File

@@ -2,7 +2,7 @@ import React from "react";
import { connect } from "react-redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { Link } from "@scm-manager/ui-types";
import { Notification, ErrorNotification, SubmitButton, Level } from "@scm-manager/ui-components";
import { ErrorNotification, Level, Notification, SubmitButton } from "@scm-manager/ui-components";
import { getLink } from "../../modules/indexResource";
import { loadPermissionsForEntity, setPermissions } from "./handlePermissions";
import PermissionsWrapper from "./PermissionsWrapper";
@@ -151,7 +151,7 @@ class SetPermissions extends React.Component<Props, State> {
};
}
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const availablePermissionLink = getLink(state, "permissions");
return {
availablePermissionLink

View File

@@ -1,7 +1,7 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { Repository, Branch } from "@scm-manager/ui-types";
import { ButtonAddons, Button } from "@scm-manager/ui-components";
import { Branch, Repository } from "@scm-manager/ui-types";
import { Button, ButtonAddons } from "@scm-manager/ui-components";
type Props = WithTranslation & {
repository: Repository;

View File

@@ -1,5 +1,5 @@
import React from "react";
import { Repository, Branch } from "@scm-manager/ui-types";
import { Branch, Repository } from "@scm-manager/ui-types";
import { WithTranslation, withTranslation } from "react-i18next";
import BranchButtonGroup from "./BranchButtonGroup";
import DefaultBranchTag from "./DefaultBranchTag";

View File

@@ -1,7 +1,7 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { Repository, Branch, BranchRequest } from "@scm-manager/ui-types";
import { Select, InputField, Level, SubmitButton, validation as validator } from "@scm-manager/ui-components";
import { Branch, BranchRequest, Repository } from "@scm-manager/ui-types";
import { InputField, Level, Select, SubmitButton, validation as validator } from "@scm-manager/ui-components";
import { orderBranches } from "../util/orderBranches";
type Props = WithTranslation & {

View File

@@ -1,7 +1,7 @@
import React from "react";
import BranchDetail from "./BranchDetail";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Repository, Branch } from "@scm-manager/ui-types";
import { Branch, Repository } from "@scm-manager/ui-types";
type Props = {
repository: Repository;

View File

@@ -1,12 +1,12 @@
import React from "react";
import BranchView from "../components/BranchView";
import { connect } from "react-redux";
import { compose } from "redux";
import { Redirect, Route, Switch, withRouter } from "react-router-dom";
import { Repository, Branch } from "@scm-manager/ui-types";
import { Branch, Repository } from "@scm-manager/ui-types";
import { fetchBranch, getBranch, getFetchBranchFailure, isFetchBranchPending } from "../modules/branches";
import { ErrorNotification, Loading } from "@scm-manager/ui-components";
import { ErrorNotification, Loading, NotFoundError } from "@scm-manager/ui-components";
import { History } from "history";
import { NotFoundError } from "@scm-manager/ui-components";
import queryString from "query-string";
type Props = {
@@ -28,7 +28,6 @@ type Props = {
class BranchRoot extends React.Component<Props> {
componentDidMount() {
const { fetchBranch, repository, branchName } = this.props;
fetchBranch(repository, branchName);
}
@@ -73,7 +72,7 @@ class BranchRoot extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository } = ownProps;
const branchName = decodeURIComponent(ownProps.match.params.branch);
const branch = getBranch(state, repository, branchName);
@@ -88,7 +87,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranch: (repository: Repository, branchName: string) => {
dispatch(fetchBranch(repository, branchName));
@@ -96,9 +95,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(BranchRoot)
);
export default compose(withRouter, connect(mapStateToProps, mapDispatchToProps))(BranchRoot);

View File

@@ -75,7 +75,7 @@ class BranchesOverview extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository } = ownProps;
const loading = isFetchBranchesPending(state, repository);
const error = getFetchBranchesFailure(state, repository);
@@ -91,7 +91,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranches: (repository: Repository) => {
dispatch(fetchBranches(repository));
@@ -102,8 +102,5 @@ const mapDispatchToProps = dispatch => {
export default compose(
withTranslation("repos"),
withRouter,
connect(
mapStateToProps,
mapDispatchToProps
)
connect(mapStateToProps, mapDispatchToProps)
)(BranchesOverview);

View File

@@ -4,20 +4,21 @@ import { withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import queryString from "query-string";
import { History } from "history";
import { Repository, Branch, BranchRequest } from "@scm-manager/ui-types";
import { Branch, BranchRequest, Repository } from "@scm-manager/ui-types";
import { ErrorNotification, Loading, Subtitle } from "@scm-manager/ui-components";
import BranchForm from "../components/BranchForm";
import {
fetchBranches,
getBranches,
getBranchCreateLink,
createBranch,
createBranchReset,
isCreateBranchPending,
fetchBranches,
getBranchCreateLink,
getBranches,
getCreateBranchFailure,
isFetchBranchesPending,
getFetchBranchesFailure
getFetchBranchesFailure,
isCreateBranchPending,
isFetchBranchesPending
} from "../modules/branches";
import { compose } from "redux";
type Props = WithTranslation & {
loading?: boolean;
@@ -92,7 +93,7 @@ class CreateBranch extends React.Component<Props> {
}
}
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranches: (repository: Repository) => {
dispatch(fetchBranches(repository));
@@ -111,7 +112,7 @@ const mapDispatchToProps = dispatch => {
};
};
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository } = ownProps;
const loading = isFetchBranchesPending(state, repository) || isCreateBranchPending(state, repository);
const error = getFetchBranchesFailure(state, repository) || getCreateBranchFailure(state, repository);
@@ -126,9 +127,8 @@ const mapStateToProps = (state, ownProps) => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(CreateBranch))
);
export default compose(
withTranslation("repos"),
connect(mapStateToProps, mapDispatchToProps),
withRouter
)(CreateBranch);

View File

@@ -2,27 +2,27 @@ import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import reducer, {
FETCH_BRANCHES,
FETCH_BRANCHES_FAILURE,
FETCH_BRANCHES_PENDING,
FETCH_BRANCHES_SUCCESS,
FETCH_BRANCH_PENDING,
FETCH_BRANCH_SUCCESS,
FETCH_BRANCH_FAILURE,
CREATE_BRANCH,
CREATE_BRANCH_FAILURE,
CREATE_BRANCH_PENDING,
CREATE_BRANCH_SUCCESS,
fetchBranches,
createBranch,
FETCH_BRANCH_FAILURE,
FETCH_BRANCH_PENDING,
FETCH_BRANCH_SUCCESS,
FETCH_BRANCHES,
FETCH_BRANCHES_FAILURE,
FETCH_BRANCHES_PENDING,
FETCH_BRANCHES_SUCCESS,
fetchBranch,
fetchBranches,
fetchBranchSuccess,
getBranch,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending,
createBranch,
isCreateBranchPending,
getCreateBranchFailure,
getFetchBranchesFailure,
isCreateBranchPending,
isFetchBranchesPending,
isPermittedToCreateBranches
} from "./branches";

View File

@@ -1,4 +1,4 @@
import { FAILURE_SUFFIX, PENDING_SUFFIX, SUCCESS_SUFFIX, RESET_SUFFIX } from "../../../modules/types";
import { FAILURE_SUFFIX, PENDING_SUFFIX, RESET_SUFFIX, SUCCESS_SUFFIX } from "../../../modules/types";
import { apiClient } from "@scm-manager/ui-components";
import { Action, Branch, BranchRequest, Repository } from "@scm-manager/ui-types";
import { isPending } from "../../../modules/pending";

View File

@@ -0,0 +1,51 @@
import React, { FC } from "react";
import styled from "styled-components";
import { useLocation } from "react-router-dom";
import { Level, BranchSelector } from "@scm-manager/ui-components";
import CodeViewSwitcher from "./CodeViewSwitcher";
import { useTranslation } from "react-i18next";
import { Branch } from "@scm-manager/ui-types";
const ActionBar = styled.div`
background-color: whitesmoke;
border: 1px solid #dbdbdb;
border-radius: 4px;
color: #363636;
font-size: 1.25em;
font-weight: 300;
line-height: 1.25;
padding: 0.5em 0.75em;
margin-bottom: 1em;
`;
type Props = {
selectedBranch?: string;
branches: Branch[];
onSelectBranch: () => void;
switchViewLink: string;
};
const CodeActionBar: FC<Props> = ({ selectedBranch, branches, onSelectBranch, switchViewLink }) => {
const { t } = useTranslation("repos");
const location = useLocation();
return (
<ActionBar>
<Level
left={
branches?.length > 0 && (
<BranchSelector
label={t("code.branchSelector")}
branches={branches}
selectedBranch={selectedBranch}
onSelectBranch={onSelectBranch}
/>
)
}
right={<CodeViewSwitcher currentUrl={location.pathname} switchViewLink={switchViewLink} />}
/>
</ActionBar>
);
};
export default CodeActionBar;

View File

@@ -0,0 +1,60 @@
import React, { FC } from "react";
import styled from "styled-components";
import { Button, ButtonAddons } from "@scm-manager/ui-components";
import { useTranslation } from "react-i18next";
const SmallButton = styled(Button)`
border-radius: 4px;
font-size: 1rem;
font-weight: 600;
`;
const ButtonAddonsMarginRight = styled(ButtonAddons)`
margin-right: -0.2em;
`;
type Props = {
currentUrl: string;
switchViewLink: string;
};
const CodeViewSwitcher: FC<Props> = ({ currentUrl, switchViewLink }) => {
const { t } = useTranslation("repos");
const resolveLocation = () => {
if (currentUrl.includes("/code/branch") || currentUrl.includes("/code/changesets")) {
return "changesets";
}
if (currentUrl.includes("/code/sources")) {
return "sources";
}
return "";
};
const isSourcesTab = () => {
return resolveLocation() === "sources";
};
const isChangesetsTab = () => {
return resolveLocation() === "changesets";
};
return (
<ButtonAddonsMarginRight>
<SmallButton
label={t("code.commits")}
icon="fa fa-exchange-alt"
color={isChangesetsTab() ? "link is-selected" : undefined}
link={isSourcesTab() ? switchViewLink : undefined}
/>
<SmallButton
label={t("code.sources")}
icon="fa fa-code"
color={isSourcesTab() ? "link is-selected" : undefined}
link={isChangesetsTab() ? switchViewLink : undefined}
/>
</ButtonAddonsMarginRight>
);
};
export default CodeViewSwitcher;

View File

@@ -0,0 +1,113 @@
import React from "react";
import { Route, RouteComponentProps, withRouter } from "react-router-dom";
import Sources from "../../sources/containers/Sources";
import ChangesetsRoot from "../../containers/ChangesetsRoot";
import { Branch, Repository } from "@scm-manager/ui-types";
import { ErrorPage, Loading } from "@scm-manager/ui-components";
import { compose } from "redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { connect } from "react-redux";
import {
fetchBranches,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending
} from "../../branches/modules/branches";
type Props = RouteComponentProps &
WithTranslation & {
repository: Repository;
baseUrl: string;
// State props
branches: Branch[];
error: Error;
loading: boolean;
selectedBranch: string;
// Dispatch props
fetchBranches: (p: Repository) => void;
};
class CodeOverview extends React.Component<Props> {
componentDidMount() {
const { repository } = this.props;
this.props.fetchBranches(repository);
}
render() {
const { repository, baseUrl, branches, selectedBranch, error, loading, t } = this.props;
const url = baseUrl;
if (loading) {
return <Loading />;
}
if (error) {
return (
<ErrorPage title={t("repositoryRoot.errorTitle")} subtitle={t("repositoryRoot.errorSubtitle")} error={error} />
);
}
return (
<>
<Route
path={`${url}/sources`}
exact={true}
render={() => <Sources repository={repository} baseUrl={`${url}`} branches={branches} />}
/>
<Route
path={`${url}/sources/:revision/:path*`}
render={() => (
<Sources repository={repository} baseUrl={`${url}`} branches={branches} selectedBranch={selectedBranch} />
)}
/>
<Route
path={`${url}/changesets`}
render={() => <ChangesetsRoot repository={repository} baseUrl={`${url}`} branches={branches} />}
/>
<Route
path={`${url}/branch/:branch/changesets/`}
render={() => (
<ChangesetsRoot
repository={repository}
baseUrl={`${url}`}
branches={branches}
selectedBranch={selectedBranch}
/>
)}
/>
</>
);
}
}
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranches: (repo: Repository) => {
dispatch(fetchBranches(repo));
}
};
};
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository, location } = ownProps;
const error = getFetchBranchesFailure(state, repository);
const loading = isFetchBranchesPending(state, repository);
const branches = getBranches(state, repository);
const branchFromURL =
!location.pathname.includes("/code/changesets/") && decodeURIComponent(location.pathname.split("/")[6]);
const selectedBranch = branchFromURL && branchFromURL !== "undefined" ? branchFromURL : "";
return {
error,
loading,
branches,
selectedBranch
};
};
export default compose(
withRouter,
withTranslation("repos"),
connect(mapStateToProps, mapDispatchToProps)
)(CodeOverview);

View File

@@ -1,5 +1,5 @@
import React from "react";
import { shallow, mount } from "@scm-manager/ui-tests/enzyme-router";
import { mount, shallow } from "@scm-manager/ui-tests/enzyme-router";
import "@scm-manager/ui-tests/enzyme";
import "@scm-manager/ui-tests/i18n";

View File

@@ -1,7 +1,7 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { Repository } from "@scm-manager/ui-types";
import { MailLink, DateFromNow } from "@scm-manager/ui-components";
import { DateFromNow, MailLink } from "@scm-manager/ui-components";
type Props = WithTranslation & {
repository: Repository;

View File

@@ -1,5 +1,5 @@
import React from "react";
import { shallow, mount } from "@scm-manager/ui-tests/enzyme-router";
import { mount, shallow } from "@scm-manager/ui-tests/enzyme-router";
import "@scm-manager/ui-tests/i18n";
import RepositoryNavLink from "./RepositoryNavLink";

View File

@@ -9,6 +9,7 @@ type Props = {
linkName: string;
activeWhenMatch?: (route: any) => boolean;
activeOnlyWhenExact: boolean;
icon?: string;
};
/**

View File

@@ -5,16 +5,16 @@ import styled from "styled-components";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Changeset, Repository, Tag } from "@scm-manager/ui-types";
import {
DateFromNow,
ChangesetId,
ChangesetTag,
AvatarImage,
AvatarWrapper,
Button,
ChangesetAuthor,
ChangesetDiff,
AvatarWrapper,
AvatarImage,
ChangesetId,
changesets,
Level,
Button
ChangesetTag,
DateFromNow,
Level
} from "@scm-manager/ui-components";
type Props = WithTranslation & {

View File

@@ -2,14 +2,14 @@ import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Repository, RepositoryType } from "@scm-manager/ui-types";
import { Subtitle, InputField, Select, Textarea, Level, SubmitButton } from "@scm-manager/ui-components";
import { InputField, Level, Select, SubmitButton, Subtitle, Textarea } from "@scm-manager/ui-components";
import * as validator from "./repositoryValidation";
type Props = WithTranslation & {
submitForm: (p: Repository) => void;
repository?: Repository;
repositoryTypes: RepositoryType[];
namespaceStrategy: string;
repositoryTypes?: RepositoryType[];
namespaceStrategy?: string;
loading?: boolean;
};
@@ -127,13 +127,16 @@ class RepositoryForm extends React.Component<Props, State> {
);
}
createSelectOptions(repositoryTypes: RepositoryType[]) {
return repositoryTypes.map(repositoryType => {
return {
label: repositoryType.displayName,
value: repositoryType.name
};
});
createSelectOptions(repositoryTypes?: RepositoryType[]) {
if (repositoryTypes) {
return repositoryTypes.map(repositoryType => {
return {
label: repositoryType.displayName,
value: repositoryType.name
};
});
}
return [];
}
renderNamespaceField = () => {

View File

@@ -1,2 +1,3 @@
import RepositoryForm from "./RepositoryForm";
export default RepositoryForm;

View File

@@ -22,14 +22,14 @@ class RepositoryEntry extends React.Component<Props> {
renderChangesetsLink = (repository: Repository, repositoryLink: string) => {
if (repository._links["changesets"]) {
return <RepositoryEntryLink icon="exchange-alt" to={repositoryLink + "/changesets"} />;
return <RepositoryEntryLink icon="exchange-alt" to={repositoryLink + "/code/changesets/"} />;
}
return null;
};
renderSourcesLink = (repository: Repository, repositoryLink: string) => {
if (repository._links["sources"]) {
return <RepositoryEntryLink icon="code" to={repositoryLink + "/sources"} />;
return <RepositoryEntryLink icon="code" to={repositoryLink + "/code/sources/"} />;
}
return null;
};

View File

@@ -1,2 +1,3 @@
import RepositoryList from "./RepositoryList";
export default RepositoryList;

View File

@@ -1,5 +1,6 @@
import React from "react";
import { connect } from "react-redux";
import { compose } from "redux";
import { withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { Changeset, Repository } from "@scm-manager/ui-types";
@@ -42,7 +43,7 @@ class ChangesetView extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps: Props) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const repository = ownProps.repository;
const id = ownProps.match.params.id;
const changeset = getChangeset(state, repository, id);
@@ -55,7 +56,7 @@ const mapStateToProps = (state, ownProps: Props) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchChangesetIfNeeded: (repository: Repository, id: string) => {
dispatch(fetchChangesetIfNeeded(repository, id));
@@ -63,9 +64,8 @@ const mapDispatchToProps = dispatch => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(ChangesetView))
);
export default compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps),
withTranslation("repos")
)(ChangesetView);

View File

@@ -5,10 +5,10 @@ import { withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { Branch, Changeset, PagedCollection, Repository } from "@scm-manager/ui-types";
import {
ChangesetList,
ErrorNotification,
getPageFromMatch,
LinkPaginator,
ChangesetList,
Loading,
Notification
} from "@scm-manager/ui-components";
@@ -41,7 +41,6 @@ type Props = WithTranslation & {
class Changesets extends React.Component<Props> {
componentDidMount() {
const { fetchChangesets, repository, branch, page } = this.props;
fetchChangesets(repository, branch, page);
}
@@ -93,7 +92,7 @@ class Changesets extends React.Component<Props> {
};
}
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchChangesets: (repo: Repository, branch: Branch, page: number) => {
dispatch(fetchChangesets(repo, branch, page));
@@ -118,11 +117,4 @@ const mapStateToProps = (state: any, ownProps: Props) => {
};
};
export default compose(
withTranslation("repos"),
withRouter,
connect(
mapStateToProps,
mapDispatchToProps
)
)(Changesets);
export default compose(withTranslation("repos"), withRouter, connect(mapStateToProps, mapDispatchToProps))(Changesets);

View File

@@ -1,61 +1,20 @@
import React from "react";
import { compose } from "redux";
import { connect } from "react-redux";
import { Route, withRouter } from "react-router-dom";
import { Route, withRouter, RouteComponentProps } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { Branch, Repository } from "@scm-manager/ui-types";
import { BranchSelector, ErrorNotification, Loading } from "@scm-manager/ui-components";
import { Repository, Branch } from "@scm-manager/ui-types";
import Changesets from "./Changesets";
import {
fetchBranches,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending
} from "../branches/modules/branches";
import { compose } from "redux";
import CodeActionBar from "../codeSection/components/CodeActionBar";
type Props = WithTranslation & {
repository: Repository;
baseUrl: string;
selected: string;
baseUrlWithBranch: string;
baseUrlWithoutBranch: string;
// State props
branches: Branch[];
loading: boolean;
error: Error;
// Dispatch props
fetchBranches: (p: Repository) => void;
// Context props
history: any; // TODO flow type
match: any;
};
type Props = WithTranslation &
RouteComponentProps & {
repository: Repository;
selectedBranch: string;
baseUrl: string;
branches: Branch[];
};
class ChangesetsRoot extends React.Component<Props> {
componentDidMount() {
this.props.fetchBranches(this.props.repository);
this.redirectToDefaultBranch();
}
redirectToDefaultBranch = () => {
if (this.shouldRedirectToDefaultBranch()) {
const defaultBranches = this.props.branches.filter(b => b.defaultBranch === true);
if (defaultBranches.length > 0) {
this.branchSelected(defaultBranches[0]);
}
}
};
shouldRedirectToDefaultBranch = () => {
return (
this.props.branches &&
this.props.branches.length > 0 &&
this.props.branches.filter(b => b.name === this.props.selected).length === 0
);
};
stripEndingSlash = (url: string) => {
if (url.endsWith("/")) {
return url.substring(0, url.length - 1);
@@ -63,96 +22,57 @@ class ChangesetsRoot extends React.Component<Props> {
return url;
};
branchSelected = (branch?: Branch) => {
let url;
if (branch) {
url = `${this.props.baseUrlWithBranch}/${encodeURIComponent(branch.name)}/changesets/`;
} else {
url = `${this.props.baseUrlWithoutBranch}/`;
}
this.props.history.push(url);
isBranchAvailable = () => {
const { branches, selectedBranch } = this.props;
return branches?.filter(b => b.name === selectedBranch).length === 0;
};
findSelectedBranch = () => {
const { selected, branches } = this.props;
return branches.find((branch: Branch) => branch.name === selected);
evaluateSwitchViewLink = () => {
const { baseUrl, selectedBranch } = this.props;
if (selectedBranch) {
return `${baseUrl}/sources/${encodeURIComponent(selectedBranch)}/`;
}
return `${baseUrl}/sources/`;
};
onSelectBranch = (branch?: Branch) => {
const { baseUrl, history } = this.props;
if (branch) {
const url = `${baseUrl}/branch/${encodeURIComponent(branch.name)}/changesets/`;
history.push(url);
} else {
history.push(`${baseUrl}/changesets/`);
}
};
render() {
const { repository, error, loading, match, branches } = this.props;
if (error) {
return <ErrorNotification error={error} />;
}
if (loading) {
return <Loading />;
}
const { repository, branches, match, selectedBranch } = this.props;
if (!repository) {
return null;
}
const url = this.stripEndingSlash(match.url);
const branch = branches ? this.findSelectedBranch() : null;
const changesets = <Changesets repository={repository} branch={branch} />;
return (
<div className="panel">
{this.renderBranchSelector()}
<Route path={`${url}/:page?`} component={() => changesets} />
</div>
);
}
renderBranchSelector = () => {
const { repository, branches, selected, t } = this.props;
if (repository._links.branches) {
return (
<div className="panel-heading">
<BranchSelector
label={t("changesets.branchSelectorLabel")}
branches={branches}
selectedBranch={selected}
selected={(b: Branch) => {
this.branchSelected(b);
}}
<>
<CodeActionBar
branches={branches}
selectedBranch={!this.isBranchAvailable() ? selectedBranch : undefined}
onSelectBranch={this.onSelectBranch}
switchViewLink={this.evaluateSwitchViewLink()}
/>
<div className="panel">
<Route
path={`${url}/:page?`}
component={() => (
<Changesets repository={repository} branch={branches?.filter(b => b.name === selectedBranch)[0]} />
)}
/>
</div>
);
}
return null;
};
</>
);
}
}
const mapDispatchToProps = dispatch => {
return {
fetchBranches: (repo: Repository) => {
dispatch(fetchBranches(repo));
}
};
};
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository, match } = ownProps;
const loading = isFetchBranchesPending(state, repository);
const error = getFetchBranchesFailure(state, repository);
const branches = getBranches(state, repository);
const selected = decodeURIComponent(match.params.branch);
return {
loading,
error,
branches,
selected
};
};
export default compose(
withRouter,
withTranslation("repos"),
connect(
mapStateToProps,
mapDispatchToProps
)
)(ChangesetsRoot);
export default compose(withRouter, withTranslation("repos"))(ChangesetsRoot);

View File

@@ -2,7 +2,7 @@ import React from "react";
import { connect } from "react-redux";
import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { Repository, RepositoryType, NamespaceStrategies } from "@scm-manager/ui-types";
import { NamespaceStrategies, Repository, RepositoryType } from "@scm-manager/ui-types";
import { Page } from "@scm-manager/ui-components";
import {
fetchRepositoryTypesIfNeeded,
@@ -76,7 +76,7 @@ class Create extends React.Component<Props> {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: any) => {
const repositoryTypes = getRepositoryTypes(state);
const namespaceStrategies = getNamespaceStrategies(state);
const pageLoading = isFetchRepositoryTypesPending(state) || isFetchNamespaceStrategiesPending(state);
@@ -94,7 +94,7 @@ const mapStateToProps = state => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchRepositoryTypesIfNeeded: () => {
dispatch(fetchRepositoryTypesIfNeeded());
@@ -111,7 +111,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(Create));
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(Create));

View File

@@ -1,10 +1,11 @@
import React from "react";
import { connect } from "react-redux";
import { compose } from "redux";
import { withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { Repository } from "@scm-manager/ui-types";
import { Level, DeleteButton, confirmAlert, ErrorNotification } from "@scm-manager/ui-components";
import { confirmAlert, DeleteButton, ErrorNotification, Level } from "@scm-manager/ui-components";
import { deleteRepo, getDeleteRepoFailure, isDeleteRepoPending } from "../modules/repos";
type Props = WithTranslation & {
@@ -72,7 +73,7 @@ class DeleteRepo extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { namespace, name } = ownProps.repository;
const loading = isDeleteRepoPending(state, namespace, name);
const error = getDeleteRepoFailure(state, namespace, name);
@@ -82,7 +83,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
deleteRepo: (repo: Repository, callback: () => void) => {
dispatch(deleteRepo(repo, callback));
@@ -90,7 +91,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(withTranslation("repos")(DeleteRepo)));
export default compose(connect(mapStateToProps, mapDispatchToProps), withRouter, withTranslation("repos"))(DeleteRepo);

View File

@@ -4,10 +4,11 @@ import { withRouter } from "react-router-dom";
import RepositoryForm from "../components/form";
import DeleteRepo from "./DeleteRepo";
import { Repository } from "@scm-manager/ui-types";
import { modifyRepo, isModifyRepoPending, getModifyRepoFailure, modifyRepoReset } from "../modules/repos";
import { getModifyRepoFailure, isModifyRepoPending, modifyRepo, modifyRepoReset } from "../modules/repos";
import { History } from "history";
import { ErrorNotification } from "@scm-manager/ui-components";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { compose } from "redux";
type Props = {
loading: boolean;
@@ -71,7 +72,7 @@ class EditRepo extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { namespace, name } = ownProps.repository;
const loading = isModifyRepoPending(state, namespace, name);
const error = getModifyRepoFailure(state, namespace, name);
@@ -81,7 +82,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
modifyRepo: (repo: Repository, callback: () => void) => {
dispatch(modifyRepo(repo, callback));
@@ -92,7 +93,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(EditRepo));
export default compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(EditRepo);

View File

@@ -1,16 +1,16 @@
import React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { RouteComponentProps, withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { History } from "history";
import { RepositoryCollection } from "@scm-manager/ui-types";
import {
CreateButton,
LinkPaginator,
Notification,
OverviewPageActions,
Page,
PageActions,
OverviewPageActions,
CreateButton,
Notification,
LinkPaginator,
urls
} from "@scm-manager/ui-components";
import { getRepositoriesLink } from "../../modules/indexResource";
@@ -23,21 +23,18 @@ import {
} from "../modules/repos";
import RepositoryList from "../components/list";
type Props = WithTranslation & {
loading: boolean;
error: Error;
showCreateButton: boolean;
collection: RepositoryCollection;
page: number;
reposLink: string;
type Props = WithTranslation &
RouteComponentProps & {
loading: boolean;
error: Error;
showCreateButton: boolean;
collection: RepositoryCollection;
page: number;
reposLink: string;
// context props
history: History;
location: any;
// dispatched functions
fetchReposByPage: (link: string, page: number, filter?: string) => void;
};
// dispatched functions
fetchReposByPage: (link: string, page: number, filter?: string) => void;
};
class Overview extends React.Component<Props> {
componentDidMount() {
@@ -103,7 +100,7 @@ class Overview extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { match } = ownProps;
const collection = getRepositoryCollection(state);
const loading = isFetchReposPending(state);
@@ -121,14 +118,11 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchReposByPage: (link: string, page: number, filter?: string) => {
dispatch(fetchReposByPage(link, page, filter));
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(withRouter(Overview)));
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(withRouter(Overview)));

View File

@@ -14,12 +14,11 @@ import CreateBranch from "../branches/containers/CreateBranch";
import Permissions from "../permissions/containers/Permissions";
import EditRepoNavLink from "../components/EditRepoNavLink";
import BranchRoot from "../branches/containers/BranchRoot";
import ChangesetsRoot from "./ChangesetsRoot";
import ChangesetView from "./ChangesetView";
import PermissionsNavLink from "../components/PermissionsNavLink";
import Sources from "../sources/containers/Sources";
import RepositoryNavLink from "../components/RepositoryNavLink";
import { getLinks, getRepositoriesLink } from "../../modules/indexResource";
import CodeOverview from "../codeSection/containers/CodeOverview";
import ChangesetView from "./ChangesetView";
import SourceExtensions from "../sources/containers/SourceExtensions";
type Props = WithTranslation & {
@@ -62,16 +61,30 @@ class RepositoryRoot extends React.Component<Props> {
return route.location.pathname.match(regex);
};
matchesChangesets = (route: any) => {
matchesCode = (route: any) => {
const url = this.matchedUrl();
const regex = new RegExp(`${url}(/branch)?/?[^/]*/changesets?.*`);
const regex = new RegExp(`${url}(/code)/.*`);
return route.location.pathname.match(regex);
};
matchesSources = (route: any) => {
const url = this.matchedUrl();
const regex = new RegExp(`${url}(/sources|/sourceext)/.*`);
return route.location.pathname.match(regex);
getCodeLinkname = () => {
const { repository } = this.props;
if (repository?._links?.sources) {
return "sources";
}
if (repository?._links?.changesets) {
return "changesets";
}
return "";
};
evaluateDestinationForCodeLink = () => {
const { repository } = this.props;
let url = `${this.matchedUrl()}/code`;
if (repository?._links?.sources) {
return `${url}/sources/`;
}
return `${url}/changesets`;
};
render() {
@@ -109,6 +122,14 @@ class RepositoryRoot extends React.Component<Props> {
<div className="column is-three-quarters">
<Switch>
<Redirect exact from={this.props.match.url} to={redirectedUrl} />
{/* redirect pre 2.0.0-rc2 links */}
<Redirect from={`${url}/changeset/:id`} to={`${url}/code/changeset/:id`} />
<Redirect exact from={`${url}/sources`} to={`${url}/code/sources`} />
<Redirect from={`${url}/sources/:revision/:path*`} to={`${url}/code/sources/:revision/:path*`} />
<Redirect exact from={`${url}/changesets`} to={`${url}/code/changesets`} />
<Redirect from={`${url}/branch/:branch/changesets`} to={`${url}/code/branch/:branch/changesets/`} />
<Route path={`${url}/info`} exact component={() => <RepositoryDetails repository={repository} />} />
<Route path={`${url}/settings/general`} component={() => <EditRepo repository={repository} />} />
<Route
@@ -117,44 +138,23 @@ class RepositoryRoot extends React.Component<Props> {
<Permissions namespace={this.props.repository.namespace} repoName={this.props.repository.name} />
)}
/>
<Route exact path={`${url}/changeset/:id`} render={() => <ChangesetView repository={repository} />} />
<Route
path={`${url}/sources`}
exact={true}
render={() => <Sources repository={repository} baseUrl={`${url}/sources`} />}
exact
path={`${url}/code/changeset/:id`}
render={() => <ChangesetView repository={repository} />}
/>
<Route
path={`${url}/sources/:revision/:path*`}
render={() => <Sources repository={repository} baseUrl={`${url}/sources`} />}
/>
<Route
path={`${url}/sourceext/:extension`}
path={`${url}/code/sourceext/:extension`}
exact={true}
render={() => <SourceExtensions repository={repository} />}
/>
<Route
path={`${url}/sourceext/:extension/:revision/:path*`}
render={() => <SourceExtensions repository={repository} />}
path={`${url}/code/sourceext/:extension/:revision/:path*`}
render={() => <SourceExtensions repository={repository} baseUrl={`${url}/code/sources`} />}
/>
<Route
path={`${url}/changesets`}
render={() => (
<ChangesetsRoot
repository={repository}
baseUrlWithBranch={`${url}/branch`}
baseUrlWithoutBranch={`${url}/changesets`}
/>
)}
/>
<Route
path={`${url}/branch/:branch/changesets`}
render={() => (
<ChangesetsRoot
repository={repository}
baseUrlWithBranch={`${url}/branch`}
baseUrlWithoutBranch={`${url}/changesets`}
/>
)}
path={`${url}/code`}
render={() => <CodeOverview baseUrl={`${url}/code`} repository={repository} />}
/>
<Route
path={`${url}/branch/:branch`}
@@ -189,20 +189,11 @@ class RepositoryRoot extends React.Component<Props> {
/>
<RepositoryNavLink
repository={repository}
linkName="changesets"
to={`${url}/changesets/`}
icon="fas fa-exchange-alt"
label={t("repositoryRoot.menu.historyNavLink")}
activeWhenMatch={this.matchesChangesets}
activeOnlyWhenExact={false}
/>
<RepositoryNavLink
repository={repository}
linkName="sources"
to={`${url}/sources`}
linkName={this.getCodeLinkname()}
to={this.evaluateDestinationForCodeLink()}
icon="fas fa-code"
label={t("repositoryRoot.menu.sourcesNavLink")}
activeWhenMatch={this.matchesSources}
activeWhenMatch={this.matchesCode}
activeOnlyWhenExact={false}
/>
<ExtensionPoint name="repository.navigation" props={extensionProps} renderAll={true} />
@@ -220,7 +211,7 @@ class RepositoryRoot extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { namespace, name } = ownProps.match.params;
const repository = getRepository(state, namespace, name);
const loading = isFetchRepoPending(state, namespace, name);
@@ -238,7 +229,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchRepoByName: (link: string, namespace: string, name: string) => {
dispatch(fetchRepoByName(link, namespace, name));
@@ -246,7 +237,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(RepositoryRoot));
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(RepositoryRoot));

View File

@@ -2,50 +2,50 @@ import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import reducer, {
FETCH_REPOS_PENDING,
FETCH_REPOS_SUCCESS,
fetchRepos,
FETCH_REPOS_FAILURE,
fetchReposSuccess,
getRepositoryCollection,
FETCH_REPOS,
isFetchReposPending,
getFetchReposFailure,
fetchReposByLink,
fetchReposByPage,
FETCH_REPO,
fetchRepoByLink,
fetchRepoByName,
FETCH_REPO_PENDING,
FETCH_REPO_SUCCESS,
FETCH_REPO_FAILURE,
fetchRepoSuccess,
getRepository,
isFetchRepoPending,
getFetchRepoFailure,
CREATE_REPO,
CREATE_REPO_FAILURE,
CREATE_REPO_PENDING,
CREATE_REPO_SUCCESS,
createRepo,
CREATE_REPO_FAILURE,
isCreateRepoPending,
CREATE_REPO,
getCreateRepoFailure,
isAbleToCreateRepos,
DELETE_REPO,
DELETE_REPO_FAILURE,
DELETE_REPO_PENDING,
DELETE_REPO_SUCCESS,
deleteRepo,
DELETE_REPO_PENDING,
DELETE_REPO_FAILURE,
isDeleteRepoPending,
FETCH_REPO,
FETCH_REPO_FAILURE,
FETCH_REPO_PENDING,
FETCH_REPO_SUCCESS,
FETCH_REPOS,
FETCH_REPOS_FAILURE,
FETCH_REPOS_PENDING,
FETCH_REPOS_SUCCESS,
fetchRepoByLink,
fetchRepoByName,
fetchRepos,
fetchReposByLink,
fetchReposByPage,
fetchReposSuccess,
fetchRepoSuccess,
getCreateRepoFailure,
getDeleteRepoFailure,
modifyRepo,
getFetchRepoFailure,
getFetchReposFailure,
getModifyRepoFailure,
getPermissionsLink,
getRepository,
getRepositoryCollection,
isAbleToCreateRepos,
isCreateRepoPending,
isDeleteRepoPending,
isFetchRepoPending,
isFetchReposPending,
isModifyRepoPending,
MODIFY_REPO,
MODIFY_REPO_FAILURE,
MODIFY_REPO_PENDING,
MODIFY_REPO_SUCCESS,
MODIFY_REPO_FAILURE,
MODIFY_REPO,
isModifyRepoPending,
getModifyRepoFailure,
getPermissionsLink
modifyRepo
} from "./repos";
import { Repository, RepositoryCollection } from "@scm-manager/ui-types";

View File

@@ -1,7 +1,7 @@
import fetchMock from "fetch-mock";
import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import {
import reducer, {
FETCH_REPOSITORY_TYPES,
FETCH_REPOSITORY_TYPES_FAILURE,
FETCH_REPOSITORY_TYPES_PENDING,
@@ -13,7 +13,6 @@ import {
isFetchRepositoryTypesPending,
shouldFetchRepositoryTypes
} from "./repositoryTypes";
import reducer from "./repositoryTypes";
const git = {
name: "git",

View File

@@ -1,10 +1,11 @@
import React from "react";
import { shallow, mount } from "@scm-manager/ui-tests/enzyme-router";
import { mount, shallow } from "@scm-manager/ui-tests/enzyme-router";
import "@scm-manager/ui-tests/enzyme";
import "@scm-manager/ui-tests/i18n";
import DeletePermissionButton from "./DeletePermissionButton";
import { confirmAlert } from "@scm-manager/ui-components";
jest.mock("@scm-manager/ui-components", () => ({
confirmAlert: jest.fn(),
DeleteButton: require.requireActual("@scm-manager/ui-components").DeleteButton

View File

@@ -1,6 +1,6 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { ButtonGroup, Button, SubmitButton, Modal } from "@scm-manager/ui-components";
import { Button, ButtonGroup, Modal, SubmitButton } from "@scm-manager/ui-components";
import PermissionCheckbox from "../../../permissions/components/PermissionCheckbox";
type Props = WithTranslation & {

View File

@@ -5,8 +5,8 @@ import {
Button,
GroupAutocomplete,
LabelWithHelpIcon,
Radio,
Level,
Radio,
SubmitButton,
Subtitle,
UserAutocomplete

View File

@@ -175,7 +175,7 @@ class Permissions extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const namespace = ownProps.namespace;
const repoName = ownProps.repoName;
const error =
@@ -216,7 +216,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchPermissions: (link: string, namespace: string, repoName: string) => {
dispatch(fetchPermissions(link, namespace, repoName));
@@ -245,7 +245,4 @@ const mapDispatchToProps = dispatch => {
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(Permissions));
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(Permissions));

View File

@@ -3,14 +3,14 @@ import { connect } from "react-redux";
import { History } from "history";
import { WithTranslation, withTranslation } from "react-i18next";
import styled from "styled-components";
import { RepositoryRole, Permission } from "@scm-manager/ui-types";
import { Permission, RepositoryRole } from "@scm-manager/ui-types";
import { Button, Icon } from "@scm-manager/ui-components";
import {
modifyPermission,
isModifyPermissionPending,
deletePermission,
findVerbsForRole,
isDeletePermissionPending,
findVerbsForRole
isModifyPermissionPending,
modifyPermission
} from "../modules/permissions";
import DeletePermissionButton from "../components/buttons/DeletePermissionButton";
import RoleSelector from "../components/RoleSelector";
@@ -208,7 +208,7 @@ class SinglePermission extends React.Component<Props, State> {
};
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const permission = ownProps.permission;
const loading = isModifyPermissionPending(state, ownProps.namespace, ownProps.repoName, permission);
const deleteLoading = isDeletePermissionPending(state, ownProps.namespace, ownProps.repoName, permission);
@@ -219,7 +219,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
modifyPermission: (permission: Permission, namespace: string, repoName: string) => {
dispatch(modifyPermission(permission, namespace, repoName));
@@ -229,7 +229,4 @@ const mapDispatchToProps = dispatch => {
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(SinglePermission));
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(SinglePermission));

View File

@@ -1,7 +1,6 @@
import { Action } from "@scm-manager/ui-components";
import { apiClient } from "@scm-manager/ui-components";
import { Action, apiClient } from "@scm-manager/ui-components";
import * as types from "../../../modules/types";
import { RepositoryRole, Permission, PermissionCollection, PermissionCreateEntry } from "@scm-manager/ui-types";
import { Permission, PermissionCollection, PermissionCreateEntry, RepositoryRole } from "@scm-manager/ui-types";
import { isPending } from "../../../modules/pending";
import { getFailure } from "../../../modules/failure";
import { Dispatch } from "redux";

View File

@@ -5,9 +5,9 @@ import { withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import styled from "styled-components";
import { binder } from "@scm-manager/ui-extensions";
import { Repository, File } from "@scm-manager/ui-types";
import { File, Repository } from "@scm-manager/ui-types";
import { ErrorNotification, Loading, Notification } from "@scm-manager/ui-components";
import { getFetchSourcesFailure, isFetchSourcesPending, getSources, fetchSources } from "../modules/sources";
import { fetchSources, getFetchSourcesFailure, getSources, isFetchSourcesPending } from "../modules/sources";
import FileTreeLeaf from "./FileTreeLeaf";
type Props = WithTranslation & {
@@ -174,10 +174,4 @@ const mapStateToProps = (state: any, ownProps: Props) => {
};
};
export default compose(
withRouter,
connect(
mapStateToProps,
mapDispatchToProps
)
)(withTranslation("repos")(FileTree));
export default compose(withRouter, connect(mapStateToProps, mapDispatchToProps))(withTranslation("repos")(FileTree));

View File

@@ -88,14 +88,16 @@ class FileTreeLeaf extends React.Component<Props> {
render() {
const { file } = this.props;
const renderFileSize = (file: File) => <FileSize bytes={file.length} />;
const renderFileSize = (file: File) => <FileSize bytes={file?.length ? file.length : 0} />;
const renderCommitDate = (file: File) => <DateFromNow date={file.commitDate} />;
return (
<tr>
<td>{this.createFileIcon(file)}</td>
<MinWidthTd className="is-word-break">{this.createFileName(file)}</MinWidthTd>
<NoWrapTd className="is-hidden-mobile">{file.directory ? "" : this.contentIfPresent(file, "length", renderFileSize)}</NoWrapTd>
<NoWrapTd className="is-hidden-mobile">
{file.directory ? "" : this.contentIfPresent(file, "length", renderFileSize)}
</NoWrapTd>
<td className="is-hidden-mobile">{this.contentIfPresent(file, "commitDate", renderCommitDate)}</td>
<MinWidthTd className={classNames("is-word-break", "is-hidden-touch")}>
{this.contentIfPresent(file, "description", file => file.description)}

View File

@@ -1,6 +1,6 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { ButtonAddons, Button } from "@scm-manager/ui-components";
import { Button, ButtonAddons } from "@scm-manager/ui-components";
type Props = WithTranslation & {
className?: string;

View File

@@ -1,8 +1,7 @@
import React from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { apiClient, SyntaxHighlighter } from "@scm-manager/ui-components";
import { File } from "@scm-manager/ui-types";
import { ErrorNotification, Loading } from "@scm-manager/ui-components";
import { apiClient, ErrorNotification, Loading, SyntaxHighlighter } from "@scm-manager/ui-components";
import { File, Link } from "@scm-manager/ui-types";
type Props = WithTranslation & {
file: File;
@@ -13,6 +12,7 @@ type State = {
content: string;
error?: Error;
loaded: boolean;
currentFileRevision: string;
};
class SourcecodeViewer extends React.Component<Props, State> {
@@ -21,31 +21,45 @@ class SourcecodeViewer extends React.Component<Props, State> {
this.state = {
content: "",
loaded: false
loaded: false,
currentFileRevision: ""
};
}
componentDidMount() {
const { file } = this.props;
getContent(file._links.self.href)
.then(result => {
if (result.error) {
this.setState({
...this.state,
error: result.error,
loaded: true
});
} else {
this.setState({
...this.state,
content: result,
loaded: true
});
}
})
.catch(err => {});
this.fetchContentIfChanged();
}
componentDidUpdate() {
this.fetchContentIfChanged();
}
private fetchContentIfChanged() {
const { file } = this.props;
const { currentFileRevision } = this.state;
if (file.revision !== currentFileRevision) {
this.fetchContent();
}
}
fetchContent = () => {
const { file } = this.props;
getContent((file._links.self as Link).href)
.then(content => {
this.setState({
content,
loaded: true,
currentFileRevision: file.revision
});
})
.catch(error => {
this.setState({
error,
loaded: true
});
});
};
render() {
const { content, error, loaded } = this.state;
const language = this.props.language;
@@ -71,17 +85,7 @@ export function getLanguage(language: string) {
}
export function getContent(url: string) {
return apiClient
.get(url)
.then(response => response.text())
.then(response => {
return response;
})
.catch(err => {
return {
error: err
};
});
return apiClient.get(url).then(response => response.text());
}
export default withTranslation("repos")(SourcecodeViewer);

View File

@@ -17,6 +17,7 @@ type Props = WithTranslation & {
repository: Repository;
revision: string;
path: string;
breadcrumb: React.ReactNode;
};
type State = {
@@ -25,6 +26,14 @@ type State = {
errorFromExtension?: Error;
};
const Header = styled.div`
border-bottom: solid 1px #dbdbdb;
font-size: 1.25em;
font-weight: 300;
line-height: 1.25;
padding: 0.5em 0.75em;
`;
const VCenteredChild = styled.div`
align-items: center;
`;
@@ -37,6 +46,10 @@ const RightMarginFileButtonAddons = styled(FileButtonAddons)`
margin-right: 0.5em;
`;
const BorderBottom = styled.div`
border-bottom: solid 1px #dbdbdb;
`;
const LighterGreyBackgroundPanelBlock = styled.div`
background-color: #fbfbfb;
`;
@@ -128,51 +141,54 @@ class Content extends React.Component<Props, State> {
})}
</p>
) : null;
const fileSize = file.directory ? "" : <FileSize bytes={file.length} />;
const fileSize = file.directory ? "" : <FileSize bytes={file?.length ? file.length : 0} />;
if (!collapsed) {
return (
<LighterGreyBackgroundPanelBlock className="panel-block">
<LighterGreyBackgroundTable className="table">
<tbody>
<tr>
<td>{t("sources.content.path")}</td>
<td className="is-word-break">{file.path}</td>
</tr>
<tr>
<td>{t("sources.content.branch")}</td>
<td className="is-word-break">{revision}</td>
</tr>
<tr>
<td>{t("sources.content.size")}</td>
<td>{fileSize}</td>
</tr>
<tr>
<td>{t("sources.content.commitDate")}</td>
<td>{date}</td>
</tr>
<tr>
<td>{t("sources.content.description")}</td>
<td className="is-word-break">{description}</td>
</tr>
<ExtensionPoint
name="repos.content.metadata"
renderAll={true}
props={{
file,
repository,
revision
}}
/>
</tbody>
</LighterGreyBackgroundTable>
</LighterGreyBackgroundPanelBlock>
<>
<LighterGreyBackgroundPanelBlock className="panel-block">
<LighterGreyBackgroundTable className="table">
<tbody>
<tr>
<td>{t("sources.content.path")}</td>
<td className="is-word-break">{file.path}</td>
</tr>
<tr>
<td>{t("sources.content.branch")}</td>
<td className="is-word-break">{revision}</td>
</tr>
<tr>
<td>{t("sources.content.size")}</td>
<td>{fileSize}</td>
</tr>
<tr>
<td>{t("sources.content.commitDate")}</td>
<td>{date}</td>
</tr>
<tr>
<td>{t("sources.content.description")}</td>
<td className="is-word-break">{description}</td>
</tr>
<ExtensionPoint
name="repos.content.metadata"
renderAll={true}
props={{
file,
repository,
revision
}}
/>
</tbody>
</LighterGreyBackgroundTable>
</LighterGreyBackgroundPanelBlock>
<BorderBottom />
</>
);
}
return null;
}
render() {
const { file, revision, repository, path } = this.props;
const { file, revision, repository, path, breadcrumb } = this.props;
const { showHistory, errorFromExtension } = this.state;
const header = this.showHeader();
@@ -187,7 +203,8 @@ class Content extends React.Component<Props, State> {
return (
<div>
<div className="panel">
<div className="panel-heading">{header}</div>
{breadcrumb}
<Header>{header}</Header>
{moreInformation}
{content}
</div>

View File

@@ -1,6 +1,6 @@
import React from "react";
import { File, Changeset, Repository, PagedCollection } from "@scm-manager/ui-types";
import { ErrorNotification, Loading, StatePaginator, ChangesetList } from "@scm-manager/ui-components";
import { Changeset, File, PagedCollection, Repository, Link } from "@scm-manager/ui-types";
import { ChangesetList, ErrorNotification, Loading, StatePaginator } from "@scm-manager/ui-components";
import { getHistory } from "./history";
type Props = {
@@ -14,6 +14,7 @@ type State = {
page: number;
pageCollection?: PagedCollection;
error?: Error;
currentRevision: string;
};
class HistoryView extends React.Component<Props, State> {
@@ -23,41 +24,52 @@ class HistoryView extends React.Component<Props, State> {
this.state = {
loaded: false,
page: 1,
changesets: []
changesets: [],
currentRevision: ""
};
}
componentDidMount() {
const { file } = this.props;
this.updateHistory(file._links.history.href);
if (file) {
this.updateHistory((file._links.history as Link).href);
}
}
componentDidUpdate() {
const { file } = this.props;
const { currentRevision } = this.state;
if (file?.revision !== currentRevision) {
this.updateHistory((file._links.history as Link).href);
}
}
updateHistory(link: string) {
const { file } = this.props;
getHistory(link)
.then(result => {
if (result.error) {
this.setState({
...this.state,
error: result.error,
loaded: true
});
} else {
this.setState({
...this.state,
loaded: true,
changesets: result.changesets,
pageCollection: result.pageCollection,
page: result.pageCollection.page
});
}
this.setState({
...this.state,
loaded: true,
changesets: result.changesets,
pageCollection: result.pageCollection,
page: result.pageCollection.page,
currentRevision: file.revision
});
})
.catch(err => {});
.catch(error =>
this.setState({
...this.state,
error,
loaded: true
})
);
}
updatePage(page: number) {
const { file } = this.props;
const internalPage = page - 1;
this.updateHistory(file._links.history.href + "?page=" + internalPage.toString());
this.updateHistory((file._links.history as Link).href + "?page=" + internalPage.toString());
}
showHistory() {

View File

@@ -1,17 +1,17 @@
import React from "react";
import { Repository, File } from "@scm-manager/ui-types";
import { withRouter, RouteComponentProps } from "react-router-dom";
import { File, Repository } from "@scm-manager/ui-types";
import { RouteComponentProps, withRouter } from "react-router-dom";
import { ExtensionPoint, binder } from "@scm-manager/ui-extensions";
import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
import { fetchSources, getFetchSourcesFailure, getSources, isFetchSourcesPending } from "../modules/sources";
import { connect } from "react-redux";
import { Loading, ErrorNotification } from "@scm-manager/ui-components";
import Notification from "@scm-manager/ui-components/src/Notification";
import { ErrorNotification, Loading, Notification } from "@scm-manager/ui-components";
import { WithTranslation, withTranslation } from "react-i18next";
type Props = WithTranslation &
RouteComponentProps & {
repository: Repository;
baseUrl: string;
// url params
extension: string;
@@ -24,7 +24,7 @@ type Props = WithTranslation &
sources?: File | null;
// dispatch props
fetchSources: (repository: Repository, revision: string, path: string) => void;
fetchSources: (repository: Repository, revision?: string, path?: string) => void;
};
const extensionPointName = "repos.sources.extensions";
@@ -33,11 +33,11 @@ class SourceExtensions extends React.Component<Props> {
componentDidMount() {
const { fetchSources, repository, revision, path } = this.props;
// TODO get typing right
fetchSources(repository, revision || "", path || "");
fetchSources(repository, revision, path);
}
render() {
const { loading, error, repository, extension, revision, path, sources, t } = this.props;
const { loading, error, repository, extension, revision, path, sources, baseUrl, t } = this.props;
if (error) {
return <ErrorNotification error={error} />;
}
@@ -45,7 +45,7 @@ class SourceExtensions extends React.Component<Props> {
return <Loading />;
}
const extprops = { extension, repository, revision, path, sources };
const extprops = { extension, repository, revision, path, sources, baseUrl };
if (!binder.hasExtension(extensionPointName, extprops)) {
return <Notification type="warning">{t("sources.extension.notBound")}</Notification>;
}
@@ -85,9 +85,4 @@ const mapDispatchToProps = (dispatch: any) => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(SourceExtensions))
);
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(SourceExtensions)));

View File

@@ -1,115 +1,90 @@
import React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { withRouter, RouteComponentProps } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { Branch, Repository } from "@scm-manager/ui-types";
import { BranchSelector, Breadcrumb, ErrorNotification, Loading } from "@scm-manager/ui-components";
import { Breadcrumb, ErrorNotification, Loading } from "@scm-manager/ui-components";
import FileTree from "../components/FileTree";
import {
fetchBranches,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending
} from "../../branches/modules/branches";
import { getFetchBranchesFailure, isFetchBranchesPending } from "../../branches/modules/branches";
import { compose } from "redux";
import Content from "./Content";
import {fetchSources, getSources, isDirectory} from "../modules/sources";
import { fetchSources, getSources, isDirectory } from "../modules/sources";
import CodeActionBar from "../../codeSection/components/CodeActionBar";
type Props = WithTranslation & {
repository: Repository;
loading: boolean;
error: Error;
baseUrl: string;
branches: Branch[];
revision: string;
path: string;
currentFileIsDirectory: boolean;
sources: File;
type Props = WithTranslation &
RouteComponentProps & {
repository: Repository;
loading: boolean;
error: Error;
baseUrl: string;
branches: Branch[];
revision: string;
path: string;
currentFileIsDirectory: boolean;
sources: File;
selectedBranch: string;
// dispatch props
fetchBranches: (p: Repository) => void;
fetchSources: (p1: Repository, p2: string, p3: string) => void;
// Context props
history: any;
match: any;
location: any;
};
type State = {
selectedBranch: any;
};
class Sources extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
selectedBranch: null
};
}
// dispatch props
fetchSources: (repository: Repository, revision: string, path: string) => void;
};
class Sources extends React.Component<Props> {
componentDidMount() {
const { fetchBranches, repository, revision, path, fetchSources } = this.props;
fetchBranches(repository);
const { repository, branches, selectedBranch, baseUrl, revision, path, fetchSources } = this.props;
fetchSources(repository, this.decodeRevision(revision), path);
this.redirectToDefaultBranch();
if (branches?.length > 0 && !selectedBranch) {
const defaultBranch = branches?.filter(b => b.defaultBranch === true)[0];
this.props.history.replace(`${baseUrl}/sources/${encodeURIComponent(defaultBranch.name)}/`);
}
}
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: Props) {
const { fetchSources, repository, revision, path } = this.props;
if (prevProps.revision !== revision || prevProps.path !== path) {
fetchSources(repository, this.decodeRevision(revision), path);
}
this.redirectToDefaultBranch();
}
decodeRevision = (revision: string) => {
return revision ? decodeURIComponent(revision) : revision;
};
redirectToDefaultBranch = () => {
const { branches } = this.props;
if (this.shouldRedirectToDefaultBranch()) {
const defaultBranches = branches.filter(b => b.defaultBranch);
if (defaultBranches.length > 0) {
this.branchSelected(defaultBranches[0]);
}
}
};
shouldRedirectToDefaultBranch = () => {
const { branches, revision } = this.props;
return branches && !revision;
};
branchSelected = (branch?: Branch) => {
onSelectBranch = (branch?: Branch) => {
const { baseUrl, history, path } = this.props;
let url;
if (branch) {
this.setState({
selectedBranch: branch
});
if (path) {
url = `${baseUrl}/${encodeURIComponent(branch.name)}/${path}`;
url = `${baseUrl}/sources/${encodeURIComponent(branch.name)}/${path}`;
url = !url.endsWith("/") ? url + "/" : url;
} else {
url = `${baseUrl}/${encodeURIComponent(branch.name)}/`;
url = `${baseUrl}/sources/${encodeURIComponent(branch.name)}/`;
}
} else {
this.setState({
selectedBranch: null
});
url = `${baseUrl}/`;
return;
}
history.push(url);
};
evaluateSwitchViewLink = () => {
const { baseUrl, selectedBranch, branches } = this.props;
if (selectedBranch && branches?.filter(b => b.name === selectedBranch).length !== 0) {
return `${baseUrl}/branch/${encodeURIComponent(selectedBranch)}/changesets/`;
}
return `${baseUrl}/changesets/`;
};
render() {
const { repository, baseUrl, loading, error, revision, path, currentFileIsDirectory } = this.props;
const {
repository,
baseUrl,
branches,
selectedBranch,
loading,
error,
revision,
path,
currentFileIsDirectory
} = this.props;
if (error) {
return <ErrorNotification error={error} />;
@@ -121,64 +96,57 @@ class Sources extends React.Component<Props, State> {
if (currentFileIsDirectory) {
return (
<div className="panel">
{this.renderBranchSelector()}
{this.renderBreadcrumb()}
<FileTree repository={repository} revision={revision} path={path} baseUrl={baseUrl} />
</div>
<>
<CodeActionBar
selectedBranch={selectedBranch}
branches={branches}
onSelectBranch={this.onSelectBranch}
switchViewLink={this.evaluateSwitchViewLink()}
/>
<div className="panel">
{this.renderBreadcrumb()}
<FileTree repository={repository} revision={revision} path={path} baseUrl={baseUrl + "/sources"} />
</div>
</>
);
} else {
return <Content repository={repository} revision={revision} path={path} />;
return (
<>
<CodeActionBar
selectedBranch={selectedBranch}
branches={branches}
onSelectBranch={this.onSelectBranch}
switchViewLink={this.evaluateSwitchViewLink()}
/>
<Content repository={repository} revision={revision} path={path} breadcrumb={this.renderBreadcrumb()} />
</>
);
}
}
renderBranchSelector = () => {
const { branches, revision, t } = this.props;
if (branches) {
return (
<div className="panel-heading">
<BranchSelector
branches={branches}
selectedBranch={revision}
label={t("changesets.branchSelectorLabel")}
selected={(b: Branch) => {
this.branchSelected(b);
}}
/>
</div>
);
}
return null;
};
renderBreadcrumb = () => {
const { revision, path, baseUrl, branches, sources, repository } = this.props;
const { selectedBranch } = this.state;
const { revision, selectedBranch, path, baseUrl, branches, sources, repository } = this.props;
return (
<Breadcrumb
repository={repository}
revision={revision}
path={path}
baseUrl={baseUrl}
branch={selectedBranch}
defaultBranch={
branches && branches.filter(b => b.defaultBranch === true)[0]
}
baseUrl={baseUrl + "/sources"}
branch={branches?.filter(b => b.name === selectedBranch)[0]}
defaultBranch={branches?.filter(b => b.defaultBranch === true)[0]}
sources={sources}
/>
);
};
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository, match } = ownProps;
const { revision, path } = match.params;
const decodedRevision = revision ? decodeURIComponent(revision) : undefined;
const loading = isFetchBranchesPending(state, repository);
const error = getFetchBranchesFailure(state, repository);
const branches = getBranches(state, repository);
const currentFileIsDirectory = decodedRevision
? isDirectory(state, repository, decodedRevision, path)
: isDirectory(state, repository, revision, path);
@@ -190,28 +158,17 @@ const mapStateToProps = (state, ownProps) => {
path,
loading,
error,
branches,
currentFileIsDirectory,
sources
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranches: (repository: Repository) => {
dispatch(fetchBranches(repository));
},
fetchSources: (repository: Repository, revision: string, path: string) => {
dispatch(fetchSources(repository, revision, path));
}
};
};
export default compose(
withTranslation("repos"),
withRouter,
connect(
mapStateToProps,
mapDispatchToProps
)
)(Sources);
export default compose(withTranslation("repos"), withRouter, connect(mapStateToProps, mapDispatchToProps))(Sources);

View File

@@ -37,22 +37,20 @@ class SourcesView extends React.Component<Props, State> {
const { file } = this.props;
getContentType(file._links.self.href)
.then(result => {
if (result.error) {
this.setState({
...this.state,
error: result.error,
loaded: true
});
} else {
this.setState({
...this.state,
contentType: result.type,
language: result.language,
loaded: true
});
}
this.setState({
...this.state,
contentType: result.type,
language: result.language,
loaded: true
});
})
.catch(err => {});
.catch(error => {
this.setState({
...this.state,
error,
loaded: true
});
});
}
showSources() {

View File

@@ -1,19 +1,19 @@
import { Repository, File } from "@scm-manager/ui-types";
import { File, Repository } from "@scm-manager/ui-types";
import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import {
default as reducer,
FETCH_SOURCES,
FETCH_SOURCES_FAILURE,
FETCH_SOURCES_PENDING,
FETCH_SOURCES_SUCCESS,
fetchSources,
getFetchSourcesFailure,
isFetchSourcesPending,
default as reducer,
getSources,
fetchSourcesSuccess,
isDirectory
getFetchSourcesFailure,
getSources,
isDirectory,
isFetchSourcesPending
} from "./sources";
const sourcesUrl = "http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/";
@@ -198,7 +198,7 @@ describe("selector tests", () => {
const state = {
sources: {
"scm/core/abc/src/main/package.json": {
sources: {noDirectory}
sources: { noDirectory }
}
}
};

View File

@@ -1,5 +1,5 @@
import * as types from "../../../modules/types";
import { Repository, File, Action, Link } from "@scm-manager/ui-types";
import { Action, File, Link, Repository } from "@scm-manager/ui-types";
import { apiClient } from "@scm-manager/ui-components";
import { isPending } from "../../../modules/pending";
import { getFailure } from "../../../modules/failure";
@@ -84,7 +84,7 @@ export function fetchSourcesFailure(repository: Repository, revision: string, pa
};
}
function createItemId(repository: Repository, revision: string, path: string) {
function createItemId(repository: Repository, revision: string | undefined, path: string) {
const revPart = revision ? revision : "_";
const pathPart = path ? path : "";
return `${repository.namespace}/${repository.name}/${decodeURIComponent(revPart)}/${pathPart}`;
@@ -121,7 +121,7 @@ export function isDirectory(state: any, repository: Repository, revision: string
export function getSources(
state: any,
repository: Repository,
revision: string,
revision: string | undefined,
path: string
): File | null | undefined {
if (state.sources) {

Some files were not shown because too many files have changed in this diff Show More