merge 2.0.0-m3

This commit is contained in:
Maren Süwer
2018-10-05 10:21:11 +02:00
28 changed files with 230 additions and 11968 deletions

View File

@@ -0,0 +1,39 @@
//@flow
import React from "react";
import injectSheet from "react-jss";
import classNames from "classnames";
const styles = {
img: {
display: "block"
},
q: {
float: "left",
paddingLeft: "3px",
float: "right"
}
};
type Props = {
message: string,
classes: any
};
class Help extends React.Component<Props> {
render() {
const { message, classes } = this.props;
const multiline = message.length > 60 ? "is-tooltip-multiline" : "";
return (
<div
className={classNames("tooltip is-tooltip-right", multiline, classes.q)}
data-tooltip={message}
>
<i
className={classNames("fa fa-question has-text-info", classes.img)}
/>
</div>
);
}
}
export default injectSheet(styles)(Help);

View File

@@ -0,0 +1,46 @@
//@flow
import React from "react";
import { Help } from "./index";
type Props = {
label: string,
helpText?: string
};
class LabelWithHelpIcon extends React.Component<Props> {
renderLabel = () => {
const label = this.props.label;
if (label) {
return <label className="label">{label}</label>;
}
return "";
};
renderHelp = () => {
const helpText = this.props.helpText;
if (helpText) {
return (
<div className="control columns is-vcentered">
<Help message={helpText} />
</div>
);
} else return null;
};
renderLabelWithHelpIcon = () => {
if (this.props.label) {
return (
<div className="field is-grouped">
<div className="control">{this.renderLabel()}</div>
{this.renderHelp()}
</div>
);
} else return null;
};
render() {
return this.renderLabelWithHelpIcon();
}
}
export default LabelWithHelpIcon;

View File

