From 1dab687e769cc830adeb2ef53642abad77e1f7a6 Mon Sep 17 00:00:00 2001
From: Kai Reinhard <K.Reinhard@micromata.de>
Date: Fri, 18 Jan 2019 15:35:50 +0000
Subject: [PATCH] BorgRepConfig...Repo config...
---
borgbutler-core/src/main/java/de/micromata/borgbutler/config/BorgRepoConfig.java | 9 +
borgbutler-webapp/src/components/views/repos/RepoConfigPanel.jsx | 53 +++++---
borgbutler-webapp/src/components/views/repos/RepoCard.jsx | 2
borgbutler-webapp/src/containers/WebApp.jsx | 2
borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx | 204 +++++++++++++++++++--------------
borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java | 10 +
borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ReposRest.java | 22 +++
7 files changed, 187 insertions(+), 115 deletions(-)
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java
index 2c45d9c..a25e288 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java
@@ -124,9 +124,15 @@
this.repoCacheAccess.clear();
}
+ public void clearRepoCacheAccess(String repo) {
+ if (this.repoCacheAccess.get(repo) != null) {
+ log.info("Clearing repository cache '" + repo + "'...");
+ this.repoCacheAccess.remove(repo);
+ }
+ }
+
public void clearRepoCacheAccess(Repository repository) {
- log.info("Clearing repository cache '" + repository.getName() + "'...");
- this.repoCacheAccess.remove(repository.getName());
+ clearRepoCacheAccess(repository.getName());
}
/**
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/BorgRepoConfig.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/BorgRepoConfig.java
index 0ffeecd..52ac43a 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/BorgRepoConfig.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/BorgRepoConfig.java
@@ -1,6 +1,5 @@
package de.micromata.borgbutler.config;
-import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
@@ -29,7 +28,6 @@
private String passwordCommand;
@Getter
@Setter
- @JsonIgnore
private String id;
public String[] getEnvironmentVariables() {
@@ -51,4 +49,11 @@
if (StringUtils.isBlank(value)) return;
list.add(variable + "=" + value);
}
+
+ public void copyFrom(BorgRepoConfig other) {
+ this.displayName = other.displayName;
+ this.repo = other.repo;
+ this.passphrase = other.passphrase;
+ this.passwordCommand = other.passwordCommand;
+ }
}
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ReposRest.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ReposRest.java
index 125f2a0..8c4660e 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ReposRest.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ReposRest.java
@@ -10,10 +10,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;
@@ -68,6 +65,23 @@
return JsonUtils.toJson(repoConfig, prettyPrinter);
}
+ @POST
+ @Path("repoConfig")
+ @Produces(MediaType.TEXT_PLAIN)
+ public void setRepoConfig(String jsonConfig) {
+ BorgRepoConfig newRepoConfig = JsonUtils.fromJson(BorgRepoConfig.class, jsonConfig);
+ BorgRepoConfig repoConfig = ConfigurationHandler.getConfiguration().getRepoConfig(newRepoConfig.getId());
+ if (repoConfig == null) {
+ log.error("Can't find repo config '" + newRepoConfig.getId() + "'. Can't save new settings.");
+ return;
+ }
+ ButlerCache.getInstance().clearRepoCacheAccess(repoConfig.getRepo());
+ ButlerCache.getInstance().clearRepoCacheAccess(newRepoConfig.getRepo());
+ repoConfig.copyFrom(newRepoConfig);
+ ConfigurationHandler.getInstance().save();
+ }
+
+
/**
*
* @param id id or name of repo.
diff --git a/borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx b/borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx
index e92d80b..15e8331 100644
--- a/borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx
+++ b/borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx
@@ -1,5 +1,5 @@
import React from 'react'
-import {Nav, NavLink, TabContent, Table, TabPane} from 'reactstrap';
+import {Badge, Nav, NavLink, TabContent, Table, TabPane} from 'reactstrap';
import {Link} from "react-router-dom";
import classNames from 'classnames';
import {PageHeader} from '../../general/BootstrapComponents';
@@ -13,8 +13,10 @@
state = {
id: this.props.match.params.id,
+ displayName: this.props.match.params.displayName,
isFetching: false,
activeTab: '1',
+ redirectOnError: true
};
componentDidMount = () => {
@@ -43,7 +45,12 @@
repo: json
})
})
- .catch(() => this.setState({isFetching: false, failed: true}));
+ .catch(() => {
+ this.setState({isFetching: false, failed: true})
+ if (this.state.redirectOnError && this.state.activeTab !== '3') {
+ this.setState({activeTab: '3', redirectOnError: false});
+ }
+ });
};
toggleTab = tab => () => {
@@ -52,22 +59,46 @@
})
};
+ afterSave() {
+ if (!this.state.failed) {
+ this.setState({
+ activeTab: '1'
+ })
+ }
+ }
+
+ afterCancel() {
+ if (!this.state.failed) {
+ this.setState({
+ activeTab: '1'
+ })
+ }
+ }
+
render = () => {
- let content = undefined;
+ let errorBadge = '';
+ let content1 = undefined;
+ let content2 = undefined;
const repo = this.state.repo;
- let pageHeader = '';
+ const displayName = (this.state.displayName) ? this.state.displayName : `Error: id=${this.state.id}`;
+ let pageHeader = <React.Fragment>
+ {displayName}
+ </React.Fragment>;
if (this.state.isFetching) {
- content = <JobMonitorPanel repo={this.state.id}/>;
+ content1 = <JobMonitorPanel repo={this.state.id}/>;
+ content2 = content1;
} else if (this.state.failed) {
- content = <ErrorAlert
+ content1 = <ErrorAlert
title={'Cannot load Repositories'}
- description={'Something went wrong during contacting the rest api.'}
+ description={'Something went wrong, may-be wrong configuration?'}
action={{
handleClick: this.fetchRepo,
title: 'Try again'
}}
/>;
+ content2 = content1;
+ errorBadge = <Badge color="danger" pill>!</Badge>;
} else if (this.state.repo) {
pageHeader = <React.Fragment>
{repo.displayName}
@@ -128,91 +159,90 @@
<td>{repo.cache.path}</td>
</tr>
}
- content = <React.Fragment>
- <Nav tabs>
- <NavLink
- className={classNames({active: this.state.activeTab === '1'})}
- onClick={this.toggleTab('1')}
- >
- Archives
- </NavLink>
- <NavLink
- className={classNames({active: this.state.activeTab === '2'})}
- onClick={this.toggleTab('2')}
- >
- Information
- </NavLink>
- <NavLink
- className={classNames({active: this.state.activeTab === '3'})}
- onClick={this.toggleTab('3')}
- >
- Configuration
- </NavLink>
- </Nav>
- <TabContent activeTab={this.state.activeTab}>
- <TabPane tabId={'1'}>
- <Table hover>
- <tbody>
- <tr>
- <th>Archive</th>
- <th>Time</th>
- <th></th>
- <th>Id</th>
- </tr>
- {repo.archives.map((archive) => {
- // Return the element. Also pass key
- let loaded = '';
- if (archive.fileListAlreadyCached) {
- loaded = <IconCheck/>;
- }
- return (
- <tr key={archive.id}>
- <td><Link to={`/archives/${repo.id}/${archive.id}`}>{archive.name}</Link></td>
- <td>{archive.time}</td>
- <td>{loaded}</td>
- <td>{archive.id}</td>
- </tr>);
- })}
- </tbody>
- </Table>
- </TabPane>
- <TabPane tabId={'2'}>
- <Table striped bordered hover>
- <tbody>
- <tr>
- <td>Id</td>
- <td>{repo.id}</td>
- </tr>
- <tr>
- <td>Name</td>
- <td>{repo.name}</td>
- </tr>
- <tr>
- <td>Location</td>
- <td>{repo.location}</td>
- </tr>
- {stats}
- <tr>
- <td>Security dir</td>
- <td>{repo.securityDir}</td>
- </tr>
- {encryption}
- {cachePath}
- </tbody>
- </Table>
- </TabPane>
- <TabPane tabId={'3'}>
- <RepoConfigPanel id={repo.id}/>
- </TabPane>
- </TabContent>
- </React.Fragment>;
+ content1 = <Table hover>
+ <tbody>
+ <tr>
+ <th>Archive</th>
+ <th>Time</th>
+ <th></th>
+ <th>Id</th>
+ </tr>
+ {repo.archives.map((archive) => {
+ // Return the element. Also pass key
+ let loaded = '';
+ if (archive.fileListAlreadyCached) {
+ loaded = <IconCheck/>;
+ }
+ return (
+ <tr key={archive.id}>
+ <td><Link to={`/archives/${repo.id}/${archive.id}`}>{archive.name}</Link></td>
+ <td>{archive.time}</td>
+ <td>{loaded}</td>
+ <td>{archive.id}</td>
+ </tr>);
+ })}
+ </tbody>
+ </Table>;
+ content2 = <Table striped bordered hover>
+ <tbody>
+ <tr>
+ <td>Id</td>
+ <td>{repo.id}</td>
+ </tr>
+ <tr>
+ <td>Name</td>
+ <td>{repo.name}</td>
+ </tr>
+ <tr>
+ <td>Location</td>
+ <td>{repo.location}</td>
+ </tr>
+ {stats}
+ <tr>
+ <td>Security dir</td>
+ <td>{repo.securityDir}</td>
+ </tr>
+ {encryption}
+ {cachePath}
+ </tbody>
+ </Table>;
}
return <React.Fragment>
<PageHeader>
{pageHeader}
</PageHeader>
- {content}
+ <Nav tabs>
+ <NavLink
+ className={classNames({active: this.state.activeTab === '1'})}
+ onClick={this.toggleTab('1')}
+ >
+ Archives {errorBadge}
+ </NavLink>
+ <NavLink
+ className={classNames({active: this.state.activeTab === '2'})}
+ onClick={this.toggleTab('2')}
+ >
+ Information {errorBadge}
+ </NavLink>
+ <NavLink
+ className={classNames({active: this.state.activeTab === '3'})}
+ onClick={this.toggleTab('3')}
+ >
+ Configuration
+ </NavLink>
+ </Nav>
+ <TabContent activeTab={this.state.activeTab}>
+ <TabPane tabId={'1'}>
+ {content1}
+ </TabPane>
+ <TabPane tabId={'2'}>
+ {content2}
+ </TabPane>
+ <TabPane tabId={'3'}>
+ <RepoConfigPanel id={this.state.id} afterCancel={this.afterCancel} afterSave={this.afterSave} repoError={this.state.failed}/>
+ </TabPane>
+ </TabContent>
</React.Fragment>;
};
@@ -221,6 +251,8 @@
this.fetchRepo = this.fetchRepo.bind(this);
this.toggleTab = this.toggleTab.bind(this);
+ this.afterCancel = this.afterCancel.bind(this);
+ this.afterSave = this.afterSave.bind(this);
}
}
diff --git a/borgbutler-webapp/src/components/views/repos/RepoCard.jsx b/borgbutler-webapp/src/components/views/repos/RepoCard.jsx
index b04cfad..b7ae760 100644
--- a/borgbutler-webapp/src/components/views/repos/RepoCard.jsx
+++ b/borgbutler-webapp/src/components/views/repos/RepoCard.jsx
@@ -18,7 +18,7 @@
let repoText = this.buildItem(null, content);
return <React.Fragment>
- <Card tag={Link} to={`/repoArchives/${repo.id}`} outline color="success" className={'repo'}
+ <Card tag={Link} to={`/repoArchives/${repo.id}/${repo.displayName}`} outline color="success" className={'repo'}
style={{backgroundColor: '#fff'}}>
<CardHeader>{repo.displayName}</CardHeader>
<CardBody>
diff --git a/borgbutler-webapp/src/components/views/repos/RepoConfigPanel.jsx b/borgbutler-webapp/src/components/views/repos/RepoConfigPanel.jsx
index ebb1c58..93a9303 100644
--- a/borgbutler-webapp/src/components/views/repos/RepoConfigPanel.jsx
+++ b/borgbutler-webapp/src/components/views/repos/RepoConfigPanel.jsx
@@ -7,9 +7,7 @@
import PropTypes from "prop-types";
import ErrorAlert from "../../general/ErrorAlert";
-class RepoConfigPanel
- extends React
- .Component {
+class RepoConfigPanel extends React.Component {
constructor(props) {
super(props);
@@ -61,27 +59,42 @@
this.setState({repoConfig: {...this.state.repoConfig, [event.target.name]: event.target.value}});
}
- onSave(event) {
- this.setState({
- loading: true
- })
- this.setState({
- loading: false
- })
- this.setReload();
+ async onSave(event) {
+ const response = fetch(getRestServiceUrl("repos/repoConfig"), {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(this.state.repoConfig)
+ });
+ if (response) await response;
+ if (this.props.afterSave) {
+ this.props.afterSave();
+ }
}
- onCancel() {
- this.setReload();
+ async onCancel() {
+ const response = this.fetch();
+ if (response) await response;
+ if (this.props.afterCancel) {
+ this.props.afterCancel();
+ }
}
render() {
let content;
+ let repoError = '';
+ if (this.props.repoError) {
+ repoError =<ErrorAlert
+ title={'Cannot access repository'}
+ description={'Repo not available or mis-configured (please refer the log files for more details).'}
+ />
+ }
if (this.state.isFetching) {
content = <React.Fragment>Loading...</React.Fragment>;
} else if (this.state.failed) {
content = <ErrorAlert
- title={'Cannot load config or repository'}
+ title={'Cannot load config of repository'}
description={'Something went wrong during contacting the rest api.'}
action={{
handleClick: this.fetchRepo,
@@ -109,7 +122,7 @@
onChange={this.handleTextChange}
placeholder="Enter the password command to get the command from."/>
<FormLabelInputField label={'Password'} fieldLength={6} type={'password'}
- name={'passwordCommand'} value={repoConfig.password}
+ name={'passphrase'} value={repoConfig.passphrase}
onChange={this.handleTextChange}
hint={"It's recommended to use password command instead."}
/>
@@ -125,13 +138,15 @@
<LoadingOverlay active={this.state.loading}/>
</React.Fragment>;
}
- return <React.Fragment>{content}</React.Fragment>;
+ return <React.Fragment>{content}{repoError}</React.Fragment>;
}
}
-RepoConfigPanel
- .propTypes = {
- id: PropTypes.string
+RepoConfigPanel.propTypes = {
+ afterCancel: PropTypes.func.isRequired,
+ afterSave: PropTypes.func.isRequired,
+ id: PropTypes.string,
+ repoError: PropTypes.bool
};
export default RepoConfigPanel;
diff --git a/borgbutler-webapp/src/containers/WebApp.jsx b/borgbutler-webapp/src/containers/WebApp.jsx
index 90c5494..7f878c8 100644
--- a/borgbutler-webapp/src/containers/WebApp.jsx
+++ b/borgbutler-webapp/src/containers/WebApp.jsx
@@ -81,7 +81,7 @@
/>
))
}
- <Route path={'/repoArchives/:id'} component={RepoArchiveListView}/>
+ <Route path={'/repoArchives/:id/:displayName'} component={RepoArchiveListView}/>
<Route path={'/archives/:repoId/:archiveId'} component={ArchiveView}/>
</Switch>
</div>
--
Gitblit v1.10.0