mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 14:35:45 +01:00
Notifications for health checks (#1664)
Add list of emergency contacts to global configuration. This user will receive e-mails and notification if some serious system error occurs like repository health check failed.
This commit is contained in:
@@ -21,8 +21,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import React from "react";
|
||||
import { WithTranslation, withTranslation } from "react-i18next";
|
||||
import React, { FC, useState, useEffect, FormEvent } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Config, NamespaceStrategies } from "@scm-manager/ui-types";
|
||||
import { Level, Notification, SubmitButton } from "@scm-manager/ui-components";
|
||||
import ProxySettings from "./ProxySettings";
|
||||
@@ -30,7 +30,7 @@ import GeneralSettings from "./GeneralSettings";
|
||||
import BaseUrlSettings from "./BaseUrlSettings";
|
||||
import LoginAttempt from "./LoginAttempt";
|
||||
|
||||
type Props = WithTranslation & {
|
||||
type Props = {
|
||||
submitForm: (p: Config) => void;
|
||||
config?: Config;
|
||||
loading?: boolean;
|
||||
@@ -39,185 +39,157 @@ type Props = WithTranslation & {
|
||||
namespaceStrategies?: NamespaceStrategies;
|
||||
};
|
||||
|
||||
type State = {
|
||||
config: Config;
|
||||
showNotification: boolean;
|
||||
error: {
|
||||
const ConfigForm: FC<Props> = ({
|
||||
submitForm,
|
||||
config,
|
||||
loading,
|
||||
configReadPermission,
|
||||
configUpdatePermission,
|
||||
namespaceStrategies
|
||||
}) => {
|
||||
const [t] = useTranslation("config");
|
||||
const [innerConfig, setInnerConfig] = useState<Config>({
|
||||
proxyPassword: null,
|
||||
proxyPort: 0,
|
||||
proxyServer: "",
|
||||
proxyUser: null,
|
||||
enableProxy: false,
|
||||
realmDescription: "",
|
||||
disableGroupingGrid: false,
|
||||
dateFormat: "",
|
||||
anonymousAccessEnabled: false,
|
||||
anonymousMode: "OFF",
|
||||
baseUrl: "",
|
||||
forceBaseUrl: false,
|
||||
loginAttemptLimit: 0,
|
||||
proxyExcludes: [],
|
||||
skipFailedAuthenticators: false,
|
||||
pluginUrl: "",
|
||||
loginAttemptLimitTimeout: 0,
|
||||
enabledXsrfProtection: true,
|
||||
enabledUserConverter: false,
|
||||
namespaceStrategy: "",
|
||||
loginInfoUrl: "",
|
||||
releaseFeedUrl: "",
|
||||
mailDomainName: "",
|
||||
emergencyContacts: [],
|
||||
enabledApiKeys: true,
|
||||
_links: {}
|
||||
});
|
||||
const [showNotification, setShowNotification] = useState(false);
|
||||
const [changed, setChanged] = useState(false);
|
||||
const [error, setError] = useState<{
|
||||
loginAttemptLimitTimeout: boolean;
|
||||
loginAttemptLimit: boolean;
|
||||
};
|
||||
changed: boolean;
|
||||
};
|
||||
}>({
|
||||
loginAttemptLimitTimeout: false,
|
||||
loginAttemptLimit: false
|
||||
});
|
||||
|
||||
class ConfigForm extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
config: {
|
||||
proxyPassword: null,
|
||||
proxyPort: 0,
|
||||
proxyServer: "",
|
||||
proxyUser: null,
|
||||
enableProxy: false,
|
||||
realmDescription: "",
|
||||
disableGroupingGrid: false,
|
||||
dateFormat: "",
|
||||
anonymousMode: "OFF",
|
||||
baseUrl: "",
|
||||
mailDomainName: "",
|
||||
forceBaseUrl: false,
|
||||
loginAttemptLimit: 0,
|
||||
proxyExcludes: [],
|
||||
skipFailedAuthenticators: false,
|
||||
pluginUrl: "",
|
||||
loginAttemptLimitTimeout: 0,
|
||||
enabledXsrfProtection: true,
|
||||
enabledUserConverter: false,
|
||||
namespaceStrategy: "",
|
||||
loginInfoUrl: "",
|
||||
_links: {}
|
||||
},
|
||||
showNotification: false,
|
||||
error: {
|
||||
loginAttemptLimitTimeout: false,
|
||||
loginAttemptLimit: false
|
||||
},
|
||||
changed: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { config, configUpdatePermission } = this.props;
|
||||
useEffect(() => {
|
||||
if (config) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
config: {
|
||||
...config
|
||||
}
|
||||
});
|
||||
setInnerConfig(config);
|
||||
}
|
||||
if (!configUpdatePermission) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
showNotification: true
|
||||
});
|
||||
setShowNotification(true);
|
||||
}
|
||||
}
|
||||
}, [config, configUpdatePermission]);
|
||||
|
||||
submit = (event: Event) => {
|
||||
const submit = (event: FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
this.setState({
|
||||
changed: false
|
||||
});
|
||||
this.props.submitForm(this.state.config);
|
||||
setChanged(false);
|
||||
submitForm(innerConfig);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loading, t, namespaceStrategies, configReadPermission, configUpdatePermission } = this.props;
|
||||
const config = this.state.config;
|
||||
const onChange = (isValid: boolean, changedValue: any, name: string) => {
|
||||
setInnerConfig({ ...innerConfig, [name]: changedValue });
|
||||
setError({ ...error, [name]: !isValid });
|
||||
setChanged(true);
|
||||
};
|
||||
|
||||
let noPermissionNotification = null;
|
||||
const hasError = () => {
|
||||
return error.loginAttemptLimit || error.loginAttemptLimitTimeout;
|
||||
};
|
||||
|
||||
if (!configReadPermission) {
|
||||
return <Notification type={"danger"} children={t("config.form.no-read-permission-notification")} />;
|
||||
}
|
||||
const onClose = () => {
|
||||
setShowNotification(false);
|
||||
};
|
||||
|
||||
if (this.state.showNotification) {
|
||||
noPermissionNotification = (
|
||||
<Notification
|
||||
type={"info"}
|
||||
children={t("config.form.no-write-permission-notification")}
|
||||
onClose={() => this.onClose()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
let noPermissionNotification = null;
|
||||
|
||||
return (
|
||||
<form onSubmit={this.submit}>
|
||||
{noPermissionNotification}
|
||||
<GeneralSettings
|
||||
namespaceStrategies={namespaceStrategies}
|
||||
loginInfoUrl={config.loginInfoUrl}
|
||||
realmDescription={config.realmDescription}
|
||||
disableGroupingGrid={config.disableGroupingGrid}
|
||||
dateFormat={config.dateFormat}
|
||||
anonymousMode={config.anonymousMode}
|
||||
skipFailedAuthenticators={config.skipFailedAuthenticators}
|
||||
pluginUrl={config.pluginUrl}
|
||||
releaseFeedUrl={config.releaseFeedUrl}
|
||||
mailDomainName={config.mailDomainName}
|
||||
enabledXsrfProtection={config.enabledXsrfProtection}
|
||||
enabledUserConverter={config.enabledUserConverter}
|
||||
enabledApiKeys={config.enabledApiKeys}
|
||||
namespaceStrategy={config.namespaceStrategy}
|
||||
onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<LoginAttempt
|
||||
loginAttemptLimit={config.loginAttemptLimit}
|
||||
loginAttemptLimitTimeout={config.loginAttemptLimitTimeout}
|
||||
onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<BaseUrlSettings
|
||||
baseUrl={config.baseUrl}
|
||||
forceBaseUrl={config.forceBaseUrl}
|
||||
onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<ProxySettings
|
||||
proxyPassword={config.proxyPassword ? config.proxyPassword : ""}
|
||||
proxyPort={config.proxyPort}
|
||||
proxyServer={config.proxyServer ? config.proxyServer : ""}
|
||||
proxyUser={config.proxyUser ? config.proxyUser : ""}
|
||||
enableProxy={config.enableProxy}
|
||||
proxyExcludes={config.proxyExcludes}
|
||||
onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<Level
|
||||
right={
|
||||
<SubmitButton
|
||||
loading={loading}
|
||||
label={t("config.form.submit")}
|
||||
disabled={!configUpdatePermission || this.hasError() || !this.state.changed}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</form>
|
||||
if (!configReadPermission) {
|
||||
return <Notification type={"danger"} children={t("config.form.no-read-permission-notification")} />;
|
||||
}
|
||||
|
||||
if (showNotification) {
|
||||
noPermissionNotification = (
|
||||
<Notification
|
||||
type={"info"}
|
||||
children={t("config.form.no-write-permission-notification")}
|
||||
onClose={() => onClose()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
onChange = (isValid: boolean, changedValue: any, name: string) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
config: {
|
||||
...this.state.config,
|
||||
[name]: changedValue
|
||||
},
|
||||
error: {
|
||||
...this.state.error,
|
||||
[name]: !isValid
|
||||
},
|
||||
changed: true
|
||||
});
|
||||
};
|
||||
return (
|
||||
<form onSubmit={submit}>
|
||||
{noPermissionNotification}
|
||||
<GeneralSettings
|
||||
namespaceStrategies={namespaceStrategies}
|
||||
loginInfoUrl={innerConfig.loginInfoUrl}
|
||||
realmDescription={innerConfig.realmDescription}
|
||||
disableGroupingGrid={innerConfig.disableGroupingGrid}
|
||||
dateFormat={innerConfig.dateFormat}
|
||||
anonymousMode={innerConfig.anonymousMode}
|
||||
skipFailedAuthenticators={innerConfig.skipFailedAuthenticators}
|
||||
pluginUrl={innerConfig.pluginUrl}
|
||||
releaseFeedUrl={innerConfig.releaseFeedUrl}
|
||||
mailDomainName={innerConfig.mailDomainName}
|
||||
enabledXsrfProtection={innerConfig.enabledXsrfProtection}
|
||||
enabledUserConverter={innerConfig.enabledUserConverter}
|
||||
enabledApiKeys={innerConfig.enabledApiKeys}
|
||||
emergencyContacts={innerConfig.emergencyContacts}
|
||||
namespaceStrategy={innerConfig.namespaceStrategy}
|
||||
onChange={(isValid, changedValue, name) => onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<LoginAttempt
|
||||
loginAttemptLimit={innerConfig.loginAttemptLimit}
|
||||
loginAttemptLimitTimeout={innerConfig.loginAttemptLimitTimeout}
|
||||
onChange={(isValid, changedValue, name) => onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<BaseUrlSettings
|
||||
baseUrl={innerConfig.baseUrl}
|
||||
forceBaseUrl={innerConfig.forceBaseUrl}
|
||||
onChange={(isValid, changedValue, name) => onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<ProxySettings
|
||||
proxyPassword={innerConfig.proxyPassword ? innerConfig.proxyPassword : ""}
|
||||
proxyPort={innerConfig.proxyPort ? innerConfig.proxyPort : 0}
|
||||
proxyServer={innerConfig.proxyServer ? innerConfig.proxyServer : ""}
|
||||
proxyUser={innerConfig.proxyUser ? innerConfig.proxyUser : ""}
|
||||
enableProxy={innerConfig.enableProxy}
|
||||
proxyExcludes={innerConfig.proxyExcludes}
|
||||
onChange={(isValid, changedValue, name) => onChange(isValid, changedValue, name)}
|
||||
hasUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
<hr />
|
||||
<Level
|
||||
right={
|
||||
<SubmitButton
|
||||
loading={loading}
|
||||
label={t("config.form.submit")}
|
||||
disabled={!configUpdatePermission || hasError() || !changed}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
hasError = () => {
|
||||
return this.state.error.loginAttemptLimit || this.state.error.loginAttemptLimitTimeout;
|
||||
};
|
||||
|
||||
onClose = () => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
showNotification: false
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default withTranslation("config")(ConfigForm);
|
||||
export default ConfigForm;
|
||||
|
||||
@@ -21,13 +21,20 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import React from "react";
|
||||
import { WithTranslation, withTranslation } from "react-i18next";
|
||||
import { Checkbox, InputField, Select } from "@scm-manager/ui-components";
|
||||
import { NamespaceStrategies, AnonymousMode } from "@scm-manager/ui-types";
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUserSuggestions } from "@scm-manager/ui-api";
|
||||
import { NamespaceStrategies, AnonymousMode, SelectValue } from "@scm-manager/ui-types";
|
||||
import {
|
||||
Checkbox,
|
||||
InputField,
|
||||
MemberNameTagGroup,
|
||||
AutocompleteAddEntryToTableField,
|
||||
Select
|
||||
} from "@scm-manager/ui-components";
|
||||
import NamespaceStrategySelect from "./NamespaceStrategySelect";
|
||||
|
||||
type Props = WithTranslation & {
|
||||
type Props = {
|
||||
realmDescription: string;
|
||||
loginInfoUrl: string;
|
||||
disableGroupingGrid: boolean;
|
||||
@@ -40,176 +47,207 @@ type Props = WithTranslation & {
|
||||
enabledXsrfProtection: boolean;
|
||||
enabledUserConverter: boolean;
|
||||
enabledApiKeys: boolean;
|
||||
emergencyContacts: string[];
|
||||
namespaceStrategy: string;
|
||||
namespaceStrategies?: NamespaceStrategies;
|
||||
onChange: (p1: boolean, p2: any, p3: string) => void;
|
||||
hasUpdatePermission: boolean;
|
||||
};
|
||||
|
||||
class GeneralSettings extends React.Component<Props> {
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
realmDescription,
|
||||
loginInfoUrl,
|
||||
pluginUrl,
|
||||
releaseFeedUrl,
|
||||
mailDomainName,
|
||||
enabledXsrfProtection,
|
||||
enabledUserConverter,
|
||||
enabledApiKeys,
|
||||
anonymousMode,
|
||||
namespaceStrategy,
|
||||
hasUpdatePermission,
|
||||
namespaceStrategies
|
||||
} = this.props;
|
||||
const GeneralSettings: FC<Props> = ({
|
||||
realmDescription,
|
||||
loginInfoUrl,
|
||||
anonymousMode,
|
||||
pluginUrl,
|
||||
releaseFeedUrl,
|
||||
mailDomainName,
|
||||
enabledXsrfProtection,
|
||||
enabledUserConverter,
|
||||
enabledApiKeys,
|
||||
emergencyContacts,
|
||||
namespaceStrategy,
|
||||
namespaceStrategies,
|
||||
onChange,
|
||||
hasUpdatePermission
|
||||
}) => {
|
||||
const { t } = useTranslation("config");
|
||||
const userSuggestions = useUserSuggestions();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.realm-description")}
|
||||
onChange={this.handleRealmDescriptionChange}
|
||||
value={realmDescription}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.realmDescriptionHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<NamespaceStrategySelect
|
||||
label={t("general-settings.namespace-strategy")}
|
||||
onChange={this.handleNamespaceStrategyChange}
|
||||
value={namespaceStrategy}
|
||||
disabled={!hasUpdatePermission}
|
||||
namespaceStrategies={namespaceStrategies}
|
||||
helpText={t("help.nameSpaceStrategyHelpText")}
|
||||
/>
|
||||
</div>
|
||||
const handleLoginInfoUrlChange = (value: string) => {
|
||||
onChange(true, value, "loginInfoUrl");
|
||||
};
|
||||
const handleRealmDescriptionChange = (value: string) => {
|
||||
onChange(true, value, "realmDescription");
|
||||
};
|
||||
const handleEnabledXsrfProtectionChange = (value: boolean) => {
|
||||
onChange(true, value, "enabledXsrfProtection");
|
||||
};
|
||||
const handleEnabledUserConverterChange = (value: boolean) => {
|
||||
onChange(true, value, "enabledUserConverter");
|
||||
};
|
||||
const handleAnonymousMode = (value: string) => {
|
||||
onChange(true, value, "anonymousMode");
|
||||
};
|
||||
const handleNamespaceStrategyChange = (value: string) => {
|
||||
onChange(true, value, "namespaceStrategy");
|
||||
};
|
||||
const handlePluginCenterUrlChange = (value: string) => {
|
||||
onChange(true, value, "pluginUrl");
|
||||
};
|
||||
const handleReleaseFeedUrlChange = (value: string) => {
|
||||
onChange(true, value, "releaseFeedUrl");
|
||||
};
|
||||
const handleMailDomainNameChange = (value: string) => {
|
||||
onChange(true, value, "mailDomainName");
|
||||
};
|
||||
const handleEnabledApiKeysChange = (value: boolean) => {
|
||||
onChange(true, value, "enabledApiKeys");
|
||||
};
|
||||
const handleEmergencyContactsChange = (p: string[]) => {
|
||||
onChange(true, p, "emergencyContacts");
|
||||
};
|
||||
|
||||
const isMember = (name: string) => {
|
||||
return emergencyContacts.includes(name);
|
||||
};
|
||||
|
||||
const addEmergencyContact = (value: SelectValue) => {
|
||||
if (isMember(value.value.id)) {
|
||||
return;
|
||||
}
|
||||
handleEmergencyContactsChange([...emergencyContacts, value.value.id]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.realm-description")}
|
||||
onChange={handleRealmDescriptionChange}
|
||||
value={realmDescription}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.realmDescriptionHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.login-info-url")}
|
||||
onChange={this.handleLoginInfoUrlChange}
|
||||
value={loginInfoUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.loginInfoUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Checkbox
|
||||
label={t("general-settings.enabled-xsrf-protection")}
|
||||
onChange={this.handleEnabledXsrfProtectionChange}
|
||||
checked={enabledXsrfProtection}
|
||||
title={t("general-settings.enabled-xsrf-protection")}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enableXsrfProtectionHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.plugin-url")}
|
||||
onChange={this.handlePluginCenterUrlChange}
|
||||
value={pluginUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.pluginUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Select
|
||||
label={t("general-settings.anonymousMode.title")}
|
||||
onChange={this.handleAnonymousMode}
|
||||
value={anonymousMode}
|
||||
disabled={!hasUpdatePermission}
|
||||
options={[
|
||||
{ label: t("general-settings.anonymousMode.full"), value: "FULL" },
|
||||
{ label: t("general-settings.anonymousMode.protocolOnly"), value: "PROTOCOL_ONLY" },
|
||||
{ label: t("general-settings.anonymousMode.off"), value: "OFF" }
|
||||
]}
|
||||
helpText={t("help.allowAnonymousAccessHelpText")}
|
||||
testId={"anonymous-mode-select"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.release-feed-url")}
|
||||
onChange={this.handleReleaseFeedUrlChange}
|
||||
value={releaseFeedUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.releaseFeedUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Checkbox
|
||||
label={t("general-settings.enabled-user-converter")}
|
||||
onChange={this.handleEnabledUserConverterChange}
|
||||
checked={enabledUserConverter}
|
||||
title={t("general-settings.enabled-user-converter")}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enabledUserConverterHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.mail-domain-name")}
|
||||
onChange={this.handleMailDomainNameChange}
|
||||
value={mailDomainName}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.mailDomainNameHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Checkbox
|
||||
label={t("general-settings.enabled-api-keys")}
|
||||
onChange={this.handleEnabledApiKeysChange}
|
||||
checked={enabledApiKeys}
|
||||
title={t("general-settings.enabled-api-keys")}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enabledApiKeysHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<NamespaceStrategySelect
|
||||
label={t("general-settings.namespace-strategy")}
|
||||
onChange={handleNamespaceStrategyChange}
|
||||
value={namespaceStrategy}
|
||||
disabled={!hasUpdatePermission}
|
||||
namespaceStrategies={namespaceStrategies}
|
||||
helpText={t("help.nameSpaceStrategyHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.login-info-url")}
|
||||
onChange={handleLoginInfoUrlChange}
|
||||
value={loginInfoUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.loginInfoUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Checkbox
|
||||
label={t("general-settings.enabled-xsrf-protection")}
|
||||
onChange={handleEnabledXsrfProtectionChange}
|
||||
checked={enabledXsrfProtection}
|
||||
title={t("general-settings.enabled-xsrf-protection")}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enableXsrfProtectionHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.plugin-url")}
|
||||
onChange={handlePluginCenterUrlChange}
|
||||
value={pluginUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.pluginUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Select
|
||||
label={t("general-settings.anonymousMode.title")}
|
||||
onChange={handleAnonymousMode}
|
||||
value={anonymousMode}
|
||||
disabled={!hasUpdatePermission}
|
||||
options={[
|
||||
{ label: t("general-settings.anonymousMode.full"), value: "FULL" },
|
||||
{ label: t("general-settings.anonymousMode.protocolOnly"), value: "PROTOCOL_ONLY" },
|
||||
{ label: t("general-settings.anonymousMode.off"), value: "OFF" }
|
||||
]}
|
||||
helpText={t("help.allowAnonymousAccessHelpText")}
|
||||
testId={"anonymous-mode-select"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.release-feed-url")}
|
||||
onChange={handleReleaseFeedUrlChange}
|
||||
value={releaseFeedUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.releaseFeedUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Checkbox
|
||||
label={t("general-settings.enabled-user-converter")}
|
||||
onChange={handleEnabledUserConverterChange}
|
||||
checked={enabledUserConverter}
|
||||
title={t("general-settings.enabled-user-converter")}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enabledUserConverterHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.mail-domain-name")}
|
||||
onChange={handleMailDomainNameChange}
|
||||
value={mailDomainName}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.mailDomainNameHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-half">
|
||||
<Checkbox
|
||||
label={t("general-settings.enabled-api-keys")}
|
||||
onChange={handleEnabledApiKeysChange}
|
||||
checked={enabledApiKeys}
|
||||
title={t("general-settings.enabled-api-keys")}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enabledApiKeysHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-full">
|
||||
<MemberNameTagGroup
|
||||
members={emergencyContacts}
|
||||
memberListChanged={handleEmergencyContactsChange}
|
||||
label={t("general-settings.emergencyContacts.label")}
|
||||
helpText={t("general-settings.emergencyContacts.helpText")}
|
||||
/>
|
||||
<AutocompleteAddEntryToTableField
|
||||
addEntry={addEmergencyContact}
|
||||
buttonLabel={t("general-settings.emergencyContacts.addButton")}
|
||||
loadSuggestions={userSuggestions}
|
||||
placeholder={t("general-settings.emergencyContacts.autocompletePlaceholder")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
handleLoginInfoUrlChange = (value: string) => {
|
||||
this.props.onChange(true, value, "loginInfoUrl");
|
||||
};
|
||||
handleRealmDescriptionChange = (value: string) => {
|
||||
this.props.onChange(true, value, "realmDescription");
|
||||
};
|
||||
handleEnabledXsrfProtectionChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "enabledXsrfProtection");
|
||||
};
|
||||
handleEnabledUserConverterChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "enabledUserConverter");
|
||||
};
|
||||
handleAnonymousMode = (value: string) => {
|
||||
this.props.onChange(true, value, "anonymousMode");
|
||||
};
|
||||
handleNamespaceStrategyChange = (value: string) => {
|
||||
this.props.onChange(true, value, "namespaceStrategy");
|
||||
};
|
||||
handlePluginCenterUrlChange = (value: string) => {
|
||||
this.props.onChange(true, value, "pluginUrl");
|
||||
};
|
||||
handleReleaseFeedUrlChange = (value: string) => {
|
||||
this.props.onChange(true, value, "releaseFeedUrl");
|
||||
};
|
||||
handleMailDomainNameChange = (value: string) => {
|
||||
this.props.onChange(true, value, "mailDomainName");
|
||||
};
|
||||
handleEnabledApiKeysChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "enabledApiKeys");
|
||||
};
|
||||
}
|
||||
|
||||
export default withTranslation("config")(GeneralSettings);
|
||||
export default GeneralSettings;
|
||||
|
||||
@@ -27,7 +27,7 @@ import { NamespaceStrategies } from "@scm-manager/ui-types";
|
||||
import { Select } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = WithTranslation & {
|
||||
namespaceStrategies: NamespaceStrategies;
|
||||
namespaceStrategies?: NamespaceStrategies;
|
||||
label: string;
|
||||
value?: string;
|
||||
disabled?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user