From 0bb78670594e33de3547b5cf5c83b29a7f23fd60 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Thu, 6 Aug 2020 09:25:41 +0300 Subject: [PATCH] Collection: add a changelog history page. --- src/Collections/Collection.tsx | 11 +- src/Collections/CollectionChangeEntries.tsx | 183 ++++++++++++++++++++ 2 files changed, 185 insertions(+), 9 deletions(-) create mode 100644 src/Collections/CollectionChangeEntries.tsx diff --git a/src/Collections/Collection.tsx b/src/Collections/Collection.tsx index 4c6eaca..d1d6513 100644 --- a/src/Collections/Collection.tsx +++ b/src/Collections/Collection.tsx @@ -11,9 +11,7 @@ import IconImport from "@material-ui/icons/ImportExport"; import AppBarOverride from "../widgets/AppBarOverride"; import Container from "../widgets/Container"; -/* FIXME: -import CollectionEntries from "../components/CollectionEntries"; - */ +import CollectionChangeEntries from "./CollectionChangeEntries"; import ImportDialog from "./ImportDialog"; import { Link } from "react-router-dom"; @@ -75,13 +73,8 @@ class Collection extends React.Component { - Change entries: TBD + - {/* - - - - */} >) { + const entries: Map> = new Map(); + if (items) { + for (const [colUid, col] of items.entries()) { + const cur = new Map(); + entries.set(colUid, cur); + for (const item of col.values()) { + cur.set(item.uid, { + item, + metadata: await item.getMeta(), + content: await item.getContent(Etebase.OutputFormat.String), + }); + } + } + } + + return entries; +} + +interface PropsType { + collection: CachedCollection; +} + +// FIXME: use the ones used by e.g. Contacts/Main so ew share the cache +export default function CollectionChangeEntries(props: PropsType) { + const [entries, setEntries] = React.useState>(); + const [dialog, setDialog] = React.useState(); + const etebase = useCredentials()!; + + const { collection, metadata } = props.collection; + const colType = metadata.type; + const items = useItems(etebase, colType); + + React.useEffect(() => { + if (items) { + decryptItems(items) + .then((entries) => setEntries(entries.get(collection.uid))); + // FIXME: handle failure to decrypt items + } + }, [items]); + + if (!entries) { + return ( + + ); + } + + const entriesList = Array.from(entries.values()).sort((a_, b_) => { + const a = a_.metadata.mtime ?? 0; + const b = b_.metadata.mtime ?? 0; + return a - b; + }); + + const rowRenderer = (params: { index: number, key: string, style: React.CSSProperties }) => { + const { key, index, style } = params; + const cacheItem = entriesList[entriesList.length - index - 1]!; + let comp; + try { + comp = parseString(cacheItem.content); + } catch (e) { + const icon = (); + return ( + setDialog(cacheItem)} + /> + ); + } + + let icon; + if (!cacheItem.item.isDeleted) { + icon = (); + } else { + icon = (); + } + + let name; + if (comp.name === "vcalendar") { + if (EventType.isEvent(comp)) { + const vevent = EventType.fromVCalendar(comp); + name = vevent.summary; + } else { + const vtodo = TaskType.fromVCalendar(comp); + name = vtodo.summary; + } + } else if (comp.name === "vcard") { + const vcard = new ContactType(comp); + name = vcard.fn; + } else { + name = "Error processing entry"; + } + + const mtime = (cacheItem.metadata.mtime) ? moment(cacheItem.metadata.mtime) : undefined; + + return ( + setDialog(cacheItem)} + /> + ); + }; + + return ( +
+ setDialog(undefined)} + > + + Raw Content + + +
Entry UID:
{dialog?.item.uid}
+
Content: +
{dialog?.content}
+
+
+ + + +
+ + + {({ height, width }) => ( + + )} + + +
+ ); +}