htmlui: added UI to browse contents of directories and download files

This commit is contained in:
Jarek Kowalski
2019-12-12 21:19:58 -08:00
parent b93e58760a
commit 3a809f01e8
7 changed files with 156 additions and 31 deletions

View File

@@ -8,21 +8,18 @@ import 'react-table/react-table.css'
import { SourcesTable } from "./SourcesTable";
import { PoliciesTable } from "./PoliciesTable";
import { SnapshotsTable } from "./SnapshotsTable";
import { DirectoryObject } from "./DirectoryObject";
import Navbar from 'react-bootstrap/Navbar';
import { NavLink } from 'react-router-dom';
import Nav from 'react-bootstrap/Nav';
import Container from 'react-bootstrap/Container';
import { withRouter } from "react-router";
import {
BrowserRouter as Router,
Switch,
Route,
} from "react-router-dom";
const SnapshotsTableWithRouter = withRouter(SnapshotsTable);
function App() {
return (
<Router>
@@ -40,21 +37,10 @@ function App() {
<Container>
<Switch>
<Route path="/snapshots/single-source/">
<SnapshotsTableWithRouter />
</Route>
<Route path="/snapshots/dir/">
<p>not implemented: directory browser</p>
</Route>
<Route path="/snapshots/file/">
<p>not implemented: file browser</p>
</Route>
<Route path="/snapshots">
<SourcesTable />
</Route>
<Route path="/policies">
<PoliciesTable />
</Route>
<Route path="/snapshots/single-source/" component={SnapshotsTable} />
<Route path="/snapshots/dir/:oid" component={DirectoryObject} />
<Route path="/snapshots" component={SourcesTable} />
<Route path="/policies" component={PoliciesTable} />
<Route exact path="/">
<p>not implemented: Status</p>
</Route>

View File

@@ -0,0 +1,81 @@
import React, { Component } from 'react';
import ReactTable from 'react-table';
import { Link } from "react-router-dom";
import {
sizeDisplayName,
objectLink,
} from './uiutil';
function objectName(name, typeID) {
if (typeID === "d") {
return name + "/";
}
return name
}
function sizeInfo(item) {
if (item.size) {
return sizeDisplayName(item.size);
}
const summ = item.summ;
if (!summ) {
return "";
}
return sizeDisplayName(summ.size) + ", " + summ.files + " files, " + summ.dirs + " dirs";
}
function sizeForSorting(item) {
if (item.size) {
return item.size;
}
if (item.summ && item.summ.size) {
return item.summ.size;
}
return 0;
}
function sizeSortMethod(a, b, desc) {
const l = sizeForSorting(a);
const r = sizeForSorting(b);
if (l < r) {
return -1;
}
if (l > r) {
return 1;
}
return 0;
}
function directoryLinkOrDownload(x) {
if (x.obj.startsWith("k")) {
return <Link to={objectLink(x.obj)}>{objectName(x.name, x.type)}</Link>;
}
return <a href={"/api/v1/objects/" + x.obj + "?fname=" + x.name}>{x.name}</a>;
}
export class DirectoryItems extends Component {
render() {
const columns = [{
id: "name",
Header: 'Name',
accessor: x => directoryLinkOrDownload(x),
}, {
id: "mtime",
accessor: "mtime",
Header: "Last Mod",
}, {
id: "size",
accessor: x => sizeInfo(x),
Header: "Size",
sortMethod: sizeSortMethod,
}]
return <ReactTable data={this.props.items} columns={columns} />;
}
}

View File

@@ -0,0 +1,61 @@
import React, { Component } from 'react';
import axios from 'axios';
import { DirectoryItems } from "./DirectoryItems";
import Button from 'react-bootstrap/Button';
import Spinner from 'react-bootstrap/Spinner';
export class DirectoryObject extends Component {
constructor() {
super();
this.state = {
items: [],
isLoading: false,
error: null,
};
}
componentDidMount() {
this.fetchDirectory(this.props);
}
fetchDirectory(props) {
console.log('fetching props:', props);
let oid = props.match.params.oid;
this.setState({
isLoading: true,
});
axios.get('/api/v1/objects/' + oid).then(result => {
this.setState({
items: result.data.entries,
isLoading: false,
});
}).catch(error => this.setState({
error,
isLoading: false
}));
}
componentWillReceiveProps(props) {
this.fetchDirectory(props);
}
render() {
let { items, isLoading, error } = this.state;
if (error) {
return <p>ERROR: {error.message}</p>;
}
if (isLoading) {
return <Spinner animation="border" variant="primary" />;
}
return <div>
<Button size="xxl" onClick={this.props.history.goBack} >
Back
</Button>
<DirectoryItems items={items} />
</div>
}
}

View File

@@ -1,6 +1,5 @@
import React, { Component } from 'react';
import ReactTable from 'react-table';
import Button from 'react-bootstrap/Button';
import axios from 'axios';
import {
@@ -67,11 +66,6 @@ export class PoliciesTable extends Component {
accessor: x => timesOfDayDisplayName(x.policy.scheduling.timesOfDay),
}]
return <div>
<Button size="xxl">
flat button
</Button>
<ReactTable data={items} columns={columns} />;
</div>
return <ReactTable data={items} columns={columns} />;
}
}

View File

@@ -58,7 +58,6 @@ export class SnapshotsTable extends Component {
selectedSnapshot: null,
});
const u = '/api/v1/snapshots?host=' + q.host + '&userName=' + q.userName + '&path=' + q.path;
console.log('u', u);
axios.get(u).then(result => {
console.log('got snapshots', result.data);
this.setState({

View File

@@ -25,7 +25,7 @@ export class SourcesTable extends Component {
selectedUser: allUsers,
};
}
;
componentDidMount() {
this.setState({ isLoading: true });
axios.get('/api/v1/sources').then(result => {
@@ -54,6 +54,7 @@ export class SourcesTable extends Component {
hostClicked(h) {
alert('host clicked ' + h);
}
render() {
let { sources, isLoading, error } = this.state;
if (error) {
@@ -124,7 +125,7 @@ export class SourcesTable extends Component {
<Dropdown.Item onClick={() => this.selectHost(allHosts)}>(all)</Dropdown.Item>
{uniqueHosts.map(v => <Dropdown.Item onClick={() => this.selectHost(v)}>{v}</Dropdown.Item>)}
</Dropdown.Menu>
</Dropdown>
</Dropdown>
&nbsp;
<Dropdown>
@@ -139,7 +140,7 @@ export class SourcesTable extends Component {
</Dropdown>
</Row>
<p></p>
<p></p>
<Row><ReactTable data={sources} columns={columns} /></Row>
</div>;

View File

@@ -29,6 +29,9 @@ function toDecimalUnitString(f, thousand, prefixes, suffix) {
export function sizeDisplayName(s) {
if (s === undefined) {
return "";
}
return toDecimalUnitString(s, 1000, base10UnitPrefixes, "B");
}
@@ -62,5 +65,5 @@ export function objectLink(n) {
if (n.startsWith("k")) {
return "/snapshots/dir/" + n;
}
return "/snapshots/file/" + n;
return "/api/v1/objects/" + n;
}