@@ -9,7 +9,8 @@ type Props = {
disabled: boolean, disabled: boolean,
buttonLabel: string, buttonLabel: string,
fieldLabel: string, fieldLabel: string,
errorMessage: string errorMessage: string,
helpText?: string
}; };
type State = { type State = {
@@ -25,7 +26,13 @@ class AddEntryToTableField extends React.Component<Props, State> {
} }
render() { render() {
const { disabled, buttonLabel, fieldLabel, errorMessage } = this.props; const {
disabled,
buttonLabel,
fieldLabel,
errorMessage,
helpText
} = this.props;
return ( return (
<div className="field"> <div className="field">
<InputField <InputField
@@ -36,6 +43,7 @@ class AddEntryToTableField extends React.Component<Props, State> {
value={this.state.entryToAdd} value={this.state.entryToAdd}
onReturnPressed={this.appendEntry} onReturnPressed={this.appendEntry}
disabled={disabled} disabled={disabled}
helpText={helpText}
/> />
<AddButton <AddButton
label={buttonLabel} label={buttonLabel}

View File

@@ -1,11 +1,13 @@
//@flow //@flow
import React from "react"; import React from "react";
import { Help } from "../index";
type Props = { type Props = {
label?: string, label?: string,
checked: boolean, checked: boolean,
onChange?: boolean => void, onChange?: boolean => void,
disabled?: boolean disabled?: boolean,
helpText?: string
}; };
class Checkbox extends React.Component<Props> { class Checkbox extends React.Component<Props> {
onCheckboxChange = (event: SyntheticInputEvent<HTMLInputElement>) => { onCheckboxChange = (event: SyntheticInputEvent<HTMLInputElement>) => {
@@ -14,9 +16,20 @@ class Checkbox extends React.Component<Props> {
} }
}; };
renderHelp = () => {
const helpText = this.props.helpText;
if (helpText) {
return (
<div className="control columns is-vcentered">
<Help message={helpText} />
</div>
);
} else return null;
};
render() { render() {
return ( return (
<div className="field"> <div className="field is-grouped">
<div className="control"> <div className="control">
<label className="checkbox" disabled={this.props.disabled}> <label className="checkbox" disabled={this.props.disabled}>
<input <input
@@ -28,6 +41,7 @@ class Checkbox extends React.Component<Props> {
{this.props.label} {this.props.label}
</label> </label>
</div> </div>
{this.renderHelp()}
</div> </div>
); );
} }

View File

@@ -1,6 +1,7 @@
//@flow //@flow
import React from "react"; import React from "react";
import classNames from "classnames"; import classNames from "classnames";
import { LabelWithHelpIcon } from "../index";
type Props = { type Props = {
label?: string, label?: string,
@@ -12,7 +13,8 @@ type Props = {
onReturnPressed?: () => void, onReturnPressed?: () => void,
validationError: boolean, validationError: boolean,
errorMessage: string, errorMessage: string,
disabled?: boolean disabled?: boolean,
helpText?: string
}; };
class InputField extends React.Component<Props> { class InputField extends React.Component<Props> {
@@ -33,15 +35,6 @@ class InputField extends React.Component<Props> {
this.props.onChange(event.target.value); this.props.onChange(event.target.value);
}; };
renderLabel = () => {
const label = this.props.label;
if (label) {
return <label className="label">{label}</label>;
}
return "";
};
handleKeyPress = (event: SyntheticKeyboardEvent<HTMLInputElement>) => { handleKeyPress = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
const onReturnPressed = this.props.onReturnPressed; const onReturnPressed = this.props.onReturnPressed;
if (!onReturnPressed) { if (!onReturnPressed) {
@@ -60,7 +53,9 @@ class InputField extends React.Component<Props> {
value, value,
validationError, validationError,
errorMessage, errorMessage,
disabled disabled,
label,
helpText
} = this.props; } = this.props;
const errorView = validationError ? "is-danger" : ""; const errorView = validationError ? "is-danger" : "";
const helper = validationError ? ( const helper = validationError ? (
@@ -70,7 +65,7 @@ class InputField extends React.Component<Props> {
); );
return ( return (
<div className="field"> <div className="field">
{this.renderLabel()} <LabelWithHelpIcon label={label} helpText={helpText} />
<div className="control"> <div className="control">
<input <input
ref={input => { ref={input => {

View File

@@ -1,6 +1,7 @@
//@flow //@flow
import React from "react"; import React from "react";
import classNames from "classnames"; import classNames from "classnames";
import { LabelWithHelpIcon } from "../index";
export type SelectItem = { export type SelectItem = {
value: string, value: string,
@@ -12,7 +13,8 @@ type Props = {
options: SelectItem[], options: SelectItem[],
value?: SelectItem, value?: SelectItem,
onChange: string => void, onChange: string => void,
loading?: boolean loading?: boolean,
helpText?: string
}; };
class Select extends React.Component<Props> { class Select extends React.Component<Props> {
@@ -30,25 +32,18 @@ class Select extends React.Component<Props> {
this.props.onChange(event.target.value); this.props.onChange(event.target.value);
}; };
renderLabel = () => {
const label = this.props.label;
if (label) {
return <label className="label">{label}</label>;
}
return "";
};
render() { render() {
const { options, value, loading } = this.props; const { options, value, label, helpText, loading } = this.props;
const loadingClass = loading ? "is-loading" : ""; const loadingClass = loading ? "is-loading" : "";
return ( return (
<div className="field"> <div className="field">
{this.renderLabel()} <LabelWithHelpIcon label={label} helpText={helpText} />
<div className={classNames( <div className={classNames(
"control select", "control select",
loadingClass loadingClass
)}> )}>
<select <select
ref={input => { ref={input => {
this.field = input; this.field = input;

View File

@@ -1,5 +1,6 @@
//@flow //@flow
import React from "react"; import React from "react";
import { LabelWithHelpIcon } from "../index";
export type SelectItem = { export type SelectItem = {
value: string, value: string,
@@ -10,7 +11,8 @@ type Props = {
label?: string, label?: string,
placeholder?: SelectItem[], placeholder?: SelectItem[],
value?: string, value?: string,
onChange: string => void onChange: string => void,
helpText?: string
}; };
class Textarea extends React.Component<Props> { class Textarea extends React.Component<Props> {
@@ -20,20 +22,12 @@ class Textarea extends React.Component<Props> {
this.props.onChange(event.target.value); this.props.onChange(event.target.value);
}; };
renderLabel = () => {
const label = this.props.label;
if (label) {
return <label className="label">{label}</label>;
}
return "";
};
render() { render() {
const { placeholder, value } = this.props; const { placeholder, value, label, helpText } = this.props;
return ( return (
<div className="field"> <div className="field">
{this.renderLabel()} <LabelWithHelpIcon label={label} helpText={helpText} />
<div className="control"> <div className="control">
<textarea <textarea
className="textarea" className="textarea"

View File

@@ -16,11 +16,11 @@ export { default as MailLink } from "./MailLink.js";
export { default as Notification } from "./Notification.js"; export { default as Notification } from "./Notification.js";
export { default as Paginator } from "./Paginator.js"; export { default as Paginator } from "./Paginator.js";
export { default as ProtectedRoute } from "./ProtectedRoute.js"; export { default as ProtectedRoute } from "./ProtectedRoute.js";
export { default as Help } from "./Help.js";
export { default as LabelWithHelpIcon } from "./LabelWithHelpIcon.js";
export { apiClient, NOT_FOUND_ERROR, UNAUTHORIZED_ERROR } from "./apiclient.js"; export { apiClient, NOT_FOUND_ERROR, UNAUTHORIZED_ERROR } from "./apiclient.js";
export * from "./buttons"; export * from "./buttons";
export * from "./forms"; export * from "./forms";
export * from "./layout"; export * from "./layout";

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@
"@fortawesome/fontawesome-free": "^5.3.1", "@fortawesome/fontawesome-free": "^5.3.1",
"@scm-manager/ui-extensions": "^0.0.7", "@scm-manager/ui-extensions": "^0.0.7",
"bulma": "^0.7.1", "bulma": "^0.7.1",
"bulma-tooltip": "^2.0.2",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"history": "^4.7.2", "history": "^4.7.2",

View File

@@ -64,5 +64,29 @@
"login-attempt-limit-timeout-invalid": "This is not a number", "login-attempt-limit-timeout-invalid": "This is not a number",
"login-attempt-limit-invalid": "This is not a number", "login-attempt-limit-invalid": "This is not a number",
"plugin-url-invalid": "This is not a valid url" "plugin-url-invalid": "This is not a valid url"
},
"help": {
"realmDescriptionHelpText": "Enter authentication realm description",
"dateFormatHelpText": "Moments date format. Please have a look at the momentjs documentation.",
"pluginRepositoryHelpText": "The url of the plugin repository. Explanation of the placeholders: version = SCM-Manager Version; os = Operation System; arch = Architecture",
"enableForwardingHelpText": "Enbale mod_proxy port forwarding.",
"enableRepositoryArchiveHelpText": "Enable repository archives. A complete page reload is required after a change of this value.",
"disableGroupingGridHelpText": "Disable repository Groups. A complete page reload is required after a change of this value.",
"allowAnonymousAccessHelpText": "Anonymous users have read access on public repositories.",
"skipFailedAuthenticatorsHelpText": "Do not stop the authentication chain, if an authenticator finds the user but fails to authenticate the user.",
"adminGroupsHelpText": "Names of groups with admin permissions.",
"adminUsersHelpText": "Names of users with admin permissions.",
"forceBaseUrlHelpText": "Redirects to the base url if the request comes from a other url",
"baseUrlHelpText": "The url of the application (with context path), i.e. http://localhost:8080/scm",
"loginAttemptLimitHelpText": "Maximum allowed login attempts. Use -1 to disable the login attempt limit.",
"loginAttemptLimitTimeoutHelpText": "Timeout in seconds for users which are temporary disabled, because of too many failed login attempts.",
"enableProxyHelpText": "Enable Proxy",
"proxyPortHelpText": "The proxy port",
"proxyPasswordHelpText": "The password for the proxy server authentication.",
"proxyServerHelpText": "The proxy server",
"proxyUserHelpText": "The username for the proxy server authentication.",
"proxyExcludesHelpText": "Glob patterns for hostnames which should be excluded from proxy settings.",
"enableXsrfProtectionHelpText": "Enable Xsrf Cookie Protection. Note: This feature is still experimental.",
"defaultNameSpaceStrategyHelpText": "The default namespace strategy"
} }
} }

View File

@@ -42,7 +42,12 @@
"group-form": { "group-form": {
"submit": "Submit", "submit": "Submit",
"name-error": "Group name is invalid", "name-error": "Group name is invalid",
"description-error": "Description is invalid" "description-error": "Description is invalid",
"help": {
"nameHelpText": "Unique name of the group",
"descriptionHelpText": "A short description of the group",
"memberHelpText": "Usernames of the group members"
}
}, },
"delete-group-button": { "delete-group-button": {
"label": "Delete", "label": "Delete",

View File

@@ -68,5 +68,11 @@
"submit-button": "Submit", "submit-button": "Submit",
"name-input-invalid": "Permission is not allowed to be empty! If it is not empty, your input name is invalid or it already exists!" "name-input-invalid": "Permission is not allowed to be empty! If it is not empty, your input name is invalid or it already exists!"
} }
} },
"help": {
"nameHelpText": "The name of the repository. This name will be part of the repository url.",
"typeHelpText": "The type of the repository (e.g. Mercurial, Git or Subversion).",
"contactHelpText": "Email address of the person who is responsible for this repository.",
"descriptionHelpText": "A short description of the repository."
}
} }

View File

@@ -51,5 +51,14 @@
"password-invalid": "Password has to be between 6 and 32 characters", "password-invalid": "Password has to be between 6 and 32 characters",
"passwordValidation-invalid": "Passwords have to be the same", "passwordValidation-invalid": "Passwords have to be the same",
"validatePassword": "Please validate password here" "validatePassword": "Please validate password here"
},
"help": {
"usernameHelpText": "Unique name of the user.",
"displayNameHelpText": "Display name of the user.",
"mailHelpText": "Email address of the user.",
"passwordHelpText": "Plain text password of the user.",
"passwordConfirmHelpText": "Repeat the password for validation.",
"adminHelpText": "An administrator is able to create, modify and delete repositories, groups and users.",
"activeHelpText": "Activate or deactive the user."
} }
} }

View File

@@ -23,12 +23,14 @@ class BaseUrlSettings extends React.Component<Props> {
label={t("base-url-settings.force-base-url")} label={t("base-url-settings.force-base-url")}
onChange={this.handleForceBaseUrlChange} onChange={this.handleForceBaseUrlChange}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.forceBaseUrlHelpText")}
/> />
<InputField <InputField
label={t("base-url-settings.base-url")} label={t("base-url-settings.base-url")}
onChange={this.handleBaseUrlChange} onChange={this.handleBaseUrlChange}
value={baseUrl} value={baseUrl}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.baseUrlHelpText")}
/> />
</div> </div>
); );

View File

@@ -41,54 +41,63 @@ class GeneralSettings extends React.Component<Props> {
onChange={this.handleRealmDescriptionChange} onChange={this.handleRealmDescriptionChange}
value={realmDescription} value={realmDescription}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.realmDescriptionHelpText")}
/> />
<InputField <InputField
label={t("general-settings.date-format")} label={t("general-settings.date-format")}
onChange={this.handleDateFormatChange} onChange={this.handleDateFormatChange}
value={dateFormat} value={dateFormat}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.dateFormatHelpText")}
/> />
<InputField <InputField
label={t("general-settings.plugin-url")} label={t("general-settings.plugin-url")}
onChange={this.handlePluginUrlChange} onChange={this.handlePluginUrlChange}
value={pluginUrl} value={pluginUrl}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.pluginRepositoryHelpText")}
/> />
<InputField <InputField
label={t("general-settings.default-namespace-strategy")} label={t("general-settings.default-namespace-strategy")}
onChange={this.handleDefaultNamespaceStrategyChange} onChange={this.handleDefaultNamespaceStrategyChange}
value={defaultNamespaceStrategy} value={defaultNamespaceStrategy}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.defaultNameSpaceStrategyHelpText")}
/> />
<Checkbox <Checkbox
checked={enabledXsrfProtection} checked={enabledXsrfProtection}
label={t("general-settings.enabled-xsrf-protection")} label={t("general-settings.enabled-xsrf-protection")}
onChange={this.handleEnabledXsrfProtectionChange} onChange={this.handleEnabledXsrfProtectionChange}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.enableXsrfProtectionHelpText")}
/> />
<Checkbox <Checkbox
checked={enableRepositoryArchive} checked={enableRepositoryArchive}
label={t("general-settings.enable-repository-archive")} label={t("general-settings.enable-repository-archive")}
onChange={this.handleEnableRepositoryArchiveChange} onChange={this.handleEnableRepositoryArchiveChange}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.enableRepositoryArchiveHelpText")}
/> />
<Checkbox <Checkbox
checked={disableGroupingGrid} checked={disableGroupingGrid}
label={t("general-settings.disable-grouping-grid")} label={t("general-settings.disable-grouping-grid")}
onChange={this.handleDisableGroupingGridChange} onChange={this.handleDisableGroupingGridChange}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.disableGroupingGridHelpText")}
/> />
<Checkbox <Checkbox
checked={anonymousAccessEnabled} checked={anonymousAccessEnabled}
label={t("general-settings.anonymous-access-enabled")} label={t("general-settings.anonymous-access-enabled")}
onChange={this.handleAnonymousAccessEnabledChange} onChange={this.handleAnonymousAccessEnabledChange}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.allowAnonymousAccessHelpText")}
/> />
<Checkbox <Checkbox
checked={skipFailedAuthenticators} checked={skipFailedAuthenticators}
label={t("general-settings.skip-failed-authenticators")} label={t("general-settings.skip-failed-authenticators")}
onChange={this.handleSkipFailedAuthenticatorsChange} onChange={this.handleSkipFailedAuthenticatorsChange}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.skipFailedAuthenticatorsHelpText")}
/> />
</div> </div>
); );

View File

@@ -47,6 +47,7 @@ class LoginAttempt extends React.Component<Props, State> {
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
validationError={this.state.loginAttemptLimitError} validationError={this.state.loginAttemptLimitError}
errorMessage={t("validation.login-attempt-limit-invalid")} errorMessage={t("validation.login-attempt-limit-invalid")}
helpText={t("help.loginAttemptLimitHelpText")}
/> />
<InputField <InputField
label={t("login-attempt.login-attempt-limit-timeout")} label={t("login-attempt.login-attempt-limit-timeout")}
@@ -55,6 +56,7 @@ class LoginAttempt extends React.Component<Props, State> {
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
validationError={this.state.loginAttemptLimitTimeoutError} validationError={this.state.loginAttemptLimitTimeoutError}
errorMessage={t("validation.login-attempt-limit-timeout-invalid")} errorMessage={t("validation.login-attempt-limit-timeout-invalid")}
helpText={t("help.loginAttemptLimitTimeoutHelpText")}
/> />
</div> </div>
); );

View File

@@ -42,6 +42,7 @@ class ProxySettings extends React.Component<Props> {
label={t("proxy-settings.enable-proxy")} label={t("proxy-settings.enable-proxy")}
onChange={this.handleEnableProxyChange} onChange={this.handleEnableProxyChange}
disabled={!hasUpdatePermission} disabled={!hasUpdatePermission}
helpText={t("help.enableProxyHelpText")}
/> />
<InputField <InputField
label={t("proxy-settings.proxy-password")} label={t("proxy-settings.proxy-password")}
@@ -49,24 +50,28 @@ class ProxySettings extends React.Component<Props> {
value={proxyPassword} value={proxyPassword}
type="password" type="password"
disabled={!enableProxy || !hasUpdatePermission} disabled={!enableProxy || !hasUpdatePermission}
helpText={t("help.proxyPasswordHelpText")}
/> />
<InputField <InputField
label={t("proxy-settings.proxy-port")} label={t("proxy-settings.proxy-port")}
value={proxyPort} value={proxyPort}
onChange={this.handleProxyPortChange} onChange={this.handleProxyPortChange}
disabled={!enableProxy || !hasUpdatePermission} disabled={!enableProxy || !hasUpdatePermission}
helpText={t("help.proxyPortHelpText")}
/> />
<InputField <InputField
label={t("proxy-settings.proxy-server")} label={t("proxy-settings.proxy-server")}
value={proxyServer} value={proxyServer}
onChange={this.handleProxyServerChange} onChange={this.handleProxyServerChange}
disabled={!enableProxy || !hasUpdatePermission} disabled={!enableProxy || !hasUpdatePermission}
helpText={t("help.proxyServerHelpText")}
/> />
<InputField <InputField
label={t("proxy-settings.proxy-user")} label={t("proxy-settings.proxy-user")}
value={proxyUser} value={proxyUser}
onChange={this.handleProxyUserChange} onChange={this.handleProxyUserChange}
disabled={!enableProxy || !hasUpdatePermission} disabled={!enableProxy || !hasUpdatePermission}
helpText={t("help.proxyUserHelpText")}
/> />
<ProxyExcludesTable <ProxyExcludesTable
proxyExcludes={proxyExcludes} proxyExcludes={proxyExcludes}

View File

@@ -24,6 +24,7 @@ class AdminGroupTable extends React.Component<Props, State> {
removeLabel={t("admin-settings.remove-group-button")} removeLabel={t("admin-settings.remove-group-button")}
onRemove={this.removeEntry} onRemove={this.removeEntry}
disabled={disabled} disabled={disabled}
helpText={t("help.adminGroupsHelpText")}
/> />
); );
} }

View File

@@ -22,6 +22,7 @@ class AdminUserTable extends React.Component<Props> {
removeLabel={t("admin-settings.remove-user-button")} removeLabel={t("admin-settings.remove-user-button")}
onRemove={this.removeEntry} onRemove={this.removeEntry}
disabled={disabled} disabled={disabled}
helpText={t("help.adminUsersHelpText")}
/> />
); );
} }

View File

@@ -1,21 +1,22 @@
//@flow //@flow
import React from "react"; import React from "react";
import { RemoveEntryOfTableButton } from "@scm-manager/ui-components"; import { RemoveEntryOfTableButton, LabelWithHelpIcon } from "@scm-manager/ui-components";
type Props = { type Props = {
items: string[], items: string[],
label: string, label: string,
removeLabel: string, removeLabel: string,
onRemove: (string[], string) => void, onRemove: (string[], string) => void,
disabled: boolean disabled: boolean,
helpText: string
}; };
class ArrayConfigTable extends React.Component<Props> { class ArrayConfigTable extends React.Component<Props> {
render() { render() {
const { label, disabled, removeLabel, items } = this.props; const { label, disabled, removeLabel, items, helpText } = this.props;
return ( return (
<div> <div>
<label className="label">{label}</label> <LabelWithHelpIcon label={label} helpText={helpText}/>
<table className="table is-hoverable is-fullwidth"> <table className="table is-hoverable is-fullwidth">
<tbody> <tbody>
{items.map(item => { {items.map(item => {

View File

@@ -22,6 +22,7 @@ class ProxyExcludesTable extends React.Component<Props, State> {
removeLabel={t("proxy-settings.remove-proxy-exclude-button")} removeLabel={t("proxy-settings.remove-proxy-exclude-button")}
onRemove={this.removeEntry} onRemove={this.removeEntry}
disabled={disabled} disabled={disabled}
helpText={t("help.proxyExcludesHelpText")}
/> />
); );
} }

View File

@@ -80,6 +80,7 @@ class GroupForm extends React.Component<Props, State> {
onChange={this.handleGroupNameChange} onChange={this.handleGroupNameChange}
value={group.name} value={group.name}
validationError={this.state.nameValidationError} validationError={this.state.nameValidationError}
helpText={t("group-form.help.nameHelpText")}
/> />
); );
} }
@@ -93,6 +94,7 @@ class GroupForm extends React.Component<Props, State> {
onChange={this.handleDescriptionChange} onChange={this.handleDescriptionChange}
value={group.description} value={group.description}
validationError={false} validationError={false}
helpText={t("group-form.help.descriptionHelpText")}
/> />
<MemberNameTable <MemberNameTable
members={this.state.group.members} members={this.state.group.members}

View File

@@ -1,7 +1,10 @@
//@flow //@flow
import React from "react"; import React from "react";
import { translate } from "react-i18next"; import { translate } from "react-i18next";
import { RemoveEntryOfTableButton } from "@scm-manager/ui-components"; import {
RemoveEntryOfTableButton,
LabelWithHelpIcon
} from "@scm-manager/ui-components";
type Props = { type Props = {
members: string[], members: string[],
@@ -16,7 +19,10 @@ class MemberNameTable extends React.Component<Props, State> {
const { t } = this.props; const { t } = this.props;
return ( return (
<div> <div>
<label className="label">{t("group.members")}</label> <LabelWithHelpIcon
label={t("group.members")}
helpText={t("group-form.help.memberHelpText")}
/>
<table className="table is-hoverable is-fullwidth"> <table className="table is-hoverable is-fullwidth">
<tbody> <tbody>
{this.props.members.map(member => { {this.props.members.map(member => {

View File

@@ -90,12 +90,14 @@ class RepositoryForm extends React.Component<Props, State> {
value={repository ? repository.contact : ""} value={repository ? repository.contact : ""}
validationError={this.state.contactValidationError} validationError={this.state.contactValidationError}
errorMessage={t("validation.contact-invalid")} errorMessage={t("validation.contact-invalid")}
helpText={t("help.contactHelpText")}
/> />
<Textarea <Textarea
label={t("repository.description")} label={t("repository.description")}
onChange={this.handleDescriptionChange} onChange={this.handleDescriptionChange}
value={repository ? repository.description : ""} value={repository ? repository.description : ""}
helpText={t("help.descriptionHelpText")}
/> />
<SubmitButton <SubmitButton
disabled={!this.isValid()} disabled={!this.isValid()}
@@ -129,12 +131,14 @@ class RepositoryForm extends React.Component<Props, State> {
value={repository ? repository.name : ""} value={repository ? repository.name : ""}
validationError={this.state.nameValidationError} validationError={this.state.nameValidationError}
errorMessage={t("validation.name-invalid")} errorMessage={t("validation.name-invalid")}
helpText={t("help.nameHelpText")}
/> />
<Select <Select
label={t("repository.type")} label={t("repository.type")}
onChange={this.handleTypeChange} onChange={this.handleTypeChange}
value={repository ? repository.type : ""} value={repository ? repository.type : ""}
options={this.createSelectOptions(repositoryTypes)} options={this.createSelectOptions(repositoryTypes)}
helpText={t("help.typeHelpText")}
/> />
</div> </div>
); );

View File

@@ -97,6 +97,7 @@ class UserForm extends React.Component<Props, State> {
value={user ? user.name : ""} value={user ? user.name : ""}
validationError={this.state.nameValidationError} validationError={this.state.nameValidationError}
errorMessage={t("validation.name-invalid")} errorMessage={t("validation.name-invalid")}
helpText={t("help.usernameHelpText")}
/> />
); );
} }
@@ -109,6 +110,7 @@ class UserForm extends React.Component<Props, State> {
value={user ? user.displayName : ""} value={user ? user.displayName : ""}
validationError={this.state.displayNameValidationError} validationError={this.state.displayNameValidationError}
errorMessage={t("validation.displayname-invalid")} errorMessage={t("validation.displayname-invalid")}
helpText={t("help.displayNameHelpText")}
/> />
<InputField <InputField
label={t("user.mail")} label={t("user.mail")}
@@ -116,6 +118,7 @@ class UserForm extends React.Component<Props, State> {
value={user ? user.mail : ""} value={user ? user.mail : ""}
validationError={this.state.mailValidationError} validationError={this.state.mailValidationError}
errorMessage={t("validation.mail-invalid")} errorMessage={t("validation.mail-invalid")}
helpText={t("help.mailHelpText")}
/> />
<InputField <InputField
label={t("user.password")} label={t("user.password")}
@@ -124,6 +127,7 @@ class UserForm extends React.Component<Props, State> {
value={user ? user.password : ""} value={user ? user.password : ""}
validationError={this.state.validatePasswordError} validationError={this.state.validatePasswordError}
errorMessage={t("validation.password-invalid")} errorMessage={t("validation.password-invalid")}
helpText={t("help.passwordHelpText")}
/> />
<InputField <InputField
label={t("validation.validatePassword")} label={t("validation.validatePassword")}
@@ -132,16 +136,19 @@ class UserForm extends React.Component<Props, State> {
value={this.state ? this.state.validatePassword : ""} value={this.state ? this.state.validatePassword : ""}
validationError={this.state.passwordValidationError} validationError={this.state.passwordValidationError}
errorMessage={t("validation.passwordValidation-invalid")} errorMessage={t("validation.passwordValidation-invalid")}
helpText={t("help.passwordConfirmHelpText")}
/> />
<Checkbox <Checkbox
label={t("user.admin")} label={t("user.admin")}
onChange={this.handleAdminChange} onChange={this.handleAdminChange}
checked={user ? user.admin : false} checked={user ? user.admin : false}
helpText={t("help.adminHelpText")}
/> />
<Checkbox <Checkbox
label={t("user.active")} label={t("user.active")}
onChange={this.handleActiveChange} onChange={this.handleActiveChange}
checked={user ? user.active : false} checked={user ? user.active : false}
helpText={t("help.activeHelpText")}
/> />
<SubmitButton <SubmitButton
disabled={!this.isValid()} disabled={!this.isValid()}

View File

@@ -35,6 +35,7 @@ $blue: #33B2E8;
// 6. Import the rest of Bulma // 6. Import the rest of Bulma
@import "bulma/bulma"; @import "bulma/bulma";
@import "bulma-tooltip/dist/css/bulma-tooltip";
// import at the end, because we need a lot of stuff from bulma/bulma // import at the end, because we need a lot of stuff from bulma/bulma
.box-link-shadow { .box-link-shadow {