Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: legacy history #879

Merged
merged 2 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { WebApplication } from '@/ui_models/application';
import {
Action,
ActionVerb,
HistoryEntry,
NoteHistoryEntry,
Expand All @@ -8,14 +9,13 @@ import {
} from '@standardnotes/snjs';
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { StateUpdater, useCallback, useMemo, useState } from 'preact/hooks';
import { StateUpdater, useCallback, useState } from 'preact/hooks';
import { useEffect } from 'react';
import { LegacyHistoryList } from './LegacyHistoryList';
import { RemoteHistoryList } from './RemoteHistoryList';
import { SessionHistoryList } from './SessionHistoryList';
import {
LegacyHistoryEntry,
ListGroup,
RemoteRevisionListGroup,
sortRevisionListIntoGroups,
} from './utils';
Expand Down Expand Up @@ -55,19 +55,45 @@ export const HistoryListContainer: FunctionComponent<Props> = observer(
note
) as NoteHistoryEntry[]
);
const [isFetchingLegacyHistory, setIsFetchingLegacyHistory] =
useState(false);
const [legacyHistory, setLegacyHistory] =
useState<ListGroup<LegacyHistoryEntry>[]>();
const legacyHistoryLength = useMemo(
() => legacyHistory?.map((group) => group.entries).flat().length ?? 0,
[legacyHistory]
);
const [legacyHistory, setLegacyHistory] = useState<Action[]>();

const [selectedTab, setSelectedTab] = useState<RevisionListTabType>(
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<{
type: RevisionListTabType;
}> = ({ type }) => {
Expand All @@ -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(
async (revisionListEntry: RevisionListEntry) => {
setShowContentLockedScreen(false);
Expand Down Expand Up @@ -132,12 +195,7 @@ export const HistoryListContainer: FunctionComponent<Props> = observer(
<div className="flex border-0 border-b-1 border-solid border-main">
<TabButton type={RevisionListTabType.Remote} />
<TabButton type={RevisionListTabType.Session} />
{isFetchingLegacyHistory && (
<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 && (
{legacyHistory && legacyHistory.length > 0 && (
<TabButton type={RevisionListTabType.Legacy} />
)}
</div>
Expand Down Expand Up @@ -165,6 +223,7 @@ export const HistoryListContainer: FunctionComponent<Props> = observer(
legacyHistory={legacyHistory}
setSelectedRevision={setSelectedRevision}
setSelectedRemoteEntry={setSelectedRemoteEntry}
fetchAndSetLegacyRevision={fetchAndSetLegacyRevision}
/>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HistoryEntry, RevisionListEntry } from '@standardnotes/snjs';
import { Fragment, FunctionComponent } from 'preact';
import { Action, HistoryEntry, RevisionListEntry } from '@standardnotes/snjs';
import { FunctionComponent } from 'preact';
import {
StateUpdater,
useCallback,
Expand All @@ -11,64 +11,53 @@ import {
import { useListKeyboardNavigation } from '../utils';
import { RevisionListTabType } from './HistoryListContainer';
import { HistoryListItem } from './HistoryListItem';
import {
LegacyHistoryEntry,
ListGroup,
previewHistoryEntryTitle,
} from './utils';
import { LegacyHistoryEntry } from './utils';

type Props = {
selectedTab: RevisionListTabType;
legacyHistory: ListGroup<LegacyHistoryEntry>[] | undefined;
legacyHistory: Action[] | undefined;
setSelectedRevision: StateUpdater<
HistoryEntry | LegacyHistoryEntry | undefined
>;
setSelectedRemoteEntry: StateUpdater<RevisionListEntry | undefined>;
fetchAndSetLegacyRevision: (revisionListEntry: Action) => Promise<void>;
};

export const LegacyHistoryList: FunctionComponent<Props> = ({
legacyHistory,
selectedTab,
setSelectedRevision,
setSelectedRemoteEntry,
fetchAndSetLegacyRevision,
}) => {
const legacyHistoryListRef = useRef<HTMLDivElement>(null);

useListKeyboardNavigation(legacyHistoryListRef);

const legacyHistoryLength = useMemo(
() => legacyHistory?.map((group) => group.entries).flat().length,
[legacyHistory]
);

const [selectedItemCreatedAt, setSelectedItemCreatedAt] = useState<Date>();
const [selectedItemUrl, setSelectedItemUrl] = useState<string>();

const firstEntry = useMemo(() => {
return legacyHistory?.find((group) => group.entries?.length)?.entries?.[0];
return legacyHistory?.[0];
}, [legacyHistory]);

const selectFirstEntry = useCallback(() => {
if (firstEntry) {
setSelectedItemCreatedAt(firstEntry.payload?.created_at);
setSelectedRevision(firstEntry);
setSelectedItemUrl(firstEntry.subactions?.[0].url);
setSelectedRevision(undefined);
fetchAndSetLegacyRevision(firstEntry);
}
}, [firstEntry, setSelectedRevision]);
}, [fetchAndSetLegacyRevision, firstEntry, setSelectedRevision]);

useEffect(() => {
if (firstEntry && !selectedItemCreatedAt) {
if (firstEntry && !selectedItemUrl) {
selectFirstEntry();
} else if (!firstEntry) {
setSelectedRevision(undefined);
}
}, [
firstEntry,
selectFirstEntry,
selectedItemCreatedAt,
setSelectedRevision,
]);
}, [firstEntry, selectFirstEntry, selectedItemUrl, setSelectedRevision]);

useEffect(() => {
if (selectedTab === RevisionListTabType.Session) {
if (selectedTab === RevisionListTabType.Legacy) {
selectFirstEntry();
legacyHistoryListRef.current?.focus();
}
Expand All @@ -77,33 +66,28 @@ export const LegacyHistoryList: FunctionComponent<Props> = ({
return (
<div
className={`flex flex-col w-full h-full focus:shadow-none ${
!legacyHistoryLength ? 'items-center justify-center' : ''
!legacyHistory?.length ? 'items-center justify-center' : ''
}`}
ref={legacyHistoryListRef}
>
{legacyHistory?.map((group) =>
group.entries && group.entries.length ? (
<Fragment key={group.title}>
<div className="px-3 mt-2.5 mb-1 font-semibold color-text uppercase color-grey-0 select-none">
{group.title}
</div>
{group.entries.map((entry, index) => (
<HistoryListItem
key={index}
isSelected={selectedItemCreatedAt === entry.payload.created_at}
onClick={() => {
setSelectedItemCreatedAt(entry.payload.created_at);
setSelectedRevision(entry);
setSelectedRemoteEntry(undefined);
}}
>
{previewHistoryEntryTitle(entry)}
</HistoryListItem>
))}
</Fragment>
) : null
)}
{!legacyHistoryLength && (
{legacyHistory?.map((entry) => {
const url = entry.subactions?.[0].url;

return (
<HistoryListItem
key={url}
isSelected={selectedItemUrl === url}
onClick={() => {
setSelectedItemUrl(url);
setSelectedRemoteEntry(undefined);
fetchAndSetLegacyRevision(entry);
}}
>
{entry.label}
</HistoryListItem>
);
})}
{!legacyHistory?.length && (
<div className="color-grey-0 select-none">No legacy history found</div>
)}
</div>
Expand Down