mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-03-05 11:50:58 +01:00
apply eslint and prettier rules
This commit is contained in:
@@ -1,28 +1,28 @@
|
||||
module.exports = {
|
||||
"extends": [
|
||||
extends: [
|
||||
"react-app",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:flowtype/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"semi": ["error", "always"],
|
||||
"quotes": ["error", "double"],
|
||||
rules: {
|
||||
semi: ["error", "always"],
|
||||
quotes: ["error", "double"],
|
||||
"jsx-a11y/href-no-hash": [0],
|
||||
"flowtype/no-types-missing-file-annotation": 2,
|
||||
"no-console": "error"
|
||||
},
|
||||
"overrides": [
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.ts", "*.tsx"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
extends: [
|
||||
"react-app",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"semi": ["error", "always"],
|
||||
"quotes": ["error", "double"],
|
||||
rules: {
|
||||
semi: ["error", "always"],
|
||||
quotes: ["error", "double"],
|
||||
"jsx-a11y/href-no-hash": [0],
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"no-console": "error"
|
||||
|
||||
@@ -25,10 +25,7 @@ class Autocomplete extends React.Component<Props, State> {
|
||||
noOptionsMessage: "No suggestion available"
|
||||
};
|
||||
|
||||
handleInputChange = (
|
||||
newValue: ValueType<SelectValue>,
|
||||
action: ActionMeta
|
||||
) => {
|
||||
handleInputChange = (newValue: ValueType<SelectValue>, action: ActionMeta) => {
|
||||
this.selectValue(newValue as SelectValue);
|
||||
};
|
||||
|
||||
@@ -42,9 +39,7 @@ class Autocomplete extends React.Component<Props, State> {
|
||||
selectValue: ValueType<SelectValue>,
|
||||
selectOptions: readonly SelectValue[]
|
||||
): boolean => {
|
||||
const isNotDuplicated = !selectOptions
|
||||
.map(option => option.label)
|
||||
.includes(inputValue);
|
||||
const isNotDuplicated = !selectOptions.map(option => option.label).includes(inputValue);
|
||||
const isNotEmpty = inputValue !== "";
|
||||
return isNotEmpty && isNotDuplicated;
|
||||
};
|
||||
|
||||
@@ -38,9 +38,7 @@ export default class BranchSelector extends React.Component<Props, State> {
|
||||
componentDidMount() {
|
||||
const { branches } = this.props;
|
||||
if (branches) {
|
||||
const selectedBranch = branches.find(
|
||||
branch => branch.name === this.props.selectedBranch
|
||||
);
|
||||
const selectedBranch = branches.find(branch => branch.name === this.props.selectedBranch);
|
||||
this.setState({
|
||||
selectedBranch
|
||||
});
|
||||
@@ -53,9 +51,7 @@ export default class BranchSelector extends React.Component<Props, State> {
|
||||
if (branches) {
|
||||
return (
|
||||
<div className={classNames("field", "is-horizontal")}>
|
||||
<ZeroflexFieldLabel
|
||||
className={classNames("field-label", "is-normal")}
|
||||
>
|
||||
<ZeroflexFieldLabel className={classNames("field-label", "is-normal")}>
|
||||
<label className={classNames("label", "is-size-6")}>{label}</label>
|
||||
</ZeroflexFieldLabel>
|
||||
<div className="field-body">
|
||||
@@ -66,11 +62,7 @@ export default class BranchSelector extends React.Component<Props, State> {
|
||||
options={branches.map(b => b.name)}
|
||||
optionSelected={this.branchSelected}
|
||||
disabled={!!disabled}
|
||||
preselectedOption={
|
||||
this.state.selectedBranch
|
||||
? this.state.selectedBranch.name
|
||||
: ""
|
||||
}
|
||||
preselectedOption={this.state.selectedBranch ? this.state.selectedBranch.name : ""}
|
||||
/>
|
||||
</MinWidthControl>
|
||||
</NoBottomMarginField>
|
||||
|
||||
@@ -62,32 +62,16 @@ class Breadcrumb extends React.Component<Props> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
baseUrl,
|
||||
branch,
|
||||
defaultBranch,
|
||||
branches,
|
||||
revision,
|
||||
path,
|
||||
repository,
|
||||
t
|
||||
} = this.props;
|
||||
const { baseUrl, branch, defaultBranch, branches, revision, path, repository, t } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="is-flex">
|
||||
<FlexStartNav
|
||||
className={classNames("breadcrumb", "sources-breadcrumb")}
|
||||
aria-label="breadcrumbs"
|
||||
>
|
||||
<FlexStartNav className={classNames("breadcrumb", "sources-breadcrumb")} aria-label="breadcrumbs">
|
||||
<ul>
|
||||
<li>
|
||||
<Link to={baseUrl + "/" + revision + "/"}>
|
||||
<HomeIcon
|
||||
title={t("breadcrumb.home")}
|
||||
name="home"
|
||||
color="inherit"
|
||||
/>
|
||||
<HomeIcon title={t("breadcrumb.home")} name="home" color="inherit" />
|
||||
</Link>
|
||||
</li>
|
||||
{this.renderPath()}
|
||||
@@ -101,11 +85,7 @@ class Breadcrumb extends React.Component<Props> {
|
||||
baseUrl,
|
||||
branch: branch ? branch : defaultBranch,
|
||||
path,
|
||||
isBranchUrl:
|
||||
branches &&
|
||||
branches.filter(
|
||||
b => b.name.replace("/", "%2F") === revision
|
||||
).length > 0,
|
||||
isBranchUrl: branches && branches.filter(b => b.name.replace("/", "%2F") === revision).length > 0,
|
||||
repository
|
||||
}}
|
||||
renderAll={true}
|
||||
|
||||
@@ -66,24 +66,14 @@ export default class CardColumn extends React.Component<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
avatar,
|
||||
title,
|
||||
description,
|
||||
contentRight,
|
||||
footerLeft,
|
||||
footerRight,
|
||||
className
|
||||
} = this.props;
|
||||
const { avatar, title, description, contentRight, footerLeft, footerRight, className } = this.props;
|
||||
const link = this.createLink();
|
||||
return (
|
||||
<>
|
||||
{link}
|
||||
<NoEventWrapper className={classNames("media", className)}>
|
||||
<AvatarWrapper className="media-left">{avatar}</AvatarWrapper>
|
||||
<FlexFullHeight
|
||||
className={classNames("media-content", "text-box", "is-flex")}
|
||||
>
|
||||
<FlexFullHeight className={classNames("media-content", "text-box", "is-flex")}>
|
||||
<div className="is-flex">
|
||||
<ContentLeft className="content">
|
||||
<p className="shorten-text is-marginless">
|
||||
@@ -95,9 +85,7 @@ export default class CardColumn extends React.Component<Props> {
|
||||
</div>
|
||||
<FooterWrapper className={classNames("level", "is-flex")}>
|
||||
<div className="level-left is-hidden-mobile">{footerLeft}</div>
|
||||
<div className="level-right is-mobile is-marginless">
|
||||
{footerRight}
|
||||
</div>
|
||||
<div className="level-right is-mobile is-marginless">{footerRight}</div>
|
||||
</FooterWrapper>
|
||||
</FlexFullHeight>
|
||||
</NoEventWrapper>
|
||||
|
||||
@@ -56,16 +56,7 @@ export default class CardColumnGroup extends React.Component<Props, State> {
|
||||
const fullColumnWidth = this.isFullSize(elements, index);
|
||||
const sizeClass = fullColumnWidth ? "is-full" : "is-half";
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"box",
|
||||
"box-link-shadow",
|
||||
"column",
|
||||
"is-clipped",
|
||||
sizeClass
|
||||
)}
|
||||
key={index}
|
||||
>
|
||||
<div className={classNames("box", "box-link-shadow", "column", "is-clipped", sizeClass)} key={index}>
|
||||
{entry}
|
||||
</div>
|
||||
);
|
||||
@@ -74,17 +65,12 @@ export default class CardColumnGroup extends React.Component<Props, State> {
|
||||
return (
|
||||
<Container>
|
||||
<h2>
|
||||
<span
|
||||
className={classNames("is-size-4", "has-cursor-pointer")}
|
||||
onClick={this.toggleCollapse}
|
||||
>
|
||||
<span className={classNames("is-size-4", "has-cursor-pointer")} onClick={this.toggleCollapse}>
|
||||
<i className={classNames("fa", icon)} /> {name}
|
||||
</span>
|
||||
</h2>
|
||||
<hr />
|
||||
<Wrapper className={classNames("columns", "is-multiline")}>
|
||||
{content}
|
||||
</Wrapper>
|
||||
<Wrapper className={classNames("columns", "is-multiline")}>{content}</Wrapper>
|
||||
<div className="is-clearfix" />
|
||||
</Container>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { enUS, de, es } from "date-fns/locale";
|
||||
import styled from "styled-components";
|
||||
|
||||
type LocaleMap = {
|
||||
[key: string]: Locale
|
||||
[key: string]: Locale;
|
||||
};
|
||||
|
||||
type DateInput = Date | string;
|
||||
@@ -67,7 +67,7 @@ class DateFromNow extends React.Component<Props> {
|
||||
return value as Date;
|
||||
}
|
||||
return parseISO(value);
|
||||
}
|
||||
};
|
||||
|
||||
getBaseDate = () => {
|
||||
const { baseDate } = this.props;
|
||||
|
||||
@@ -18,18 +18,14 @@ class ErrorNotification extends React.Component<Props> {
|
||||
} else if (error instanceof UnauthorizedError) {
|
||||
return (
|
||||
<Notification type="danger">
|
||||
<strong>{t("errorNotification.prefix")}:</strong>{" "}
|
||||
{t("errorNotification.timeout")}{" "}
|
||||
<a href="javascript:window.location.reload(true)">
|
||||
{t("errorNotification.loginLink")}
|
||||
</a>
|
||||
<strong>{t("errorNotification.prefix")}:</strong> {t("errorNotification.timeout")}{" "}
|
||||
<a href="javascript:window.location.reload(true)">{t("errorNotification.loginLink")}</a>
|
||||
</Notification>
|
||||
);
|
||||
} else if (error instanceof ForbiddenError) {
|
||||
return (
|
||||
<Notification type="danger">
|
||||
<strong>{t("errorNotification.prefix")}:</strong>{" "}
|
||||
{t("errorNotification.forbidden")}
|
||||
<strong>{t("errorNotification.prefix")}:</strong> {t("errorNotification.forbidden")}
|
||||
</Notification>
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -18,10 +18,7 @@ export default class Help extends React.Component<Props> {
|
||||
render() {
|
||||
const { message, className } = this.props;
|
||||
return (
|
||||
<HelpTooltip
|
||||
className={classNames("is-inline-block", className)}
|
||||
message={message}
|
||||
>
|
||||
<HelpTooltip className={classNames("is-inline-block", className)} message={message}>
|
||||
<HelpIcon />
|
||||
</HelpTooltip>
|
||||
);
|
||||
|
||||
@@ -8,8 +8,6 @@ type Props = {
|
||||
export default class HelpIcon extends React.Component<Props> {
|
||||
render() {
|
||||
const { className } = this.props;
|
||||
return (
|
||||
<Icon name="question-circle" color="blue-light" className={className} />
|
||||
);
|
||||
return <Icon name="question-circle" color="blue-light" className={className} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,28 +16,8 @@ export default class Icon extends React.Component<Props> {
|
||||
render() {
|
||||
const { title, name, color, className } = this.props;
|
||||
if (title) {
|
||||
return (
|
||||
<i
|
||||
title={title}
|
||||
className={classNames(
|
||||
"fas",
|
||||
"fa-fw",
|
||||
"fa-" + name,
|
||||
`has-text-${color}`,
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
return <i title={title} className={classNames("fas", "fa-fw", "fa-" + name, `has-text-${color}`, className)} />;
|
||||
}
|
||||
return (
|
||||
<i
|
||||
className={classNames(
|
||||
"fas",
|
||||
"fa-" + name,
|
||||
`has-text-${color}`,
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
return <i className={classNames("fas", "fa-" + name, `has-text-${color}`, className)} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,7 @@ class LinkPaginator extends React.Component<Props> {
|
||||
}
|
||||
|
||||
renderFirstButton() {
|
||||
return (
|
||||
<Button
|
||||
className="pagination-link"
|
||||
label={"1"}
|
||||
disabled={false}
|
||||
link={this.addFilterToLink("1")}
|
||||
/>
|
||||
);
|
||||
return <Button className="pagination-link" label={"1"} disabled={false} link={this.addFilterToLink("1")} />;
|
||||
}
|
||||
|
||||
renderPreviousButton(className: string, label?: string) {
|
||||
@@ -81,13 +74,7 @@ class LinkPaginator extends React.Component<Props> {
|
||||
}
|
||||
|
||||
currentPage(page: number) {
|
||||
return (
|
||||
<Button
|
||||
className="pagination-link is-current"
|
||||
label={"" + page}
|
||||
disabled={true}
|
||||
/>
|
||||
);
|
||||
return <Button className="pagination-link is-current" label={"" + page} disabled={true} />;
|
||||
}
|
||||
|
||||
pageLinks() {
|
||||
@@ -123,10 +110,7 @@ class LinkPaginator extends React.Component<Props> {
|
||||
if (collection) {
|
||||
return (
|
||||
<nav className="pagination is-centered" aria-label="pagination">
|
||||
{this.renderPreviousButton(
|
||||
"pagination-previous",
|
||||
t("paginator.previous")
|
||||
)}
|
||||
{this.renderPreviousButton("pagination-previous", t("paginator.previous"))}
|
||||
<ul className="pagination-list">
|
||||
{this.pageLinks().map((link, index) => {
|
||||
return <li key={index}>{link}</li>;
|
||||
|
||||
@@ -14,9 +14,7 @@ type Props = RouteComponentProps & {
|
||||
};
|
||||
|
||||
function flatten(text: string, child: any): any {
|
||||
return typeof child === "string"
|
||||
? text + child
|
||||
: React.Children.toArray(child.props.children).reduce(flatten, text);
|
||||
return typeof child === "string" ? text + child : React.Children.toArray(child.props.children).reduce(flatten, text);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,11 +30,7 @@ function MarkdownHeadingRenderer(props: Props) {
|
||||
const children = React.Children.toArray(props.children);
|
||||
const heading = children.reduce(flatten, "");
|
||||
const anchorId = headingToAnchorId(heading);
|
||||
const headingElement = React.createElement(
|
||||
"h" + props.level,
|
||||
{},
|
||||
props.children
|
||||
);
|
||||
const headingElement = React.createElement("h" + props.level, {}, props.children);
|
||||
const href = withContextPath(props.location.pathname + "#" + anchorId);
|
||||
|
||||
return (
|
||||
|
||||
@@ -11,9 +11,7 @@ const Spacing = styled.div`
|
||||
`;
|
||||
|
||||
storiesOf("MarkdownView", module)
|
||||
.addDecorator(story => (
|
||||
<MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>
|
||||
))
|
||||
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||
.add("Default", () => (
|
||||
<Spacing>
|
||||
<MarkdownView content={TestPage} skipHtml={false} />
|
||||
|
||||
@@ -71,13 +71,7 @@ class MarkdownView extends React.Component<Props> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
content,
|
||||
renderers,
|
||||
renderContext,
|
||||
enableAnchorHeadings,
|
||||
skipHtml
|
||||
} = this.props;
|
||||
const { content, renderers, renderContext, enableAnchorHeadings, skipHtml } = this.props;
|
||||
|
||||
const rendererFactory = binder.getExtension("markdown-renderer-factory");
|
||||
let rendererList = renderers;
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import React, { ReactNode } from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
type NotificationType =
|
||||
| "primary"
|
||||
| "info"
|
||||
| "success"
|
||||
| "warning"
|
||||
| "danger"
|
||||
| "inherit";
|
||||
type NotificationType = "primary" | "info" | "success" | "warning" | "danger" | "inherit";
|
||||
|
||||
type Props = {
|
||||
type: NotificationType;
|
||||
|
||||
@@ -248,9 +248,7 @@ xdescribe("paginator rendering tests", () => {
|
||||
urlToOpen = url;
|
||||
};
|
||||
|
||||
const paginator = mount(
|
||||
<Paginator collection={collection} onPageChange={callMe} />
|
||||
);
|
||||
const paginator = mount(<Paginator collection={collection} onPageChange={callMe} />);
|
||||
paginator.find("Button.pagination-previous").simulate("click");
|
||||
|
||||
expect(urlToOpen).toBe("https://www.scm-manager.org");
|
||||
|
||||
@@ -30,11 +30,7 @@ class Paginator extends React.Component<Props> {
|
||||
|
||||
renderPreviousButton() {
|
||||
const { t } = this.props;
|
||||
return this.renderButton(
|
||||
"pagination-previous",
|
||||
t("paginator.previous"),
|
||||
"prev"
|
||||
);
|
||||
return this.renderButton("pagination-previous", t("paginator.previous"), "prev");
|
||||
}
|
||||
|
||||
renderNextButton() {
|
||||
@@ -67,13 +63,7 @@ class Paginator extends React.Component<Props> {
|
||||
}
|
||||
|
||||
currentPage(page: number) {
|
||||
return (
|
||||
<Button
|
||||
className="pagination-link is-current"
|
||||
label={"" + page}
|
||||
disabled={true}
|
||||
/>
|
||||
);
|
||||
return <Button className="pagination-link is-current" label={"" + page} disabled={true} />;
|
||||
}
|
||||
|
||||
pageLinks() {
|
||||
|
||||
@@ -28,12 +28,7 @@ class ProtectedRoute extends React.Component<Props> {
|
||||
|
||||
render() {
|
||||
const { component, authenticated, ...routeProps } = this.props;
|
||||
return (
|
||||
<Route
|
||||
{...routeProps}
|
||||
render={this.renderRoute(component, authenticated)}
|
||||
/>
|
||||
);
|
||||
return <Route {...routeProps} render={this.renderRoute(component, authenticated)} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,7 @@ type Props = {
|
||||
|
||||
class StatePaginator extends React.Component<Props> {
|
||||
renderFirstButton() {
|
||||
return (
|
||||
<Button
|
||||
className="pagination-link"
|
||||
label={"1"}
|
||||
disabled={false}
|
||||
action={() => this.updateCurrentPage(1)}
|
||||
/>
|
||||
);
|
||||
return <Button className="pagination-link" label={"1"} disabled={false} action={() => this.updateCurrentPage(1)} />;
|
||||
}
|
||||
|
||||
updateCurrentPage = (newPage: number) => {
|
||||
|
||||
@@ -5,7 +5,7 @@ import SyntaxHighlighter from "./SyntaxHighlighter";
|
||||
|
||||
import JavaHttpServer from "./__resources__/HttpServer.java";
|
||||
import GoHttpServer from "./__resources__/HttpServer.go";
|
||||
import JsHttpServer from './__resources__/HttpServer.js';
|
||||
import JsHttpServer from "./__resources__/HttpServer.js";
|
||||
import PyHttpServer from "./__resources__/HttpServer.py";
|
||||
|
||||
const Spacing = styled.div`
|
||||
@@ -23,7 +23,7 @@ storiesOf("SyntaxHighlighter", module)
|
||||
<SyntaxHighlighter language="go" value={GoHttpServer} />
|
||||
</Spacing>
|
||||
))
|
||||
.add('Javascript', () => (
|
||||
.add("Javascript", () => (
|
||||
<Spacing>
|
||||
<SyntaxHighlighter language="javascript" value={JsHttpServer} />
|
||||
</Spacing>
|
||||
|
||||
@@ -12,11 +12,7 @@ type Props = {
|
||||
class SyntaxHighlighter extends React.Component<Props> {
|
||||
render() {
|
||||
return (
|
||||
<ReactSyntaxHighlighter
|
||||
showLineNumbers={false}
|
||||
language={this.props.language}
|
||||
style={arduinoLight}
|
||||
>
|
||||
<ReactSyntaxHighlighter showLineNumbers={false} language={this.props.language} style={arduinoLight}>
|
||||
{this.props.value}
|
||||
</ReactSyntaxHighlighter>
|
||||
);
|
||||
|
||||
@@ -17,15 +17,7 @@ class Tag extends React.Component<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
color,
|
||||
icon,
|
||||
label,
|
||||
title,
|
||||
onClick,
|
||||
onRemove
|
||||
} = this.props;
|
||||
const { className, color, icon, label, title, onClick, onRemove } = this.props;
|
||||
let showIcon = null;
|
||||
if (icon) {
|
||||
showIcon = (
|
||||
@@ -42,11 +34,7 @@ class Tag extends React.Component<Props> {
|
||||
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
className={classNames("tag", `is-${color}`, className)}
|
||||
title={title}
|
||||
onClick={onClick}
|
||||
>
|
||||
<span className={classNames("tag", `is-${color}`, className)} title={title} onClick={onClick}>
|
||||
{showIcon}
|
||||
{label}
|
||||
</span>
|
||||
|
||||
@@ -17,15 +17,7 @@ class Tooltip extends React.Component<Props> {
|
||||
const { className, message, location, children } = this.props;
|
||||
const multiline = message.length > 60 ? "is-tooltip-multiline" : "";
|
||||
return (
|
||||
<span
|
||||
className={classNames(
|
||||
"tooltip",
|
||||
"is-tooltip-" + location,
|
||||
multiline,
|
||||
className
|
||||
)}
|
||||
data-tooltip={message}
|
||||
>
|
||||
<span className={classNames("tooltip", "is-tooltip-" + location, multiline, className)} data-tooltip={message}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -23,9 +23,7 @@ export default class UserGroupAutocomplete extends React.Component<Props> {
|
||||
.then(response => response.json())
|
||||
.then((json: AutocompleteObject[]) => {
|
||||
return json.map(element => {
|
||||
const label = element.displayName
|
||||
? `${element.displayName} (${element.id})`
|
||||
: element.id;
|
||||
const label = element.displayName ? `${element.displayName} (${element.id})` : element.id;
|
||||
return {
|
||||
value: element,
|
||||
label
|
||||
|
||||
@@ -4,9 +4,7 @@ import { BackendError } from "./errors";
|
||||
|
||||
describe("create url", () => {
|
||||
it("should not change absolute urls", () => {
|
||||
expect(createUrl("https://www.scm-manager.org")).toBe(
|
||||
"https://www.scm-manager.org"
|
||||
);
|
||||
expect(createUrl("https://www.scm-manager.org")).toBe("https://www.scm-manager.org");
|
||||
});
|
||||
|
||||
it("should add prefix for api", () => {
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { contextPath } from "./urls";
|
||||
import {
|
||||
createBackendError,
|
||||
ForbiddenError,
|
||||
isBackendError,
|
||||
UnauthorizedError
|
||||
} from "./errors";
|
||||
import { createBackendError, ForbiddenError, isBackendError, UnauthorizedError } from "./errors";
|
||||
import { BackendErrorContent } from "./errors";
|
||||
|
||||
const applyFetchOptions: (p: RequestInit) => RequestInit = o => {
|
||||
@@ -52,22 +47,22 @@ class ApiClient {
|
||||
return fetch(createUrl(url), applyFetchOptions({})).then(handleFailure);
|
||||
}
|
||||
|
||||
post(url: string, payload: any, contentType: string = "application/json") {
|
||||
post(url: string, payload: any, contentType = "application/json") {
|
||||
return this.httpRequestWithJSONBody("POST", url, contentType, payload);
|
||||
}
|
||||
|
||||
postBinary(url: string, fileAppender: (p: FormData) => void) {
|
||||
let formData = new FormData();
|
||||
const formData = new FormData();
|
||||
fileAppender(formData);
|
||||
|
||||
let options: RequestInit = {
|
||||
const options: RequestInit = {
|
||||
method: "POST",
|
||||
body: formData
|
||||
};
|
||||
return this.httpRequestWithBinaryBody(options, url);
|
||||
}
|
||||
|
||||
put(url: string, payload: any, contentType: string = "application/json") {
|
||||
put(url: string, payload: any, contentType = "application/json") {
|
||||
return this.httpRequestWithJSONBody("PUT", url, contentType, payload);
|
||||
}
|
||||
|
||||
@@ -87,24 +82,15 @@ class ApiClient {
|
||||
return fetch(createUrl(url), options).then(handleFailure);
|
||||
}
|
||||
|
||||
httpRequestWithJSONBody(
|
||||
method: string,
|
||||
url: string,
|
||||
contentType: string,
|
||||
payload: any
|
||||
): Promise<Response> {
|
||||
let options: RequestInit = {
|
||||
httpRequestWithJSONBody(method: string, url: string, contentType: string, payload: any): Promise<Response> {
|
||||
const options: RequestInit = {
|
||||
method: method,
|
||||
body: JSON.stringify(payload)
|
||||
};
|
||||
return this.httpRequestWithBinaryBody(options, url, contentType);
|
||||
}
|
||||
|
||||
httpRequestWithBinaryBody(
|
||||
options: RequestInit,
|
||||
url: string,
|
||||
contentType?: string
|
||||
) {
|
||||
httpRequestWithBinaryBody(options: RequestInit, url: string, contentType?: string) {
|
||||
options = applyFetchOptions(options);
|
||||
if (contentType) {
|
||||
if (!options.headers) {
|
||||
@@ -118,4 +104,4 @@ class ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
export let apiClient = new ApiClient();
|
||||
export const apiClient = new ApiClient();
|
||||
|
||||
@@ -16,9 +16,7 @@ class AvatarImage extends React.Component<Props> {
|
||||
if (avatarFactory) {
|
||||
const avatar = avatarFactory(person);
|
||||
|
||||
return (
|
||||
<Image className="has-rounded-border" src={avatar} alt={person.name} />
|
||||
);
|
||||
return <Image className="has-rounded-border" src={avatar} alt={person.name} />;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -38,18 +38,7 @@ class Button extends React.Component<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
label,
|
||||
loading,
|
||||
disabled,
|
||||
type,
|
||||
color,
|
||||
className,
|
||||
icon,
|
||||
fullWidth,
|
||||
reducedMobile,
|
||||
children
|
||||
} = this.props;
|
||||
const { label, loading, disabled, type, color, className, icon, fullWidth, reducedMobile, children } = this.props;
|
||||
const loadingClass = loading ? "is-loading" : "";
|
||||
const fullWidthClass = fullWidth ? "is-fullwidth" : "";
|
||||
const reducedMobileClass = reducedMobile ? "is-reduced-mobile" : "";
|
||||
@@ -59,14 +48,7 @@ class Button extends React.Component<Props> {
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
onClick={this.onClick}
|
||||
className={classNames(
|
||||
"button",
|
||||
"is-" + color,
|
||||
loadingClass,
|
||||
fullWidthClass,
|
||||
reducedMobileClass,
|
||||
className
|
||||
)}
|
||||
className={classNames("button", "is-" + color, loadingClass, fullWidthClass, reducedMobileClass, className)}
|
||||
>
|
||||
<span className="icon is-medium">
|
||||
<Icon name={icon} color="inherit" />
|
||||
@@ -83,13 +65,7 @@ class Button extends React.Component<Props> {
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
onClick={this.onClick}
|
||||
className={classNames(
|
||||
"button",
|
||||
"is-" + color,
|
||||
loadingClass,
|
||||
fullWidthClass,
|
||||
className
|
||||
)}
|
||||
className={classNames("button", "is-" + color, loadingClass, fullWidthClass, className)}
|
||||
>
|
||||
{label} {children}
|
||||
</button>
|
||||
|
||||
@@ -28,11 +28,7 @@ class ButtonAddons extends React.Component<Props> {
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Flex className={classNames("field", "has-addons", className)}>
|
||||
{childWrapper}
|
||||
</Flex>
|
||||
);
|
||||
return <Flex className={classNames("field", "has-addons", className)}>{childWrapper}</Flex>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,7 @@ class ButtonGroup extends React.Component<Props> {
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={classNames("field", "is-grouped", className)}>
|
||||
{childWrapper}
|
||||
</div>
|
||||
);
|
||||
return <div className={classNames("field", "is-grouped", className)}>{childWrapper}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@ class DownloadButton extends React.Component<Props> {
|
||||
because jsx a does not the custom disabled attribute
|
||||
but bulma does.
|
||||
// @ts-ignore */}
|
||||
<a
|
||||
className="button is-link"
|
||||
href={url}
|
||||
disabled={disabled}
|
||||
onClick={onClickOrDefault}
|
||||
>
|
||||
<a className="button is-link" href={url} disabled={disabled} onClick={onClickOrDefault}>
|
||||
<span className="icon is-medium">
|
||||
<i className="fas fa-arrow-circle-down" />
|
||||
</span>
|
||||
|
||||
@@ -11,27 +11,13 @@ import EditButton from "./EditButton";
|
||||
import SubmitButton from "./SubmitButton";
|
||||
import { ReactElement } from "react";
|
||||
|
||||
const colors = [
|
||||
"primary",
|
||||
"link",
|
||||
"info",
|
||||
"success",
|
||||
"warning",
|
||||
"danger",
|
||||
"white",
|
||||
"light",
|
||||
"dark",
|
||||
"black",
|
||||
"text"
|
||||
];
|
||||
const colors = ["primary", "link", "info", "success", "warning", "danger", "white", "light", "dark", "black", "text"];
|
||||
|
||||
const Spacing = styled.div`
|
||||
padding: 1em;
|
||||
`;
|
||||
|
||||
const RoutingDecorator = story => (
|
||||
<MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>
|
||||
);
|
||||
const RoutingDecorator = story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>;
|
||||
|
||||
const SpacingDecorator = story => <Spacing>{story()}</Spacing>;
|
||||
|
||||
@@ -65,17 +51,7 @@ buttonStory("AddButton", () => <AddButton>Add</AddButton>);
|
||||
buttonStory("CreateButton", () => <CreateButton>Create</CreateButton>);
|
||||
buttonStory("DeleteButton", () => <DeleteButton>Delete</DeleteButton>);
|
||||
buttonStory("DownloadButton", () => (
|
||||
<DownloadButton
|
||||
displayName="Download"
|
||||
disabled={false}
|
||||
url=""
|
||||
></DownloadButton>
|
||||
)).add("Disabled", () => (
|
||||
<DownloadButton
|
||||
displayName="Download"
|
||||
disabled={true}
|
||||
url=""
|
||||
></DownloadButton>
|
||||
));
|
||||
<DownloadButton displayName="Download" disabled={false} url=""></DownloadButton>
|
||||
)).add("Disabled", () => <DownloadButton displayName="Download" disabled={true} url=""></DownloadButton>);
|
||||
buttonStory("EditButton", () => <EditButton>Edit</EditButton>);
|
||||
buttonStory("SubmitButton", () => <SubmitButton>Submit</SubmitButton>);
|
||||
|
||||
@@ -9,6 +9,4 @@ export { default as SubmitButton } from "./SubmitButton";
|
||||
export { default as DownloadButton } from "./DownloadButton";
|
||||
export { default as ButtonGroup } from "./ButtonGroup";
|
||||
export { default as ButtonAddons } from "./ButtonAddons";
|
||||
export {
|
||||
default as RemoveEntryOfTableButton
|
||||
} from "./RemoveEntryOfTableButton";
|
||||
export { default as RemoveEntryOfTableButton } from "./RemoveEntryOfTableButton";
|
||||
|
||||
@@ -123,20 +123,16 @@ class Configuration extends React.Component<Props, State> {
|
||||
|
||||
const modificationUrl = this.getModificationUrl();
|
||||
if (modificationUrl) {
|
||||
apiClient
|
||||
.put(
|
||||
modificationUrl,
|
||||
modifiedConfiguration,
|
||||
this.getContentType()
|
||||
)
|
||||
.then(() =>
|
||||
this.setState({
|
||||
modifying: false,
|
||||
configChanged: true,
|
||||
valid: false
|
||||
})
|
||||
)
|
||||
.catch(this.handleError);
|
||||
apiClient
|
||||
.put(modificationUrl, modifiedConfiguration, this.getContentType())
|
||||
.then(() =>
|
||||
this.setState({
|
||||
modifying: false,
|
||||
configChanged: true,
|
||||
valid: false
|
||||
})
|
||||
)
|
||||
.catch(this.handleError);
|
||||
} else {
|
||||
this.setState({
|
||||
error: new Error("no modification link available")
|
||||
@@ -186,11 +182,7 @@ class Configuration extends React.Component<Props, State> {
|
||||
<form onSubmit={this.modifyConfiguration}>
|
||||
{this.props.render(renderProps)}
|
||||
<hr />
|
||||
<SubmitButton
|
||||
label={t("config.form.submit")}
|
||||
disabled={!valid || readOnly}
|
||||
loading={modifying}
|
||||
/>
|
||||
<SubmitButton label={t("config.form.submit")} disabled={!valid || readOnly} loading={modifying} />
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@ type RepositoryRouteProps = {
|
||||
};
|
||||
|
||||
class ConfigurationBinder {
|
||||
i18nNamespace: string = "plugins";
|
||||
i18nNamespace = "plugins";
|
||||
|
||||
navLink(to: string, labelI18nKey: string, t: any) {
|
||||
return <NavLink to={to} label={t(labelI18nKey)} />;
|
||||
@@ -26,12 +26,7 @@ class ConfigurationBinder {
|
||||
return <Route path={path} render={() => Component} exact />;
|
||||
}
|
||||
|
||||
bindGlobal(
|
||||
to: string,
|
||||
labelI18nKey: string,
|
||||
linkName: string,
|
||||
ConfigurationComponent: any
|
||||
) {
|
||||
bindGlobal(to: string, labelI18nKey: string, linkName: string, ConfigurationComponent: any) {
|
||||
// create predicate based on the link name of the index resource
|
||||
// if the linkname is not available, the navigation link and the route are not bound to the extension points
|
||||
const configPredicate = (props: any) => {
|
||||
@@ -47,19 +42,12 @@ class ConfigurationBinder {
|
||||
binder.bind("admin.setting", ConfigNavLink, configPredicate);
|
||||
|
||||
// route for global configuration, passes the link from the index resource to component
|
||||
const ConfigRoute = ({
|
||||
url,
|
||||
links,
|
||||
...additionalProps
|
||||
}: GlobalRouteProps) => {
|
||||
const ConfigRoute = ({ url, links, ...additionalProps }: GlobalRouteProps) => {
|
||||
const link = links[linkName];
|
||||
if (link) {
|
||||
return this.route(
|
||||
url + "/settings" + to,
|
||||
<ConfigurationComponent
|
||||
link={(link as Link).href}
|
||||
{...additionalProps}
|
||||
/>
|
||||
<ConfigurationComponent link={(link as Link).href} {...additionalProps} />
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -68,20 +56,11 @@ class ConfigurationBinder {
|
||||
binder.bind("admin.route", ConfigRoute, configPredicate);
|
||||
}
|
||||
|
||||
bindRepository(
|
||||
to: string,
|
||||
labelI18nKey: string,
|
||||
linkName: string,
|
||||
RepositoryComponent: any
|
||||
) {
|
||||
bindRepository(to: string, labelI18nKey: string, linkName: string, RepositoryComponent: any) {
|
||||
// create predicate based on the link name of the current repository route
|
||||
// if the linkname is not available, the navigation link and the route are not bound to the extension points
|
||||
const repoPredicate = (props: any) => {
|
||||
return (
|
||||
props.repository &&
|
||||
props.repository._links &&
|
||||
props.repository._links[linkName]
|
||||
);
|
||||
return props.repository && props.repository._links && props.repository._links[linkName];
|
||||
};
|
||||
|
||||
// create NavigationLink with translated label
|
||||
@@ -93,20 +72,12 @@ class ConfigurationBinder {
|
||||
binder.bind("repository.navigation", RepoNavLink, repoPredicate);
|
||||
|
||||
// route for global configuration, passes the current repository to component
|
||||
const RepoRoute = ({
|
||||
url,
|
||||
repository,
|
||||
...additionalProps
|
||||
}: RepositoryRouteProps) => {
|
||||
const RepoRoute = ({ url, repository, ...additionalProps }: RepositoryRouteProps) => {
|
||||
const link = repository._links[linkName];
|
||||
if (link) {
|
||||
return this.route(
|
||||
url + to,
|
||||
<RepositoryComponent
|
||||
repository={repository}
|
||||
link={(link as Link).href}
|
||||
{...additionalProps}
|
||||
/>
|
||||
<RepositoryComponent repository={repository} link={(link as Link).href} {...additionalProps} />
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -115,20 +86,11 @@ class ConfigurationBinder {
|
||||
binder.bind("repository.route", RepoRoute, repoPredicate);
|
||||
}
|
||||
|
||||
bindRepositorySetting(
|
||||
to: string,
|
||||
labelI18nKey: string,
|
||||
linkName: string,
|
||||
RepositoryComponent: any
|
||||
) {
|
||||
bindRepositorySetting(to: string, labelI18nKey: string, linkName: string, RepositoryComponent: any) {
|
||||
// create predicate based on the link name of the current repository route
|
||||
// if the linkname is not available, the navigation link and the route are not bound to the extension points
|
||||
const repoPredicate = (props: any) => {
|
||||
return (
|
||||
props.repository &&
|
||||
props.repository._links &&
|
||||
props.repository._links[linkName]
|
||||
);
|
||||
return props.repository && props.repository._links && props.repository._links[linkName];
|
||||
};
|
||||
|
||||
// create NavigationLink with translated label
|
||||
@@ -140,20 +102,12 @@ class ConfigurationBinder {
|
||||
binder.bind("repository.setting", RepoNavLink, repoPredicate);
|
||||
|
||||
// route for global configuration, passes the current repository to component
|
||||
const RepoRoute = ({
|
||||
url,
|
||||
repository,
|
||||
...additionalProps
|
||||
}: RepositoryRouteProps) => {
|
||||
const RepoRoute = ({ url, repository, ...additionalProps }: RepositoryRouteProps) => {
|
||||
const link = repository._links[linkName];
|
||||
if (link) {
|
||||
return this.route(
|
||||
url + "/settings" + to,
|
||||
<RepositoryComponent
|
||||
repository={repository}
|
||||
link={(link as Link).href}
|
||||
{...additionalProps}
|
||||
/>
|
||||
<RepositoryComponent repository={repository} link={(link as Link).href} {...additionalProps} />
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
BackendError,
|
||||
UnauthorizedError,
|
||||
createBackendError,
|
||||
NotFoundError
|
||||
} from "./errors";
|
||||
import { BackendError, UnauthorizedError, createBackendError, NotFoundError } from "./errors";
|
||||
|
||||
describe("test createBackendError", () => {
|
||||
const earthNotFoundError = {
|
||||
|
||||
@@ -64,10 +64,7 @@ export class ConflictError extends BackendError {
|
||||
}
|
||||
}
|
||||
|
||||
export function createBackendError(
|
||||
content: BackendErrorContent,
|
||||
statusCode: number
|
||||
) {
|
||||
export function createBackendError(content: BackendErrorContent, statusCode: number) {
|
||||
switch (statusCode) {
|
||||
case 404:
|
||||
return new NotFoundError(content, statusCode);
|
||||
@@ -79,8 +76,5 @@ export function createBackendError(
|
||||
}
|
||||
|
||||
export function isBackendError(response: Response) {
|
||||
return (
|
||||
response.headers.get("Content-Type") ===
|
||||
"application/vnd.scmm-error+json;v=2"
|
||||
);
|
||||
return response.headers.get("Content-Type") === "application/vnd.scmm-error+json;v=2";
|
||||
}
|
||||
|
||||
@@ -27,11 +27,7 @@ class AddEntryToTableField extends React.Component<Props, State> {
|
||||
|
||||
isValid = () => {
|
||||
const { validateEntry } = this.props;
|
||||
if (
|
||||
!this.state.entryToAdd ||
|
||||
this.state.entryToAdd === "" ||
|
||||
!validateEntry
|
||||
) {
|
||||
if (!this.state.entryToAdd || this.state.entryToAdd === "" || !validateEntry) {
|
||||
return true;
|
||||
} else {
|
||||
return validateEntry(this.state.entryToAdd);
|
||||
@@ -39,13 +35,7 @@ class AddEntryToTableField extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
disabled,
|
||||
buttonLabel,
|
||||
fieldLabel,
|
||||
errorMessage,
|
||||
helpText
|
||||
} = this.props;
|
||||
const { disabled, buttonLabel, fieldLabel, errorMessage, helpText } = this.props;
|
||||
return (
|
||||
<div className="field">
|
||||
<InputField
|
||||
|
||||
@@ -54,11 +54,7 @@ class AutocompleteAddEntryToTableField extends React.Component<Props, State> {
|
||||
creatable={true}
|
||||
/>
|
||||
|
||||
<AddButton
|
||||
label={buttonLabel}
|
||||
action={this.addButtonClicked}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<AddButton label={buttonLabel} action={this.addButtonClicked} disabled={disabled} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,33 +12,14 @@ type Props = {
|
||||
|
||||
class DropDown extends React.Component<Props> {
|
||||
render() {
|
||||
const {
|
||||
options,
|
||||
optionValues,
|
||||
preselectedOption,
|
||||
className,
|
||||
disabled
|
||||
} = this.props;
|
||||
const { options, optionValues, preselectedOption, className, disabled } = this.props;
|
||||
return (
|
||||
<div
|
||||
className={classNames(className, "select", disabled ? "disabled" : "")}
|
||||
>
|
||||
<select
|
||||
value={preselectedOption ? preselectedOption : ""}
|
||||
onChange={this.change}
|
||||
disabled={disabled}
|
||||
>
|
||||
<div className={classNames(className, "select", disabled ? "disabled" : "")}>
|
||||
<select value={preselectedOption ? preselectedOption : ""} onChange={this.change} disabled={disabled}>
|
||||
<option key="" />
|
||||
{options.map((option, index) => {
|
||||
return (
|
||||
<option
|
||||
key={option}
|
||||
value={
|
||||
optionValues && optionValues[index]
|
||||
? optionValues[index]
|
||||
: option
|
||||
}
|
||||
>
|
||||
<option key={option} value={optionValues && optionValues[index] ? optionValues[index] : option}>
|
||||
{option}
|
||||
</option>
|
||||
);
|
||||
|
||||
@@ -47,22 +47,9 @@ class InputField extends React.Component<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
type,
|
||||
placeholder,
|
||||
value,
|
||||
validationError,
|
||||
errorMessage,
|
||||
disabled,
|
||||
label,
|
||||
helpText
|
||||
} = this.props;
|
||||
const { type, placeholder, value, validationError, errorMessage, disabled, label, helpText } = this.props;
|
||||
const errorView = validationError ? "is-danger" : "";
|
||||
const helper = validationError ? (
|
||||
<p className="help is-danger">{errorMessage}</p>
|
||||
) : (
|
||||
""
|
||||
);
|
||||
const helper = validationError ? <p className="help is-danger">{errorMessage}</p> : "";
|
||||
return (
|
||||
<div className="field">
|
||||
<LabelWithHelpIcon label={label} helpText={helpText} />
|
||||
|
||||
@@ -85,8 +85,7 @@ class PasswordConfirmation extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
handlePasswordChange = (password: string) => {
|
||||
const passwordConfirmationFailed =
|
||||
password !== this.state.confirmedPassword;
|
||||
const passwordConfirmationFailed = password !== this.state.confirmedPassword;
|
||||
|
||||
this.setState(
|
||||
{
|
||||
|
||||
@@ -33,11 +33,7 @@ export default class TagGroup extends React.Component<Props> {
|
||||
return (
|
||||
<div className="control" key={key}>
|
||||
<div className="tags has-addons">
|
||||
<Tag
|
||||
color="info is-outlined"
|
||||
label={item.displayName}
|
||||
onRemove={() => this.removeEntry(item)}
|
||||
/>
|
||||
<Tag color="info is-outlined" label={item.displayName} onRemove={() => this.removeEntry(item)} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// @create-index
|
||||
|
||||
export { default as AddEntryToTableField } from "./AddEntryToTableField";
|
||||
export {
|
||||
default as AutocompleteAddEntryToTableField
|
||||
} from "./AutocompleteAddEntryToTableField";
|
||||
export { default as AutocompleteAddEntryToTableField } from "./AutocompleteAddEntryToTableField";
|
||||
export { default as TagGroup } from "./TagGroup";
|
||||
export { default as MemberNameTagGroup } from "./MemberNameTagGroup";
|
||||
export { default as Checkbox } from "./Checkbox";
|
||||
|
||||
@@ -4,6 +4,19 @@ import * as validation from "./validation";
|
||||
import * as urls from "./urls";
|
||||
import * as repositories from "./repositories";
|
||||
|
||||
// not sure if it is required
|
||||
import {
|
||||
File,
|
||||
FileChangeType,
|
||||
Hunk,
|
||||
Change,
|
||||
BaseContext,
|
||||
AnnotationFactory,
|
||||
AnnotationFactoryContext,
|
||||
DiffEventHandler,
|
||||
DiffEventContext
|
||||
} from "./repos";
|
||||
|
||||
export { validation, urls, repositories };
|
||||
|
||||
export { default as DateFromNow } from "./DateFromNow";
|
||||
@@ -51,19 +64,6 @@ export * from "./modals";
|
||||
export * from "./navigation";
|
||||
export * from "./repos";
|
||||
|
||||
// not sure if it is required
|
||||
import {
|
||||
File,
|
||||
FileChangeType,
|
||||
Hunk,
|
||||
Change,
|
||||
BaseContext,
|
||||
AnnotationFactory,
|
||||
AnnotationFactoryContext,
|
||||
DiffEventHandler,
|
||||
DiffEventContext
|
||||
} from "./repos";
|
||||
|
||||
export {
|
||||
File,
|
||||
FileChangeType,
|
||||
|
||||
@@ -45,8 +45,7 @@ export default class Page extends React.Component<Props> {
|
||||
|
||||
isPageAction(node: any) {
|
||||
return (
|
||||
node.displayName === PageActions.displayName ||
|
||||
(node.type && node.type.displayName === PageActions.displayName)
|
||||
node.displayName === PageActions.displayName || (node.type && node.type.displayName === PageActions.displayName)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -60,12 +59,7 @@ export default class Page extends React.Component<Props> {
|
||||
if (this.isPageAction(child)) {
|
||||
pageActions = (
|
||||
<PageActionContainer
|
||||
className={classNames(
|
||||
"column",
|
||||
"is-three-fifths",
|
||||
"is-mobile-action-spacing",
|
||||
"is-flex"
|
||||
)}
|
||||
className={classNames("column", "is-three-fifths", "is-mobile-action-spacing", "is-flex")}
|
||||
>
|
||||
{child}
|
||||
</PageActionContainer>
|
||||
@@ -74,9 +68,7 @@ export default class Page extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let underline = pageActionsExists ? (
|
||||
<hr className="header-with-actions" />
|
||||
) : null;
|
||||
const underline = pageActionsExists ? <hr className="header-with-actions" /> : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -102,7 +94,7 @@ export default class Page extends React.Component<Props> {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
let content: ReactNode[] = [];
|
||||
const content: ReactNode[] = [];
|
||||
React.Children.forEach(children, child => {
|
||||
if (child) {
|
||||
if (!this.isPageAction(child)) {
|
||||
|
||||
@@ -37,11 +37,7 @@ class ConfirmAlert extends React.Component<Props> {
|
||||
<div className="field is-grouped">
|
||||
{buttons.map((button, i) => (
|
||||
<p className="control">
|
||||
<a
|
||||
className="button is-info"
|
||||
key={i}
|
||||
onClick={() => this.handleClickButton(button)}
|
||||
>
|
||||
<a className="button is-info" key={i} onClick={() => this.handleClickButton(button)}>
|
||||
{button.label}
|
||||
</a>
|
||||
</p>
|
||||
@@ -49,15 +45,7 @@ class ConfirmAlert extends React.Component<Props> {
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={title}
|
||||
closeFunction={() => this.close()}
|
||||
body={body}
|
||||
active={true}
|
||||
footer={footer}
|
||||
/>
|
||||
);
|
||||
return <Modal title={title} closeFunction={() => this.close()} body={body} active={true} footer={footer} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,15 +17,7 @@ class Modal extends React.Component<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
closeFunction,
|
||||
body,
|
||||
footer,
|
||||
active,
|
||||
className,
|
||||
headColor
|
||||
} = this.props;
|
||||
const { title, closeFunction, body, footer, active, className, headColor } = this.props;
|
||||
|
||||
const isActive = active ? "is-active" : null;
|
||||
|
||||
@@ -38,18 +30,9 @@ class Modal extends React.Component<Props> {
|
||||
<div className={classNames("modal", className, isActive)}>
|
||||
<div className="modal-background" />
|
||||
<div className="modal-card">
|
||||
<header
|
||||
className={classNames(
|
||||
"modal-card-head",
|
||||
`has-background-${headColor}`
|
||||
)}
|
||||
>
|
||||
<header className={classNames("modal-card-head", `has-background-${headColor}`)}>
|
||||
<p className="modal-card-title is-marginless">{title}</p>
|
||||
<button
|
||||
className="delete"
|
||||
aria-label="close"
|
||||
onClick={closeFunction}
|
||||
/>
|
||||
<button className="delete" aria-label="close" onClick={closeFunction} />
|
||||
</header>
|
||||
<section className="modal-card-body">{body}</section>
|
||||
{showFooter}
|
||||
|
||||
@@ -47,9 +47,7 @@ class NavLink extends React.Component<Props> {
|
||||
render() {
|
||||
const { to, activeOnlyWhenExact } = this.props;
|
||||
|
||||
return (
|
||||
<Route path={to} exact={activeOnlyWhenExact} children={this.renderLink} />
|
||||
);
|
||||
return <Route path={to} exact={activeOnlyWhenExact} children={this.renderLink} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {ReactNode} from "react";
|
||||
import React, { ReactNode } from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import PrimaryNavigationLink from "./PrimaryNavigationLink";
|
||||
import { Links } from "@scm-manager/ui-types";
|
||||
@@ -18,14 +18,7 @@ class PrimaryNavigation extends React.Component<Props> {
|
||||
return (to: string, match: string, label: string, linkName: string) => {
|
||||
const link = links[linkName];
|
||||
if (link) {
|
||||
const navigationItem = (
|
||||
<PrimaryNavigationLink
|
||||
to={to}
|
||||
match={match}
|
||||
label={t(label)}
|
||||
key={linkName}
|
||||
/>
|
||||
);
|
||||
const navigationItem = <PrimaryNavigationLink to={to} match={match} label={t(label)} key={linkName} />;
|
||||
navigationItems.push(navigationItem);
|
||||
}
|
||||
};
|
||||
@@ -41,11 +34,7 @@ class PrimaryNavigation extends React.Component<Props> {
|
||||
|
||||
if (binder.hasExtension("primary-navigation.logout", props)) {
|
||||
navigationItems.push(
|
||||
<ExtensionPoint
|
||||
key="primary-navigation.logout"
|
||||
name="primary-navigation.logout"
|
||||
props={props}
|
||||
/>
|
||||
<ExtensionPoint key="primary-navigation.logout" name="primary-navigation.logout" props={props} />
|
||||
);
|
||||
} else {
|
||||
append("/logout", "/logout", "primary-navigation.logout", "logout");
|
||||
@@ -64,26 +53,12 @@ class PrimaryNavigation extends React.Component<Props> {
|
||||
const append = this.createNavigationAppender(navigationItems);
|
||||
if (binder.hasExtension("primary-navigation.first-menu", props)) {
|
||||
navigationItems.push(
|
||||
<ExtensionPoint
|
||||
key="primary-navigation.first-menu"
|
||||
name="primary-navigation.first-menu"
|
||||
props={props}
|
||||
/>
|
||||
<ExtensionPoint key="primary-navigation.first-menu" name="primary-navigation.first-menu" props={props} />
|
||||
);
|
||||
}
|
||||
append(
|
||||
"/repos/",
|
||||
"/(repo|repos)",
|
||||
"primary-navigation.repositories",
|
||||
"repositories"
|
||||
);
|
||||
append("/repos/", "/(repo|repos)", "primary-navigation.repositories", "repositories");
|
||||
append("/users/", "/(user|users)", "primary-navigation.users", "users");
|
||||
append(
|
||||
"/groups/",
|
||||
"/(group|groups)",
|
||||
"primary-navigation.groups",
|
||||
"groups"
|
||||
);
|
||||
append("/groups/", "/(group|groups)", "primary-navigation.groups", "groups");
|
||||
append("/admin", "/admin", "primary-navigation.admin", "config");
|
||||
|
||||
navigationItems.push(
|
||||
|
||||
@@ -21,13 +21,7 @@ class PrimaryNavigationLink extends React.Component<Props> {
|
||||
render() {
|
||||
const { to, match, activeOnlyWhenExact } = this.props;
|
||||
const path = match ? match : to;
|
||||
return (
|
||||
<Route
|
||||
path={path}
|
||||
exact={activeOnlyWhenExact}
|
||||
children={this.renderLink}
|
||||
/>
|
||||
);
|
||||
return <Route path={path} exact={activeOnlyWhenExact} children={this.renderLink} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,17 +48,11 @@ class SubNavigation extends React.Component<Props> {
|
||||
const { to, activeOnlyWhenExact } = this.props;
|
||||
|
||||
// removes last part of url
|
||||
let parents = to.split("/");
|
||||
const parents = to.split("/");
|
||||
parents.splice(-1, 1);
|
||||
let parent = parents.join("/");
|
||||
const parent = parents.join("/");
|
||||
|
||||
return (
|
||||
<Route
|
||||
path={parent}
|
||||
exact={activeOnlyWhenExact}
|
||||
children={this.renderLink}
|
||||
/>
|
||||
);
|
||||
return <Route path={parent} exact={activeOnlyWhenExact} children={this.renderLink} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,7 @@ import React from "react";
|
||||
import { translate, InjectedTranslateProps } from "react-i18next";
|
||||
import classNames from "classnames";
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
Change,
|
||||
Diff as DiffComponent,
|
||||
getChangeKey,
|
||||
Hunk
|
||||
} from "react-diff-view";
|
||||
import { Change, Diff as DiffComponent, getChangeKey, Hunk } from "react-diff-view";
|
||||
import { Button, ButtonGroup } from "../buttons";
|
||||
import Tag from "../Tag";
|
||||
import Icon from "../Icon";
|
||||
@@ -183,14 +178,10 @@ class DiffFile extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
renderFileTitle = (file: File) => {
|
||||
if (
|
||||
file.oldPath !== file.newPath &&
|
||||
(file.type === "copy" || file.type === "rename")
|
||||
) {
|
||||
if (file.oldPath !== file.newPath && (file.type === "copy" || file.type === "rename")) {
|
||||
return (
|
||||
<>
|
||||
{file.oldPath} <Icon name="arrow-right" color="inherit" />{" "}
|
||||
{file.newPath}
|
||||
{file.oldPath} <Icon name="arrow-right" color="inherit" /> {file.newPath}
|
||||
</>
|
||||
);
|
||||
} else if (file.type === "delete") {
|
||||
@@ -200,10 +191,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
hoverFileTitle = (file: File): string => {
|
||||
if (
|
||||
file.oldPath !== file.newPath &&
|
||||
(file.type === "copy" || file.type === "rename")
|
||||
) {
|
||||
if (file.oldPath !== file.newPath && (file.type === "copy" || file.type === "rename")) {
|
||||
return `${file.oldPath} > ${file.newPath}`;
|
||||
} else if (file.type === "delete") {
|
||||
return file.oldPath;
|
||||
@@ -222,19 +210,9 @@ class DiffFile extends React.Component<Props, State> {
|
||||
value = file.type;
|
||||
}
|
||||
const color =
|
||||
value === "added"
|
||||
? "success is-outlined"
|
||||
: value === "deleted"
|
||||
? "danger is-outlined"
|
||||
: "info is-outlined";
|
||||
value === "added" ? "success is-outlined" : value === "deleted" ? "danger is-outlined" : "info is-outlined";
|
||||
|
||||
return (
|
||||
<ChangeTypeTag
|
||||
className={classNames("is-rounded", "has-text-weight-normal")}
|
||||
color={color}
|
||||
label={value}
|
||||
/>
|
||||
);
|
||||
return <ChangeTypeTag className={classNames("is-rounded", "has-text-weight-normal")} color={color} label={value} />;
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -245,9 +223,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
let body = null;
|
||||
let icon = "angle-right";
|
||||
if (!collapsed) {
|
||||
const fileAnnotations = fileAnnotationFactory
|
||||
? fileAnnotationFactory(file)
|
||||
: null;
|
||||
const fileAnnotations = fileAnnotationFactory ? fileAnnotationFactory(file) : null;
|
||||
icon = "angle-down";
|
||||
body = (
|
||||
<div className="panel-block is-paddingless">
|
||||
@@ -258,32 +234,20 @@ class DiffFile extends React.Component<Props, State> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const collapseIcon =
|
||||
file && !file.isBinary ? <Icon name={icon} color="inherit" /> : null;
|
||||
const collapseIcon = file && !file.isBinary ? <Icon name={icon} color="inherit" /> : null;
|
||||
|
||||
const fileControls = fileControlFactory
|
||||
? fileControlFactory(file, this.setCollapse)
|
||||
: null;
|
||||
const fileControls = fileControlFactory ? fileControlFactory(file, this.setCollapse) : null;
|
||||
return (
|
||||
<DiffFilePanel
|
||||
className={classNames("panel", "is-size-6")}
|
||||
collapsed={(file && file.isBinary) || collapsed}
|
||||
>
|
||||
<DiffFilePanel className={classNames("panel", "is-size-6")} collapsed={(file && file.isBinary) || collapsed}>
|
||||
<div className="panel-heading">
|
||||
<FlexWrapLevel className="level">
|
||||
<FullWidthTitleHeader
|
||||
className={classNames(
|
||||
"level-left",
|
||||
"is-flex",
|
||||
"has-cursor-pointer"
|
||||
)}
|
||||
className={classNames("level-left", "is-flex", "has-cursor-pointer")}
|
||||
onClick={this.toggleCollapse}
|
||||
title={this.hoverFileTitle(file)}
|
||||
>
|
||||
{collapseIcon}
|
||||
<TitleWrapper
|
||||
className={classNames("is-ellipsis-overflow", "is-size-6")}
|
||||
>
|
||||
<TitleWrapper className={classNames("is-ellipsis-overflow", "is-size-6")}>
|
||||
{this.renderFileTitle(file)}
|
||||
</TitleWrapper>
|
||||
{this.renderChangeTag(file)}
|
||||
|
||||
@@ -63,10 +63,7 @@ export type DiffEventContext = BaseContext & {
|
||||
|
||||
export type DiffEventHandler = (context: DiffEventContext) => void;
|
||||
|
||||
export type FileControlFactory = (
|
||||
file: File,
|
||||
setCollapseState: (p: boolean) => void
|
||||
) => ReactNode | null | undefined;
|
||||
export type FileControlFactory = (file: File, setCollapseState: (p: boolean) => void) => ReactNode | null | undefined;
|
||||
|
||||
export type DiffObjectProps = {
|
||||
sideBySide: boolean;
|
||||
|
||||
@@ -27,10 +27,7 @@ class ChangesetAuthor extends React.Component<Props> {
|
||||
renderWithMail(name: string, mail: string) {
|
||||
const { t } = this.props;
|
||||
return (
|
||||
<a
|
||||
href={"mailto:" + mail}
|
||||
title={t("changeset.author.mailto") + " " + mail}
|
||||
>
|
||||
<a href={"mailto:" + mail} title={t("changeset.author.mailto") + " " + mail}>
|
||||
{name}
|
||||
</a>
|
||||
);
|
||||
|
||||
@@ -19,18 +19,8 @@ class ChangesetButtonGroup extends React.Component<Props> {
|
||||
const sourcesLink = createSourcesLink(repository, changeset);
|
||||
return (
|
||||
<ButtonAddons className="is-marginless">
|
||||
<Button
|
||||
link={changesetLink}
|
||||
icon="exchange-alt"
|
||||
label={t("changeset.buttons.details")}
|
||||
reducedMobile={true}
|
||||
/>
|
||||
<Button
|
||||
link={sourcesLink}
|
||||
icon="code"
|
||||
label={t("changeset.buttons.sources")}
|
||||
reducedMobile={true}
|
||||
/>
|
||||
<Button link={changesetLink} icon="exchange-alt" label={t("changeset.buttons.details")} reducedMobile={true} />
|
||||
<Button link={sourcesLink} icon="code" label={t("changeset.buttons.sources")} reducedMobile={true} />
|
||||
</ButtonAddons>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,11 +28,7 @@ class ChangesetDiff extends React.Component<Props> {
|
||||
render() {
|
||||
const { changeset, defaultCollapse, t } = this.props;
|
||||
if (!this.isDiffSupported(changeset)) {
|
||||
return (
|
||||
<Notification type="danger">
|
||||
{t("changeset.diffNotSupported")}
|
||||
</Notification>
|
||||
);
|
||||
return <Notification type="danger">{t("changeset.diffNotSupported")}</Notification>;
|
||||
} else {
|
||||
const url = this.createUrl(changeset);
|
||||
return <LoadingDiff url={url} defaultCollapse={defaultCollapse} />;
|
||||
|
||||
@@ -12,13 +12,7 @@ class ChangesetList extends React.Component<Props> {
|
||||
render() {
|
||||
const { repository, changesets } = this.props;
|
||||
const content = changesets.map(changeset => {
|
||||
return (
|
||||
<ChangesetRow
|
||||
key={changeset.id}
|
||||
repository={repository}
|
||||
changeset={changeset}
|
||||
/>
|
||||
);
|
||||
return <ChangesetRow key={changeset.id} repository={repository} changeset={changeset} />;
|
||||
});
|
||||
return <>{content}</>;
|
||||
}
|
||||
|
||||
@@ -98,18 +98,10 @@ class ChangesetRow extends React.Component<Props> {
|
||||
</ExtensionPoint>
|
||||
</h4>
|
||||
<p className="is-hidden-touch">
|
||||
<Interpolate
|
||||
i18nKey="changeset.summary"
|
||||
id={changesetId}
|
||||
time={dateFromNow}
|
||||
/>
|
||||
<Interpolate i18nKey="changeset.summary" id={changesetId} time={dateFromNow} />
|
||||
</p>
|
||||
<p className="is-hidden-desktop">
|
||||
<Interpolate
|
||||
i18nKey="changeset.shortSummary"
|
||||
id={changesetId}
|
||||
time={dateFromNow}
|
||||
/>
|
||||
<Interpolate i18nKey="changeset.shortSummary" id={changesetId} time={dateFromNow} />
|
||||
</p>
|
||||
<AuthorWrapper className="is-size-7">
|
||||
<ChangesetAuthor changeset={changeset} />
|
||||
@@ -123,10 +115,7 @@ class ChangesetRow extends React.Component<Props> {
|
||||
</div>
|
||||
</div>
|
||||
<VCenteredChildColumn className={classNames("column", "is-flex")}>
|
||||
<ChangesetButtonGroup
|
||||
repository={repository}
|
||||
changeset={changeset}
|
||||
/>
|
||||
<ChangesetButtonGroup repository={repository} changeset={changeset} />
|
||||
<ExtensionPoint
|
||||
name="changeset.right"
|
||||
props={{
|
||||
|
||||
@@ -17,10 +17,7 @@ class ChangesetTagsCollapsed extends React.Component<Props> {
|
||||
const message = tags.map(tag => tag.name).join(", ");
|
||||
return (
|
||||
<Tooltip location="top" message={message}>
|
||||
<ChangesetTagBase
|
||||
icon="tags"
|
||||
label={tags.length + " " + t("changeset.tags")}
|
||||
/>
|
||||
<ChangesetTagBase icon="tags" label={tags.length + " " + t("changeset.tags")} />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,17 +5,11 @@ export type Description = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
export function createChangesetLink(
|
||||
repository: Repository,
|
||||
changeset: Changeset
|
||||
) {
|
||||
export function createChangesetLink(repository: Repository, changeset: Changeset) {
|
||||
return `/repo/${repository.namespace}/${repository.name}/changeset/${changeset.id}`;
|
||||
}
|
||||
|
||||
export function createSourcesLink(
|
||||
repository: Repository,
|
||||
changeset: Changeset
|
||||
) {
|
||||
export function createSourcesLink(repository: Repository, changeset: Changeset) {
|
||||
return `/repo/${repository.namespace}/${repository.name}/sources/${changeset.id}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
import { File, FileChangeType, Hunk } from "./DiffTypes";
|
||||
import {
|
||||
getPath,
|
||||
createHunkIdentifier,
|
||||
createHunkIdentifierFromContext
|
||||
} from "./diffs";
|
||||
import { getPath, createHunkIdentifier, createHunkIdentifierFromContext } from "./diffs";
|
||||
|
||||
describe("tests for diff util functions", () => {
|
||||
const file = (
|
||||
type: FileChangeType,
|
||||
oldPath: string,
|
||||
newPath: string
|
||||
): File => {
|
||||
const file = (type: FileChangeType, oldPath: string, newPath: string): File => {
|
||||
return {
|
||||
hunks: [],
|
||||
type: type,
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
import * as diffs from "./diffs";
|
||||
|
||||
export { diffs };
|
||||
|
||||
export * from "./changesets";
|
||||
|
||||
export { default as Diff } from "./Diff";
|
||||
export { default as DiffFile } from "./DiffFile";
|
||||
export { default as LoadingDiff } from "./LoadingDiff";
|
||||
|
||||
import {
|
||||
File,
|
||||
FileChangeType,
|
||||
@@ -21,6 +13,14 @@ import {
|
||||
DiffEventContext
|
||||
} from "./DiffTypes";
|
||||
|
||||
export { diffs };
|
||||
|
||||
export * from "./changesets";
|
||||
|
||||
export { default as Diff } from "./Diff";
|
||||
export { default as DiffFile } from "./DiffFile";
|
||||
export { default as LoadingDiff } from "./LoadingDiff";
|
||||
|
||||
export {
|
||||
File,
|
||||
FileChangeType,
|
||||
|
||||
@@ -8,7 +8,7 @@ export function getProtocolLinkByType(repository: Repository, type: string) {
|
||||
if (!Array.isArray(protocols)) {
|
||||
protocols = [protocols];
|
||||
}
|
||||
for (let proto of protocols) {
|
||||
for (const proto of protocols) {
|
||||
if (proto.name === type) {
|
||||
return proto.href;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
concat,
|
||||
getPageFromMatch,
|
||||
getQueryStringFromLocation,
|
||||
withEndingSlash
|
||||
} from "./urls";
|
||||
import { concat, getPageFromMatch, getQueryStringFromLocation, withEndingSlash } from "./urls";
|
||||
|
||||
describe("tests for withEndingSlash", () => {
|
||||
it("should append missing slash", () => {
|
||||
|
||||
@@ -16,7 +16,7 @@ export function withEndingSlash(url: string) {
|
||||
|
||||
export function concat(base: string, ...parts: string[]) {
|
||||
let url = base;
|
||||
for (let p of parts) {
|
||||
for (const p of parts) {
|
||||
url = withEndingSlash(url) + p;
|
||||
}
|
||||
return url;
|
||||
|
||||
@@ -19,7 +19,7 @@ describe("test name validation", () => {
|
||||
"!!!",
|
||||
"!_!"
|
||||
];
|
||||
for (let name of invalidNames) {
|
||||
for (const name of invalidNames) {
|
||||
it(`should return false for '${name}'`, () => {
|
||||
expect(validator.isNameValid(name)).toBe(false);
|
||||
});
|
||||
@@ -42,7 +42,7 @@ describe("test name validation", () => {
|
||||
"this.one_as-well",
|
||||
"and@this"
|
||||
];
|
||||
for (let name of validNames) {
|
||||
for (const name of validNames) {
|
||||
it(`should return true for '${name}'`, () => {
|
||||
expect(validator.isNameValid(name)).toBe(true);
|
||||
});
|
||||
@@ -59,7 +59,7 @@ describe("test mail validation", () => {
|
||||
"s.sdorra@ ostfalia.de",
|
||||
"s.sdorra@[ostfalia.de"
|
||||
];
|
||||
for (let mail of invalid) {
|
||||
for (const mail of invalid) {
|
||||
it(`should return false for '${mail}'`, () => {
|
||||
expect(validator.isMailValid(mail)).toBe(false);
|
||||
});
|
||||
@@ -78,7 +78,7 @@ describe("test mail validation", () => {
|
||||
"s'sdorra@scm.solutions",
|
||||
'"S Sdorra"@scm.solutions'
|
||||
];
|
||||
for (let mail of valid) {
|
||||
for (const mail of valid) {
|
||||
it(`should return true for '${mail}'`, () => {
|
||||
expect(validator.isMailValid(mail)).toBe(true);
|
||||
});
|
||||
@@ -87,13 +87,13 @@ describe("test mail validation", () => {
|
||||
|
||||
describe("test number validation", () => {
|
||||
const invalid = ["1a", "35gu", "dj6", "45,5", "test"];
|
||||
for (let number of invalid) {
|
||||
for (const number of invalid) {
|
||||
it(`should return false for '${number}'`, () => {
|
||||
expect(validator.isNumberValid(number)).toBe(false);
|
||||
});
|
||||
}
|
||||
const valid = ["1", "35", "2", "235", "34.4"];
|
||||
for (let number of valid) {
|
||||
for (const number of valid) {
|
||||
it(`should return true for '${number}'`, () => {
|
||||
expect(validator.isNumberValid(number)).toBe(true);
|
||||
});
|
||||
@@ -102,13 +102,13 @@ describe("test number validation", () => {
|
||||
|
||||
describe("test path validation", () => {
|
||||
const invalid = ["//", "some//path", "end//"];
|
||||
for (let path of invalid) {
|
||||
for (const path of invalid) {
|
||||
it(`should return false for '${path}'`, () => {
|
||||
expect(validator.isPathValid(path)).toBe(false);
|
||||
});
|
||||
}
|
||||
const valid = ["", "/", "dir", "some/path", "end/"];
|
||||
for (let path of valid) {
|
||||
for (const path of valid) {
|
||||
it(`should return true for '${path}'`, () => {
|
||||
expect(validator.isPathValid(path)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -50,9 +50,7 @@ describe("ExtensionPoint test", () => {
|
||||
mockedBinder.hasExtension.mockReturnValue(true);
|
||||
mockedBinder.getExtensions.mockReturnValue([labelOne, labelTwo]);
|
||||
|
||||
const rendered = mount(
|
||||
<ExtensionPointEnzymeFix name="something.special" renderAll={true} />
|
||||
);
|
||||
const rendered = mount(<ExtensionPointEnzymeFix name="something.special" renderAll={true} />);
|
||||
const text = rendered.text();
|
||||
expect(text).toContain("Extension One");
|
||||
expect(text).toContain("Extension Two");
|
||||
@@ -123,11 +121,7 @@ describe("ExtensionPoint test", () => {
|
||||
};
|
||||
|
||||
const HelloUser = () => {
|
||||
return (
|
||||
<UserContext.Consumer>
|
||||
{({ name }) => <Hello name={name} />}
|
||||
</UserContext.Consumer>
|
||||
);
|
||||
return <UserContext.Consumer>{({ name }) => <Hello name={name} />}</UserContext.Consumer>;
|
||||
};
|
||||
|
||||
mockedBinder.hasExtension.mockReturnValue(true);
|
||||
|
||||
@@ -41,25 +41,13 @@ describe("binder tests", () => {
|
||||
});
|
||||
|
||||
type Props = {
|
||||
category: string
|
||||
category: string;
|
||||
};
|
||||
|
||||
it("should return only extensions which predicates matches", () => {
|
||||
binder.bind(
|
||||
"hitchhicker.trillian",
|
||||
"heartOfGold",
|
||||
(props: Props) => props.category === "a"
|
||||
);
|
||||
binder.bind(
|
||||
"hitchhicker.trillian",
|
||||
"earth",
|
||||
(props: Props) => props.category === "b"
|
||||
);
|
||||
binder.bind(
|
||||
"hitchhicker.trillian",
|
||||
"earth2",
|
||||
(props: Props) => props.category === "a"
|
||||
);
|
||||
binder.bind("hitchhicker.trillian", "heartOfGold", (props: Props) => props.category === "a");
|
||||
binder.bind("hitchhicker.trillian", "earth", (props: Props) => props.category === "b");
|
||||
binder.bind("hitchhicker.trillian", "earth2", (props: Props) => props.category === "a");
|
||||
|
||||
const extensions = binder.getExtensions("hitchhicker.trillian", {
|
||||
category: "b"
|
||||
|
||||
@@ -31,7 +31,7 @@ export class Binder {
|
||||
}
|
||||
const registration = {
|
||||
predicate: predicate ? predicate : () => true,
|
||||
extension,
|
||||
extension
|
||||
};
|
||||
this.extensionPoints[extensionPoint].push(registration);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type Branch = {
|
||||
name: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Collection, Links } from './hal';
|
||||
import { Tag } from './Tags';
|
||||
import { Branch } from './Branches';
|
||||
import { Collection, Links } from "./hal";
|
||||
import { Tag } from "./Tags";
|
||||
import { Branch } from "./Branches";
|
||||
|
||||
export type Changeset = Collection & {
|
||||
id: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type Config = {
|
||||
proxyPassword: string | null;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Collection, Links } from './hal';
|
||||
import { Collection, Links } from "./hal";
|
||||
|
||||
export type Member = {
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type IndexResources = {
|
||||
version: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type Me = {
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type NamespaceStrategies = {
|
||||
current: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Collection, Links } from './hal';
|
||||
import { Collection, Links } from "./hal";
|
||||
|
||||
export type Plugin = {
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PagedCollection, Links } from './hal';
|
||||
import { PagedCollection, Links } from "./hal";
|
||||
|
||||
export type Repository = {
|
||||
namespace: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type PermissionCreateEntry = {
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type RepositoryRole = {
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Collection } from './hal';
|
||||
import { Collection } from "./hal";
|
||||
|
||||
export type RepositoryType = {
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
// TODO ?? check ?? links
|
||||
export type SubRepository = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type Tag = {
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Links } from './hal';
|
||||
import { Links } from "./hal";
|
||||
|
||||
export type DisplayedUser = {
|
||||
id: string;
|
||||
|
||||
@@ -5,7 +5,11 @@ export { Me } from "./Me";
|
||||
export { DisplayedUser, User } from "./User";
|
||||
export { Group, Member } from "./Group";
|
||||
|
||||
export { Repository, RepositoryCollection, RepositoryGroup } from "./Repositories";
|
||||
export {
|
||||
Repository,
|
||||
RepositoryCollection,
|
||||
RepositoryGroup
|
||||
} from "./Repositories";
|
||||
export { RepositoryType, RepositoryTypeCollection } from "./RepositoryTypes";
|
||||
|
||||
export { Branch, BranchRequest } from "./Branches";
|
||||
@@ -18,13 +22,22 @@ export { Config } from "./Config";
|
||||
|
||||
export { IndexResources } from "./IndexResources";
|
||||
|
||||
export { Permission, PermissionCreateEntry, PermissionCollection } from "./RepositoryPermissions";
|
||||
export {
|
||||
Permission,
|
||||
PermissionCreateEntry,
|
||||
PermissionCollection
|
||||
} from "./RepositoryPermissions";
|
||||
|
||||
export { SubRepository, File } from "./Sources";
|
||||
|
||||
export { SelectValue, AutocompleteObject } from "./Autocomplete";
|
||||
|
||||
export { Plugin, PluginCollection, PluginGroup, PendingPlugins } from "./Plugin";
|
||||
export {
|
||||
Plugin,
|
||||
PluginCollection,
|
||||
PluginGroup,
|
||||
PendingPlugins
|
||||
} from "./Plugin";
|
||||
|
||||
export { RepositoryRole } from "./RepositoryRole";
|
||||
|
||||
|
||||
@@ -91,24 +91,13 @@ class ConfigForm extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
loading,
|
||||
t,
|
||||
namespaceStrategies,
|
||||
configReadPermission,
|
||||
configUpdatePermission
|
||||
} = this.props;
|
||||
const { loading, t, namespaceStrategies, configReadPermission, configUpdatePermission } = this.props;
|
||||
const config = this.state.config;
|
||||
|
||||
let noPermissionNotification = null;
|
||||
|
||||
if (!configReadPermission) {
|
||||
return (
|
||||
<Notification
|
||||
type={"danger"}
|
||||
children={t("config.form.no-read-permission-notification")}
|
||||
/>
|
||||
);
|
||||
return <Notification type={"danger"} children={t("config.form.no-read-permission-notification")} />;
|
||||
}
|
||||
|
||||
if (this.state.showNotification) {
|
||||
@@ -135,27 +124,21 @@ class ConfigForm extends React.Component<Props, State> {
|
||||
pluginUrl={config.pluginUrl}
|
||||
enabledXsrfProtection={config.enabledXsrfProtection}
|
||||
namespaceStrategy={config.namespaceStrategy}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.onChange(isValid, changedValue, name)
|
||||
}
|
||||
onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<LoginAttempt
|
||||
loginAttemptLimit={config.loginAttemptLimit}
|
||||
loginAttemptLimitTimeout={config.loginAttemptLimitTimeout}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.onChange(isValid, changedValue, name)
|
||||
}
|
||||
onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<BaseUrlSettings
|
||||
baseUrl={config.baseUrl}
|
||||
forceBaseUrl={config.forceBaseUrl}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.onChange(isValid, changedValue, name)
|
||||
}
|
||||
onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
@@ -166,18 +149,14 @@ class ConfigForm extends React.Component<Props, State> {
|
||||
proxyUser={config.proxyUser ? config.proxyUser : ""}
|
||||
enableProxy={config.enableProxy}
|
||||
proxyExcludes={config.proxyExcludes}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.onChange(isValid, changedValue, name)
|
||||
}
|
||||
onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<SubmitButton
|
||||
loading={loading}
|
||||
label={t("config.form.submit")}
|
||||
disabled={
|
||||
!configUpdatePermission || this.hasError() || !this.state.changed
|
||||
}
|
||||
disabled={!configUpdatePermission || this.hasError() || !this.state.changed}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
@@ -199,10 +178,7 @@ class ConfigForm extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
hasError = () => {
|
||||
return (
|
||||
this.state.error.loginAttemptLimit ||
|
||||
this.state.error.loginAttemptLimitTimeout
|
||||
);
|
||||
return this.state.error.loginAttemptLimit || this.state.error.loginAttemptLimitTimeout;
|
||||
};
|
||||
|
||||
onClose = () => {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
InputField,
|
||||
Subtitle,
|
||||
validation as validator
|
||||
} from "@scm-manager/ui-components";
|
||||
import { InputField, Subtitle, validation as validator } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
loginAttemptLimit: number;
|
||||
@@ -29,12 +25,7 @@ class LoginAttempt extends React.Component<Props, State> {
|
||||
};
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
loginAttemptLimit,
|
||||
loginAttemptLimitTimeout,
|
||||
hasUpdatePermission
|
||||
} = this.props;
|
||||
const { t, loginAttemptLimit, loginAttemptLimitTimeout, hasUpdatePermission } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -73,11 +64,7 @@ class LoginAttempt extends React.Component<Props, State> {
|
||||
...this.state,
|
||||
loginAttemptLimitError: !validator.isNumberValid(value)
|
||||
});
|
||||
this.props.onChange(
|
||||
validator.isNumberValid(value),
|
||||
value,
|
||||
"loginAttemptLimit"
|
||||
);
|
||||
this.props.onChange(validator.isNumberValid(value), value, "loginAttemptLimit");
|
||||
};
|
||||
|
||||
handleLoginAttemptLimitTimeoutChange = (value: string) => {
|
||||
@@ -85,11 +72,7 @@ class LoginAttempt extends React.Component<Props, State> {
|
||||
...this.state,
|
||||
loginAttemptLimitTimeoutError: !validator.isNumberValid(value)
|
||||
});
|
||||
this.props.onChange(
|
||||
validator.isNumberValid(value),
|
||||
value,
|
||||
"loginAttemptLimitTimeout"
|
||||
);
|
||||
this.props.onChange(validator.isNumberValid(value), value, "loginAttemptLimitTimeout");
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,7 @@ class NamespaceStrategySelect extends React.Component<Props> {
|
||||
|
||||
findSelected = () => {
|
||||
const { namespaceStrategies, value } = this.props;
|
||||
if (
|
||||
!namespaceStrategies ||
|
||||
!namespaceStrategies.available ||
|
||||
namespaceStrategies.available.indexOf(value) < 0
|
||||
) {
|
||||
if (!namespaceStrategies || !namespaceStrategies.available || namespaceStrategies.available.indexOf(value) < 0) {
|
||||
return namespaceStrategies.current;
|
||||
}
|
||||
return value;
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
Checkbox,
|
||||
InputField,
|
||||
Subtitle,
|
||||
AddEntryToTableField
|
||||
} from "@scm-manager/ui-components";
|
||||
import { Checkbox, InputField, Subtitle, AddEntryToTableField } from "@scm-manager/ui-components";
|
||||
import ProxyExcludesTable from "../table/ProxyExcludesTable";
|
||||
|
||||
type Props = {
|
||||
@@ -92,9 +87,7 @@ class ProxySettings extends React.Component<Props> {
|
||||
<div className="column is-full">
|
||||
<ProxyExcludesTable
|
||||
proxyExcludes={proxyExcludes}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.props.onChange(isValid, changedValue, name)
|
||||
}
|
||||
onChange={(isValid, changedValue, name) => this.props.onChange(isValid, changedValue, name)}
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
/>
|
||||
<AddEntryToTableField
|
||||
@@ -130,11 +123,7 @@ class ProxySettings extends React.Component<Props> {
|
||||
if (this.isProxyExcludeMember(proxyExcludeName)) {
|
||||
return;
|
||||
}
|
||||
this.props.onChange(
|
||||
true,
|
||||
[...this.props.proxyExcludes, proxyExcludeName],
|
||||
"proxyExcludes"
|
||||
);
|
||||
this.props.onChange(true, [...this.props.proxyExcludes, proxyExcludeName], "proxyExcludes");
|
||||
};
|
||||
|
||||
isProxyExcludeMember = (proxyExcludeName: string) => {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import React from "react";
|
||||
import {
|
||||
RemoveEntryOfTableButton,
|
||||
LabelWithHelpIcon
|
||||
} from "@scm-manager/ui-components";
|
||||
import { RemoveEntryOfTableButton, LabelWithHelpIcon } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
items: string[];
|
||||
|
||||
@@ -6,18 +6,8 @@ import { History } from "history";
|
||||
import { connect } from "react-redux";
|
||||
import { compose } from "redux";
|
||||
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 { Page, Navigation, NavLink, Section, SubNavigation } from "@scm-manager/ui-components";
|
||||
import { getLinks, getAvailablePluginsLink, getInstalledPluginsLink } from "../../modules/indexResource";
|
||||
import AdminDetails from "./AdminDetails";
|
||||
import PluginsOverview from "../plugins/containers/PluginsOverview";
|
||||
import GlobalConfig from "./GlobalConfig";
|
||||
@@ -73,96 +63,45 @@ class Admin extends React.Component<Props> {
|
||||
<Switch>
|
||||
<Redirect exact from={url} to={`${url}/info`} />
|
||||
<Route path={`${url}/info`} exact component={AdminDetails} />
|
||||
<Route
|
||||
path={`${url}/settings/general`}
|
||||
exact
|
||||
component={GlobalConfig}
|
||||
/>
|
||||
<Redirect
|
||||
exact
|
||||
from={`${url}/plugins`}
|
||||
to={`${url}/plugins/installed/`}
|
||||
/>
|
||||
<Route path={`${url}/settings/general`} exact component={GlobalConfig} />
|
||||
<Redirect exact from={`${url}/plugins`} to={`${url}/plugins/installed/`} />
|
||||
<Route
|
||||
path={`${url}/plugins/installed`}
|
||||
exact
|
||||
render={() => (
|
||||
<PluginsOverview
|
||||
baseUrl={`${url}/plugins/installed`}
|
||||
installed={true}
|
||||
/>
|
||||
)}
|
||||
render={() => <PluginsOverview baseUrl={`${url}/plugins/installed`} installed={true} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/plugins/installed/:page`}
|
||||
exact
|
||||
render={() => (
|
||||
<PluginsOverview
|
||||
baseUrl={`${url}/plugins/installed`}
|
||||
installed={true}
|
||||
/>
|
||||
)}
|
||||
render={() => <PluginsOverview baseUrl={`${url}/plugins/installed`} installed={true} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/plugins/available`}
|
||||
exact
|
||||
render={() => (
|
||||
<PluginsOverview
|
||||
baseUrl={`${url}/plugins/available`}
|
||||
installed={false}
|
||||
/>
|
||||
)}
|
||||
render={() => <PluginsOverview baseUrl={`${url}/plugins/available`} installed={false} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/plugins/available/:page`}
|
||||
exact
|
||||
render={() => (
|
||||
<PluginsOverview
|
||||
baseUrl={`${url}/plugins/available`}
|
||||
installed={false}
|
||||
/>
|
||||
)}
|
||||
render={() => <PluginsOverview baseUrl={`${url}/plugins/available`} installed={false} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/role/:role`}
|
||||
render={() => (
|
||||
<SingleRepositoryRole
|
||||
baseUrl={`${url}/roles`}
|
||||
history={this.props.history}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/roles`}
|
||||
exact
|
||||
render={() => <RepositoryRoles baseUrl={`${url}/roles`} />}
|
||||
render={() => <SingleRepositoryRole baseUrl={`${url}/roles`} history={this.props.history} />}
|
||||
/>
|
||||
<Route path={`${url}/roles`} exact render={() => <RepositoryRoles baseUrl={`${url}/roles`} />} />
|
||||
<Route
|
||||
path={`${url}/roles/create`}
|
||||
render={() => (
|
||||
<CreateRepositoryRole history={this.props.history} />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/roles/:page`}
|
||||
exact
|
||||
render={() => <RepositoryRoles baseUrl={`${url}/roles`} />}
|
||||
/>
|
||||
<ExtensionPoint
|
||||
name="admin.route"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
render={() => <CreateRepositoryRole history={this.props.history} />}
|
||||
/>
|
||||
<Route path={`${url}/roles/:page`} exact render={() => <RepositoryRoles baseUrl={`${url}/roles`} />} />
|
||||
<ExtensionPoint name="admin.route" props={extensionProps} renderAll={true} />
|
||||
</Switch>
|
||||
</div>
|
||||
<div className="column is-one-quarter">
|
||||
<Navigation>
|
||||
<Section label={t("admin.menu.navigationLabel")}>
|
||||
<NavLink
|
||||
to={`${url}/info`}
|
||||
icon="fas fa-info-circle"
|
||||
label={t("admin.menu.informationNavLink")}
|
||||
/>
|
||||
<NavLink to={`${url}/info`} icon="fas fa-info-circle" label={t("admin.menu.informationNavLink")} />
|
||||
{(availablePluginsLink || installedPluginsLink) && (
|
||||
<SubNavigation
|
||||
to={`${url}/plugins/`}
|
||||
@@ -170,16 +109,10 @@ class Admin extends React.Component<Props> {
|
||||
label={t("plugins.menu.pluginsNavLink")}
|
||||
>
|
||||
{installedPluginsLink && (
|
||||
<NavLink
|
||||
to={`${url}/plugins/installed/`}
|
||||
label={t("plugins.menu.installedNavLink")}
|
||||
/>
|
||||
<NavLink to={`${url}/plugins/installed/`} label={t("plugins.menu.installedNavLink")} />
|
||||
)}
|
||||
{availablePluginsLink && (
|
||||
<NavLink
|
||||
to={`${url}/plugins/available/`}
|
||||
label={t("plugins.menu.availableNavLink")}
|
||||
/>
|
||||
<NavLink to={`${url}/plugins/available/`} label={t("plugins.menu.availableNavLink")} />
|
||||
)}
|
||||
</SubNavigation>
|
||||
)}
|
||||
@@ -190,24 +123,10 @@ class Admin extends React.Component<Props> {
|
||||
activeWhenMatch={this.matchesRoles}
|
||||
activeOnlyWhenExact={false}
|
||||
/>
|
||||
<ExtensionPoint
|
||||
name="admin.navigation"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
<SubNavigation
|
||||
to={`${url}/settings/general`}
|
||||
label={t("admin.menu.settingsNavLink")}
|
||||
>
|
||||
<NavLink
|
||||
to={`${url}/settings/general`}
|
||||
label={t("admin.menu.generalNavLink")}
|
||||
/>
|
||||
<ExtensionPoint
|
||||
name="admin.setting"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
<ExtensionPoint name="admin.navigation" props={extensionProps} renderAll={true} />
|
||||
<SubNavigation to={`${url}/settings/general`} label={t("admin.menu.settingsNavLink")}>
|
||||
<NavLink to={`${url}/settings/general`} label={t("admin.menu.generalNavLink")} />
|
||||
<ExtensionPoint name="admin.setting" props={extensionProps} renderAll={true} />
|
||||
</SubNavigation>
|
||||
</Section>
|
||||
</Navigation>
|
||||
|
||||
@@ -15,8 +15,7 @@ type Props = {
|
||||
};
|
||||
|
||||
const BoxShadowBox = styled.div`
|
||||
box-shadow: 0 2px 3px rgba(40, 177, 232, 0.1),
|
||||
0 0 0 2px rgba(40, 177, 232, 0.2);
|
||||
box-shadow: 0 2px 3px rgba(40, 177, 232, 0.1), 0 0 0 2px rgba(40, 177, 232, 0.2);
|
||||
`;
|
||||
|
||||
const ImageWrapper = styled.div`
|
||||
@@ -38,22 +37,13 @@ class AdminDetails extends React.Component<Props> {
|
||||
<BoxShadowBox className="box">
|
||||
<article className="media">
|
||||
<ImageWrapper className="media-left">
|
||||
<Image
|
||||
src="/images/iconCommunitySupport.png"
|
||||
alt={t("admin.info.communityIconAlt")}
|
||||
/>
|
||||
<Image src="/images/iconCommunitySupport.png" alt={t("admin.info.communityIconAlt")} />
|
||||
</ImageWrapper>
|
||||
<div className="media-content">
|
||||
<div className="content">
|
||||
<h3 className="has-text-weight-medium">
|
||||
{t("admin.info.communityTitle")}
|
||||
</h3>
|
||||
<h3 className="has-text-weight-medium">{t("admin.info.communityTitle")}</h3>
|
||||
<p>{t("admin.info.communityInfo")}</p>
|
||||
<a
|
||||
className="button is-info is-pulled-right"
|
||||
target="_blank"
|
||||
href="https://scm-manager.org/support/"
|
||||
>
|
||||
<a className="button is-info is-pulled-right" target="_blank" href="https://scm-manager.org/support/">
|
||||
{t("admin.info.communityButton")}
|
||||
</a>
|
||||
</div>
|
||||
@@ -63,16 +53,11 @@ class AdminDetails extends React.Component<Props> {
|
||||
<BoxShadowBox className="box">
|
||||
<article className="media">
|
||||
<ImageWrapper className="media-left">
|
||||
<Image
|
||||
src="/images/iconEnterpriseSupport.png"
|
||||
alt={t("admin.info.enterpriseIconAlt")}
|
||||
/>
|
||||
<Image src="/images/iconEnterpriseSupport.png" alt={t("admin.info.enterpriseIconAlt")} />
|
||||
</ImageWrapper>
|
||||
<div className="media-content">
|
||||
<div className="content">
|
||||
<h3 className="has-text-weight-medium">
|
||||
{t("admin.info.enterpriseTitle")}
|
||||
</h3>
|
||||
<h3 className="has-text-weight-medium">{t("admin.info.enterpriseTitle")}</h3>
|
||||
<p>
|
||||
{t("admin.info.enterpriseInfo")}
|
||||
<br />
|
||||
|
||||
@@ -119,13 +119,7 @@ class GlobalConfig extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
renderContent = () => {
|
||||
const {
|
||||
error,
|
||||
loading,
|
||||
config,
|
||||
configUpdatePermission,
|
||||
namespaceStrategies
|
||||
} = this.props;
|
||||
const { error, loading, config, configUpdatePermission, namespaceStrategies } = this.props;
|
||||
const { configReadPermission } = this.state;
|
||||
if (!error) {
|
||||
return (
|
||||
@@ -165,13 +159,9 @@ const mapDispatchToProps = dispatch => {
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const loading =
|
||||
isFetchConfigPending(state) ||
|
||||
isModifyConfigPending(state) ||
|
||||
isFetchNamespaceStrategiesPending(state);
|
||||
isFetchConfigPending(state) || isModifyConfigPending(state) || isFetchNamespaceStrategiesPending(state);
|
||||
const error =
|
||||
getFetchConfigFailure(state) ||
|
||||
getModifyConfigFailure(state) ||
|
||||
getFetchNamespaceStrategiesFailure(state);
|
||||
getFetchConfigFailure(state) || getModifyConfigFailure(state) || getFetchNamespaceStrategiesFailure(state);
|
||||
|
||||
const config = getConfig(state);
|
||||
const configUpdatePermission = getConfigUpdatePermission(state);
|
||||
|
||||
@@ -233,8 +233,7 @@ describe("config reducer", () => {
|
||||
|
||||
it("should return empty arrays for null values", () => {
|
||||
// $FlowFixMe
|
||||
const config = reducer({}, fetchConfigSuccess(configWithNullValues))
|
||||
.entries;
|
||||
const config = reducer({}, fetchConfigSuccess(configWithNullValues)).entries;
|
||||
expect(config.adminUsers).toEqual([]);
|
||||
expect(config.adminGroups).toEqual([]);
|
||||
expect(config.proxyExcludes).toEqual([]);
|
||||
|
||||
@@ -5,8 +5,7 @@ import { isPending } from "../../modules/pending";
|
||||
import { getFailure } from "../../modules/failure";
|
||||
import { MODIFY_CONFIG_SUCCESS } from "./config";
|
||||
|
||||
export const FETCH_NAMESPACESTRATEGIES_TYPES =
|
||||
"scm/config/FETCH_NAMESPACESTRATEGIES_TYPES";
|
||||
export const FETCH_NAMESPACESTRATEGIES_TYPES = "scm/config/FETCH_NAMESPACESTRATEGIES_TYPES";
|
||||
export const FETCH_NAMESPACESTRATEGIES_TYPES_PENDING = `${FETCH_NAMESPACESTRATEGIES_TYPES}_${types.PENDING_SUFFIX}`;
|
||||
export const FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS = `${FETCH_NAMESPACESTRATEGIES_TYPES}_${types.SUCCESS_SUFFIX}`;
|
||||
export const FETCH_NAMESPACESTRATEGIES_TYPES_FAILURE = `${FETCH_NAMESPACESTRATEGIES_TYPES}_${types.FAILURE_SUFFIX}`;
|
||||
@@ -15,10 +14,7 @@ export function fetchNamespaceStrategiesIfNeeded() {
|
||||
return function(dispatch: any, getState: () => object) {
|
||||
const state = getState();
|
||||
if (shouldFetchNamespaceStrategies(state)) {
|
||||
return fetchNamespaceStrategies(
|
||||
dispatch,
|
||||
state.indexResources.links.namespaceStrategies.href
|
||||
);
|
||||
return fetchNamespaceStrategies(dispatch, state.indexResources.links.namespaceStrategies.href);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -37,10 +33,7 @@ function fetchNamespaceStrategies(dispatch: any, url: string) {
|
||||
}
|
||||
|
||||
export function shouldFetchNamespaceStrategies(state: object) {
|
||||
if (
|
||||
isFetchNamespaceStrategiesPending(state) ||
|
||||
getFetchNamespaceStrategiesFailure(state)
|
||||
) {
|
||||
if (isFetchNamespaceStrategiesPending(state) || getFetchNamespaceStrategiesFailure(state)) {
|
||||
return false;
|
||||
}
|
||||
return !state.namespaceStrategies || !state.namespaceStrategies.current;
|
||||
@@ -52,9 +45,7 @@ export function fetchNamespaceStrategiesPending(): Action {
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchNamespaceStrategiesSuccess(
|
||||
namespaceStrategies: NamespaceStrategies
|
||||
): Action {
|
||||
export function fetchNamespaceStrategiesSuccess(namespaceStrategies: NamespaceStrategies): Action {
|
||||
return {
|
||||
type: FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS,
|
||||
payload: namespaceStrategies
|
||||
@@ -76,10 +67,7 @@ export default function reducer(
|
||||
type: "UNKNOWN"
|
||||
}
|
||||
): object {
|
||||
if (
|
||||
action.type === FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS &&
|
||||
action.payload
|
||||
) {
|
||||
if (action.type === FETCH_NAMESPACESTRATEGIES_TYPES_SUCCESS && action.payload) {
|
||||
return action.payload;
|
||||
} else if (action.type === MODIFY_CONFIG_SUCCESS && action.payload) {
|
||||
const config = action.payload;
|
||||
|
||||
@@ -39,12 +39,7 @@ class ExecutePendingAction extends React.Component<Props, State> {
|
||||
const { showModal } = this.state;
|
||||
const { pendingPlugins } = this.props;
|
||||
if (showModal) {
|
||||
return (
|
||||
<ExecutePendingModal
|
||||
pendingPlugins={pendingPlugins}
|
||||
onClose={this.closeModal}
|
||||
/>
|
||||
);
|
||||
return <ExecutePendingModal pendingPlugins={pendingPlugins} onClose={this.closeModal} />;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -54,11 +49,7 @@ class ExecutePendingAction extends React.Component<Props, State> {
|
||||
return (
|
||||
<>
|
||||
{this.renderModal()}
|
||||
<Button
|
||||
color="primary"
|
||||
label={t("plugins.executePending")}
|
||||
action={this.openModal}
|
||||
/>
|
||||
<Button color="primary" label={t("plugins.executePending")} action={this.openModal} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -25,18 +25,14 @@ class ExecutePendingActionModal extends React.Component<Props> {
|
||||
pendingPlugins={pendingPlugins}
|
||||
execute={this.executeAndRestart}
|
||||
>
|
||||
<Notification type="warning">
|
||||
{t("plugins.modal.restartNotification")}
|
||||
</Notification>
|
||||
<Notification type="warning">{t("plugins.modal.restartNotification")}</Notification>
|
||||
</PluginActionModal>
|
||||
);
|
||||
}
|
||||
|
||||
executeAndRestart = () => {
|
||||
const { pendingPlugins } = this.props;
|
||||
return apiClient
|
||||
.post(pendingPlugins._links.execute.href)
|
||||
.then(waitForRestart);
|
||||
return apiClient.post(pendingPlugins._links.execute.href).then(waitForRestart);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import React from "react";
|
||||
import {
|
||||
apiClient,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
ErrorNotification,
|
||||
Modal,
|
||||
Notification
|
||||
} from "@scm-manager/ui-components";
|
||||
import { apiClient, Button, ButtonGroup, ErrorNotification, Modal, Notification } from "@scm-manager/ui-components";
|
||||
import { PendingPlugins } from "@scm-manager/ui-types";
|
||||
import { translate } from "react-i18next";
|
||||
import waitForRestart from "./waitForRestart";
|
||||
@@ -43,11 +36,7 @@ class ExecutePendingModal extends React.Component<Props, State> {
|
||||
} else if (success) {
|
||||
return <SuccessNotification />;
|
||||
} else {
|
||||
return (
|
||||
<Notification type="warning">
|
||||
{t("plugins.modal.restartNotification")}
|
||||
</Notification>
|
||||
);
|
||||
return <Notification type="warning">{t("plugins.modal.restartNotification")}</Notification>;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -98,17 +87,16 @@ class ExecutePendingModal extends React.Component<Props, State> {
|
||||
const { pendingPlugins, t } = this.props;
|
||||
return (
|
||||
<>
|
||||
{pendingPlugins._embedded &&
|
||||
pendingPlugins._embedded.update.length > 0 && (
|
||||
<>
|
||||
<strong>{t("plugins.modal.updateQueue")}</strong>
|
||||
<ul>
|
||||
{pendingPlugins._embedded.update.map(plugin => (
|
||||
<li key={plugin.name}>{plugin.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{pendingPlugins._embedded && pendingPlugins._embedded.update.length > 0 && (
|
||||
<>
|
||||
<strong>{t("plugins.modal.updateQueue")}</strong>
|
||||
<ul>
|
||||
{pendingPlugins._embedded.update.map(plugin => (
|
||||
<li key={plugin.name}>{plugin.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -117,17 +105,16 @@ class ExecutePendingModal extends React.Component<Props, State> {
|
||||
const { pendingPlugins, t } = this.props;
|
||||
return (
|
||||
<>
|
||||
{pendingPlugins._embedded &&
|
||||
pendingPlugins._embedded.uninstall.length > 0 && (
|
||||
<>
|
||||
<strong>{t("plugins.modal.uninstallQueue")}</strong>
|
||||
<ul>
|
||||
{pendingPlugins._embedded.uninstall.map(plugin => (
|
||||
<li key={plugin.name}>{plugin.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{pendingPlugins._embedded && pendingPlugins._embedded.uninstall.length > 0 && (
|
||||
<>
|
||||
<strong>{t("plugins.modal.uninstallQueue")}</strong>
|
||||
<ul>
|
||||
{pendingPlugins._embedded.uninstall.map(plugin => (
|
||||
<li key={plugin.name}>{plugin.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user