mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-07 05:55:44 +01:00
implemented git repository type configuration
This commit is contained in:
@@ -12,6 +12,6 @@
|
||||
"@scm-manager/ui-extensions": "^0.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/ui-bundler": "^0.0.19"
|
||||
"@scm-manager/ui-bundler": "^0.0.21"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,17 +116,17 @@ public class GitRepositoryHandler
|
||||
public void init(SCMContextProvider context)
|
||||
{
|
||||
super.init(context);
|
||||
scheduleGc();
|
||||
scheduleGc(getConfig().getGcExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfig(GitConfig config)
|
||||
{
|
||||
scheduleGc(config.getGcExpression());
|
||||
super.setConfig(config);
|
||||
scheduleGc();
|
||||
}
|
||||
|
||||
private void scheduleGc()
|
||||
private void scheduleGc(String expression)
|
||||
{
|
||||
synchronized (LOCK){
|
||||
if ( task != null ){
|
||||
@@ -134,11 +134,10 @@ public class GitRepositoryHandler
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
String exp = getConfig().getGcExpression();
|
||||
if (!Strings.isNullOrEmpty(exp))
|
||||
if (!Strings.isNullOrEmpty(expression))
|
||||
{
|
||||
logger.info("schedule git gc task with expression {}", exp);
|
||||
task = scheduler.schedule(exp, GitGcTask.class);
|
||||
logger.info("schedule git gc task with expression {}", expression);
|
||||
task = scheduler.schedule(expression, GitGcTask.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
183
scm-plugins/scm-git-plugin/src/main/js/GitConfiguration.js
Normal file
183
scm-plugins/scm-git-plugin/src/main/js/GitConfiguration.js
Normal file
@@ -0,0 +1,183 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import type { Links } from "@scm-manager/ui-types";
|
||||
import {
|
||||
apiClient,
|
||||
Title,
|
||||
InputField,
|
||||
Checkbox,
|
||||
SubmitButton,
|
||||
Loading,
|
||||
ErrorNotification
|
||||
} from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
url: string,
|
||||
|
||||
// context props
|
||||
t: (string) => string
|
||||
};
|
||||
|
||||
type Configuration = {
|
||||
repositoryDirectory?: string,
|
||||
gcExpression?: string,
|
||||
disabled: boolean,
|
||||
_links?: Links
|
||||
}
|
||||
|
||||
type State = Configuration & {
|
||||
error?: Error,
|
||||
fetching: boolean,
|
||||
modifying: boolean
|
||||
};
|
||||
|
||||
class GitConfiguration extends React.Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
disabled: false,
|
||||
fetching: true,
|
||||
modifying: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { url } = this.props;
|
||||
|
||||
// TODO capture content-type for sending
|
||||
|
||||
apiClient.get(url)
|
||||
.then(response => response.json())
|
||||
.then(this.loadConfig)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
handleError = (error: Error) => {
|
||||
this.setState({
|
||||
error,
|
||||
fetching: false,
|
||||
modifying: false
|
||||
});
|
||||
};
|
||||
|
||||
loadConfig = (configuration: Configuration) => {
|
||||
this.setState({
|
||||
...configuration,
|
||||
fetching: false,
|
||||
error: undefined
|
||||
});
|
||||
};
|
||||
|
||||
handleInputChange = (value: string, name: string) => {
|
||||
this.setState({
|
||||
[name]: value
|
||||
});
|
||||
};
|
||||
|
||||
handleCheckboxChange = (value: boolean, name: string) => {
|
||||
this.setState({
|
||||
[name]: value
|
||||
});
|
||||
};
|
||||
|
||||
isValid = (): boolean => {
|
||||
const { repositoryDirectory } = this.state;
|
||||
return !!repositoryDirectory;
|
||||
};
|
||||
|
||||
getModificationUrl = (): ?string => {
|
||||
const links = this.state._links;
|
||||
if (links && links.update) {
|
||||
return links.update.href;
|
||||
}
|
||||
};
|
||||
|
||||
isReadOnly = (): boolean => {
|
||||
const links = this.state._links;
|
||||
return !links || !links.update;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { fetching, error } = this.state;
|
||||
|
||||
if (error) {
|
||||
return this.renderWithFrame(<ErrorNotification error={error}/>);
|
||||
} else if (fetching) {
|
||||
return this.renderWithFrame(<Loading/>);
|
||||
}
|
||||
|
||||
return this.renderForm();
|
||||
}
|
||||
|
||||
renderWithFrame(child) {
|
||||
const { t } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<Title title={t("scm-git-plugin.config.title")}/>
|
||||
{child}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
modifyConfiguration = (event: Event) => {
|
||||
event.preventDefault();
|
||||
|
||||
this.setState({ modifying: true });
|
||||
|
||||
const { repositoryDirectory, gcExpression, disabled } = this.state;
|
||||
|
||||
const configuration = {
|
||||
repositoryDirectory,
|
||||
gcExpression,
|
||||
disabled
|
||||
};
|
||||
|
||||
apiClient.put(this.getModificationUrl(), configuration, "application/vnd.scmm-gitconfig+json;v=2")
|
||||
.then(() => this.setState({ modifying: false }))
|
||||
.catch(this.handleError);
|
||||
};
|
||||
|
||||
renderForm() {
|
||||
const { repositoryDirectory, gcExpression, disabled, modifying } = this.state;
|
||||
|
||||
const { t } = this.props;
|
||||
const readOnly = this.isReadOnly();
|
||||
|
||||
return this.renderWithFrame(
|
||||
<form onSubmit={this.modifyConfiguration}>
|
||||
<InputField name="repositoryDirectory"
|
||||
label={t("scm-git-plugin.config.directory")}
|
||||
helpText={t("scm-git-plugin.config.directoryHelpText")}
|
||||
value={repositoryDirectory}
|
||||
onChange={this.handleInputChange}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
<InputField name="gcExpression"
|
||||
label={t("scm-git-plugin.config.gcExpression")}
|
||||
helpText={t("scm-git-plugin.config.gcExpressionHelpText")}
|
||||
value={gcExpression}
|
||||
onChange={this.handleInputChange}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
<Checkbox name="disabled"
|
||||
label={t("scm-git-plugin.config.disabled")}
|
||||
helpText={t("scm-git-plugin.config.disabledHelpText")}
|
||||
checked={disabled}
|
||||
onChange={this.handleCheckboxChange}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
<hr/>
|
||||
<SubmitButton
|
||||
label={t("scm-git-plugin.config.submit")}
|
||||
disabled={!this.isValid() || readOnly}
|
||||
loading={modifying}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate("plugins")(GitConfiguration);
|
||||
@@ -0,0 +1,21 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { NavLink } from "@scm-manager/ui-components";
|
||||
import { translate } from "react-i18next";
|
||||
|
||||
type Props = {
|
||||
url: string,
|
||||
|
||||
// context props
|
||||
t: (string) => string
|
||||
}
|
||||
class GitConfigurationNavLink extends React.Component<Props> {
|
||||
|
||||
render() {
|
||||
const { url, t } = this.props;
|
||||
return <NavLink to={`${url}/git`} label={t("scm-git-plugin.config.link")} />;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate("plugins")(GitConfigurationNavLink);
|
||||
@@ -0,0 +1,25 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import type { Links } from "@scm-manager/ui-types";
|
||||
import GitConfiguration from "./GitConfiguration";
|
||||
import { Route } from "react-router-dom";
|
||||
|
||||
type Props = {
|
||||
url: string,
|
||||
links: Links
|
||||
}
|
||||
|
||||
class GitConfigurationRoute extends React.Component<Props> {
|
||||
|
||||
render() {
|
||||
const { url, links } = this.props;
|
||||
|
||||
const configLink = links["gitConfig"].href;
|
||||
return <Route path={url + "/git"}
|
||||
component={() => <GitConfiguration url={configLink} />}
|
||||
exact />;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GitConfigurationRoute;
|
||||
@@ -2,6 +2,10 @@
|
||||
import { binder } from "@scm-manager/ui-extensions";
|
||||
import ProtocolInformation from "./ProtocolInformation";
|
||||
import GitAvatar from "./GitAvatar";
|
||||
import GitConfigurationNavLink from "./GitConfigurationNavLink";
|
||||
import GitConfigurationRoute from "./GitConfigurationRoute";
|
||||
|
||||
// repository
|
||||
|
||||
const gitPredicate = (props: Object) => {
|
||||
return props.repository && props.repository.type === "git";
|
||||
@@ -9,3 +13,12 @@ const gitPredicate = (props: Object) => {
|
||||
|
||||
binder.bind("repos.repository-details.information", ProtocolInformation, gitPredicate);
|
||||
binder.bind("repos.repository-avatar", GitAvatar, gitPredicate);
|
||||
|
||||
// global config
|
||||
|
||||
const gitConfigPredicate = (props: Object) => {
|
||||
return props.links && props.links["gitConfig"];
|
||||
};
|
||||
|
||||
binder.bind("config.navigation", GitConfigurationNavLink, gitConfigPredicate);
|
||||
binder.bind("config.route", GitConfigurationRoute, gitConfigPredicate);
|
||||
|
||||
@@ -4,6 +4,17 @@
|
||||
"clone" : "Clone the repository",
|
||||
"create" : "Create a new repository",
|
||||
"replace" : "Push an existing repository"
|
||||
},
|
||||
"config": {
|
||||
"link": "Git",
|
||||
"title": "Git Configuration",
|
||||
"directory": "Repository Directory",
|
||||
"directoryHelpText": "Location of the Git repositories.",
|
||||
"gcExpression": "GC Cron Expression",
|
||||
"gcExpressionHelpText": "Use Quartz Cron Expressions (SECOND MINUTE HOUR DAYOFMONTH MONTH DAYOFWEEK) to run git gc in intervals.",
|
||||
"disabled": "Disabled",
|
||||
"disabledHelpText": "Enable or disable the Git plugin",
|
||||
"submit": "Submit"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,9 +707,9 @@
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85"
|
||||
|
||||
"@scm-manager/ui-bundler@^0.0.19":
|
||||
version "0.0.19"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.19.tgz#646ab1fa1e5389fad614542215c60678fb9816ae"
|
||||
"@scm-manager/ui-bundler@^0.0.21":
|
||||
version "0.0.21"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.21.tgz#f8b5fa355415cc67b8aaf8744e1701a299dff647"
|
||||
dependencies:
|
||||
"@babel/core" "^7.0.0"
|
||||
"@babel/plugin-proposal-class-properties" "^7.0.0"
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
"@scm-manager/ui-extensions": "^0.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/ui-bundler": "^0.0.19"
|
||||
"@scm-manager/ui-bundler": "^0.0.21"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,9 +641,9 @@
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85"
|
||||
|
||||
"@scm-manager/ui-bundler@^0.0.19":
|
||||
version "0.0.19"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.19.tgz#646ab1fa1e5389fad614542215c60678fb9816ae"
|
||||
"@scm-manager/ui-bundler@^0.0.21":
|
||||
version "0.0.21"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.21.tgz#f8b5fa355415cc67b8aaf8744e1701a299dff647"
|
||||
dependencies:
|
||||
"@babel/core" "^7.0.0"
|
||||
"@babel/plugin-proposal-class-properties" "^7.0.0"
|
||||
@@ -660,7 +660,6 @@
|
||||
browserify-css "^0.14.0"
|
||||
colors "^1.3.1"
|
||||
commander "^2.17.1"
|
||||
connect-history-api-fallback "^1.5.0"
|
||||
eslint "^5.4.0"
|
||||
eslint-config-react-app "^2.1.0"
|
||||
eslint-plugin-flowtype "^2.50.0"
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
"@scm-manager/ui-extensions": "^0.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/ui-bundler": "^0.0.19"
|
||||
"@scm-manager/ui-bundler": "^0.0.21"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,9 +641,9 @@
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85"
|
||||
|
||||
"@scm-manager/ui-bundler@^0.0.19":
|
||||
version "0.0.19"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.19.tgz#646ab1fa1e5389fad614542215c60678fb9816ae"
|
||||
"@scm-manager/ui-bundler@^0.0.21":
|
||||
version "0.0.21"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.21.tgz#f8b5fa355415cc67b8aaf8744e1701a299dff647"
|
||||
dependencies:
|
||||
"@babel/core" "^7.0.0"
|
||||
"@babel/plugin-proposal-class-properties" "^7.0.0"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"eslint-fix": "eslint src --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/ui-bundler": "^0.0.19",
|
||||
"@scm-manager/ui-bundler": "^0.0.21",
|
||||
"create-index": "^2.3.0",
|
||||
"enzyme": "^3.5.0",
|
||||
"enzyme-adapter-react-16": "^1.3.1",
|
||||
|
||||
@@ -4,15 +4,16 @@ import { Help } from "../index";
|
||||
|
||||
type Props = {
|
||||
label?: string,
|
||||
name?: string,
|
||||
checked: boolean,
|
||||
onChange?: boolean => void,
|
||||
onChange?: (value: boolean, name?: string) => void,
|
||||
disabled?: boolean,
|
||||
helpText?: string
|
||||
};
|
||||
class Checkbox extends React.Component<Props> {
|
||||
onCheckboxChange = (event: SyntheticInputEvent<HTMLInputElement>) => {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(event.target.checked);
|
||||
this.props.onChange(event.target.checked, this.props.name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@ import { LabelWithHelpIcon } from "../index";
|
||||
|
||||
type Props = {
|
||||
label?: string,
|
||||
name?: string,
|
||||
placeholder?: string,
|
||||
value?: string,
|
||||
type?: string,
|
||||
autofocus?: boolean,
|
||||
onChange: string => void,
|
||||
onChange: (value: string, name?: string) => void,
|
||||
onReturnPressed?: () => void,
|
||||
validationError: boolean,
|
||||
errorMessage: string,
|
||||
@@ -32,7 +33,7 @@ class InputField extends React.Component<Props> {
|
||||
}
|
||||
|
||||
handleInput = (event: SyntheticInputEvent<HTMLInputElement>) => {
|
||||
this.props.onChange(event.target.value);
|
||||
this.props.onChange(event.target.value, this.props.name);
|
||||
};
|
||||
|
||||
handleKeyPress = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
||||
|
||||
@@ -641,9 +641,9 @@
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85"
|
||||
|
||||
"@scm-manager/ui-bundler@^0.0.19":
|
||||
version "0.0.19"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.19.tgz#646ab1fa1e5389fad614542215c60678fb9816ae"
|
||||
"@scm-manager/ui-bundler@^0.0.21":
|
||||
version "0.0.21"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.21.tgz#f8b5fa355415cc67b8aaf8744e1701a299dff647"
|
||||
dependencies:
|
||||
"@babel/core" "^7.0.0"
|
||||
"@babel/plugin-proposal-class-properties" "^7.0.0"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"check": "flow check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/ui-bundler": "^0.0.19"
|
||||
"@scm-manager/ui-bundler": "^0.0.21"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
|
||||
@@ -707,9 +707,9 @@
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85"
|
||||
|
||||
"@scm-manager/ui-bundler@^0.0.19":
|
||||
version "0.0.19"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.19.tgz#646ab1fa1e5389fad614542215c60678fb9816ae"
|
||||
"@scm-manager/ui-bundler@^0.0.21":
|
||||
version "0.0.21"
|
||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.21.tgz#f8b5fa355415cc67b8aaf8744e1701a299dff647"
|
||||
dependencies:
|
||||
"@babel/core" "^7.0.0"
|
||||
"@babel/plugin-proposal-class-properties" "^7.0.0"
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"pre-commit": "jest && flow && eslint src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/ui-bundler": "^0.0.19",
|
||||
"@scm-manager/ui-bundler": "^0.0.21",
|
||||
"copyfiles": "^2.0.0",
|
||||
"enzyme": "^3.3.0",
|
||||
"enzyme-adapter-react-16": "^1.1.1",
|
||||
|
||||
@@ -2,12 +2,19 @@
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Route } from "react-router";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
|
||||
import type { Links } from "@scm-manager/ui-types";
|
||||
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
|
||||
import GlobalConfig from "./GlobalConfig";
|
||||
import type { History } from "history";
|
||||
import {connect} from "react-redux";
|
||||
import {compose} from "redux";
|
||||
import { getLinks } from "../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
links: Links,
|
||||
|
||||
// context objects
|
||||
t: string => string,
|
||||
match: any,
|
||||
@@ -27,15 +34,23 @@ class Config extends React.Component<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { links, t } = this.props;
|
||||
|
||||
const url = this.matchedUrl();
|
||||
const extensionProps = {
|
||||
links,
|
||||
url
|
||||
};
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<div className="columns">
|
||||
<div className="column is-three-quarters">
|
||||
<Route path={url} exact component={GlobalConfig} />
|
||||
<ExtensionPoint name="config.route"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</div>
|
||||
<div className="column">
|
||||
<Navigation>
|
||||
@@ -44,6 +59,10 @@ class Config extends React.Component<Props> {
|
||||
to={`${url}`}
|
||||
label={t("global-config.navigation-label")}
|
||||
/>
|
||||
<ExtensionPoint name="config.navigation"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</Section>
|
||||
</Navigation>
|
||||
</div>
|
||||
@@ -53,4 +72,15 @@ class Config extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("config")(Config);
|
||||
const mapStateToProps = (state: any) => {
|
||||
const links = getLinks(state);
|
||||
return {
|
||||
links
|
||||
};
|
||||
};
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps),
|
||||
translate("config")
|
||||
)(Config);
|
||||
|
||||
|
||||
@@ -101,7 +101,6 @@ class Main extends React.Component<Props> {
|
||||
authenticated={authenticated}
|
||||
/>
|
||||
<ProtectedRoute
|
||||
exact
|
||||
path="/config"
|
||||
component={Config}
|
||||
authenticated={authenticated}
|
||||
|
||||
1335
scm-ui/yarn.lock
1335
scm-ui/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user