fix: legacy history (#879)

This commit is contained in:
Aman Harwara
2022-02-18 19:38:38 +05:30
committed by GitHub
parent 01e5d0fcb1
commit fbabbbb7d3
2 changed files with 109 additions and 66 deletions

View File

@@ -1,5 +1,6 @@
import { WebApplication } from '@/ui_models/application'; import { WebApplication } from '@/ui_models/application';
import { import {
Action,
ActionVerb, ActionVerb,
HistoryEntry, HistoryEntry,
NoteHistoryEntry, NoteHistoryEntry,
@@ -8,14 +9,13 @@ import {
} from '@standardnotes/snjs'; } from '@standardnotes/snjs';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact'; import { FunctionComponent } from 'preact';
import { StateUpdater, useCallback, useMemo, useState } from 'preact/hooks'; import { StateUpdater, useCallback, useState } from 'preact/hooks';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { LegacyHistoryList } from './LegacyHistoryList'; import { LegacyHistoryList } from './LegacyHistoryList';
import { RemoteHistoryList } from './RemoteHistoryList'; import { RemoteHistoryList } from './RemoteHistoryList';
import { SessionHistoryList } from './SessionHistoryList'; import { SessionHistoryList } from './SessionHistoryList';
import { import {
LegacyHistoryEntry, LegacyHistoryEntry,
ListGroup,
RemoteRevisionListGroup, RemoteRevisionListGroup,
sortRevisionListIntoGroups, sortRevisionListIntoGroups,
} from './utils'; } from './utils';
@@ -55,19 +55,45 @@ export const HistoryListContainer: FunctionComponent<Props> = observer(
note note
) as NoteHistoryEntry[] ) as NoteHistoryEntry[]
); );
const [isFetchingLegacyHistory, setIsFetchingLegacyHistory] = const [legacyHistory, setLegacyHistory] = useState<Action[]>();
useState(false);
const [legacyHistory, setLegacyHistory] =
useState<ListGroup<LegacyHistoryEntry>[]>();
const legacyHistoryLength = useMemo(
() => legacyHistory?.map((group) => group.entries).flat().length ?? 0,
[legacyHistory]
);
const [selectedTab, setSelectedTab] = useState<RevisionListTabType>( const [selectedTab, setSelectedTab] = useState<RevisionListTabType>(
RevisionListTabType.Remote RevisionListTabType.Remote
); );
useEffect(() => {
const fetchLegacyHistory = async () => {
const actionExtensions = application.actionsManager.getExtensions();
actionExtensions.forEach(async (ext) => {
const actionExtension =
await application.actionsManager.loadExtensionInContextOfItem(
ext,
note
);
if (!actionExtension) {
return;
}
const isLegacyNoteHistoryExt = actionExtension?.actions.some(
(action) => action.verb === ActionVerb.Nested
);
if (!isLegacyNoteHistoryExt) {
return;
}
const legacyHistoryEntries = actionExtension.actions.filter(
(action) => action.subactions?.[0]
);
setLegacyHistory(legacyHistoryEntries);
});
};
fetchLegacyHistory();
}, [application.actionsManager, note]);
const TabButton: FunctionComponent<{ const TabButton: FunctionComponent<{
type: RevisionListTabType; type: RevisionListTabType;
}> = ({ type }) => { }> = ({ type }) => {
@@ -88,6 +114,43 @@ export const HistoryListContainer: FunctionComponent<Props> = observer(
); );
}; };
const fetchAndSetLegacyRevision = useCallback(
async (revisionListEntry: Action) => {
setSelectedRemoteEntry(undefined);
setSelectedRevision(undefined);
setIsFetchingSelectedRevision(true);
try {
if (!revisionListEntry.subactions?.[0]) {
throw new Error('Could not find revision action url');
}
const response = await application.actionsManager.runAction(
revisionListEntry.subactions[0],
note
);
if (!response) {
throw new Error('Could not fetch revision');
}
setSelectedRevision(response.item as HistoryEntry);
} catch (error) {
console.error(error);
setSelectedRevision(undefined);
} finally {
setIsFetchingSelectedRevision(false);
}
},
[
application.actionsManager,
note,
setIsFetchingSelectedRevision,
setSelectedRemoteEntry,
setSelectedRevision,
]
);
const fetchAndSetRemoteRevision = useCallback( const fetchAndSetRemoteRevision = useCallback(
async (revisionListEntry: RevisionListEntry) => { async (revisionListEntry: RevisionListEntry) => {
setShowContentLockedScreen(false); setShowContentLockedScreen(false);
@@ -132,12 +195,7 @@ export const HistoryListContainer: FunctionComponent<Props> = observer(
<div className="flex border-0 border-b-1 border-solid border-main"> <div className="flex border-0 border-b-1 border-solid border-main">
<TabButton type={RevisionListTabType.Remote} /> <TabButton type={RevisionListTabType.Remote} />
<TabButton type={RevisionListTabType.Session} /> <TabButton type={RevisionListTabType.Session} />
{isFetchingLegacyHistory && ( {legacyHistory && legacyHistory.length > 0 && (
<div className="flex items-center justify-center px-3 py-2.5">
<div className="sk-spinner w-3 h-3 spinner-info" />
</div>
)}
{legacyHistory && legacyHistoryLength > 0 && (
<TabButton type={RevisionListTabType.Legacy} /> <TabButton type={RevisionListTabType.Legacy} />
)} )}
</div> </div>
@@ -165,6 +223,7 @@ export const HistoryListContainer: FunctionComponent<Props> = observer(
legacyHistory={legacyHistory} legacyHistory={legacyHistory}
setSelectedRevision={setSelectedRevision} setSelectedRevision={setSelectedRevision}
setSelectedRemoteEntry={setSelectedRemoteEntry} setSelectedRemoteEntry={setSelectedRemoteEntry}
fetchAndSetLegacyRevision={fetchAndSetLegacyRevision}
/> />
)} )}
</div> </div>

View File

@@ -1,5 +1,5 @@
import { HistoryEntry, RevisionListEntry } from '@standardnotes/snjs'; import { Action, HistoryEntry, RevisionListEntry } from '@standardnotes/snjs';
import { Fragment, FunctionComponent } from 'preact'; import { FunctionComponent } from 'preact';
import { import {
StateUpdater, StateUpdater,
useCallback, useCallback,
@@ -11,19 +11,16 @@ import {
import { useListKeyboardNavigation } from '../utils'; import { useListKeyboardNavigation } from '../utils';
import { RevisionListTabType } from './HistoryListContainer'; import { RevisionListTabType } from './HistoryListContainer';
import { HistoryListItem } from './HistoryListItem'; import { HistoryListItem } from './HistoryListItem';
import { import { LegacyHistoryEntry } from './utils';
LegacyHistoryEntry,
ListGroup,
previewHistoryEntryTitle,
} from './utils';
type Props = { type Props = {
selectedTab: RevisionListTabType; selectedTab: RevisionListTabType;
legacyHistory: ListGroup<LegacyHistoryEntry>[] | undefined; legacyHistory: Action[] | undefined;
setSelectedRevision: StateUpdater< setSelectedRevision: StateUpdater<
HistoryEntry | LegacyHistoryEntry | undefined HistoryEntry | LegacyHistoryEntry | undefined
>; >;
setSelectedRemoteEntry: StateUpdater<RevisionListEntry | undefined>; setSelectedRemoteEntry: StateUpdater<RevisionListEntry | undefined>;
fetchAndSetLegacyRevision: (revisionListEntry: Action) => Promise<void>;
}; };
export const LegacyHistoryList: FunctionComponent<Props> = ({ export const LegacyHistoryList: FunctionComponent<Props> = ({
@@ -31,44 +28,36 @@ export const LegacyHistoryList: FunctionComponent<Props> = ({
selectedTab, selectedTab,
setSelectedRevision, setSelectedRevision,
setSelectedRemoteEntry, setSelectedRemoteEntry,
fetchAndSetLegacyRevision,
}) => { }) => {
const legacyHistoryListRef = useRef<HTMLDivElement>(null); const legacyHistoryListRef = useRef<HTMLDivElement>(null);
useListKeyboardNavigation(legacyHistoryListRef); useListKeyboardNavigation(legacyHistoryListRef);
const legacyHistoryLength = useMemo( const [selectedItemUrl, setSelectedItemUrl] = useState<string>();
() => legacyHistory?.map((group) => group.entries).flat().length,
[legacyHistory]
);
const [selectedItemCreatedAt, setSelectedItemCreatedAt] = useState<Date>();
const firstEntry = useMemo(() => { const firstEntry = useMemo(() => {
return legacyHistory?.find((group) => group.entries?.length)?.entries?.[0]; return legacyHistory?.[0];
}, [legacyHistory]); }, [legacyHistory]);
const selectFirstEntry = useCallback(() => { const selectFirstEntry = useCallback(() => {
if (firstEntry) { if (firstEntry) {
setSelectedItemCreatedAt(firstEntry.payload?.created_at); setSelectedItemUrl(firstEntry.subactions?.[0].url);
setSelectedRevision(firstEntry); setSelectedRevision(undefined);
fetchAndSetLegacyRevision(firstEntry);
} }
}, [firstEntry, setSelectedRevision]); }, [fetchAndSetLegacyRevision, firstEntry, setSelectedRevision]);
useEffect(() => { useEffect(() => {
if (firstEntry && !selectedItemCreatedAt) { if (firstEntry && !selectedItemUrl) {
selectFirstEntry(); selectFirstEntry();
} else if (!firstEntry) { } else if (!firstEntry) {
setSelectedRevision(undefined); setSelectedRevision(undefined);
} }
}, [ }, [firstEntry, selectFirstEntry, selectedItemUrl, setSelectedRevision]);
firstEntry,
selectFirstEntry,
selectedItemCreatedAt,
setSelectedRevision,
]);
useEffect(() => { useEffect(() => {
if (selectedTab === RevisionListTabType.Session) { if (selectedTab === RevisionListTabType.Legacy) {
selectFirstEntry(); selectFirstEntry();
legacyHistoryListRef.current?.focus(); legacyHistoryListRef.current?.focus();
} }
@@ -77,33 +66,28 @@ export const LegacyHistoryList: FunctionComponent<Props> = ({
return ( return (
<div <div
className={`flex flex-col w-full h-full focus:shadow-none ${ className={`flex flex-col w-full h-full focus:shadow-none ${
!legacyHistoryLength ? 'items-center justify-center' : '' !legacyHistory?.length ? 'items-center justify-center' : ''
}`} }`}
ref={legacyHistoryListRef} ref={legacyHistoryListRef}
> >
{legacyHistory?.map((group) => {legacyHistory?.map((entry) => {
group.entries && group.entries.length ? ( const url = entry.subactions?.[0].url;
<Fragment key={group.title}>
<div className="px-3 mt-2.5 mb-1 font-semibold color-text uppercase color-grey-0 select-none"> return (
{group.title} <HistoryListItem
</div> key={url}
{group.entries.map((entry, index) => ( isSelected={selectedItemUrl === url}
<HistoryListItem onClick={() => {
key={index} setSelectedItemUrl(url);
isSelected={selectedItemCreatedAt === entry.payload.created_at} setSelectedRemoteEntry(undefined);
onClick={() => { fetchAndSetLegacyRevision(entry);
setSelectedItemCreatedAt(entry.payload.created_at); }}
setSelectedRevision(entry); >
setSelectedRemoteEntry(undefined); {entry.label}
}} </HistoryListItem>
> );
{previewHistoryEntryTitle(entry)} })}
</HistoryListItem> {!legacyHistory?.length && (
))}
</Fragment>
) : null
)}
{!legacyHistoryLength && (
<div className="color-grey-0 select-none">No legacy history found</div> <div className="color-grey-0 select-none">No legacy history found</div>
)} )}
</div> </div>