Prevent accidental duplicate notes in workspace actions
This commit is contained in:
+59
-10
@@ -159,6 +159,7 @@
|
|||||||
<div class="grid gap-3 md:grid-cols-2">
|
<div class="grid gap-3 md:grid-cols-2">
|
||||||
<select id="typeInput" class="field">
|
<select id="typeInput" class="field">
|
||||||
<option value="personal">personal</option>
|
<option value="personal">personal</option>
|
||||||
|
<option value="general">general</option>
|
||||||
<option value="job">job</option>
|
<option value="job">job</option>
|
||||||
<option value="manager">manager</option>
|
<option value="manager">manager</option>
|
||||||
<option value="billing">billing</option>
|
<option value="billing">billing</option>
|
||||||
@@ -188,6 +189,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-4 flex flex-wrap gap-3">
|
<div class="mt-4 flex flex-wrap gap-3">
|
||||||
<button id="createBtn" class="btn btn-accent-emerald">Create Note</button>
|
<button id="createBtn" class="btn btn-accent-emerald">Create Note</button>
|
||||||
|
<button id="copyBtn" class="btn btn-secondary" disabled>Copy Note</button>
|
||||||
<button id="saveBtn" class="btn btn-accent-indigo" disabled>Save Changes</button>
|
<button id="saveBtn" class="btn btn-accent-indigo" disabled>Save Changes</button>
|
||||||
<button id="hideBtn" class="btn btn-secondary" disabled>Hide</button>
|
<button id="hideBtn" class="btn btn-secondary" disabled>Hide</button>
|
||||||
<button id="deleteBtn" class="btn btn-danger" disabled>Soft Delete</button>
|
<button id="deleteBtn" class="btn btn-danger" disabled>Soft Delete</button>
|
||||||
@@ -260,16 +262,42 @@
|
|||||||
const saveBtn = document.getElementById('saveBtn');
|
const saveBtn = document.getElementById('saveBtn');
|
||||||
const hideBtn = document.getElementById('hideBtn');
|
const hideBtn = document.getElementById('hideBtn');
|
||||||
const deleteBtn = document.getElementById('deleteBtn');
|
const deleteBtn = document.getElementById('deleteBtn');
|
||||||
|
const createBtn = document.getElementById('createBtn');
|
||||||
|
const copyBtn = document.getElementById('copyBtn');
|
||||||
|
|
||||||
let recorderStream = null;
|
let recorderStream = null;
|
||||||
let mediaRecorder = null;
|
let mediaRecorder = null;
|
||||||
let recordChunks = [];
|
let recordChunks = [];
|
||||||
let lastRecordedFile = null;
|
let lastRecordedFile = null;
|
||||||
|
let actionInFlight = false;
|
||||||
|
|
||||||
function writeOutput(value) {
|
function writeOutput(value) {
|
||||||
output.textContent = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
output.textContent = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setActionBusy(isBusy) {
|
||||||
|
actionInFlight = isBusy;
|
||||||
|
const disabled = !!isBusy;
|
||||||
|
createBtn.disabled = disabled || !!selectedNote;
|
||||||
|
copyBtn.disabled = disabled || !selectedNote;
|
||||||
|
saveBtn.disabled = disabled || !selectedNote;
|
||||||
|
hideBtn.disabled = disabled || !selectedNote;
|
||||||
|
deleteBtn.disabled = disabled || !selectedNote;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runNoteAction(handler) {
|
||||||
|
if (actionInFlight) {
|
||||||
|
writeOutput('Please wait for the current action to finish.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setActionBusy(true);
|
||||||
|
try {
|
||||||
|
await handler();
|
||||||
|
} finally {
|
||||||
|
setActionBusy(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function escapeHtml(value) {
|
function escapeHtml(value) {
|
||||||
return String(value || '')
|
return String(value || '')
|
||||||
.replace(/&/g, '&')
|
.replace(/&/g, '&')
|
||||||
@@ -747,9 +775,9 @@
|
|||||||
lastRecordedFile = null;
|
lastRecordedFile = null;
|
||||||
selectedAttachmentsStatus.textContent = 'Select a note to view attachments.';
|
selectedAttachmentsStatus.textContent = 'Select a note to view attachments.';
|
||||||
selectedAttachmentsList.innerHTML = '';
|
selectedAttachmentsList.innerHTML = '';
|
||||||
saveBtn.disabled = true;
|
setActionBusy(false);
|
||||||
hideBtn.disabled = true;
|
createBtn.disabled = false;
|
||||||
deleteBtn.disabled = true;
|
copyBtn.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNote(note) {
|
function selectNote(note) {
|
||||||
@@ -769,9 +797,9 @@
|
|||||||
recordPreview.classList.add('hidden');
|
recordPreview.classList.add('hidden');
|
||||||
recordStatus.textContent = 'Ready';
|
recordStatus.textContent = 'Ready';
|
||||||
lastRecordedFile = null;
|
lastRecordedFile = null;
|
||||||
saveBtn.disabled = false;
|
setActionBusy(false);
|
||||||
hideBtn.disabled = false;
|
createBtn.disabled = true;
|
||||||
deleteBtn.disabled = false;
|
copyBtn.disabled = false;
|
||||||
hideBtn.textContent = toBoolFlag(note.hidden) ? 'Unhide' : 'Hide';
|
hideBtn.textContent = toBoolFlag(note.hidden) ? 'Unhide' : 'Hide';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -882,6 +910,9 @@
|
|||||||
async function createNote() {
|
async function createNote() {
|
||||||
await ensurePocketBaseClient();
|
await ensurePocketBaseClient();
|
||||||
ensureLoggedIn();
|
ensureLoggedIn();
|
||||||
|
if (selectedNote) {
|
||||||
|
throw new Error('A note is selected. Use Save Changes to update it or Copy Note to duplicate it intentionally.');
|
||||||
|
}
|
||||||
const payload = buildNotePayload();
|
const payload = buildNotePayload();
|
||||||
const record = await pb.collection(NOTES_COLLECTION).create(payload);
|
const record = await pb.collection(NOTES_COLLECTION).create(payload);
|
||||||
const uploaded = await uploadPendingAttachments(record.id);
|
const uploaded = await uploadPendingAttachments(record.id);
|
||||||
@@ -893,6 +924,23 @@
|
|||||||
writeOutput({ message: 'Note created', id: record.id, attachmentsUploaded: uploaded.length });
|
writeOutput({ message: 'Note created', id: record.id, attachmentsUploaded: uploaded.length });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function copyNote() {
|
||||||
|
if (!selectedNote) throw new Error('Select a note first');
|
||||||
|
const sourceId = selectedNote.id;
|
||||||
|
await ensurePocketBaseClient();
|
||||||
|
ensureLoggedIn();
|
||||||
|
const payload = buildNotePayload();
|
||||||
|
payload.title = `${payload.title} (Copy)`;
|
||||||
|
const record = await pb.collection(NOTES_COLLECTION).create(payload);
|
||||||
|
const uploaded = await uploadPendingAttachments(record.id);
|
||||||
|
await loadNotes();
|
||||||
|
const refreshed = allNotes.find((n) => n.id === record.id) || record;
|
||||||
|
selectNote(refreshed);
|
||||||
|
renderList();
|
||||||
|
await renderSelectedAttachments();
|
||||||
|
writeOutput({ message: 'Note copied', sourceId, newId: record.id, attachmentsUploaded: uploaded.length });
|
||||||
|
}
|
||||||
|
|
||||||
async function saveNote() {
|
async function saveNote() {
|
||||||
if (!selectedNote) throw new Error('Select a note first');
|
if (!selectedNote) throw new Error('Select a note first');
|
||||||
await ensurePocketBaseClient();
|
await ensurePocketBaseClient();
|
||||||
@@ -946,10 +994,11 @@
|
|||||||
bind('loginBtn', loginPocketBase);
|
bind('loginBtn', loginPocketBase);
|
||||||
bind('logoutBtn', logoutPocketBase);
|
bind('logoutBtn', logoutPocketBase);
|
||||||
bind('refreshBtn', loadNotes);
|
bind('refreshBtn', loadNotes);
|
||||||
bind('createBtn', createNote);
|
bind('createBtn', () => runNoteAction(createNote));
|
||||||
bind('saveBtn', saveNote);
|
bind('copyBtn', () => runNoteAction(copyNote));
|
||||||
bind('hideBtn', toggleHidden);
|
bind('saveBtn', () => runNoteAction(saveNote));
|
||||||
bind('deleteBtn', softDelete);
|
bind('hideBtn', () => runNoteAction(toggleHidden));
|
||||||
|
bind('deleteBtn', () => runNoteAction(softDelete));
|
||||||
|
|
||||||
document.getElementById('pickFilesBtn').addEventListener('click', () => {
|
document.getElementById('pickFilesBtn').addEventListener('click', () => {
|
||||||
attachmentsInput.click();
|
attachmentsInput.click();
|
||||||
|
|||||||
Reference in New Issue
Block a user