diff --git a/Gemfile.lock b/Gemfile.lock
index c578fae74..d2fe3cd95 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -213,7 +213,7 @@ DEPENDENCIES
dotenv-rails
haml
lograge (~> 0.11.2)
- newrelic_rpm
+ newrelic_rpm (~> 7.0)
non-stupid-digest-assets
puma
rack-cors
diff --git a/app/assets/javascripts/components/NotesContextMenu.tsx b/app/assets/javascripts/components/NotesContextMenu.tsx
index 3afd7df89..292e7265b 100644
--- a/app/assets/javascripts/components/NotesContextMenu.tsx
+++ b/app/assets/javascripts/components/NotesContextMenu.tsx
@@ -3,12 +3,14 @@ import { toDirective, useCloseOnBlur, useCloseOnClickOutside } from './utils';
import { observer } from 'mobx-react-lite';
import { NotesOptions } from './NotesOptions';
import { useCallback, useEffect, useRef } from 'preact/hooks';
+import { WebApplication } from '@/ui_models/application';
type Props = {
+ application: WebApplication;
appState: AppState;
};
-const NotesContextMenu = observer(({ appState }: Props) => {
+const NotesContextMenu = observer(({ application, appState }: Props) => {
const {
contextMenuOpen,
contextMenuPosition,
@@ -46,7 +48,11 @@ const NotesContextMenu = observer(({ appState }: Props) => {
maxHeight: contextMenuMaxHeight,
}}
>
-
+
) : null;
});
diff --git a/app/assets/javascripts/components/NotesOptions.tsx b/app/assets/javascripts/components/NotesOptions.tsx
index 3f6d07052..3346ff1e4 100644
--- a/app/assets/javascripts/components/NotesOptions.tsx
+++ b/app/assets/javascripts/components/NotesOptions.tsx
@@ -9,15 +9,33 @@ import {
DisclosurePanel,
} from '@reach/disclosure';
import { SNNote } from '@standardnotes/snjs/dist/@types';
+import { WebApplication } from '@/ui_models/application';
+import { KeyboardModifier } from '@/services/ioService';
type Props = {
+ application: WebApplication;
appState: AppState;
closeOnBlur: (event: { relatedTarget: EventTarget | null }) => void;
onSubmenuChange?: (submenuOpen: boolean) => void;
};
+type DeletePermanentlyButtonProps = {
+ closeOnBlur: Props["closeOnBlur"];
+ onClick: () => void;
+}
+
+const DeletePermanentlyButton = ({
+ closeOnBlur,
+ onClick,
+}: DeletePermanentlyButtonProps) => (
+
+);
+
export const NotesOptions = observer(
- ({ appState, closeOnBlur, onSubmenuChange }: Props) => {
+ ({ application, appState, closeOnBlur, onSubmenuChange }: Props) => {
const [tagsMenuOpen, setTagsMenuOpen] = useState(false);
const [tagsMenuPosition, setTagsMenuPosition] = useState<{
top: number;
@@ -29,6 +47,7 @@ export const NotesOptions = observer(
});
const [tagsMenuMaxHeight, setTagsMenuMaxHeight] =
useState('auto');
+ const [altKeyDown, setAltKeyDown] = useState(false);
const toggleOn = (condition: (note: SNNote) => boolean) => {
const notesMatchingAttribute = notes.filter(condition);
@@ -59,6 +78,22 @@ export const NotesOptions = observer(
}
}, [tagsMenuOpen, onSubmenuChange]);
+ useEffect(() => {
+ const removeAltKeyObserver = application.io.addKeyObserver({
+ modifiers: [KeyboardModifier.Alt],
+ onKeyDown: () => {
+ setAltKeyDown(true);
+ },
+ onKeyUp: () => {
+ setAltKeyDown(false);
+ }
+ });
+
+ return () => {
+ removeAltKeyObserver();
+ };
+ }, [application]);
+
const openTagsMenu = () => {
const defaultFontSize = window.getComputedStyle(
document.documentElement
@@ -235,18 +270,26 @@ export const NotesOptions = observer(
Unarchive
)}
- {notTrashed && (
-
- )}
+ {notTrashed &&
+ (altKeyDown ? (
+ {
+ await appState.notes.deleteNotesPermanently();
+ }}
+ />
+ ) : (
+
+ ))}
{trashed && (
<>
Restore
-
+ />