Skip to content

Commit 49041bf

Browse files
committed
Remove Attachements for now and bug fixes
1 parent bbf3a4e commit 49041bf

File tree

8 files changed

+26
-382
lines changed

8 files changed

+26
-382
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Windows/Linux/Android Builds: https://github.com/toolworks-dev/trusty-notes/rele
2929
- [x] Improved Sync
3030
- [x] Rich Text
3131
- [x] Browser Extension
32-
- [x] Attachments/Files (In Progress but working)
32+
- [ ] Attachments/Files
3333
- [x] Desktop Application
3434
- [x] Mobile Application
3535

browser-extension/background.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,23 +68,14 @@ async function encryptAndStoreNotes(notes) {
6868
cryptoService = await CryptoService.new(settings.seed_phrase);
6969
}
7070

71-
// Filter out attachment data to save storage space in extension
7271
const notesWithoutAttachments = notes.map(note => ({
7372
id: note.id,
7473
title: note.title,
7574
content: note.content,
7675
created_at: note.created_at,
7776
updated_at: note.updated_at,
7877
deleted: note.deleted,
79-
pending_sync: note.pending_sync,
80-
// Keep minimal attachment metadata
81-
attachments: note.attachments?.map(att => ({
82-
id: att.id,
83-
name: att.name,
84-
type: att.type,
85-
size: att.size,
86-
timestamp: att.timestamp
87-
})) || []
78+
pending_sync: note.pending_sync
8879
}));
8980

9081
const encrypted = await cryptoService.encrypt(notesWithoutAttachments);

browser-extension/popup/popup.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,7 @@ async function saveNote() {
373373
content: contentInput.innerHTML || '',
374374
created_at: currentEditingNote?.created_at || now,
375375
updated_at: now,
376-
pending_sync: true,
377-
attachments: currentEditingNote?.attachments || []
376+
pending_sync: true
378377
};
379378

380379
try {

src/App.tsx

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -314,39 +314,34 @@ function App() {
314314
}
315315
}, []);
316316

