From db097d27175eb0fcc24e6e5521e6ef63dde467d6 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 5 Sep 2023 03:32:22 +0200 Subject: [PATCH] Added directory breadcrumb buttons to see path and navigate back (#141) * Added directory breadcrumbs to - be able to view the current path one came to the current directory - be able to quickly navigate upwards * layout fixes * use breadcrumps for history in DirectoryObject.jsx / DirectoryBreadcrumbs.jsx * - get path of snapshot - no tooltip if no OID - disable / improve wrapping of tooltip - disable clicking on current breadcrumb item * enable copying of OID to clipboard * fix warning about className and readOnly form --------- Co-authored-by: Peter Tandler --- package.json | 1 + src/DirectoryBreadcrumbs.jsx | 40 ++++++++++++++++++++++++++++++++++++ src/DirectoryItems.jsx | 6 +++--- src/DirectoryObject.jsx | 32 ++++++++++++++++------------- src/SnapshotsTable.jsx | 18 ++++++++++------ src/uiutil.jsx | 18 ++++++++-------- 6 files changed, 83 insertions(+), 32 deletions(-) create mode 100644 src/DirectoryBreadcrumbs.jsx diff --git a/package.json b/package.json index d154752..a7282a0 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-regular-svg-icons": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.1.1", "@fortawesome/react-fontawesome": "^0.2.0", diff --git a/src/DirectoryBreadcrumbs.jsx b/src/DirectoryBreadcrumbs.jsx new file mode 100644 index 0000000..c839558 --- /dev/null +++ b/src/DirectoryBreadcrumbs.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import Breadcrumb from 'react-bootstrap/Breadcrumb'; +import { useHistory, useLocation } from 'react-router-dom'; +import { OverlayTrigger, Tooltip } from "react-bootstrap"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faInfoCircle } from "@fortawesome/free-solid-svg-icons"; + +export function DirectoryBreadcrumbs() { + const location = useLocation(); + const history = useHistory(); + + const breadcrumbs = [] + for (let state = location.state; state; state = state.prevState) { + breadcrumbs.unshift(state) + } + + return ( + + { + breadcrumbs.map((state, i) => { + const index = breadcrumbs.length - i - 1 // revert index + return { + if (index) history.go(-index); + }} + active={!index}> + {state.label} + {state.oid && !index && <> OID: {state.oid}} + > + + } + ; + }) + } + + ) +} diff --git a/src/DirectoryItems.jsx b/src/DirectoryItems.jsx index 5159e32..8fc2ce8 100644 --- a/src/DirectoryItems.jsx +++ b/src/DirectoryItems.jsx @@ -24,9 +24,9 @@ function sizeInfo(item) { return 0; } -function directoryLinkOrDownload(x) { +function directoryLinkOrDownload(x, state) { if (x.obj.startsWith("k")) { - return {objectName(x.name, x.type)}; + return {objectName(x.name, x.type)}; } return directoryLinkOrDownload(x), + accessor: x => directoryLinkOrDownload(x, this.props.historyState), }, { id: "mtime", accessor: "mtime", diff --git a/src/DirectoryObject.jsx b/src/DirectoryObject.jsx index f4973d8..315591d 100644 --- a/src/DirectoryObject.jsx +++ b/src/DirectoryObject.jsx @@ -7,7 +7,8 @@ import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; import Spinner from 'react-bootstrap/Spinner'; import { DirectoryItems } from "./DirectoryItems"; -import { CLIEquivalent, GoBackButton } from './uiutil'; +import { CLIEquivalent } from './uiutil'; +import { DirectoryBreadcrumbs } from "./DirectoryBreadcrumbs"; export class DirectoryObject extends Component { constructor() { @@ -118,33 +119,36 @@ export class DirectoryObject extends Component { } return <> + - - -   + {this.state.mountInfo.path ? <> - + {window.kopiaUI && <>   - + }   - + : <> - + }   - + +   + + + You can mount/restore all the files & directories that you see below or restore files + individually. - -   - - You can mount/restore all the files & directories that you see below or restore files individually.   - + diff --git a/src/SnapshotsTable.jsx b/src/SnapshotsTable.jsx index 8a0f882..92bda9b 100644 --- a/src/SnapshotsTable.jsx +++ b/src/SnapshotsTable.jsx @@ -249,8 +249,8 @@ export class SnapshotsTable extends Component { originalSnapshotDescription: x.description, }) }} - title={x.description + " - Click to update snapshot description."} - className={x.description ? "text-warning" : "text-muted"}>; + title={x.description + " - Click to update snapshot description."} + className={x.description ? "text-warning" : "text-muted"}>; } newPinFor(x) { @@ -323,6 +323,9 @@ export class SnapshotsTable extends Component { if (isLoading && !snapshots) { return ; } + const searchParams = new URLSearchParams(window.location.search); + const path = searchParams.get("path"); + snapshots.sort((a, b) => -compare(a.startTime, b.startTime)); @@ -336,7 +339,10 @@ export class SnapshotsTable extends Component { id: 'startTime', Header: 'Start time', width: 200, - accessor: x => {rfc3339TimestampForDisplay(x.startTime)}, + accessor: x => { + let timestamp = rfc3339TimestampForDisplay(x.startTime); + return {timestamp}; + }, }, { id: 'description', Header: '', @@ -465,9 +471,9 @@ export class SnapshotsTable extends Component { Enter new description this.setState({ updatedSnapshotDescription: e.target.value })} /> + size="sm" + value={this.state.updatedSnapshotDescription} + onChange={e => this.setState({ updatedSnapshotDescription: e.target.value })} /> diff --git a/src/uiutil.jsx b/src/uiutil.jsx index fef39f1..09562c1 100644 --- a/src/uiutil.jsx +++ b/src/uiutil.jsx @@ -93,9 +93,9 @@ export function rfc3339TimestampForDisplay(n) { return t.toLocaleString(); } -export function objectLink(n) { +export function objectLink(n, label, prevState) { if (n.startsWith("k") || n.startsWith("Ik")) { - return "/snapshots/dir/" + n; + return { pathname: "/snapshots/dir/" + n, state: { label, oid: n, prevState } }; } return "/api/v1/objects/" + n; } @@ -120,7 +120,7 @@ export function redirect(e) { /** * Convert a number of milliseconds into a string containing multiple units. - * + * * e.g. 90000 --> "1m 30s" or "1 minute 30 seconds" * * @param {number} ms - A duration (as a number of milliseconds). @@ -136,9 +136,9 @@ export function formatMillisecondsUsingMultipleUnits(ms) { * Separate a duration into integer magnitudes of multiple units which, * when combined together, equal the original duration (minus any partial * milliseconds, if the original duration included any partial milliseconds). - * + * * e.g. 100000123.999 --> 1 day 3 hours 46 minutes 40 seconds 123 milliseconds - * + * * @param {number} ms - A duration (as a number of milliseconds). * @returns {object} An object having numeric properties named `days`, `hours`, * `minutes`, `seconds`, and `milliseconds`; whose values, @@ -161,16 +161,16 @@ export function separateMillisecondsIntoMagnitudes(ms) { * Format a duration in terms of the largest unit having a non-zero magnitude, * together with the next largest unit (e.g. hours --> hours and minutes), * disregarding all smaller units (i.e. truncate, as opposed to round). - * + * * There are some exceptions, which are listed below. - * + * * Exceptions: * 1. If the largest unit having a non-zero magnitude is `seconds` and the * magnitude is at least 10, format it as an integer number of seconds. * 2. If the largest unit having a non-zero magnitude is `seconds` and the * magnitude is less than 10, or if the largest unit having a non-zero * magnitude is `milliseconds`, format it as a fractional number of seconds. - * + * * @param {object} magnitudes - An object having numeric properties named * `days`, `hours`, `minutes`, `seconds`, and * `milliseconds`; whose values, when combined @@ -234,7 +234,7 @@ export function formatMagnitudesUsingMultipleUnits(magnitudes, abbreviateUnits = /** * Convert a number of milliseconds into a formatted string, either * using multiple units (e.g. "1m 5s") or using seconds (e.g. "65.0s"). - * + * * @param {number} ms - The number of milliseconds (i.e. some duration). * @param {boolean} useMultipleUnits - Whether you want to use multiple units. * @returns {string} The formatted string.