Merge pull request #888 from colouring-cities/edit-history-latest

Add a line of text saying when the building was last edited
This commit is contained in:
Ed Chalstrey 2022-08-11 10:19:50 +01:00 committed by GitHub
commit 4278944a4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 127 additions and 2 deletions

View File

@ -33,7 +33,7 @@
.section-header .section-header-actions {
display: inline-block;
flex-basis: 200px;
flex-basis: 400px;
display: flex;
flex-flow: row wrap;
align-items: center;

View File

@ -19,6 +19,8 @@ import { ViewEditControl } from './header-buttons/view-edit-control';
import './data-container.css';
import { dataFields } from '../config/data-fields-config'
import { EditHistoryLatest } from './edit-history/edit-history-latest';
interface DataContainerProps {
title: string;
cat: string;
@ -330,7 +332,7 @@ const withCopyEdit: (wc: React.ComponentType<CategoryViewProps>) => DataContaine
<NavLink
className="icon-button history"
to={`/${this.props.mode}/${this.props.cat}/${this.props.building.building_id}/history`}
>History</NavLink>
>Edit History</NavLink>
<ViewEditControl
cat={this.props.cat}
mode={this.props.mode}
@ -345,6 +347,9 @@ const withCopyEdit: (wc: React.ComponentType<CategoryViewProps>) => DataContaine
}
</ContainerHeader>
<div className="section-body">
<EditHistoryLatest
building={this.props.building}
/>
{
this.props.inactive ?
<Fragment>

View File

@ -0,0 +1,67 @@
import React from 'react';
import { Link } from 'react-router-dom';
import './building-edit-summary.css';
import { Category } from '../../config/categories-config';
import { DataFieldDefinition, dataFields } from '../../config/data-fields-config';
import { arrayToDictionary, parseDate } from '../../helpers';
import { EditHistoryEntry } from '../../models/edit-history-entry';
import { CategoryEditSummary } from './category-edit-summary';
interface BuildingEditLatestProps {
historyEntry: EditHistoryEntry;
showBuildingId?: boolean;
hyperlinkCategories?: boolean;
}
function formatDate(dt: Date) {
return dt.toLocaleString(undefined, {
weekday: 'short',
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
function enrichHistoryEntries(forwardPatch: object, reversePatch: object) {
return Object
.entries(forwardPatch)
.map(([key, value]) => {
const {
title = `Unknown field (${key})`,
category = undefined
} = dataFields[key] as DataFieldDefinition ?? {};
return {
title,
category,
value,
oldValue: reversePatch && reversePatch[key]
};
});
}
const BuildingEditLatest: React.FunctionComponent<BuildingEditLatestProps> = ({
historyEntry,
showBuildingId = false,
hyperlinkCategories = false
}) => {
const entriesWithMetadata = enrichHistoryEntries(historyEntry.forward_patch, historyEntry.reverse_patch);
const entriesByCategory = arrayToDictionary(entriesWithMetadata, x => x.category);
const categoryHyperlinkTemplate = hyperlinkCategories && historyEntry.building_id != undefined ?
`/edit/$category/${historyEntry.building_id}` :
undefined;
return (
<h2 className="edit-history-timestamp">Building last edited on {formatDate(parseDate(historyEntry.revision_timestamp))}</h2>
);
};
export {
BuildingEditLatest
};

View File

@ -0,0 +1,46 @@
import React, { useEffect, useState } from 'react';
import './edit-history.css';
import { apiGet } from '../../apiHelpers';
import { Building } from '../../models/building';
import { EditHistoryEntry } from '../../models/edit-history-entry';
import ContainerHeader from '../container-header';
import { BuildingEditLatest } from './building-edit-latest';
interface EditHistoryLatestProps {
building: Building;
}
const EditHistoryLatest: React.FunctionComponent<EditHistoryLatestProps> = (props) => {
const [history, setHistory] = useState<EditHistoryEntry[]>(undefined);
useEffect(() => {
const fetchData = async () => {
const {history} = await apiGet(`/api/buildings/${props.building.building_id}/history.json`);
setHistory(history);
};
if (props.building != undefined) { // only call fn if there is a building provided
fetchData(); // define and call, because effect cannot return anything and an async fn always returns a Promise
}
}, [props.building]); // only re-run effect on building prop change
return (
<>
<ul className="edit-history-first" id="first-only">
{history && history.map(entry => (
<li key={`${entry.revision_id}`} className="edit-history-list-element">
<BuildingEditLatest historyEntry={entry} />
</li>
))}
</ul>
</>
);
};
export {
EditHistoryLatest
};

View File

@ -6,3 +6,10 @@
list-style: none;
padding-left: 1rem;
}
ul[id="first-only"] li{
display: none;
}
ul[id="first-only"] li:first-of-type {
display: block;
}