Merge branch 'release/10.12.0'

This commit is contained in:
Mo
2022-02-18 10:03:00 -06:00
34 changed files with 1843 additions and 2758 deletions

View File

@@ -43,44 +43,45 @@ GEM
arel (8.0.0) arel (8.0.0)
bindex (0.8.1) bindex (0.8.1)
builder (3.2.4) builder (3.2.4)
byebug (11.1.1) byebug (11.1.3)
capistrano (3.11.2) capistrano (3.16.0)
airbrussh (>= 1.0.0) airbrussh (>= 1.0.0)
i18n i18n
rake (>= 10.0.0) rake (>= 10.0.0)
sshkit (>= 1.9.0) sshkit (>= 1.9.0)
capistrano-bundler (1.6.0) capistrano-bundler (2.0.1)
capistrano (~> 3.1) capistrano (~> 3.1)
capistrano-git-with-submodules (2.0.3) capistrano-git-with-submodules (2.0.4)
capistrano (~> 3.7) capistrano (~> 3.7)
capistrano-passenger (0.2.0) capistrano-passenger (0.2.1)
capistrano (~> 3.0) capistrano (~> 3.0)
capistrano-rails (1.4.0) capistrano-rails (1.6.1)
capistrano (~> 3.1) capistrano (~> 3.1)
capistrano-bundler (~> 1.1) capistrano-bundler (>= 1.1, < 3)
capistrano-rvm (0.1.2) capistrano-rvm (0.1.2)
capistrano (~> 3.0) capistrano (~> 3.0)
sshkit (~> 1.2) sshkit (~> 1.2)
capistrano-sidekiq (1.0.3) capistrano-sidekiq (2.0.0)
capistrano (>= 3.9.0) capistrano (>= 3.9.0)
sidekiq (>= 3.4, < 6.0) capistrano-bundler
concurrent-ruby (1.1.5) sidekiq (>= 6.0)
connection_pool (2.2.2) concurrent-ruby (1.1.9)
connection_pool (2.2.5)
crass (1.0.6) crass (1.0.6)
dotenv (2.7.5) dotenv (2.7.6)
dotenv-rails (2.7.5) dotenv-rails (2.7.6)
dotenv (= 2.7.5) dotenv (= 2.7.6)
railties (>= 3.2, < 6.1) railties (>= 3.2)
erubi (1.9.0) erubi (1.10.0)
execjs (2.7.0) execjs (2.8.1)
ffi (1.12.1) ffi (1.15.5)
ffi (1.12.1-x64-mingw32) ffi (1.15.5-x64-mingw32)
globalid (0.4.2) globalid (1.0.0)
activesupport (>= 4.2.0) activesupport (>= 5.0)
haml (5.1.2) haml (5.2.2)
temple (>= 0.8.0) temple (>= 0.8.0)
tilt tilt
i18n (1.8.2) i18n (1.10.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
json (1.8.6) json (1.8.6)
lograge (0.11.2) lograge (0.11.2)
@@ -88,37 +89,31 @@ GEM
activesupport (>= 4) activesupport (>= 4)
railties (>= 4) railties (>= 4)
request_store (~> 1.0) request_store (~> 1.0)
loofah (2.4.0) loofah (2.14.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.1) mail (2.7.1)
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
method_source (0.9.2) method_source (1.0.0)
mini_mime (1.0.2) mini_mime (1.1.2)
mini_portile2 (2.5.0) minitest (5.15.0)
minitest (5.14.0) net-scp (3.0.0)
net-scp (2.0.0) net-ssh (>= 2.6.5, < 7.0.0)
net-ssh (>= 2.6.5, < 6.0.0) net-ssh (6.1.0)
net-ssh (5.2.0) newrelic_rpm (7.2.0)
newrelic_rpm (7.0.0)
nio4r (2.5.8) nio4r (2.5.8)
nokogiri (1.11.1) nokogiri (1.13.1-x64-mingw32)
mini_portile2 (~> 2.5.0)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.11.1-x64-mingw32) nokogiri (1.13.1-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.11.1-x86_64-darwin)
racc (~> 1.4) racc (~> 1.4)
non-stupid-digest-assets (1.0.9) non-stupid-digest-assets (1.0.9)
sprockets (>= 2.0) sprockets (>= 2.0)
puma (4.3.9) puma (5.6.2)
nio4r (~> 2.0) nio4r (~> 2.0)
racc (1.5.2) racc (1.6.0)
rack (2.2.3) rack (2.2.3)
rack-cors (1.1.1) rack-cors (1.1.1)
rack (>= 2.0.0) rack (>= 2.0.0)
rack-protection (2.0.8.1)
rack
rack-test (1.1.0) rack-test (1.1.0)
rack (>= 1.0, < 3) rack (>= 1.0, < 3)
rails (5.1.7) rails (5.1.7)
@@ -136,7 +131,7 @@ GEM
rails-dom-testing (2.0.3) rails-dom-testing (2.0.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0) rails-html-sanitizer (1.4.2)
loofah (~> 2.3) loofah (~> 2.3)
railties (5.1.7) railties (5.1.7)
actionpack (= 5.1.7) actionpack (= 5.1.7)
@@ -144,13 +139,13 @@ GEM
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rake (13.0.1) rake (13.0.6)
rb-fsevent (0.10.3) rb-fsevent (0.11.1)
rb-inotify (0.10.1) rb-inotify (0.10.1)
ffi (~> 1.0) ffi (~> 1.0)
rdoc (4.3.0) rdoc (4.3.0)
redis (4.1.3) redis (4.6.0)
request_store (1.5.0) request_store (1.5.1)
rack (>= 1.4) rack (>= 1.4)
responders (2.4.1) responders (2.4.1)
actionpack (>= 4.2.0, < 6.0) actionpack (>= 4.2.0, < 6.0)
@@ -163,30 +158,29 @@ GEM
sdoc (0.4.2) sdoc (0.4.2)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0) rdoc (~> 4.0)
secure_headers (6.3.0) secure_headers (6.3.3)
sidekiq (5.2.7) sidekiq (6.4.1)
connection_pool (~> 2.2, >= 2.2.2) connection_pool (>= 2.2.2)
rack (>= 1.5.0) rack (~> 2.0)
rack-protection (>= 1.5.0) redis (>= 4.2.0)
redis (>= 3.3.5, < 5) spring (3.1.1)
spring (2.1.0) sprockets (4.0.2)
sprockets (4.0.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-rails (3.2.1) sprockets-rails (3.2.2)
actionpack (>= 4.0) actionpack (>= 4.0)
activesupport (>= 4.0) activesupport (>= 4.0)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
sshkit (1.20.0) sshkit (1.21.2)
net-scp (>= 1.1.2) net-scp (>= 1.1.2)
net-ssh (>= 2.8.0) net-ssh (>= 2.8.0)
temple (0.8.2) temple (0.8.2)
thor (1.0.1) thor (1.2.1)
thread_safe (0.3.6) thread_safe (0.3.6)
tilt (2.0.10) tilt (2.0.10)
tzinfo (1.2.6) tzinfo (1.2.9)
thread_safe (~> 0.1) thread_safe (~> 0.1)
tzinfo-data (1.2019.3) tzinfo-data (1.2021.5)
tzinfo (>= 1.0.0) tzinfo (>= 1.0.0)
uglifier (4.2.0) uglifier (4.2.0)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)

