mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-09 15:05:44 +01:00
merged
This commit is contained in:
@@ -79,7 +79,9 @@ final class GitHunkParser {
|
|||||||
++oldLineCounter;
|
++oldLineCounter;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("cannot handle diff line: " + line);
|
if (!line.equals("\\ No newline at end of file")) {
|
||||||
|
throw new IllegalStateException("cannot handle diff line: " + line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,17 @@ class GitHunkParserTest {
|
|||||||
" a\n" +
|
" a\n" +
|
||||||
"~illegal line\n";
|
"~illegal line\n";
|
||||||
|
|
||||||
|
private static final String NO_NEWLINE_DIFF = "diff --git a/.editorconfig b/.editorconfig\n" +
|
||||||
|
"index ea2a3ba..2f02f32 100644\n" +
|
||||||
|
"--- a/.editorconfig\n" +
|
||||||
|
"+++ b/.editorconfig\n" +
|
||||||
|
"@@ -10,3 +10,4 @@\n" +
|
||||||
|
" indent_style = space\n" +
|
||||||
|
" indent_size = 2\n" +
|
||||||
|
" charset = utf-8\n" +
|
||||||
|
"+added line\n" +
|
||||||
|
"\\ No newline at end of file\n";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldParseHunks() {
|
void shouldParseHunks() {
|
||||||
List<Hunk> hunks = new GitHunkParser().parse(DIFF_001);
|
List<Hunk> hunks = new GitHunkParser().parse(DIFF_001);
|
||||||
@@ -127,6 +138,27 @@ class GitHunkParserTest {
|
|||||||
assertThrows(IllegalStateException.class, () -> new GitHunkParser().parse(ILLEGAL_DIFF));
|
assertThrows(IllegalStateException.class, () -> new GitHunkParser().parse(ILLEGAL_DIFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldIgnoreNoNewlineLine() {
|
||||||
|
List<Hunk> hunks = new GitHunkParser().parse(NO_NEWLINE_DIFF);
|
||||||
|
|
||||||
|
Hunk hunk = hunks.get(0);
|
||||||
|
|
||||||
|
Iterator<DiffLine> lines = hunk.iterator();
|
||||||
|
|
||||||
|
DiffLine line1 = lines.next();
|
||||||
|
assertThat(line1.getOldLineNumber()).hasValue(10);
|
||||||
|
assertThat(line1.getNewLineNumber()).hasValue(10);
|
||||||
|
assertThat(line1.getContent()).isEqualTo("indent_style = space");
|
||||||
|
|
||||||
|
lines.next();
|
||||||
|
lines.next();
|
||||||
|
DiffLine lastLine = lines.next();
|
||||||
|
assertThat(lastLine.getOldLineNumber()).isEmpty();
|
||||||
|
assertThat(lastLine.getNewLineNumber()).hasValue(13);
|
||||||
|
assertThat(lastLine.getContent()).isEqualTo("added line");
|
||||||
|
}
|
||||||
|
|
||||||
private void assertHunk(Hunk hunk, int oldStart, int oldLineCount, int newStart, int newLineCount) {
|
private void assertHunk(Hunk hunk, int oldStart, int oldLineCount, int newStart, int newLineCount) {
|
||||||
assertThat(hunk.getOldStart()).isEqualTo(oldStart);
|
assertThat(hunk.getOldStart()).isEqualTo(oldStart);
|
||||||
assertThat(hunk.getOldLineCount()).isEqualTo(oldLineCount);
|
assertThat(hunk.getOldLineCount()).isEqualTo(oldLineCount);
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ import { translate } from "react-i18next";
|
|||||||
import { InputField, Checkbox } from "@scm-manager/ui-components";
|
import { InputField, Checkbox } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Configuration = {
|
type Configuration = {
|
||||||
"hgBinary": string,
|
hgBinary: string,
|
||||||
"pythonBinary": string,
|
pythonBinary: string,
|
||||||
"pythonPath"?: string,
|
pythonPath?: string,
|
||||||
"encoding": string,
|
encoding: string,
|
||||||
"useOptimizedBytecode": boolean,
|
useOptimizedBytecode: boolean,
|
||||||
"showRevisionInId": boolean,
|
showRevisionInId: boolean,
|
||||||
"disableHookSSLValidation": boolean,
|
disableHookSSLValidation: boolean,
|
||||||
"enableHttpPostArgs": boolean,
|
enableHttpPostArgs: boolean,
|
||||||
"_links": Links
|
_links: Links
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -23,29 +23,26 @@ type Props = {
|
|||||||
onConfigurationChange: (Configuration, boolean) => void,
|
onConfigurationChange: (Configuration, boolean) => void,
|
||||||
|
|
||||||
// context props
|
// context props
|
||||||
t: (string) => string
|
t: string => string
|
||||||
}
|
};
|
||||||
|
|
||||||
type State = Configuration & {
|
type State = Configuration & {
|
||||||
validationErrors: string[]
|
validationErrors: string[]
|
||||||
};
|
};
|
||||||
|
|
||||||
class HgConfigurationForm extends React.Component<Props, State> {
|
class HgConfigurationForm extends React.Component<Props, State> {
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { ...props.initialConfiguration, validationErrors: [] };
|
this.state = { ...props.initialConfiguration, validationErrors: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
updateValidationStatus = () => {
|
updateValidationStatus = () => {
|
||||||
const requiredFields = [
|
const requiredFields = ["hgBinary", "pythonBinary", "encoding"];
|
||||||
"hgBinary", "pythonBinary", "encoding"
|
|
||||||
];
|
|
||||||
|
|
||||||
const validationErrors = [];
|
const validationErrors = [];
|
||||||
for (let field of requiredFields) {
|
for (let field of requiredFields) {
|
||||||
if (!this.state[field]) {
|
if (!this.state[field]) {
|
||||||
validationErrors.push( field );
|
validationErrors.push(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,58 +53,73 @@ class HgConfigurationForm extends React.Component<Props, State> {
|
|||||||
return validationErrors.length === 0;
|
return validationErrors.length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
hasValidationError = (name: string) => {
|
hasValidationError = (name: string) => {
|
||||||
return this.state.validationErrors.indexOf(name) >= 0;
|
return this.state.validationErrors.indexOf(name) >= 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChange = (value: any, name: string) => {
|
handleChange = (value: any, name: string) => {
|
||||||
this.setState({
|
this.setState(
|
||||||
[name]: value
|
{
|
||||||
}, () => this.props.onConfigurationChange(this.state, this.updateValidationStatus()));
|
[name]: value
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
this.props.onConfigurationChange(
|
||||||
|
this.state,
|
||||||
|
this.updateValidationStatus()
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
inputField = (name: string) => {
|
inputField = (name: string) => {
|
||||||
const { readOnly, t } = this.props;
|
const { readOnly, t } = this.props;
|
||||||
return <InputField
|
return (
|
||||||
name={ name }
|
<div className="column is-half">
|
||||||
label={t("scm-hg-plugin.config." + name)}
|
<InputField
|
||||||
helpText={t("scm-hg-plugin.config." + name + "HelpText")}
|
name={name}
|
||||||
value={this.state[name]}
|
label={t("scm-hg-plugin.config." + name)}
|
||||||
onChange={this.handleChange}
|
helpText={t("scm-hg-plugin.config." + name + "HelpText")}
|
||||||
validationError={this.hasValidationError(name)}
|
value={this.state[name]}
|
||||||
errorMessage={t("scm-hg-plugin.config.required")}
|
onChange={this.handleChange}
|
||||||
disabled={readOnly}
|
validationError={this.hasValidationError(name)}
|
||||||
/>;
|
errorMessage={t("scm-hg-plugin.config.required")}
|
||||||
|
disabled={readOnly}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
checkbox = (name: string) => {
|
checkbox = (name: string) => {
|
||||||
const { readOnly, t } = this.props;
|
const { readOnly, t } = this.props;
|
||||||
return <Checkbox
|
return (
|
||||||
name={ name }
|
<Checkbox
|
||||||
label={t("scm-hg-plugin.config." + name)}
|
name={name}
|
||||||
helpText={t("scm-hg-plugin.config." + name + "HelpText")}
|
label={t("scm-hg-plugin.config." + name)}
|
||||||
checked={this.state[name]}
|
helpText={t("scm-hg-plugin.config." + name + "HelpText")}
|
||||||
onChange={this.handleChange}
|
checked={this.state[name]}
|
||||||
disabled={readOnly}
|
onChange={this.handleChange}
|
||||||
/>;
|
disabled={readOnly}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="columns is-multiline">
|
||||||
{this.inputField("hgBinary")}
|
{this.inputField("hgBinary")}
|
||||||
{this.inputField("pythonBinary")}
|
{this.inputField("pythonBinary")}
|
||||||
{this.inputField("pythonPath")}
|
{this.inputField("pythonPath")}
|
||||||
{this.inputField("encoding")}
|
{this.inputField("encoding")}
|
||||||
{this.checkbox("useOptimizedBytecode")}
|
<div className="column is-half">
|
||||||
{this.checkbox("showRevisionInId")}
|
{this.checkbox("useOptimizedBytecode")}
|
||||||
{this.checkbox("disableHookSSLValidation")}
|
{this.checkbox("showRevisionInId")}
|
||||||
{this.checkbox("enableHttpPostArgs")}
|
</div>
|
||||||
</>
|
<div className="column is-half">
|
||||||
|
{this.checkbox("disableHookSSLValidation")}
|
||||||
|
{this.checkbox("enableHttpPostArgs")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate("plugins")(HgConfigurationForm);
|
export default translate("plugins")(HgConfigurationForm);
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import Tooltip from './Tooltip';
|
import classNames from "classnames";
|
||||||
import HelpIcon from './HelpIcon';
|
import Tooltip from "./Tooltip";
|
||||||
|
import HelpIcon from "./HelpIcon";
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
@@ -14,21 +15,22 @@ const styles = {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
message: string,
|
message: string,
|
||||||
|
className?: string,
|
||||||
classes: any
|
classes: any
|
||||||
}
|
};
|
||||||
|
|
||||||
class Help extends React.Component<Props> {
|
class Help extends React.Component<Props> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { message, classes } = this.props;
|
const { message, className, classes } = this.props;
|
||||||
return (
|
return (
|
||||||
<Tooltip className={classes.tooltip} message={message}>
|
<Tooltip
|
||||||
|
className={classNames(classes.tooltip, className)}
|
||||||
|
message={message}
|
||||||
|
>
|
||||||
<HelpIcon />
|
<HelpIcon />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default injectSheet(styles)(Help);
|
export default injectSheet(styles)(Help);
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import classNames from "classnames";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
classes: any
|
classes: any
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
textinfo: {
|
textinfo: {
|
||||||
color: "#98d8f3 !important"
|
color: "#98d8f3 !important"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class HelpIcon extends React.Component<Props> {
|
class HelpIcon extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { classes } = this.props;
|
const { classes } = this.props;
|
||||||
return <i className={classNames("fa fa-question-circle has-text-info", classes.textinfo)}></i>;
|
return (
|
||||||
|
<Icon className={classes.textinfo} name="question-circle" />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,26 @@ import classNames from "classnames";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title?: string,
|
title?: string,
|
||||||
name: string
|
name: string,
|
||||||
}
|
color: string,
|
||||||
|
className?: string
|
||||||
|
};
|
||||||
|
|
||||||
export default class Icon extends React.Component<Props> {
|
export default class Icon extends React.Component<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
color: "grey-light"
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { title, name } = this.props;
|
const { title, name, color, className } = this.props;
|
||||||
if(title) {
|
if (title) {
|
||||||
return (
|
return (
|
||||||
<i title={title} className={classNames("is-icon", "fas", "fa-fw", "fa-" + name)}/>
|
<i
|
||||||
|
title={title}
|
||||||
|
className={classNames("fas", "fa-fw", "fa-" + name, `has-text-${color}`, className)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return <i className={classNames("fas", "fa-" + name, `has-text-${color}`, className)} />;
|
||||||
<i className={classNames("is-icon", "fas", "fa-" + name)}/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import SyntaxHighlighter from "./SyntaxHighlighter";
|
|
||||||
import Markdown from "react-markdown/with-html";
|
|
||||||
import {binder} from "@scm-manager/ui-extensions";
|
|
||||||
import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer";
|
|
||||||
import { withRouter } from "react-router-dom";
|
import { withRouter } from "react-router-dom";
|
||||||
|
import injectSheet from "react-jss";
|
||||||
|
import Markdown from "react-markdown/with-html";
|
||||||
|
import { binder } from "@scm-manager/ui-extensions";
|
||||||
|
import SyntaxHighlighter from "./SyntaxHighlighter";
|
||||||
|
import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
content: string,
|
content: string,
|
||||||
@@ -14,11 +14,34 @@ type Props = {
|
|||||||
enableAnchorHeadings: boolean,
|
enableAnchorHeadings: boolean,
|
||||||
|
|
||||||
// context props
|
// context props
|
||||||
|
classes: any,
|
||||||
location: any
|
location: any
|
||||||
};
|
};
|
||||||
|
|
||||||
class MarkdownView extends React.Component<Props> {
|
const styles = {
|
||||||
|
markdown: {
|
||||||
|
"& > .content": {
|
||||||
|
"& > h1, h2, h3, h4, h5, h6": {
|
||||||
|
margin: "0.5rem 0",
|
||||||
|
fontSize: "0.9rem"
|
||||||
|
},
|
||||||
|
"& > h1": {
|
||||||
|
fontWeight: "700"
|
||||||
|
},
|
||||||
|
"& > h2": {
|
||||||
|
fontWeight: "600"
|
||||||
|
},
|
||||||
|
"& > h3, h4, h5, h6": {
|
||||||
|
fontWeight: "500"
|
||||||
|
},
|
||||||
|
"& strong": {
|
||||||
|
fontWeight: "500"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownView extends React.Component<Props> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
enableAnchorHeadings: false
|
enableAnchorHeadings: false
|
||||||
};
|
};
|
||||||
@@ -45,16 +68,22 @@ class MarkdownView extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {content, renderers, renderContext, enableAnchorHeadings} = this.props;
|
const {
|
||||||
|
content,
|
||||||
|
renderers,
|
||||||
|
renderContext,
|
||||||
|
enableAnchorHeadings,
|
||||||
|
classes
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
const rendererFactory = binder.getExtension("markdown-renderer-factory");
|
const rendererFactory = binder.getExtension("markdown-renderer-factory");
|
||||||
let rendererList = renderers;
|
let rendererList = renderers;
|
||||||
|
|
||||||
if (rendererFactory){
|
if (rendererFactory) {
|
||||||
rendererList = rendererFactory(renderContext);
|
rendererList = rendererFactory(renderContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rendererList){
|
if (!rendererList) {
|
||||||
rendererList = {};
|
rendererList = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,12 +91,12 @@ class MarkdownView extends React.Component<Props> {
|
|||||||
rendererList.heading = MarkdownHeadingRenderer;
|
rendererList.heading = MarkdownHeadingRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rendererList.code){
|
if (!rendererList.code) {
|
||||||
rendererList.code = SyntaxHighlighter;
|
rendererList.code = SyntaxHighlighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={el => (this.contentRef = el)}>
|
<div className={classes.markdown} ref={el => (this.contentRef = el)}>
|
||||||
<Markdown
|
<Markdown
|
||||||
className="content"
|
className="content"
|
||||||
skipHtml={true}
|
skipHtml={true}
|
||||||
@@ -80,4 +109,4 @@ class MarkdownView extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(MarkdownView);
|
export default injectSheet(styles)(withRouter(MarkdownView));
|
||||||
|
|||||||
60
scm-ui-components/packages/ui-components/src/Tag.js
Normal file
60
scm-ui-components/packages/ui-components/src/Tag.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
className?: string,
|
||||||
|
color: string,
|
||||||
|
icon?: string,
|
||||||
|
label: string,
|
||||||
|
title?: string,
|
||||||
|
onClick?: () => void,
|
||||||
|
onRemove?: () => void
|
||||||
|
};
|
||||||
|
|
||||||
|
class Tag extends React.Component<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
color: "light"
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
className,
|
||||||
|
color,
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
title,
|
||||||
|
onClick,
|
||||||
|
onRemove
|
||||||
|
} = this.props;
|
||||||
|
let showIcon = null;
|
||||||
|
if (icon) {
|
||||||
|
showIcon = (
|
||||||
|
<>
|
||||||
|
<i className={classNames("fas", `fa-${icon}`)} />
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let showDelete = null;
|
||||||
|
if (onRemove) {
|
||||||
|
showDelete = <a className="tag is-delete" onClick={onRemove} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span
|
||||||
|
className={classNames("tag", `is-${color}`, className)}
|
||||||
|
title={title}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
{showIcon}
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
{showDelete}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tag;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Button, { type ButtonProps } from "./Button";
|
import Button, { type ButtonProps } from "./Button";
|
||||||
|
|
||||||
class AddButton extends React.Component<ButtonProps> {
|
class AddButton extends React.Component<ButtonProps> {
|
||||||
render() {
|
render() {
|
||||||
return <Button color="default" {...this.props} />;
|
return <Button color="default" icon="plus" {...this.props} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AddButton;
|
export default AddButton;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { withRouter } from "react-router-dom";
|
import { withRouter } from "react-router-dom";
|
||||||
|
import Icon from "../Icon";
|
||||||
|
|
||||||
export type ButtonProps = {
|
export type ButtonProps = {
|
||||||
label?: string,
|
label?: string,
|
||||||
@@ -9,10 +10,12 @@ export type ButtonProps = {
|
|||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
action?: (event: Event) => void,
|
action?: (event: Event) => void,
|
||||||
link?: string,
|
link?: string,
|
||||||
fullWidth?: boolean,
|
|
||||||
className?: string,
|
className?: string,
|
||||||
|
icon?: string,
|
||||||
|
fullWidth?: boolean,
|
||||||
|
reducedMobile?: boolean,
|
||||||
children?: React.Node,
|
children?: React.Node,
|
||||||
|
|
||||||
// context props
|
// context props
|
||||||
classes: any
|
classes: any
|
||||||
};
|
};
|
||||||
@@ -47,12 +50,40 @@ class Button extends React.Component<Props> {
|
|||||||
disabled,
|
disabled,
|
||||||
type,
|
type,
|
||||||
color,
|
color,
|
||||||
|
className,
|
||||||
|
icon,
|
||||||
fullWidth,
|
fullWidth,
|
||||||
children,
|
reducedMobile,
|
||||||
className
|
children
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const loadingClass = loading ? "is-loading" : "";
|
const loadingClass = loading ? "is-loading" : "";
|
||||||
const fullWidthClass = fullWidth ? "is-fullwidth" : "";
|
const fullWidthClass = fullWidth ? "is-fullwidth" : "";
|
||||||
|
const reducedMobileClass = reducedMobile ? "is-reduced-mobile" : "";
|
||||||
|
if (icon) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type={type}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={this.onClick}
|
||||||
|
className={classNames(
|
||||||
|
"button",
|
||||||
|
"is-" + color,
|
||||||
|
loadingClass,
|
||||||
|
fullWidthClass,
|
||||||
|
reducedMobileClass,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className="icon is-medium">
|
||||||
|
<Icon name={icon} color="inherit" />
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{label} {children}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type={type}
|
type={type}
|
||||||
@@ -69,8 +100,7 @@ class Button extends React.Component<Props> {
|
|||||||
{label} {children}
|
{label} {children}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(Button);
|
export default withRouter(Button);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ButtonAddons extends React.Component<Props> {
|
|||||||
const childWrapper = [];
|
const childWrapper = [];
|
||||||
React.Children.forEach(children, child => {
|
React.Children.forEach(children, child => {
|
||||||
if (child) {
|
if (child) {
|
||||||
childWrapper.push(<p className="control">{child}</p>);
|
childWrapper.push(<p className="control" key={childWrapper.length}>{child}</p>);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import Button, { type ButtonProps } from "./Button";
|
|||||||
|
|
||||||
class DeleteButton extends React.Component<ButtonProps> {
|
class DeleteButton extends React.Component<ButtonProps> {
|
||||||
render() {
|
render() {
|
||||||
return <Button color="warning" {...this.props} />;
|
return <Button color="warning" icon="times" {...this.props} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class DownloadButton extends React.Component<Props> {
|
|||||||
const { displayName, url, disabled, onClick } = this.props;
|
const { displayName, url, disabled, onClick } = this.props;
|
||||||
const onClickOrDefault = !!onClick ? onClick : () => {};
|
const onClickOrDefault = !!onClick ? onClick : () => {};
|
||||||
return (
|
return (
|
||||||
<a className="button is-large is-link" href={url} disabled={disabled} onClick={onClickOrDefault}>
|
<a className="button is-link" href={url} disabled={disabled} onClick={onClickOrDefault}>
|
||||||
<span className="icon is-medium">
|
<span className="icon is-medium">
|
||||||
<i className="fas fa-arrow-circle-down" />
|
<i className="fas fa-arrow-circle-down" />
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
//@flow
|
|
||||||
import React from "react";
|
|
||||||
import { translate } from "react-i18next";
|
|
||||||
import RemoveEntryOfTableButton from "../buttons/RemoveEntryOfTableButton";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
members: string[],
|
|
||||||
t: string => string,
|
|
||||||
memberListChanged: (string[]) => void
|
|
||||||
};
|
|
||||||
|
|
||||||
type State = {};
|
|
||||||
|
|
||||||
class MemberNameTable extends React.Component<Props, State> {
|
|
||||||
render() {
|
|
||||||
const { t } = this.props;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<table className="table is-hoverable is-fullwidth">
|
|
||||||
<tbody>
|
|
||||||
{this.props.members.map(member => {
|
|
||||||
return (
|
|
||||||
<tr key={member}>
|
|
||||||
<td key={member}>{member}</td>
|
|
||||||
<td>
|
|
||||||
<RemoveEntryOfTableButton
|
|
||||||
entryname={member}
|
|
||||||
removeEntry={this.removeEntry}
|
|
||||||
disabled={false}
|
|
||||||
label={t("remove-member-button.label")}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeEntry = (membername: string) => {
|
|
||||||
const newMembers = this.props.members.filter(name => name !== membername);
|
|
||||||
this.props.memberListChanged(newMembers);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default translate("groups")(MemberNameTable);
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import type { DisplayedUser } from "@scm-manager/ui-types";
|
||||||
|
import TagGroup from "./TagGroup";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
members: string[],
|
||||||
|
memberListChanged: (string[]) => void,
|
||||||
|
t: string => string
|
||||||
|
};
|
||||||
|
|
||||||
|
class MemberNameTagGroup extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { members, t } = this.props;
|
||||||
|
const membersExtended = members.map(id => {
|
||||||
|
return { id, displayName: id, mail: "" };
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<TagGroup
|
||||||
|
items={membersExtended}
|
||||||
|
label={t("group.members")}
|
||||||
|
helpText={t("groupForm.help.memberHelpText")}
|
||||||
|
onRemove={this.removeEntry}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEntry = (membersExtended: DisplayedUser[]) => {
|
||||||
|
const members = membersExtended.map(function(item) {
|
||||||
|
return item["id"];
|
||||||
|
});
|
||||||
|
this.props.memberListChanged(members);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate("groups")(MemberNameTagGroup);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {translate} from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import InputField from "./InputField";
|
import InputField from "./InputField";
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -40,26 +40,28 @@ class PasswordConfirmation extends React.Component<Props, State> {
|
|||||||
render() {
|
render() {
|
||||||
const { t } = this.props;
|
const { t } = this.props;
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="columns is-multiline">
|
||||||
<InputField
|
<div className="column is-half">
|
||||||
label={t("password.newPassword")}
|
<InputField
|
||||||
type="password"
|
label={t("password.newPassword")}
|
||||||
onChange={this.handlePasswordChange}
|
type="password"
|
||||||
value={this.state.password ? this.state.password : ""}
|
onChange={this.handlePasswordChange}
|
||||||
validationError={!this.state.passwordValid}
|
value={this.state.password ? this.state.password : ""}
|
||||||
errorMessage={t("password.passwordInvalid")}
|
validationError={!this.state.passwordValid}
|
||||||
helpText={t("password.passwordHelpText")}
|
errorMessage={t("password.passwordInvalid")}
|
||||||
/>
|
/>
|
||||||
<InputField
|
</div>
|
||||||
label={t("password.confirmPassword")}
|
<div className="column is-half">
|
||||||
type="password"
|
<InputField
|
||||||
onChange={this.handlePasswordValidationChange}
|
label={t("password.confirmPassword")}
|
||||||
value={this.state ? this.state.confirmedPassword : ""}
|
type="password"
|
||||||
validationError={this.state.passwordConfirmationFailed}
|
onChange={this.handlePasswordValidationChange}
|
||||||
errorMessage={t("password.passwordConfirmFailed")}
|
value={this.state ? this.state.confirmedPassword : ""}
|
||||||
helpText={t("password.passwordConfirmHelpText")}
|
validationError={this.state.passwordConfirmationFailed}
|
||||||
/>
|
errorMessage={t("password.passwordConfirmFailed")}
|
||||||
</>
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +101,7 @@ class PasswordConfirmation extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
isValid = () => {
|
isValid = () => {
|
||||||
return this.state.passwordValid && !this.state.passwordConfirmationFailed
|
return this.state.passwordValid && !this.state.passwordConfirmationFailed;
|
||||||
};
|
};
|
||||||
|
|
||||||
propagateChange = () => {
|
propagateChange = () => {
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
import injectSheet from "react-jss";
|
||||||
|
import type { DisplayedUser } from "@scm-manager/ui-types";
|
||||||
|
import { Help, Tag } from "../index";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
items: DisplayedUser[],
|
||||||
|
label: string,
|
||||||
|
helpText?: string,
|
||||||
|
onRemove: (DisplayedUser[]) => void,
|
||||||
|
|
||||||
|
// context props
|
||||||
|
classes: Object
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
help: {
|
||||||
|
position: "relative"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TagGroup extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { items, label, helpText, classes } = this.props;
|
||||||
|
let help = null;
|
||||||
|
if (helpText) {
|
||||||
|
help = <Help className={classes.help} message={helpText} />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="field is-grouped is-grouped-multiline">
|
||||||
|
{label && items ? (
|
||||||
|
<div className="control">
|
||||||
|
<strong>
|
||||||
|
{label}
|
||||||
|
{help}
|
||||||
|
{items.length > 0 ? ":" : ""}
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
{items.map((item, key) => {
|
||||||
|
return (
|
||||||
|
<div className="control" key={key}>
|
||||||
|
<div className="tags has-addons">
|
||||||
|
<Tag
|
||||||
|
color="info is-outlined"
|
||||||
|
label={item.displayName}
|
||||||
|
onRemove={() => this.removeEntry(item)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEntry = item => {
|
||||||
|
const newItems = this.props.items.filter(name => name !== item);
|
||||||
|
this.props.onRemove(newItems);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default injectSheet(styles)(TagGroup);
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
export { default as AddEntryToTableField } from "./AddEntryToTableField.js";
|
export { default as AddEntryToTableField } from "./AddEntryToTableField.js";
|
||||||
export { default as AutocompleteAddEntryToTableField } from "./AutocompleteAddEntryToTableField.js";
|
export { default as AutocompleteAddEntryToTableField } from "./AutocompleteAddEntryToTableField.js";
|
||||||
export { default as MemberNameTable } from "./MemberNameTable.js";
|
export { default as TagGroup } from "./TagGroup.js";
|
||||||
|
export { default as MemberNameTagGroup } from "./MemberNameTagGroup.js";
|
||||||
export { default as Checkbox } from "./Checkbox.js";
|
export { default as Checkbox } from "./Checkbox.js";
|
||||||
export { default as Radio } from "./Radio.js";
|
export { default as Radio } from "./Radio.js";
|
||||||
export { default as FilterInput } from "./FilterInput.js";
|
export { default as FilterInput } from "./FilterInput.js";
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export { default as FileSize } from "./FileSize.js";
|
|||||||
export { default as ProtectedRoute } from "./ProtectedRoute.js";
|
export { default as ProtectedRoute } from "./ProtectedRoute.js";
|
||||||
export { default as Help } from "./Help";
|
export { default as Help } from "./Help";
|
||||||
export { default as HelpIcon } from "./HelpIcon";
|
export { default as HelpIcon } from "./HelpIcon";
|
||||||
|
export { default as Tag } from "./Tag";
|
||||||
export { default as Tooltip } from "./Tooltip";
|
export { default as Tooltip } from "./Tooltip";
|
||||||
// TODO do we need this? getPageFromMatch is already exported by urls
|
// TODO do we need this? getPageFromMatch is already exported by urls
|
||||||
export { getPageFromMatch } from "./urls";
|
export { getPageFromMatch } from "./urls";
|
||||||
|
|||||||
@@ -18,7 +18,15 @@ class Modal extends React.Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
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;
|
const isActive = active ? "is-active" : null;
|
||||||
|
|
||||||
@@ -31,7 +39,12 @@ class Modal extends React.Component<Props> {
|
|||||||
<div className={classNames("modal", className, isActive)}>
|
<div className={classNames("modal", className, isActive)}>
|
||||||
<div className="modal-background" />
|
<div className="modal-background" />
|
||||||
<div className="modal-card">
|
<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>
|
<p className="modal-card-title is-marginless">{title}</p>
|
||||||
<button
|
<button
|
||||||
className="delete"
|
className="delete"
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Change, Diff as DiffComponent, DiffObjectProps, File, getChangeKey, Hunk} from "react-diff-view";
|
import {
|
||||||
|
Change,
|
||||||
|
Diff as DiffComponent,
|
||||||
|
DiffObjectProps,
|
||||||
|
File,
|
||||||
|
getChangeKey,
|
||||||
|
Hunk
|
||||||
|
} from "react-diff-view";
|
||||||
import injectSheets from "react-jss";
|
import injectSheets from "react-jss";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import {translate} from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import {Button, ButtonGroup} from "../buttons";
|
import { Button, ButtonGroup } from "../buttons";
|
||||||
|
import Tag from "../Tag";
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
panel: {
|
panel: {
|
||||||
@@ -34,12 +42,35 @@ const styles = {
|
|||||||
},
|
},
|
||||||
changeType: {
|
changeType: {
|
||||||
marginLeft: ".75rem"
|
marginLeft: ".75rem"
|
||||||
|
},
|
||||||
|
diff: {
|
||||||
|
/* column sizing */
|
||||||
|
"& > colgroup .diff-gutter-col": {
|
||||||
|
width: "3.25rem"
|
||||||
|
},
|
||||||
|
/* prevent following content from moving down */
|
||||||
|
"& > .diff-gutter:empty:hover::after": {
|
||||||
|
fontSize: "0.7rem"
|
||||||
|
},
|
||||||
|
/* smaller font size for code */
|
||||||
|
"& .diff-line": {
|
||||||
|
fontSize: "0.75rem"
|
||||||
|
},
|
||||||
|
/* comment padding for sideBySide view */
|
||||||
|
"&.split .diff-widget-content .is-indented-line": {
|
||||||
|
paddingLeft: "3.25rem"
|
||||||
|
},
|
||||||
|
/* comment padding for combined view */
|
||||||
|
"&.unified .diff-widget-content .is-indented-line": {
|
||||||
|
paddingLeft: "6.5rem"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = DiffObjectProps & {
|
type Props = DiffObjectProps & {
|
||||||
file: File,
|
file: File,
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
|
||||||
// context props
|
// context props
|
||||||
classes: any,
|
classes: any,
|
||||||
t: string => string
|
t: string => string
|
||||||
@@ -179,23 +210,21 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
const color =
|
const color =
|
||||||
value === "added"
|
value === "added"
|
||||||
? "is-success"
|
? "success is-outlined"
|
||||||
: value === "deleted"
|
: value === "deleted"
|
||||||
? "is-danger"
|
? "danger is-outlined"
|
||||||
: "is-info";
|
: "info is-outlined";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<Tag
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"tag",
|
|
||||||
"is-rounded",
|
"is-rounded",
|
||||||
"has-text-weight-normal",
|
"has-text-weight-normal",
|
||||||
color,
|
|
||||||
classes.changeType
|
classes.changeType
|
||||||
)}
|
)}
|
||||||
>
|
color={color}
|
||||||
{value}
|
label={value}
|
||||||
</span>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -219,15 +248,18 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
: null;
|
: null;
|
||||||
icon = "fa fa-angle-down";
|
icon = "fa fa-angle-down";
|
||||||
body = (
|
body = (
|
||||||
<div className="panel-block is-paddingless is-size-7">
|
<div className="panel-block is-paddingless">
|
||||||
{fileAnnotations}
|
{fileAnnotations}
|
||||||
<DiffComponent viewType={viewType}>
|
<DiffComponent
|
||||||
|
className={classNames(viewType, classes.diff)}
|
||||||
|
viewType={viewType}
|
||||||
|
>
|
||||||
{file.hunks.map(this.renderHunk)}
|
{file.hunks.map(this.renderHunk)}
|
||||||
</DiffComponent>
|
</DiffComponent>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const collapseIcon = collapsible? <i className={icon} />: null;
|
const collapseIcon = collapsible ? <i className={icon} /> : null;
|
||||||
|
|
||||||
const fileControls = fileControlFactory
|
const fileControls = fileControlFactory
|
||||||
? fileControlFactory(file, this.setCollapse)
|
? fileControlFactory(file, this.setCollapse)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const styles = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
avatarFigure: {
|
avatarFigure: {
|
||||||
marginTop: ".25rem",
|
marginTop: ".5rem",
|
||||||
marginRight: ".5rem"
|
marginRight: ".5rem"
|
||||||
},
|
},
|
||||||
avatarImage: {
|
avatarImage: {
|
||||||
@@ -35,6 +35,9 @@ const styles = {
|
|||||||
metadata: {
|
metadata: {
|
||||||
marginLeft: 0
|
marginLeft: 0
|
||||||
},
|
},
|
||||||
|
authorMargin: {
|
||||||
|
marginTop: "0.5rem"
|
||||||
|
},
|
||||||
isVcentered: {
|
isVcentered: {
|
||||||
alignSelf: "center"
|
alignSelf: "center"
|
||||||
},
|
},
|
||||||
@@ -70,15 +73,6 @@ class ChangesetRow extends React.Component<Props> {
|
|||||||
<div className="column is-three-fifths">
|
<div className="column is-three-fifths">
|
||||||
<div className="columns is-gapless">
|
<div className="columns is-gapless">
|
||||||
<div className="column is-four-fifths">
|
<div className="column is-four-fifths">
|
||||||
<h4 className="has-text-weight-bold is-ellipsis-overflow">
|
|
||||||
<ExtensionPoint
|
|
||||||
name="changeset.description"
|
|
||||||
props={{ changeset, value: description.title }}
|
|
||||||
renderAll={false}
|
|
||||||
>
|
|
||||||
{description.title}
|
|
||||||
</ExtensionPoint>
|
|
||||||
</h4>
|
|
||||||
<div className="media">
|
<div className="media">
|
||||||
<AvatarWrapper>
|
<AvatarWrapper>
|
||||||
<figure
|
<figure
|
||||||
@@ -90,6 +84,15 @@ class ChangesetRow extends React.Component<Props> {
|
|||||||
</figure>
|
</figure>
|
||||||
</AvatarWrapper>
|
</AvatarWrapper>
|
||||||
<div className={classNames(classes.metadata, "media-right")}>
|
<div className={classNames(classes.metadata, "media-right")}>
|
||||||
|
<h4 className="has-text-weight-bold is-ellipsis-overflow">
|
||||||
|
<ExtensionPoint
|
||||||
|
name="changeset.description"
|
||||||
|
props={{ changeset, value: description.title }}
|
||||||
|
renderAll={false}
|
||||||
|
>
|
||||||
|
{description.title}
|
||||||
|
</ExtensionPoint>
|
||||||
|
</h4>
|
||||||
<p className="is-hidden-touch">
|
<p className="is-hidden-touch">
|
||||||
<Interpolate
|
<Interpolate
|
||||||
i18nKey="changeset.summary"
|
i18nKey="changeset.summary"
|
||||||
@@ -104,7 +107,7 @@ class ChangesetRow extends React.Component<Props> {
|
|||||||
time={dateFromNow}
|
time={dateFromNow}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<p className="is-size-7">
|
<p className={classNames("is-size-7", classes.authorMargin)}>
|
||||||
<ChangesetAuthor changeset={changeset} />
|
<ChangesetAuthor changeset={changeset} />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ type Props = {
|
|||||||
class ChangesetTag extends React.Component<Props> {
|
class ChangesetTag extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { tag } = this.props;
|
const { tag } = this.props;
|
||||||
return <ChangesetTagBase icon={"fa-tag"} label={tag.name} />;
|
return <ChangesetTagBase icon="tag" label={tag.name} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,19 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import injectSheet from "react-jss";
|
import Tag from "../../Tag";
|
||||||
import classNames from "classnames";
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
spacing: {
|
|
||||||
marginRight: ".25rem"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
icon: string,
|
icon: string,
|
||||||
label: string,
|
label: string
|
||||||
|
|
||||||
// context props
|
|
||||||
classes: Object
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChangesetTagBase extends React.Component<Props> {
|
class ChangesetTagBase extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { icon, label, classes } = this.props;
|
const { icon, label } = this.props;
|
||||||
return (
|
return (
|
||||||
<span className={classNames("tag", "is-info")}>
|
<Tag color="info" icon={icon} label={label} />
|
||||||
<span className={classNames("fa", icon, classes.spacing)} /> {label}
|
|
||||||
</span>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default injectSheet(styles)(ChangesetTagBase);
|
export default ChangesetTagBase;
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { Tag } from "@scm-manager/ui-types";
|
|
||||||
import ChangesetTagBase from "./ChangesetTagBase";
|
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
|
import type { Tag } from "@scm-manager/ui-types";
|
||||||
import Tooltip from "../../Tooltip";
|
import Tooltip from "../../Tooltip";
|
||||||
|
import ChangesetTagBase from "./ChangesetTagBase";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
tags: Tag[],
|
tags: Tag[],
|
||||||
|
|
||||||
// context props
|
// context props
|
||||||
t: (string) => string
|
t: string => string
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChangesetTagsCollapsed extends React.Component<Props> {
|
class ChangesetTagsCollapsed extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { tags, t } = this.props;
|
const { tags, t } = this.props;
|
||||||
const message = tags.map((tag) => tag.name).join(", ");
|
const message = tags.map(tag => tag.name).join(", ");
|
||||||
return (
|
return (
|
||||||
<Tooltip location="top" message={message}>
|
<Tooltip location="top" message={message}>
|
||||||
<ChangesetTagBase icon={"fa-tags"} label={ tags.length + " " + t("changeset.tags") } />
|
<ChangesetTagBase
|
||||||
|
icon="tags"
|
||||||
|
label={tags.length + " " + t("changeset.tags")}
|
||||||
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import type { Links } from "./hal";
|
import type { Links } from "./hal";
|
||||||
|
|
||||||
|
export type DisplayedUser = {
|
||||||
|
id: string,
|
||||||
|
displayName: string,
|
||||||
|
mail: string
|
||||||
|
};
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
displayName: string,
|
displayName: string,
|
||||||
name: string,
|
name: string,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export type { Action } from "./Action";
|
|||||||
export type { Link, Links, Collection, PagedCollection } from "./hal";
|
export type { Link, Links, Collection, PagedCollection } from "./hal";
|
||||||
|
|
||||||
export type { Me } from "./Me";
|
export type { Me } from "./Me";
|
||||||
export type { User } from "./User";
|
export type { DisplayedUser, User } from "./User";
|
||||||
export type { Group, Member } from "./Group";
|
export type { Group, Member } from "./Group";
|
||||||
|
|
||||||
export type { Repository, RepositoryCollection, RepositoryGroup } from "./Repositories";
|
export type { Repository, RepositoryCollection, RepositoryGroup } from "./Repositories";
|
||||||
|
|||||||
@@ -79,8 +79,6 @@
|
|||||||
"password": {
|
"password": {
|
||||||
"label": "Passwort",
|
"label": "Passwort",
|
||||||
"newPassword": "Neues Passwort",
|
"newPassword": "Neues Passwort",
|
||||||
"passwordHelpText": "Klartext Passwort des Benutzers.",
|
|
||||||
"passwordConfirmHelpText": "Passwort zur Bestätigen wiederholen.",
|
|
||||||
"currentPassword": "Aktuelles Passwort",
|
"currentPassword": "Aktuelles Passwort",
|
||||||
"currentPasswordHelpText": "Dieses Passwort wird momentan bereits verwendet.",
|
"currentPasswordHelpText": "Dieses Passwort wird momentan bereits verwendet.",
|
||||||
"confirmPassword": "Passwort wiederholen",
|
"confirmPassword": "Passwort wiederholen",
|
||||||
|
|||||||
@@ -38,15 +38,11 @@
|
|||||||
"add-member-button": {
|
"add-member-button": {
|
||||||
"label": "Mitglied hinzufügen"
|
"label": "Mitglied hinzufügen"
|
||||||
},
|
},
|
||||||
"remove-member-button": {
|
|
||||||
"label": "Mitglied entfernen"
|
|
||||||
},
|
|
||||||
"add-member-textfield": {
|
"add-member-textfield": {
|
||||||
"label": "Mitglied hinzufügen",
|
|
||||||
"error": "Ungültiger Name für Mitglied"
|
"error": "Ungültiger Name für Mitglied"
|
||||||
},
|
},
|
||||||
"add-member-autocomplete": {
|
"add-member-autocomplete": {
|
||||||
"placeholder": "Benutzername eingeben",
|
"placeholder": "Mitglied hinzufügen",
|
||||||
"loading": "Suche...",
|
"loading": "Suche...",
|
||||||
"no-options": "Kein Vorschlag für Benutzername verfügbar"
|
"no-options": "Kein Vorschlag für Benutzername verfügbar"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -80,8 +80,6 @@
|
|||||||
"password": {
|
"password": {
|
||||||
"label": "Password",
|
"label": "Password",
|
||||||
"newPassword": "New password",
|
"newPassword": "New password",
|
||||||
"passwordHelpText": "Plain text password of the user",
|
|
||||||
"passwordConfirmHelpText": "Repeat the password for confirmation",
|
|
||||||
"currentPassword": "Current password",
|
"currentPassword": "Current password",
|
||||||
"currentPasswordHelpText": "The password currently in use",
|
"currentPasswordHelpText": "The password currently in use",
|
||||||
"confirmPassword": "Confirm password",
|
"confirmPassword": "Confirm password",
|
||||||
|
|||||||
@@ -38,15 +38,11 @@
|
|||||||
"add-member-button": {
|
"add-member-button": {
|
||||||
"label": "Add Member"
|
"label": "Add Member"
|
||||||
},
|
},
|
||||||
"remove-member-button": {
|
|
||||||
"label": "Remove Member"
|
|
||||||
},
|
|
||||||
"add-member-textfield": {
|
"add-member-textfield": {
|
||||||
"label": "Add Member",
|
|
||||||
"error": "Invalid member name"
|
"error": "Invalid member name"
|
||||||
},
|
},
|
||||||
"add-member-autocomplete": {
|
"add-member-autocomplete": {
|
||||||
"placeholder": "Enter Member",
|
"placeholder": "Add Member",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
"no-options": "No suggestion available"
|
"no-options": "No suggestion available"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,15 +38,11 @@
|
|||||||
"add-member-button": {
|
"add-member-button": {
|
||||||
"label": "Añadir miembro"
|
"label": "Añadir miembro"
|
||||||
},
|
},
|
||||||
"remove-member-button": {
|
|
||||||
"label": "Eliminar miembro"
|
|
||||||
},
|
|
||||||
"add-member-textfield": {
|
"add-member-textfield": {
|
||||||
"label": "Añadir miembro",
|
|
||||||
"error": "El nombre del miembro es incorrecto"
|
"error": "El nombre del miembro es incorrecto"
|
||||||
},
|
},
|
||||||
"add-member-autocomplete": {
|
"add-member-autocomplete": {
|
||||||
"placeholder": "Introducir el nombre del miembro",
|
"placeholder": "Añadir miembro",
|
||||||
"loading": "Cargando...",
|
"loading": "Cargando...",
|
||||||
"no-options": "No hay sugerencias disponibles"
|
"no-options": "No hay sugerencias disponibles"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import classNames from "classnames";
|
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
|
import { Tag } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
system?: boolean,
|
system?: boolean,
|
||||||
@@ -25,9 +25,11 @@ class SystemRoleTag extends React.Component<Props> {
|
|||||||
|
|
||||||
if (system) {
|
if (system) {
|
||||||
return (
|
return (
|
||||||
<span className={classNames("tag is-dark", classes.tag)}>
|
<Tag
|
||||||
{t("repositoryRole.system")}
|
className={classes.tag}
|
||||||
</span>
|
color="dark"
|
||||||
|
label={t("repositoryRole.system")}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ const styles = {
|
|||||||
marginTop: "0.5em"
|
marginTop: "0.5em"
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
marginLeft: "1.5em"
|
marginLeft: "1.5em",
|
||||||
|
minHeight: "10.5rem"
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
display: "block",
|
display: "block",
|
||||||
|
|||||||
@@ -110,30 +110,42 @@ class ChangeUserPassword extends React.Component<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<form onSubmit={this.submit}>
|
<form onSubmit={this.submit}>
|
||||||
{message}
|
{message}
|
||||||
<InputField
|
<div className="columns">
|
||||||
label={t("password.currentPassword")}
|
<div className="column">
|
||||||
type="password"
|
<InputField
|
||||||
onChange={oldPassword =>
|
label={t("password.currentPassword")}
|
||||||
this.setState({ ...this.state, oldPassword })
|
type="password"
|
||||||
}
|
onChange={oldPassword =>
|
||||||
value={this.state.oldPassword ? this.state.oldPassword : ""}
|
this.setState({ ...this.state, oldPassword })
|
||||||
helpText={t("password.currentPasswordHelpText")}
|
}
|
||||||
/>
|
value={this.state.oldPassword ? this.state.oldPassword : ""}
|
||||||
|
helpText={t("password.currentPasswordHelpText")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<PasswordConfirmation
|
<PasswordConfirmation
|
||||||
passwordChanged={this.passwordChanged}
|
passwordChanged={this.passwordChanged}
|
||||||
key={this.state.passwordChanged ? "changed" : "unchanged"}
|
key={this.state.passwordChanged ? "changed" : "unchanged"}
|
||||||
/>
|
/>
|
||||||
<SubmitButton
|
<div className="columns">
|
||||||
disabled={!this.isValid()}
|
<div className="column">
|
||||||
loading={loading}
|
<SubmitButton
|
||||||
label={t("password.submit")}
|
disabled={!this.isValid()}
|
||||||
/>
|
loading={loading}
|
||||||
|
label={t("password.submit")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordChanged = (password: string, passwordValid: boolean) => {
|
passwordChanged = (password: string, passwordValid: boolean) => {
|
||||||
this.setState({ ...this.state, password, passwordValid: (!!password && passwordValid) });
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
password,
|
||||||
|
passwordValid: !!password && passwordValid
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onClose = () => {
|
onClose = () => {
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import { translate } from "react-i18next";
|
|||||||
import {
|
import {
|
||||||
Subtitle,
|
Subtitle,
|
||||||
AutocompleteAddEntryToTableField,
|
AutocompleteAddEntryToTableField,
|
||||||
LabelWithHelpIcon,
|
MemberNameTagGroup,
|
||||||
MemberNameTable,
|
|
||||||
InputField,
|
InputField,
|
||||||
SubmitButton,
|
SubmitButton,
|
||||||
Textarea,
|
Textarea,
|
||||||
@@ -55,10 +54,7 @@ class GroupForm extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isFalsy(value) {
|
isFalsy(value) {
|
||||||
if (!value) {
|
return !value;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid = () => {
|
isValid = () => {
|
||||||
@@ -85,11 +81,7 @@ class GroupForm extends React.Component<Props, State> {
|
|||||||
const { loadUserSuggestions, t } = this.props;
|
const { loadUserSuggestions, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LabelWithHelpIcon
|
<MemberNameTagGroup
|
||||||
label={t("group.members")}
|
|
||||||
helpText={t("groupForm.help.memberHelpText")}
|
|
||||||
/>
|
|
||||||
<MemberNameTable
|
|
||||||
members={group.members}
|
members={group.members}
|
||||||
memberListChanged={this.memberListChanged}
|
memberListChanged={this.memberListChanged}
|
||||||
/>
|
/>
|
||||||
@@ -97,7 +89,6 @@ class GroupForm extends React.Component<Props, State> {
|
|||||||
addEntry={this.addMember}
|
addEntry={this.addMember}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
buttonLabel={t("add-member-button.label")}
|
buttonLabel={t("add-member-button.label")}
|
||||||
fieldLabel={t("add-member-textfield.label")}
|
|
||||||
errorMessage={t("add-member-textfield.error")}
|
errorMessage={t("add-member-textfield.error")}
|
||||||
loadSuggestions={loadUserSuggestions}
|
loadSuggestions={loadUserSuggestions}
|
||||||
placeholder={t("add-member-autocomplete.placeholder")}
|
placeholder={t("add-member-autocomplete.placeholder")}
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import injectSheet from "react-jss";
|
||||||
|
import classNames from "classnames";
|
||||||
import type { Link } from "@scm-manager/ui-types";
|
import type { Link } from "@scm-manager/ui-types";
|
||||||
import {
|
import {
|
||||||
Notification,
|
Notification,
|
||||||
ErrorNotification,
|
ErrorNotification,
|
||||||
SubmitButton
|
SubmitButton
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import { translate } from "react-i18next";
|
import { getLink } from "../../modules/indexResource";
|
||||||
import {
|
import {
|
||||||
loadPermissionsForEntity,
|
loadPermissionsForEntity,
|
||||||
setPermissions
|
setPermissions
|
||||||
} from "./handlePermissions";
|
} from "./handlePermissions";
|
||||||
import PermissionCheckbox from "./PermissionCheckbox";
|
import PermissionCheckbox from "./PermissionCheckbox";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { getLink } from "../../modules/indexResource";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
t: string => string,
|
|
||||||
availablePermissionLink: string,
|
availablePermissionLink: string,
|
||||||
selectedPermissionsLink: Link
|
selectedPermissionsLink: Link,
|
||||||
|
|
||||||
|
// context props
|
||||||
|
classes: any,
|
||||||
|
t: string => string
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -30,6 +35,17 @@ type State = {
|
|||||||
overwritePermissionsLink?: Link
|
overwritePermissionsLink?: Link
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
permissionsWrapper: {
|
||||||
|
paddingBottom: "0",
|
||||||
|
|
||||||
|
"& .field .control": {
|
||||||
|
width: "100%",
|
||||||
|
wordWrap: "break-word"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class SetPermissions extends React.Component<Props, State> {
|
class SetPermissions extends React.Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -135,17 +151,35 @@ class SetPermissions extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderPermissions = () => {
|
renderPermissions = () => {
|
||||||
|
const { classes } = this.props;
|
||||||
const { overwritePermissionsLink, permissions } = this.state;
|
const { overwritePermissionsLink, permissions } = this.state;
|
||||||
return Object.keys(permissions).map(p => (
|
const permissionArray = Object.keys(permissions);
|
||||||
<div key={p}>
|
return (
|
||||||
<PermissionCheckbox
|
<div className="columns">
|
||||||
permission={p}
|
<div className={classNames("column", "is-half", classes.permissionsWrapper)}>
|
||||||
checked={permissions[p]}
|
{permissionArray.slice(0, (permissionArray.length/2)+1).map(p => (
|
||||||
onChange={this.valueChanged}
|
<PermissionCheckbox
|
||||||
disabled={!overwritePermissionsLink}
|
key={p}
|
||||||
/>
|
permission={p}
|
||||||
|
checked={permissions[p]}
|
||||||
|
onChange={this.valueChanged}
|
||||||
|
disabled={!overwritePermissionsLink}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className={classNames("column", "is-half", classes.permissionsWrapper)}>
|
||||||
|
{permissionArray.slice((permissionArray.length/2)+1, permissionArray.length).map(p => (
|
||||||
|
<PermissionCheckbox
|
||||||
|
key={p}
|
||||||
|
permission={p}
|
||||||
|
checked={permissions[p]}
|
||||||
|
onChange={this.valueChanged}
|
||||||
|
disabled={!overwritePermissionsLink}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
));
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
valueChanged = (value: boolean, name: string) => {
|
valueChanged = (value: boolean, name: string) => {
|
||||||
@@ -174,5 +208,4 @@ const mapStateToProps = state => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps)(
|
export default connect(mapStateToProps)(
|
||||||
translate("permissions")(SetPermissions)
|
injectSheet(styles)(translate("permissions")(SetPermissions)));
|
||||||
);
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import classNames from "classnames";
|
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
|
import { Tag } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
defaultBranch?: boolean,
|
defaultBranch?: boolean,
|
||||||
|
|
||||||
|
// context props
|
||||||
classes: any,
|
classes: any,
|
||||||
t: string => string
|
t: string => string
|
||||||
};
|
};
|
||||||
@@ -23,9 +25,11 @@ class DefaultBranchTag extends React.Component<Props> {
|
|||||||
|
|
||||||
if (defaultBranch) {
|
if (defaultBranch) {
|
||||||
return (
|
return (
|
||||||
<span className={classNames("tag is-dark", classes.tag)}>
|
<Tag
|
||||||
{t("branch.defaultTag")}
|
className={classes.tag}
|
||||||
</span>
|
color="dark"
|
||||||
|
label={t("branch.defaultTag")}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -105,17 +105,25 @@ class SetUserPassword extends React.Component<Props, State> {
|
|||||||
passwordChanged={this.passwordChanged}
|
passwordChanged={this.passwordChanged}
|
||||||
key={this.state.passwordChanged ? "changed" : "unchanged"}
|
key={this.state.passwordChanged ? "changed" : "unchanged"}
|
||||||
/>
|
/>
|
||||||
<SubmitButton
|
<div className="columns">
|
||||||
disabled={!this.state.passwordValid}
|
<div className="column">
|
||||||
loading={loading}
|
<SubmitButton
|
||||||
label={t("singleUserPassword.button")}
|
disabled={!this.state.passwordValid}
|
||||||
/>
|
loading={loading}
|
||||||
|
label={t("singleUserPassword.button")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordChanged = (password: string, passwordValid: boolean) => {
|
passwordChanged = (password: string, passwordValid: boolean) => {
|
||||||
this.setState({ ...this.state, password, passwordValid: (!!password && passwordValid) });
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
password,
|
||||||
|
passwordValid: !!password && passwordValid
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onClose = () => {
|
onClose = () => {
|
||||||
|
|||||||
@@ -162,9 +162,9 @@ class UserForm extends React.Component<Props, State> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{passwordChangeField}
|
||||||
<div className="columns">
|
<div className="columns">
|
||||||
<div className="column">
|
<div className="column">
|
||||||
{passwordChangeField}
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={t("user.active")}
|
label={t("user.active")}
|
||||||
onChange={this.handleActiveChange}
|
onChange={this.handleActiveChange}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
@import "bulma/sass/utilities/initial-variables";
|
@import "bulma/sass/utilities/initial-variables";
|
||||||
@import "bulma/sass/utilities/functions";
|
@import "bulma/sass/utilities/functions";
|
||||||
|
|
||||||
|
$turquoise: #00d1df;
|
||||||
$blue: #33b2e8;
|
$blue: #33b2e8;
|
||||||
$cyan: $blue;
|
$cyan: $blue;
|
||||||
$green: #00c79b;
|
$green: #00c79b;
|
||||||
$mint: #11dfd0;
|
|
||||||
|
|
||||||
.is-ellipsis-overflow {
|
.is-ellipsis-overflow {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -36,7 +36,7 @@ $mint: #11dfd0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
min-height: calc(100vh - 260px);
|
min-height: calc(100vh - 300px);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shown in top section when pageactions set
|
// shown in top section when pageactions set
|
||||||
@@ -96,7 +96,14 @@ $danger-75: scale-color($danger, $lightness: 25%);
|
|||||||
$danger-50: scale-color($danger, $lightness: 50%);
|
$danger-50: scale-color($danger, $lightness: 50%);
|
||||||
$danger-25: scale-color($danger, $lightness: 75%);
|
$danger-25: scale-color($danger, $lightness: 75%);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// not supported by ie
|
||||||
|
// css vars for external reuse
|
||||||
:root {
|
:root {
|
||||||
|
// asc sorted initial variables
|
||||||
|
--black: #{$black};
|
||||||
|
--white: #{$white};
|
||||||
|
|
||||||
// asc sorted derived-variables
|
// asc sorted derived-variables
|
||||||
--primary: #{$primary};
|
--primary: #{$primary};
|
||||||
--primary-75: #{$primary-75};
|
--primary-75: #{$primary-75};
|
||||||
@@ -131,7 +138,14 @@ $danger-25: scale-color($danger, $lightness: 75%);
|
|||||||
--link-50: #{$link-50};
|
--link-50: #{$link-50};
|
||||||
--link-25: #{$link-25};
|
--link-25: #{$link-25};
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// readability issues with original color
|
||||||
|
.has-text-warning {
|
||||||
|
color: #ffb600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// border and background colors
|
||||||
.has-background-dark-75 {
|
.has-background-dark-75 {
|
||||||
background-color: $dark-75;
|
background-color: $dark-75;
|
||||||
}
|
}
|
||||||
@@ -196,11 +210,183 @@ $danger-25: scale-color($danger, $lightness: 75%);
|
|||||||
background-color: $danger-25;
|
background-color: $danger-25;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-background-brown {
|
.has-background-warning-invert {
|
||||||
background-color: #000000b3;
|
background-color: $warning-invert;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tags
|
||||||
|
.tag:not(body) {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background-color: $white;
|
||||||
|
|
||||||
|
&.is-delete {
|
||||||
|
background-color: $light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-outlined {
|
||||||
|
background-color: $white;
|
||||||
|
}
|
||||||
|
&.is-black.is-outlined {
|
||||||
|
color: $black;
|
||||||
|
border-color: $black;
|
||||||
|
}
|
||||||
|
&.is-dark.is-outlined {
|
||||||
|
color: $dark;
|
||||||
|
border-color: $dark;
|
||||||
|
}
|
||||||
|
&.is-light.is-outlined {
|
||||||
|
color: $light;
|
||||||
|
border-color: $light;
|
||||||
|
}
|
||||||
|
&.is-white.is-outlined {
|
||||||
|
color: $white;
|
||||||
|
border-color: $white;
|
||||||
|
}
|
||||||
|
&.is-primary.is-outlined {
|
||||||
|
color: $primary;
|
||||||
|
border-color: $primary;
|
||||||
|
}
|
||||||
|
&.is-link.is-outlined {
|
||||||
|
color: $link;
|
||||||
|
border-color: $link;
|
||||||
|
}
|
||||||
|
&.is-info.is-outlined {
|
||||||
|
color: $info;
|
||||||
|
border-color: $info;
|
||||||
|
}
|
||||||
|
&.is-success.is-outlined {
|
||||||
|
color: $success;
|
||||||
|
border-color: $success;
|
||||||
|
}
|
||||||
|
&.is-warning.is-outlined {
|
||||||
|
color: $warning;
|
||||||
|
border-color: $warning;
|
||||||
|
}
|
||||||
|
&.is-danger.is-outlined {
|
||||||
|
color: $danger;
|
||||||
|
border-color: $danger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
.button {
|
||||||
|
padding-left: 1.5em;
|
||||||
|
padding-right: 1.5em;
|
||||||
|
height: 2.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-primary:hover,
|
||||||
|
&.is-primary.is-hovered {
|
||||||
|
background-color: scale-color($primary, $lightness: -10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-primary:active,
|
||||||
|
&.is-primary.is-active {
|
||||||
|
background-color: scale-color($primary, $lightness: -20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-primary[disabled] {
|
||||||
|
background-color: scale-color($primary, $lightness: 75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-info:hover,
|
||||||
|
&.is-info.is-hovered {
|
||||||
|
background-color: scale-color($info, $lightness: -10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-info:active,
|
||||||
|
&.is-info.is-active {
|
||||||
|
background-color: scale-color($info, $lightness: -20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-info[disabled] {
|
||||||
|
background-color: scale-color($info, $lightness: 75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-link:hover,
|
||||||
|
&.is-link.is-hovered {
|
||||||
|
background-color: scale-color($link, $lightness: -10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-link:active,
|
||||||
|
&.is-link.is-active {
|
||||||
|
background-color: scale-color($link, $lightness: -20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-link[disabled] {
|
||||||
|
background-color: scale-color($link, $lightness: 75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-success:hover,
|
||||||
|
&.is-success.is-hovered {
|
||||||
|
background-color: scale-color($success, $lightness: -10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-success:active,
|
||||||
|
&.is-success.is-active {
|
||||||
|
background-color: scale-color($success, $lightness: -20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-success[disabled] {
|
||||||
|
background-color: scale-color($success, $lightness: 75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-warning:hover,
|
||||||
|
&.is-warning.is-hovered {
|
||||||
|
background-color: scale-color($warning, $lightness: -10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-warning:active,
|
||||||
|
&.is-warning.is-active {
|
||||||
|
background-color: scale-color($warning, $lightness: -20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-warning[disabled] {
|
||||||
|
background-color: scale-color($warning, $lightness: 75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-danger:hover,
|
||||||
|
&.is-danger.is-hovered {
|
||||||
|
background-color: scale-color($danger, $lightness: -10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-danger:active,
|
||||||
|
&.is-danger.is-active {
|
||||||
|
background-color: scale-color($danger, $lightness: -20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-danger[disabled] {
|
||||||
|
background-color: scale-color($danger, $lightness: 75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-reduced-mobile,
|
||||||
|
&.reduced-mobile {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
|
||||||
|
@media screen and (max-width: 1087px) {
|
||||||
|
> span:nth-child(2) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 1087px) and (min-width: 769px) {
|
||||||
|
// simultaneously with left margin of Bulma
|
||||||
|
> .icon:first-child:not(:last-child) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
// simultaneously with left margin of Bulma
|
||||||
|
.icon:first-child:not(:last-child) {
|
||||||
|
margin-right: calc(-0.375em - 1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// import at the end, because we need a lot of stuff from bulma/bulma
|
|
||||||
.box-link-shadow {
|
.box-link-shadow {
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
@@ -235,53 +421,7 @@ ul.is-separated {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.user {
|
// columns
|
||||||
display: inline-block;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
// buttons
|
|
||||||
.button {
|
|
||||||
padding-left: 1.5em;
|
|
||||||
padding-right: 1.5em;
|
|
||||||
height: 2.5rem;
|
|
||||||
|
|
||||||
&.is-primary {
|
|
||||||
background-color: #00d1df;
|
|
||||||
}
|
|
||||||
&.is-primary:hover,
|
|
||||||
&.is-primary.is-hovered {
|
|
||||||
background-color: #00b9c6;
|
|
||||||
}
|
|
||||||
&.is-primary:active,
|
|
||||||
&.is-primary.is-active {
|
|
||||||
background-color: #00a1ac;
|
|
||||||
}
|
|
||||||
&.is-primary[disabled] {
|
|
||||||
background-color: #40dde7;
|
|
||||||
}
|
|
||||||
&.reduced-mobile {
|
|
||||||
@media screen and (max-width: 1087px) {
|
|
||||||
> span:nth-child(2) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (max-width: 1087px) and (min-width: 769px) {
|
|
||||||
// simultaneously with left margin of Bulma
|
|
||||||
> .icon:first-child:not(:last-child) {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
// simultaneously with left margin of Bulma
|
|
||||||
.icon:first-child:not(:last-child) {
|
|
||||||
margin-right: calc(-0.375em - 1px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiline Columns
|
|
||||||
.columns.is-multiline {
|
.columns.is-multiline {
|
||||||
.column {
|
.column {
|
||||||
height: 120px;
|
height: 120px;
|
||||||
@@ -416,7 +556,7 @@ ul.is-separated {
|
|||||||
|
|
||||||
.panel-heading {
|
.panel-heading {
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 1px solid #dbdbdb;
|
border-bottom: 1px solid $border;
|
||||||
border-radius: 0.25rem 0.25rem 0 0;
|
border-radius: 0.25rem 0.25rem 0 0;
|
||||||
|
|
||||||
> .field {
|
> .field {
|
||||||
@@ -427,14 +567,6 @@ ul.is-separated {
|
|||||||
.panel-block {
|
.panel-block {
|
||||||
display: block;
|
display: block;
|
||||||
border: none;
|
border: none;
|
||||||
|
|
||||||
& .comment-wrapper:first-child div:first-child {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .diff-widget-content div {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-footer {
|
.panel-footer {
|
||||||
@@ -445,7 +577,7 @@ ul.is-separated {
|
|||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
padding: 0.5em 0.75em;
|
padding: 0.5em 0.75em;
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid #dbdbdb;
|
border-top: 1px solid $border;
|
||||||
border-radius: 0 0 0.25rem 0.25rem;
|
border-radius: 0 0 0.25rem 0.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -470,10 +602,6 @@ form .field:not(.is-grouped) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-icon {
|
|
||||||
color: $grey-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
// label with help-icon compensation
|
// label with help-icon compensation
|
||||||
.label-icon-spacing {
|
.label-icon-spacing {
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
@@ -499,14 +627,19 @@ form .field:not(.is-grouped) {
|
|||||||
.pagination-ellipsis {
|
.pagination-ellipsis {
|
||||||
padding-left: 1.5em;
|
padding-left: 1.5em;
|
||||||
padding-right: 1.5em;
|
padding-right: 1.5em;
|
||||||
height: 2.5rem;
|
height: 2.8rem;
|
||||||
|
min-width: 5rem;
|
||||||
}
|
}
|
||||||
.pagination-previous,
|
.pagination-previous,
|
||||||
.pagination-next {
|
.pagination-next {
|
||||||
|
height: 2.8rem;
|
||||||
min-width: 6.75em;
|
min-width: 6.75em;
|
||||||
}
|
}
|
||||||
|
.pagination-link.is-current {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
// dark hero colors
|
// hero
|
||||||
.hero.is-dark {
|
.hero.is-dark {
|
||||||
background-color: #002e4b;
|
background-color: #002e4b;
|
||||||
background-image: url(../images/scmManagerHero.jpg);
|
background-image: url(../images/scmManagerHero.jpg);
|
||||||
@@ -528,7 +661,7 @@ form .field:not(.is-grouped) {
|
|||||||
background-color: whitesmoke;
|
background-color: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sidebar menu
|
// aside
|
||||||
.aside-background {
|
.aside-background {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@@ -537,6 +670,8 @@ form .field:not(.is-grouped) {
|
|||||||
top: 0;
|
top: 0;
|
||||||
background-color: whitesmoke;
|
background-color: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// menu
|
||||||
.menu {
|
.menu {
|
||||||
div {
|
div {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -544,7 +679,6 @@ form .field:not(.is-grouped) {
|
|||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-label {
|
.menu-label {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
@@ -614,17 +748,6 @@ form .field:not(.is-grouped) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// modal
|
|
||||||
.modal {
|
|
||||||
.modal-card-foot {
|
|
||||||
justify-content: flex-end; // pulled-right
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-card-body div div:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-menu li {
|
.sub-menu li {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
|
||||||
@@ -650,6 +773,17 @@ form .field:not(.is-grouped) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// modal
|
||||||
|
.modal {
|
||||||
|
.modal-card-foot {
|
||||||
|
justify-content: flex-end; // pulled-right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-card-body div div:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
// cursor
|
// cursor
|
||||||
.has-cursor-pointer {
|
.has-cursor-pointer {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
Reference in New Issue
Block a user