mirror of https://github.com/micromata/borgbackup-butler.git

Kai Reinhard
24.51.2019 8f71271a3e022c74bf654cbae0eefb528ad17e60
Options openDownloads and autoChangeDir implemented.
5 files modified
257 ■■■■■ changed files
borgbutler-webapp/src/components/views/archives/FileListEntry.jsx 6 ●●●●● patch | view | raw | blame | history
borgbutler-webapp/src/components/views/archives/FileListFilter.jsx 206 ●●●●● patch | view | raw | blame | history
borgbutler-webapp/src/components/views/archives/FileListPanel.jsx 22 ●●●● patch | view | raw | blame | history
borgbutler-webapp/src/components/views/archives/FileListTable.jsx 3 ●●●● patch | view | raw | blame | history
borgbutler-webapp/src/css/my-style.css 20 ●●●●● patch | view | raw | blame | history
borgbutler-webapp/src/components/views/archives/FileListEntry.jsx
@@ -23,7 +23,8 @@
        }
        fetch(getRestServiceUrl('archives/restore', {
            archiveId: archiveId,
            fileNumber: fileNumber
            fileNumber: fileNumber,
            openDownloads: this.props.openDownloads
        }))
            .then(response => {
                if (response.status === 202) { // ACCEPTED
@@ -185,7 +186,8 @@
    entry: PropTypes.shape({}).isRequired,
    search: PropTypes.string,
    mode: PropTypes.string,
    diffArchiveId: PropTypes.string
    diffArchiveId: PropTypes.string,
    openDownloads: PropTypes.bool
};
export default FileListEntry;
borgbutler-webapp/src/components/views/archives/FileListFilter.jsx
@@ -1,85 +1,147 @@
import React from 'react';
import {Dropdown, DropdownItem, DropdownMenu, DropdownToggle} from 'reactstrap';
import PropTypes from 'prop-types';
import {FormButton, FormInput, FormLabel, FormOption, FormSelect} from '../../general/forms/FormComponents';
import {
    FormButton,
    FormCheckbox,
    FormInput,
    FormLabel,
    FormOption,
    FormSelect
} from '../../general/forms/FormComponents';
import {IconRefresh} from '../../general/IconComponents';
import I18n from '../../general/translation/I18n';
function FileListFilter({reload, changeFilter, filter, currentArchiveId, archiveShortInfoList}) {
    let archiveOptions =
        archiveShortInfoList
            .map(archive => {
                //if (archiveId === archive)
                let label = archive.time;
                if (archive.fileListAlreadyCached) {
                    label = `${archive.time} ✓`
                }
                let disabled = undefined;
                if (archive.id === currentArchiveId) {
                    disabled = true;
                }
                return <FormOption
                    value={archive.id}
                    label={label}
                    disabled={disabled}
                    key={archive.id}
class FileListFilter extends React.Component {
    constructor(props) {
        super(props);
        this.toggle = this.toggle.bind(this);
        this.state = {
            dropdownOpen: false
        };
    }
    toggle() {
        this.setState(prevState => ({
            dropdownOpen: !prevState.dropdownOpen
        }));
    }
    render = () => {
        const archiveShortInfoList = this.props.archiveShortInfoList;
        const currentArchiveId = this.props.currentArchiveId;
        const reload = this.props.reload;
        const filter = this.props.filter;
        let archiveOptions =
            archiveShortInfoList
                .map(archive => {
                    //if (archiveId === archive)
                    let label = archive.time;
                    if (archive.fileListAlreadyCached) {
                        label = `${archive.time} ✓`
                    }
                    let disabled = undefined;
                    if (archive.id === currentArchiveId) {
                        disabled = true;
                    }
                    return <FormOption
                        value={archive.id}
                        label={label}
                        disabled={disabled}
                        key={archive.id}
                    />
                });
        return (
            <form
                onSubmit={reload}
                className={'form-inline'}
            >
                <FormLabel length={1}>
                    Filter:
                </FormLabel>
                <FormInput
                    value={filter.search}
                    name={'search'}
                    onChange={this.props.changeFilter}
                    fieldLength={7}
                    autoFocus
                    hint={'You may enter several key words separated by white spaces. Hit simply return to proceed. Example: \'borg xls !film\' searches for Excel files containing \'borg\', but not \'film\'.'}
                />
            });
    return (
        <form
            onSubmit={reload}
            className={'form-inline'}
        >
            <FormLabel length={1}>
                Filter:
            </FormLabel>
            <FormInput
                value={filter.search}
                name={'search'}
                onChange={changeFilter}
                fieldLength={5}
                autoFocus
                hint={'You may enter several key words separated by white spaces. Hit simply return to proceed. Example: \'borg xls !film\' searches for Excel files containing \'borg\', but not \'film\'.'}
            />
            <FormSelect
                value={filter.mode}
                name={'mode'}
                onChange={changeFilter}
            >
                <FormOption value={'tree'}/>
                <FormOption value={'flat'}/>
            </FormSelect>
            <FormSelect
                value={filter.maxSize}
                name={'maxSize'}
                onChange={changeFilter}
                hint={<I18n name={'common.limitsResultSize'}/>}
            >
                <FormOption value={'50'}/>
                <FormOption value={'100'}/>
                <FormOption value={'500'}/>
                <FormOption value={'1000'}/>
                <FormOption value={'10000'}/>
            </FormSelect>
            <FormSelect
                value={filter.diffArchiveId}
                name={'diffArchiveId'}
                onChange={(event) => {changeFilter(event, () => reload(event))}}
                hint={'Show differences between current archive and this selected archive.'}
            >
                <FormOption value={''} label={'Select diff archive'}/>
                {archiveOptions}
            </FormSelect>
            <FormButton type={'submit'} bsStyle={'primary'}>
                <IconRefresh/>
            </FormButton>
        </form>
    );
                <FormSelect
                    value={filter.diffArchiveId}
                    name={'diffArchiveId'}
                    onChange={(event) => {
                        this.props.changeFilter(event, () => reload(event))
                    }}
                    hint={'Show differences between current archive and this selected archive.'}
                >
                    <FormOption value={''} label={'Select diff archive'}/>
                    {archiveOptions}
                </FormSelect>
                <Dropdown isOpen={this.state.dropdownOpen} toggle={this.toggle}>
                    <DropdownToggle outline color="secondary" caret>
                        Settings
                    </DropdownToggle>
                    <DropdownMenu>
                        <DropdownItem disabled>
                            <div className={'label'}>Mode:{' '}</div>
                            <div className={'value'}>
                                <FormSelect
                                    value={filter.mode}
                                    name={'mode'}
                                    onChange={this.props.changeFilter}
                                >
                                    <FormOption value={'tree'}/>
                                    <FormOption value={'flat'}/>
                                </FormSelect>
                            </div>
                        </DropdownItem>
                        <DropdownItem disabled>
                            <div className={'label'}>Result size:{' '}</div>
                            <div className={'value'}>
                                <FormSelect
                                    value={filter.maxSize}
                                    name={'maxSize'}
                                    onChange={this.props.changeFilter}
                                    hint={<I18n name={'common.limitsResultSize'}/>}
                                >
                                    <FormOption value={'50'}/>
                                    <FormOption value={'100'}/>
                                    <FormOption value={'500'}/>
                                    <FormOption value={'1000'}/>
                                    <FormOption value={'10000'}/>
                                </FormSelect>
                            </div>
                        </DropdownItem>
                        <DropdownItem divider/>
                        <DropdownItem disabled>
                            <FormCheckbox checked={filter.autoChangeDirectoryToLeafItem}
                                          hint={'Step automatically into single sub directories.'}
                                          name="autoChangeDirectoryToLeafItem"
                                          label={'Step automatically into sub dirs'}
                                          onChange={this.props.changeFilterCheckbox}/>
                        </DropdownItem>
                        <DropdownItem disabled>
                            <FormCheckbox checked={filter.openDownloads}
                                          name="openDownloads"
                                          label={'Open downloads automatically'}
                                          onChange={this.props.changeFilterCheckbox}/>
                        </DropdownItem>
                    </DropdownMenu>
                </Dropdown>
                <FormButton type={'submit'} bsStyle={'primary'}>
                    <IconRefresh/>
                </FormButton>
            </form>
        );
    }
}
FileListFilter.propTypes = {
    changeFilter: PropTypes.func.isRequired,
    changeFilterCheckbox: PropTypes.func.isRequired,
    filter: PropTypes.shape({
        search: PropTypes.string,
        maxSize: PropTypes.oneOf(['50', '100', '500', '1000', '10000']),
borgbutler-webapp/src/components/views/archives/FileListPanel.jsx
@@ -18,7 +18,9 @@
            mode: 'tree',
            currentDirectory: '',
            maxSize: '50',
            diffArchiveId: ''
            diffArchiveId: '',
            autoChangeDirectoryToLeafItem: true,
            openDownloads: true
        }
    };
@@ -58,6 +60,10 @@
            });
    };
    handleCheckboxChange = event => {
        this.setState({filter: {...this.state.filter, [event.target.name]: event.target.checked}});
    }
    changeCurrentDirectory = (currentDirectory) => {
        this.setState({filter: {...this.state.filter, currentDirectory: currentDirectory}},
            () => {
@@ -78,7 +84,8 @@
            mode: this.state.filter.mode,
            currentDirectory: this.state.filter.currentDirectory,
            maxResultSize: this.state.filter.maxSize,
            diffArchive: this.state.filter.diffArchive
            diffArchive: this.state.filter.diffArchive,
            autoChangeDirectoryToLeafItem: this.state.filter.autoChangeDirectoryToLeafItem
        }), {
            method: 'GET',
            headers: {
@@ -87,9 +94,15 @@
        })
            .then(response => response.json())
            .then(json => {
                let currentDirectory = this.state.filter.currentDirectory;
                const fileList = json;
                if (fileList && fileList.length > 0) {
                    currentDirectory = fileList[0].path.replace(fileList[0].displayPath, '');
                }
                this.setState({
                    isFetching: false,
                    fileList: json
                    fileList: fileList,
                    filter: {...this.state.filter, currentDirectory: currentDirectory}
                })
            })
            .catch(() => this.setState({isFetching: false, failed: true}));
@@ -117,7 +130,6 @@
                </React.Fragment>;
            } else {
                let breadcrumb;
                if (this.state.filter.mode === 'tree' && this.state.filter.currentDirectory.length > 0) {
                    breadcrumb = (
                        <Breadcrumb>
@@ -130,6 +142,7 @@
                    <FileListFilter
                        filter={this.state.filter}
                        changeFilter={this.handleInputChange}
                        changeFilterCheckbox={this.handleCheckboxChange}
                        reload={(event) => {
                            event.preventDefault();
                            this.fetchArchiveFileList();
@@ -141,6 +154,7 @@
                    <FileListTable
                        archive={this.props.archive}
                        diffArchiveId={this.state.filter.diffArchiveId}
                        openDownloads={this.state.filter.openDownloads}
                        entries={this.state.fileList}
                        search={this.state.filter.search}
                        mode={this.state.filter.mode}
borgbutler-webapp/src/components/views/archives/FileListTable.jsx
@@ -3,7 +3,7 @@
import {Table} from 'reactstrap';
import FileListEntry from './FileListEntry';
function FileListTable({archive, diffArchiveId, entries, search, mode, changeCurrentDirectory}) {
function FileListTable({archive, diffArchiveId, openDownloads, entries, search, mode, changeCurrentDirectory}) {
    const lowercaseSearch = search.split(' ')[0].toLowerCase();
    return (
        <Table striped bordered hover size={'sm'} responsive>
@@ -24,6 +24,7 @@
                    entry={entry}
                    search={lowercaseSearch}
                    mode={mode}
                    openDownloads={openDownloads}
                    key={index}
                />)}
            </tbody>
borgbutler-webapp/src/css/my-style.css
@@ -422,6 +422,26 @@
    background-color: #bbbbbb;
}
.dropdown-menu {
    width: 300px;
    justify-content: left;
}
.dropdown-menu label {
    justify-content: left;
}
.dropdown-menu .label {
    width: 130px;
    float: left;
    padding-top: 10px;
}
.dropdown-menu .value {
    width: 150px;
    clear: right;
}
/* @media only screen and (max-width: 1050px) {
    .navbar.navbar-light a.nav-link {
        font-size: 0.8rem;