View File

@@ -7,7 +7,7 @@ import {
PermissionDialog, PermissionDialog,
removeFromArray, removeFromArray,
} from '@standardnotes/snjs'; } from '@standardnotes/snjs';
import { PANEL_NAME_NOTES, PANEL_NAME_NAVIGATION } from '@/views/constants'; import { PANEL_NAME_NOTES, PANEL_NAME_NAVIGATION } from '@/constants';
import { STRING_DEFAULT_FILE_ERROR } from '@/strings'; import { STRING_DEFAULT_FILE_ERROR } from '@/strings';
import { alertDialog } from '@/services/alertService'; import { alertDialog } from '@/services/alertService';
import { WebAppEvent, WebApplication } from '@/ui_models/application'; import { WebAppEvent, WebApplication } from '@/ui_models/application';

View File

@@ -1,6 +1,6 @@
import { WebApplication } from '@/ui_models/application'; import { WebApplication } from '@/ui_models/application';
import { AppState } from '@/ui_models/app_state'; import { AppState } from '@/ui_models/app_state';
import { MENU_MARGIN_FROM_APP_BORDER } from '@/views/constants'; import { MENU_MARGIN_FROM_APP_BORDER } from '@/constants';
import { import {
Disclosure, Disclosure,
DisclosureButton, DisclosureButton,
@@ -101,7 +101,7 @@ export const ChangeEditorButton: FunctionComponent<Props> = observer(
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
ref={buttonRef} ref={buttonRef}
className="sn-icon-button" className="sn-icon-button border-contrast"
> >
<VisuallyHidden>Change editor</VisuallyHidden> <VisuallyHidden>Change editor</VisuallyHidden>
<Icon type="dashboard" className="block" /> <Icon type="dashboard" className="block" />

View File

@@ -1,7 +1,7 @@
import { SmartTagsSection } from '@/components/Tags/SmartTagsSection'; import { SmartTagsSection } from '@/components/Tags/SmartTagsSection';
import { TagsSection } from '@/components/Tags/TagsSection'; import { TagsSection } from '@/components/Tags/TagsSection';
import { WebApplication } from '@/ui_models/application'; import { WebApplication } from '@/ui_models/application';
import { PANEL_NAME_NAVIGATION } from '@/views/constants'; import { PANEL_NAME_NAVIGATION } from '@/constants';
import { ApplicationEvent, PrefKey } from '@standardnotes/snjs'; import { ApplicationEvent, PrefKey } from '@standardnotes/snjs';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact'; import { FunctionComponent } from 'preact';

View File

@@ -9,7 +9,7 @@ import { NotesListItem } from './NotesListItem';
import { import {
FOCUSABLE_BUT_NOT_TABBABLE, FOCUSABLE_BUT_NOT_TABBABLE,
NOTES_LIST_SCROLL_THRESHOLD, NOTES_LIST_SCROLL_THRESHOLD,
} from '@/views/constants'; } from '@/constants';
type Props = { type Props = {
application: WebApplication; application: WebApplication;

View File

@@ -4,7 +4,7 @@ import { AppState } from '@/ui_models/app_state';
import { import {
MENU_MARGIN_FROM_APP_BORDER, MENU_MARGIN_FROM_APP_BORDER,
MAX_MENU_SIZE_MULTIPLIER, MAX_MENU_SIZE_MULTIPLIER,
} from '@/views/constants'; } from '@/constants';
import { import {
Disclosure, Disclosure,
DisclosureButton, DisclosureButton,

View File

@@ -17,7 +17,7 @@ import {
MENU_MARGIN_FROM_APP_BORDER, MENU_MARGIN_FROM_APP_BORDER,
MAX_MENU_SIZE_MULTIPLIER, MAX_MENU_SIZE_MULTIPLIER,
BYTES_IN_ONE_MEGABYTE, BYTES_IN_ONE_MEGABYTE,
} from '@/views/constants'; } from '@/constants';
export type NotesOptionsProps = { export type NotesOptionsProps = {
application: WebApplication; application: WebApplication;
@@ -560,7 +560,7 @@ export const NotesOptions = observer(
}} }}
> >
<Icon type="trash" className={iconClass} /> <Icon type="trash" className={iconClass} />
Move to Trash Move to trash
</button> </button>
))} ))}
{trashed && ( {trashed && (

View File

@@ -163,6 +163,12 @@ export const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
}; };
const selectEditor = async (itemToBeSelected: EditorMenuItem) => { const selectEditor = async (itemToBeSelected: EditorMenuItem) => {
const areBothEditorsPlain = !currentEditor && !itemToBeSelected.component;
if (areBothEditorsPlain) {
return;
}
let shouldSelectEditor = true; let shouldSelectEditor = true;
if (itemToBeSelected.component) { if (itemToBeSelected.component) {

View File

@@ -69,7 +69,7 @@ export const NotesOptionsPanel = observer(
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
ref={buttonRef} ref={buttonRef}
className="sn-icon-button" className="sn-icon-button border-contrast"
> >
<VisuallyHidden>Actions</VisuallyHidden> <VisuallyHidden>Actions</VisuallyHidden>
<Icon type="more" className="block" /> <Icon type="more" className="block" />

View File

@@ -1,7 +1,7 @@
import { KeyboardKey, KeyboardModifier } from '@/services/ioService'; import { KeyboardKey, KeyboardModifier } from '@/services/ioService';
import { WebApplication } from '@/ui_models/application'; import { WebApplication } from '@/ui_models/application';
import { AppState } from '@/ui_models/app_state'; import { AppState } from '@/ui_models/app_state';
import { PANEL_NAME_NOTES } from '@/views/constants'; import { PANEL_NAME_NOTES } from '@/constants';
import { PrefKey } from '@standardnotes/snjs'; import { PrefKey } from '@standardnotes/snjs';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact'; import { FunctionComponent } from 'preact';

View File

@@ -28,7 +28,9 @@ export const PinNoteButton: FunctionComponent<Props> = observer(
return ( return (
<button <button
className={`sn-icon-button ${pinned ? 'toggled' : ''} ${className}`} className={`sn-icon-button border-contrast ${
pinned ? 'toggled' : ''
} ${className}`}
onClick={togglePinned} onClick={togglePinned}
> >
<VisuallyHidden>Pin selected notes</VisuallyHidden> <VisuallyHidden>Pin selected notes</VisuallyHidden>

View File

@@ -58,9 +58,9 @@ const toggleFocusMode = (enabled: boolean) => {
} }
}; };
export const sortThemes = (a: SNTheme, b: SNTheme) => { export const sortThemes = (a: ThemeItem, b: ThemeItem) => {
const aIsLayerable = a.isLayerable(); const aIsLayerable = a.component?.isLayerable();
const bIsLayerable = b.isLayerable(); const bIsLayerable = b.component?.isLayerable();
if (aIsLayerable && !bIsLayerable) { if (aIsLayerable && !bIsLayerable) {
return 1; return 1;
@@ -105,15 +105,13 @@ export const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
const reloadThemes = useCallback(() => { const reloadThemes = useCallback(() => {
const themes = ( const themes = (
application.getDisplayableItems(ContentType.Theme) as SNTheme[] application.getDisplayableItems(ContentType.Theme) as SNTheme[]
) ).map((item) => {
.sort(sortThemes) return {
.map((item) => { name: item.name,
return { identifier: item.identifier,
name: item.name, component: item,
identifier: item.identifier, };
component: item, }) as ThemeItem[];
};
}) as ThemeItem[];
GetFeatures() GetFeatures()
.filter( .filter(
@@ -132,7 +130,7 @@ export const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
} }
}); });
setThemes(themes); setThemes(themes.sort(sortThemes));
setDefaultThemeOn( setDefaultThemeOn(
!themes !themes

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,4 +1,4 @@
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/views/constants'; import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/constants';
import { FunctionComponent } from 'preact'; import { FunctionComponent } from 'preact';
type HistoryListItemProps = { type HistoryListItemProps = {

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>

View File

@@ -66,7 +66,7 @@ export const SelectedRevisionContent: FunctionComponent<SelectedRevisionContentP
{!componentViewer && ( {!componentViewer && (
<div className="relative flex-grow min-h-0 overflow-x-hidden overflow-y-auto"> <div className="relative flex-grow min-h-0 overflow-x-hidden overflow-y-auto">
{selectedRevision.payload.content.text.length ? ( {selectedRevision.payload.content.text.length ? (
<p className="p-4 pt-0"> <p className="p-4 pt-0 color-text text-editor font-editor">
{selectedRevision.payload.content.text} {selectedRevision.payload.content.text}
</p> </p>
) : ( ) : (

View File

@@ -1,4 +1,4 @@
import { DAYS_IN_A_WEEK, DAYS_IN_A_YEAR } from '@/views/constants'; import { DAYS_IN_A_WEEK, DAYS_IN_A_YEAR } from '@/constants';
import { import {
HistoryEntry, HistoryEntry,
NoteHistoryEntry, NoteHistoryEntry,
@@ -84,13 +84,17 @@ export const sortRevisionListIntoGroups = <EntryType extends RevisionEntry>(
}, },
]; ];
const addBeforeLastGroup = (group: ListGroup<EntryType>) => {
sortedGroups.splice(sortedGroups.length - 1, 0, group);
};
revisionList?.forEach((entry) => { revisionList?.forEach((entry) => {
const groupIndex = getGroupIndexForEntry(entry, sortedGroups); const groupIndex = getGroupIndexForEntry(entry, sortedGroups);
if (groupIndex > -1) { if (groupIndex > -1) {
sortedGroups[groupIndex]?.entries?.push(entry); sortedGroups[groupIndex]?.entries?.push(entry);
} else { } else {
sortedGroups.push({ addBeforeLastGroup({
title: formatDateAsMonthYearString( title: formatDateAsMonthYearString(
new Date( new Date(
(entry as RevisionListEntry).created_at ?? (entry as RevisionListEntry).created_at ??

View File

@@ -4,7 +4,7 @@ import { JSXInternal } from 'preact/src/jsx';
import { Icon } from '../Icon'; import { Icon } from '../Icon';
import { Switch, SwitchProps } from '../Switch'; import { Switch, SwitchProps } from '../Switch';
import { IconType } from '@standardnotes/snjs'; import { IconType } from '@standardnotes/snjs';
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/views/constants'; import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/constants';
export enum MenuItemType { export enum MenuItemType {
IconButton, IconButton,

View File

@@ -1,8 +1,5 @@
import { KeyboardKey } from '@/services/ioService'; import { KeyboardKey } from '@/services/ioService';
import { import { FOCUSABLE_BUT_NOT_TABBABLE, MILLISECONDS_IN_A_DAY } from '@/constants';
FOCUSABLE_BUT_NOT_TABBABLE,
MILLISECONDS_IN_A_DAY,
} from '@/views/constants';
import { import {
StateUpdater, StateUpdater,
useCallback, useCallback,

View File

@@ -23,7 +23,6 @@ module.exports = {
self: {}, // fixes error happening on `import { SKAlert } from 'sn-stylekit'` self: {}, // fixes error happening on `import { SKAlert } from 'sn-stylekit'`
}, },
transform: { transform: {
'\\.(pug)$': '../../../node_modules/jest-transform-pug',
'^.+\\.(ts|tsx)?$': 'ts-jest', '^.+\\.(ts|tsx)?$': 'ts-jest',
'\\.svg$': 'svg-jest', '\\.svg$': 'svg-jest',
}, },

View File

@@ -100,20 +100,6 @@ export class ThemeManager extends ApplicationService {
this.setThemeAsPerColorScheme(prefersDarkColorScheme.matches); this.setThemeAsPerColorScheme(prefersDarkColorScheme.matches);
break; break;
} }
case ApplicationEvent.LocalDataLoaded: {
const themes = this.application.getDisplayableItems(
ContentType.Theme
) as SNTheme[];
themes.forEach((theme) => {
if (
theme.active &&
this.application.getFeatureStatus(theme.identifier) !==
FeatureStatus.Entitled
) {
this.application.toggleTheme(theme);
}
});
}
} }
} }
@@ -137,13 +123,19 @@ export class ThemeManager extends ApplicationService {
let hasChange = false; let hasChange = false;
for (const themeUuid of this.activeThemes) { for (const themeUuid of this.activeThemes) {
const theme = this.application.findItem(themeUuid) as SNTheme; const theme = this.application.findItem(themeUuid) as SNTheme;
if ( if (!theme) {
!theme ||
this.application.getFeatureStatus(theme.identifier) !==
FeatureStatus.Entitled
) {
this.deactivateTheme(themeUuid); this.deactivateTheme(themeUuid);
hasChange = true; hasChange = true;
} else {
const status = this.application.getFeatureStatus(theme.identifier);
if (status !== FeatureStatus.Entitled) {
if (theme.active) {
this.application.toggleTheme(theme);
} else {
this.deactivateTheme(theme.uuid);
}
hasChange = true;
}
} }
} }
@@ -160,7 +152,7 @@ export class ThemeManager extends ApplicationService {
private async activateCachedThemes() { private async activateCachedThemes() {
const cachedThemes = await this.getCachedThemes(); const cachedThemes = await this.getCachedThemes();
for (const theme of cachedThemes) { for (const theme of cachedThemes) {
this.activateTheme(theme); this.activateTheme(theme, true);
} }
} }
@@ -202,22 +194,26 @@ export class ThemeManager extends ApplicationService {
} }
} }
private activateTheme(theme: SNTheme) { private activateTheme(theme: SNTheme, skipEntitlementCheck = false) {
if (this.activeThemes.find((uuid) => uuid === theme.uuid)) { if (this.activeThemes.find((uuid) => uuid === theme.uuid)) {
return; return;
} }
if ( if (
!skipEntitlementCheck &&
this.application.getFeatureStatus(theme.identifier) !== this.application.getFeatureStatus(theme.identifier) !==
FeatureStatus.Entitled FeatureStatus.Entitled
) { ) {
return; return;
} }
this.activeThemes.push(theme.uuid);
const url = this.application.componentManager.urlForComponent(theme); const url = this.application.componentManager.urlForComponent(theme);
if (!url) { if (!url) {
return; return;
} }
this.activeThemes.push(theme.uuid);
const link = document.createElement('link'); const link = document.createElement('link');
link.href = url; link.href = url;
link.type = 'text/css'; link.type = 'text/css';

View File

@@ -1,5 +0,0 @@
declare module "*.pug" {
import { compileTemplate } from 'pug';
const content: compileTemplate;
export default content;
}

View File

@@ -1,7 +1,7 @@
import { confirmDialog } from '@/services/alertService'; import { confirmDialog } from '@/services/alertService';
import { KeyboardModifier } from '@/services/ioService'; import { KeyboardModifier } from '@/services/ioService';
import { StringEmptyTrash, Strings, StringUtils } from '@/strings'; import { StringEmptyTrash, Strings, StringUtils } from '@/strings';
import { MENU_MARGIN_FROM_APP_BORDER } from '@/views/constants'; import { MENU_MARGIN_FROM_APP_BORDER } from '@/constants';
import { import {
UuidString, UuidString,
SNNote, SNNote,

View File

@@ -1,6 +1,6 @@
import { Platform, platformFromString } from '@standardnotes/snjs'; import { Platform, platformFromString } from '@standardnotes/snjs';
import { IsDesktopPlatform, IsWebPlatform } from '@/version'; import { IsDesktopPlatform, IsWebPlatform } from '@/version';
import { EMAIL_REGEX } from '@Views/constants'; import { EMAIL_REGEX } from '../constants';
export { isMobile } from './isMobile'; export { isMobile } from './isMobile';
declare const process: { declare const process: {

View File

@@ -946,3 +946,11 @@
.sn-component .border-t-0 { .sn-component .border-t-0 {
border-top-width: 0; border-top-width: 0;
} }
.text-editor {
font-size: var(--sn-stylekit-font-size-editor);
}
.sn-component .border-contrast {
border-color: var(--sn-stylekit-contrast-border-color);
}

View File

@@ -15,8 +15,8 @@
<link color="#5bbad5" href="favicon/safari-pinned-tab.svg" rel="mask-icon"></link> <link color="#5bbad5" href="favicon/safari-pinned-tab.svg" rel="mask-icon"></link>
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<meta ng-bind="title" content="Standard Notes" name="apple-mobile-web-app-title"/> <meta content="Standard Notes" name="apple-mobile-web-app-title"/>
<meta ng-bind="title" content="Standard Notes" name="application-name"/> <meta content="Standard Notes" name="application-name"/>
<base href="/"></base> <base href="/"></base>
<title>Notes · Standard Notes</title> <title>Notes · Standard Notes</title>

View File

@@ -22,8 +22,8 @@
</link> </link>
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<meta ng-bind="title" content="Standard Notes" name="apple-mobile-web-app-title" /> <meta content="Standard Notes" name="apple-mobile-web-app-title" />
<meta ng-bind="title" content="Standard Notes" name="application-name" /> <meta content="Standard Notes" name="application-name" />
<title>Dev · Notes · Standard Notes</title> <title>Dev · Notes · Standard Notes</title>
</head> </head>

View File

@@ -1,6 +1,6 @@
{ {
"name": "standard-notes-web", "name": "standard-notes-web",
"version": "3.11.0", "version": "3.11.1",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -21,79 +21,73 @@
"prepare": "husky install" "prepare": "husky install"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.15.8", "@babel/core": "^7.17.5",
"@babel/plugin-transform-react-jsx": "^7.14.9", "@babel/plugin-transform-react-jsx": "^7.17.3",
"@babel/preset-env": "^7.15.8", "@babel/preset-env": "^7.16.11",
"@babel/preset-typescript": "^7.15.0", "@babel/preset-typescript": "^7.16.7",
"@reach/disclosure": "^0.16.2", "@reach/disclosure": "^0.16.2",
"@reach/visually-hidden": "^0.16.0", "@reach/visually-hidden": "^0.16.0",
"@svgr/webpack": "^6.2.1", "@svgr/webpack": "^6.2.1",
"@types/jest": "^27.0.3", "@types/jest": "^27.4.0",
"@types/lodash": "^4.14.176", "@types/lodash": "^4.14.178",
"@types/pug": "^2.0.5", "@types/react": "^17.0.39",
"@types/react": "^17.0.31", "@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/eslint-plugin": "^5.1.0", "@typescript-eslint/parser": "^5.12.0",
"@typescript-eslint/parser": "^5.1.0",
"apply-loader": "^2.0.0", "apply-loader": "^2.0.0",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"babel-loader": "^8.2.3", "babel-loader": "^8.2.3",
"connect": "^3.7.0", "connect": "^3.7.0",
"copy-webpack-plugin": "^10.2.0", "copy-webpack-plugin": "^10.2.4",
"css-loader": "^6.4.0", "css-loader": "^6.6.0",
"dotenv": "^10.0.0", "dotenv": "^16.0.0",
"eslint": "^8.0.1", "eslint": "^8.9.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-react": "^7.26.1", "eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.2.1-beta-149b420f6-20211119", "eslint-plugin-react-hooks": "^4.3.0",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"html-webpack-plugin": "^5.4.0", "html-webpack-plugin": "^5.5.0",
"husky": "^7.0.4", "husky": "^7.0.4",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jest": "^27.3.1", "jest": "^27.5.1",
"jest-transform-pug": "^0.1.0", "lint-staged": ">=12",
"lint-staged": ">=10",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mini-css-extract-plugin": "^2.4.3", "mini-css-extract-plugin": "^2.5.3",
"ng-cache-loader": "0.0.26", "node-sass": "^7.0.1",
"node-sass": "^6.0.1", "prettier": "^2.5.1",
"prettier": "^2.5.0", "pretty-quick": "^3.1.3",
"pretty-quick": "^3.1.2", "sass-loader": "^12.6.0",
"pug": "^3.0.2", "serve-static": "^1.14.2",
"pug-jest": "^1.0.1", "@standardnotes/stylekit": "5.8.0",
"pug-loader": "^2.4.0",
"sass-loader": "^12.2.0",
"serve-static": "^1.14.1",
"@standardnotes/stylekit": "5.7.0",
"svg-jest": "^1.0.1", "svg-jest": "^1.0.1",
"ts-jest": "^27.0.7", "ts-jest": "^27.1.3",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.6",
"typescript": "4.4.4", "typescript": "4.5.5",
"typescript-eslint": "0.0.1-alpha.0", "typescript-eslint": "0.0.1-alpha.0",
"webpack": "^5.59.1", "webpack": "^5.69.1",
"webpack-cli": "^4.9.1", "webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.3.1", "webpack-dev-server": "^4.7.4",
"webpack-merge": "^5.8.0" "webpack-merge": "^5.8.0"
}, },
"dependencies": { "dependencies": {
"@bugsnag/js": "^7.13.2", "@bugsnag/js": "^7.16.1",
"@reach/alert": "^0.16.0", "@reach/alert": "^0.16.0",
"@reach/alert-dialog": "^0.16.2", "@reach/alert-dialog": "^0.16.2",
"@reach/checkbox": "^0.16.0", "@reach/checkbox": "^0.16.0",
"@reach/dialog": "^0.16.2", "@reach/dialog": "^0.16.2",
"@reach/listbox": "^0.16.2", "@reach/listbox": "^0.16.2",
"@reach/tooltip": "^0.16.2", "@reach/tooltip": "^0.16.2",
"@standardnotes/components": "1.7.3", "@standardnotes/components": "1.7.4",
"@standardnotes/features": "1.32.6", "@standardnotes/features": "1.32.8",
"@standardnotes/snjs": "2.61.0", "@standardnotes/snjs": "2.61.4",
"@standardnotes/settings": "^1.11.3", "@standardnotes/settings": "^1.11.3",
"@standardnotes/sncrypto-web": "1.7.0", "@standardnotes/sncrypto-web": "1.7.0",
"mobx": "^6.3.5", "mobx": "^6.4.0",
"mobx-react-lite": "^3.2.2", "mobx-react-lite": "^3.3.0",
"preact": "^10.5.15", "preact": "^10.6.6",
"qrcode.react": "^1.0.1", "qrcode.react": "^1.0.1",
"react-dnd": "^14.0.4", "react-dnd": "^15.1.1",
"react-dnd-html5-backend": "^14.0.2", "react-dnd-html5-backend": "^15.1.2",
"react-dnd-touch-backend": "^14.1.1" "react-dnd-touch-backend": "^15.1.1"
}, },
"lint-staged": { "lint-staged": {
"app/**/*.{js,ts,jsx,tsx}": "eslint --cache --fix", "app/**/*.{js,ts,jsx,tsx}": "eslint --cache --fix",

View File

@@ -40,9 +40,9 @@
"binary": "4e08fb2de17ab480787a1e042b2d43106e2798093e760fc507ed773401d27c71" "binary": "4e08fb2de17ab480787a1e042b2d43106e2798093e760fc507ed773401d27c71"
}, },
"org.standardnotes.bold-editor": { "org.standardnotes.bold-editor": {
"version": "1.3.3", "version": "1.3.5",
"base64": "51a5d2e77aacbcfda21b4a3429e9fe3fb6b61175e5188b6ec26854432ac41fc2", "base64": "bcecfd1a6ee1909c9f484890cf58d6d52479f8d33c16e1d5d916d1a78a75b90f",
"binary": "a30533208fbc33f115786ff912b6d605052adda03a62b47513ce390931fe11d1" "binary": "84d6ca88665d4d6a1aeb456f8acce1a662bfe4550128aac1fb748abed974f236"
}, },
"org.standardnotes.plus-editor": { "org.standardnotes.plus-editor": {
"version": "1.6.1", "version": "1.6.1",

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{ {
"name": "sn-bold-editor", "name": "sn-bold-editor",
"version": "1.3.3", "version": "1.3.5",
"main": "dist/dist.js", "main": "dist/dist.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
@@ -25,8 +25,8 @@
"dompurify": "^2.2.9", "dompurify": "^2.2.9",
"eslint": "^7.23.0", "eslint": "^7.23.0",
"eslint-plugin-react": "^7.23.1", "eslint-plugin-react": "^7.23.1",
"filesafe-embed": "1.0.11", "filesafe-embed": "1.0.13",
"filesafe-js": "1.0.4", "filesafe-js": "1.0.5",
"html-webpack-plugin": "^5.3.1", "html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^1.4.0", "mini-css-extract-plugin": "^1.4.0",
"node-sass": "^5.0.0", "node-sass": "^5.0.0",

View File

@@ -76,29 +76,6 @@ module.exports = (env) => {
test: /\.svg$/i, test: /\.svg$/i,
use: ['@svgr/webpack'], use: ['@svgr/webpack'],
}, },
{
test: /\.html$/,
exclude: [path.resolve(__dirname, 'index.html')],
use: [
{
loader: 'ng-cache-loader',
options: {
prefix: 'templates:**',
},
},
],
},
{
test: /\.pug$/,
use: [
{
loader: 'apply-loader',
},
{
loader: 'pug-loader',
},
],
},
], ],
}, },
}; };

4048
yarn.lock

File diff suppressed because it is too large Load Diff