317-
async function handleSave() {
317+
const handleSave = async () => {
318318
try {
319319
const now = Date.now();
320-
321-
const recentNote = notes.find(note =>
322-
note.title === title &&
323-
note.content === content &&
324-
now - note.updated_at < 2000
325-
);
326-
327-
if (recentNote) {
328-
console.debug('Preventing duplicate save');
329-
return;
330-
}
331-
332-
const note: Note = {
333-
id: selectedNote?.id || now,
320+
const noteToSave = {
321+
id: selectedNote?.id,
334322
title: title.trim() === '' ? 'Untitled' : title,
335323
content,
336324
created_at: selectedNote?.created_at || now,
337-
updated_at: now,
325+
updated_at: now
338326
};
339327

340-
await WebStorageService.saveNote(note);
328+
await WebStorageService.saveNote(noteToSave);
341329
await loadNotes();
342330

343-
// Always select the saved note to prevent duplicate creation
344-
setSelectedNote(note);
331+
if (!selectedNote) {
332+
const updatedNotes = await WebStorageService.getNotes();
333+
const newNote = updatedNotes.find(note =>
334+
note.title === noteToSave.title &&
335+
note.content === noteToSave.content
336+
);
337+
if (newNote) {
338+
setSelectedNote(newNote);
339+
}
340+
}
345341
} catch (error) {
346342
console.error('Failed to save note:', error);
347-
alert(`Failed to save note: ${error}`);
348343
}
349-
}
344+
};
350345

351346
async function deleteNote(noteId: number) {
352347
if (!window.confirm('Are you sure you want to delete this note?')) return;

src/components/NoteEditor.tsx

Lines changed: 5 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useState, useEffect } from 'react';
22
import {
3-
Stack,
43
Text,
54
Button,
65
Group,
@@ -9,70 +8,25 @@ import {
98
Box,
109
TextInput
1110
} from '@mantine/core';
12-
import { notifications } from '@mantine/notifications';
13-
import { IconTrash, IconChevronLeft, IconPaperclip, IconDownload } from '@tabler/icons-react';
11+
import { IconTrash, IconChevronLeft } from '@tabler/icons-react';
1412
import { WebStorageService } from '../services/webStorage';
1513
import { Note } from '../types/sync';
1614
import { MarkdownEditor } from './MarkdownEditor';
1715

18-
interface AttachmentsListProps {
19-
note: Note;
20-
onRemove: (attachmentId: string) => void;
21-
onDownload: (attachmentId: string) => void;
22-
isSyncing: boolean;
23-
}
24-
25-
function AttachmentsList({ note, onRemove, onDownload, isSyncing }: AttachmentsListProps) {
26-
if (!note.attachments?.length) return null;
27-
28-
return (
29-
<Stack gap="xs" mt="md">
30-
<Text fw={500} size="sm">Attachments</Text>
31-
{note.attachments.map(attachment => (
32-
<Group key={attachment.id} justify="space-between">
33-
<Text size="sm">{attachment.name}</Text>
34-
<Group gap="xs">
35-
<ActionIcon
36-
variant="subtle"
37-
size="sm"
38-
onClick={() => onDownload(attachment.id)}
39-
disabled={isSyncing}
40-
>
41-
<IconDownload size={16} />
42-
</ActionIcon>
43-
<ActionIcon
44-
color="red"
45-
variant="subtle"
46-
size="sm"
47-
onClick={() => onRemove(attachment.id)}
48-
disabled={isSyncing}
49-
>
50-
<IconTrash size={16} />
51-
</ActionIcon>
52-
</Group>
53-
</Group>
54-
))}
55-
</Stack>
56-
);
57-
}
58-
59-
interface NoteEditorProps {
16+
export interface NoteEditorProps {
6017
note: Note;
6118
isMobile?: boolean;
6219
isKeyboardVisible?: boolean;
6320
onBack?: () => void;
64-
loadNotes: () => void;
21+
loadNotes: () => Promise<void>;
6522
}
6623

6724
export function NoteEditor({ note, isMobile = false, isKeyboardVisible = false, onBack, loadNotes }: NoteEditorProps) {
68-
const [currentNote, setCurrentNote] = useState(note);
6925
const [title, setTitle] = useState(note.title || 'Untitled');
7026
const [content, setContent] = useState(note.content || '');
7127
const [saveStatus, setSaveStatus] = useState<'saved' | 'saving' | null>('saved');
72-
const [isSyncing, setIsSyncing] = useState(false);
7328

7429
useEffect(() => {
75-
setCurrentNote(note);
7630
setTitle(note.title || 'Untitled');
7731
setContent(note.content || '');
7832
}, [note]);
@@ -109,88 +63,14 @@ export function NoteEditor({ note, isMobile = false, isKeyboardVisible = false,
10963
}
11064
}, [isMobile]);
11165

112-
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
113-
const file = event.target.files?.[0];
114-
if (!file || !currentNote?.id) return;
115-
116-
try {
117-
setIsSyncing(true);
118-
119-
if (file.size > 10 * 1024 * 1024) {
120-
throw new Error('File size exceeds 10MB limit');
121-
}
122-
123-
const updatedNote = await WebStorageService.addAttachment(currentNote.id, file);
124-
setCurrentNote(updatedNote);
125-
await loadNotes();
126-
127-
notifications.show({
128-
title: 'Success',
129-
message: 'File attached successfully',
130-
color: 'green',
131-
});
132-
} catch (error) {
133-
console.error('Failed to attach file:', error);
134-
notifications.show({
135-
title: 'Error',
136-
message: error instanceof Error ? error.message : 'Failed to attach file',
137-
color: 'red',
138-
});
139-
} finally {
140-
setIsSyncing(false);
141-
}
142-
};
143-
144-
const handleDownload = async (attachmentId: string) => {
145-
try {
146-
setIsSyncing(true);
147-
await WebStorageService.downloadAttachment(note.id!, attachmentId);
148-
} catch (error) {
149-
console.error('Failed to download file:', error);
150-
notifications.show({
151-
title: 'Error',
152-
message: error instanceof Error ? error.message : 'Failed to download file',
153-
color: 'red',
154-
});
155-
} finally {
156-
setIsSyncing(false);
157-
}
158-
};
159-
160-
const handleRemoveAttachment = async (attachmentId: string) => {
161-
if (!confirm('Are you sure you want to remove this attachment?')) return;
162-
163-
try {
164-
setIsSyncing(true);
165-
await WebStorageService.removeAttachment(note.id!, attachmentId);
166-
167-
// Get the updated note after attachment removal
168-
const notes = await WebStorageService.getNotes();
169-
const updated = notes.find(n => n.id === note.id);
170-
if (updated) {
171-
setCurrentNote(updated);
172-
}
173-
174-
await loadNotes();
175-
} catch (error) {
176-
console.error('Failed to remove attachment:', error);
177-
notifications.show({
178-
title: 'Error',
179-
message: error instanceof Error ? error.message : 'Failed to remove attachment',
180-
color: 'red',
181-
});
182-
} finally {
183-
setIsSyncing(false);
184-
}
185-
};
186-
18766
const saveNote = async () => {
18867
setSaveStatus('saving');
18968
const updatedNote = {
19069
...note,
19170
title,
19271
content,
193-
updated_at: Date.now()
72+
updated_at: Date.now(),
73+
pending_sync: true
19474
};
19575

19676
await WebStorageService.saveNote(updatedNote);
@@ -250,18 +130,6 @@ export function NoteEditor({ note, isMobile = false, isKeyboardVisible = false,
250130
size="md"
251131
onBlur={saveNote}
252132
/>
253-
<label htmlFor="file-upload">
254-
<ActionIcon component="span" variant="subtle" radius="xl">
255-
<IconPaperclip size={20} />
256-
</ActionIcon>
257-
</label>
258-
<input
259-
id="file-upload"
260-
type="file"
261-
onChange={handleFileUpload}
262-
style={{ display: 'none' }}
263-
disabled={isSyncing}
264-
/>
265133
</Group>
266134
</Paper>
267135

@@ -282,17 +150,6 @@ export function NoteEditor({ note, isMobile = false, isKeyboardVisible = false,
282150
/>
283151
</Box>
284152

285-
{currentNote.attachments && currentNote.attachments.length > 0 && (
286-
<Paper p="md" mb="md" withBorder>
287-
<AttachmentsList
288-
note={currentNote}
289-
onRemove={handleRemoveAttachment}
290-
onDownload={handleDownload}
291-
isSyncing={isSyncing}
292-
/>
293-
</Paper>
294-
)}
295-
296153
<Paper className="mobile-fixed-bottom" style={{
297154
position: 'fixed',
298155
bottom: 0,

src/services/cryptoService.ts

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Buffer } from 'buffer/';
22
import { mnemonicToSeedSync, wordlists } from 'bip39';
3-
import { Note, Attachment } from '../types/sync';
3+
import { Note } from '../types/sync';
44
const WORDLIST = wordlists.english;
55

66
interface EncryptedNote {
@@ -10,7 +10,6 @@ interface EncryptedNote {
1010
timestamp: number;
1111
signature: string;
1212
deleted?: boolean;
13-
attachments?: Attachment[];
1413
}
1514

1615
export class CryptoService {
@@ -91,8 +90,7 @@ export class CryptoService {
9190
content: note.content,
9291
created_at: note.created_at,
9392
updated_at: note.updated_at,
94-
deleted: note.deleted,
95-
attachments: note.attachments
93+
deleted: note.deleted
9694
});
9795

9896
const key = await crypto.subtle.importKey(
@@ -164,60 +162,4 @@ export class CryptoService {
164162
const keyData = await crypto.subtle.exportKey('raw', this.verifyingKey!);
165163
return Buffer.from(keyData).toString('base64');
166164
}
167-
168-
async encryptFile(file: File): Promise<Attachment> {
169-
const arrayBuffer = await file.arrayBuffer();
170-
const nonceBytes = crypto.getRandomValues(new Uint8Array(12));
171-
172-
const key = await crypto.subtle.importKey(
173-
'raw',
174-
this.encryptionKey,
175-
{ name: 'AES-GCM' },
176-
false,
177-
['encrypt']
178-
);
179-
180-
const encryptedData = await crypto.subtle.encrypt(
181-
{
182-
name: 'AES-GCM',
183-
iv: nonceBytes
184-
},
185-
key,
186-
arrayBuffer
187-
);
188-
189-
return {
190-
id: crypto.randomUUID(),
191-
name: file.name,
192-
type: file.type,
193-
size: file.size,
194-
data: Buffer.from(encryptedData).toString('base64'),
195-
nonce: Buffer.from(nonceBytes).toString('base64'),
196-
timestamp: Date.now()
197-
};
198-
}
199-
200-
async decryptFile(attachment: Attachment): Promise<Blob> {
201-
const encryptedData = Buffer.from(attachment.data, 'base64');
202-
const nonce = Buffer.from(attachment.nonce, 'base64');
203-
204-
const key = await crypto.subtle.importKey(
205-
'raw',
206-
this.encryptionKey,
207-
{ name: 'AES-GCM' },
208-
false,
209-
['decrypt']
210-
);
211-
212-
const decryptedData = await crypto.subtle.decrypt(
213-
{
214-
name: 'AES-GCM',
215-
iv: nonce
216-
},
217-
key,
218-
encryptedData
219-
);
220-
221-
return new Blob([decryptedData], { type: attachment.type });
222-
}
223165
}

0 commit comments

Comments
 (0)