create note added

This commit is contained in:
2026-02-27 14:40:10 -06:00
parent 1a497a98e8
commit 20a19006d5
3 changed files with 101 additions and 7 deletions
+4 -2
View File
@@ -801,7 +801,7 @@ export const initStore = async () => {
// 1.2 Fetch Buckets // 1.2 Fetch Buckets
try { try {
const buckets = await pb.collection(BUCKETS_COLLECTION).getFullList({ sort: 'name' }); const buckets = await pb.collection(BUCKETS_COLLECTION).getFullList({ sort: 'name', requestKey: null });
setStore("buckets", buckets.map((b: any) => ({ setStore("buckets", buckets.map((b: any) => ({
id: b.id, id: b.id,
name: b.name, name: b.name,
@@ -817,7 +817,8 @@ export const initStore = async () => {
const currentUserId = pb.authStore.model?.id; const currentUserId = pb.authStore.model?.id;
const notesRecords = await pb.collection(NOTES_COLLECTION).getFullList({ const notesRecords = await pb.collection(NOTES_COLLECTION).getFullList({
filter: `isPrivate = false || user = "${currentUserId}"`, filter: `isPrivate = false || user = "${currentUserId}"`,
sort: '-created' sort: '-created',
requestKey: null
}); });
setStore("notes", notesRecords.map(mapRecordToNote)); setStore("notes", notesRecords.map(mapRecordToNote));
} catch (notesErr) { } catch (notesErr) {
@@ -828,6 +829,7 @@ export const initStore = async () => {
try { try {
const tagRecords = await pb.collection(TAGS_COLLECTION).getFullList({ const tagRecords = await pb.collection(TAGS_COLLECTION).getFullList({
filter: `user = "${pb.authStore.model?.id}"`, filter: `user = "${pb.authStore.model?.id}"`,
requestKey: null
}); });
const loadedTags: TagDefinition[] = tagRecords.map(r => ({ const loadedTags: TagDefinition[] = tagRecords.map(r => ({
id: r.id, id: r.id,
+11 -2
View File
@@ -21,7 +21,12 @@ export const NotepadView: Component<{
const currentUserId = pb.authStore.model?.id; const currentUserId = pb.authStore.model?.id;
// Derived states // Derived states
const activeNote = createMemo(() => store.notes.find(n => n.id === props.selectedNoteId) || null); const activeNote = createMemo(() => {
const id = props.selectedNoteId?.trim();
const note = store.notes.find(n => n.id === id) || null;
console.log('[DEBUG NotepadView] store.notes length:', store.notes.length, 'selectedNoteId:', id, 'found Note:', !!note);
return note;
});
const handleUpdateNote = async (id: string, data: Partial<Note>) => { const handleUpdateNote = async (id: string, data: Partial<Note>) => {
try { try {
@@ -148,7 +153,11 @@ export const NotepadView: Component<{
)}> )}>
<Show when={activeNote()} fallback={ <Show when={activeNote()} fallback={
<div class="text-center space-y-4 opacity-40 select-none"> <div class="text-center space-y-4 opacity-40 select-none">
<p class="text-sm font-medium tracking-wide">Select a note or create a new one</p> <Show when={props.selectedNoteId && store.notes.length === 0} fallback={
<p class="text-sm font-medium tracking-wide">Select a note or create a new one</p>
}>
<p class="text-sm font-medium tracking-wide">Loading note...</p>
</Show>
</div> </div>
}> }>
{(note) => { {(note) => {
+86 -3
View File
@@ -132,6 +132,14 @@
<button onclick="loadSpecificNote()" style="padding: 8px 16px; cursor: pointer;">Load Note</button> <button onclick="loadSpecificNote()" style="padding: 8px 16px; cursor: pointer;">Load Note</button>
</div> </div>
<p style="font-size: 13px; color: #666; margin-top: 20px;"><strong>Test API Creation:</strong></p>
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
<input type="text" id="new-note-title" style="flex: 1; padding: 8px;" placeholder="New Note Title...">
<button onclick="createNoteViaAPI()"
style="padding: 8px 16px; cursor: pointer; background: #28a745; color: white; border: none; border-radius: 4px; font-weight: bold;">Create
& Open Note</button>
</div>
<p style="font-size: 13px; color: #666; margin-top: 20px;"><strong>Manual Auth:</strong></p> <p style="font-size: 13px; color: #666; margin-top: 20px;"><strong>Manual Auth:</strong></p>
<input type="text" id="token" class="manual-token" placeholder="Paste PB Token here..."> <input type="text" id="token" class="manual-token" placeholder="Paste PB Token here...">
<button class="send-manual" onclick="sendAuthFromInput()">Send Manual Token</button> <button class="send-manual" onclick="sendAuthFromInput()">Send Manual Token</button>
@@ -149,18 +157,56 @@
<li><code>/embed/quick-add</code>: Renders a standalone task creation form.</li> <li><code>/embed/quick-add</code>: Renders a standalone task creation form.</li>
</ul> </ul>
<p><strong>2. Authentication Protocol:</strong></p> <p><strong>2. Creating Notes Programmatically (API):</strong></p>
<p>Before embedding, a sister app can create a Note via PocketBase API to retrieve a new
<code>noteId</code>. By default, notes should have an array of <code>tags</code> and a
<code>title</code>.</p>
<p><em>Using the PocketBase JS SDK:</em></p>
<pre
style="background: #f8f9fa; padding: 15px; border-radius: 4px; border: 1px solid #e9ecef; overflow-x: auto; font-size: 12px;">
const record = await pb.collection('notes').create({
title: "Sister App Payload",
content: "&lt;p&gt;Initial content here...&lt;/p&gt;",
tags: ["sister_app_export"],
isPrivate: false,
user: pb.authStore.model.id, // Must be authenticated user ID
tasks: [] // Optional array of linked task IDs
});
const newNoteId = record.id;
// Then iframe to /embed/notes?noteId=${newNoteId}
</pre>
<p><em>Using standard REST API (fetch):</em></p>
<pre
style="background: #f8f9fa; padding: 15px; border-radius: 4px; border: 1px solid #e9ecef; overflow-x: auto; font-size: 12px;">
const res = await fetch('https://pocketbase.ccllc.pro/api/collections/notes/records', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'YOUR_PB_AUTH_TOKEN'
},
body: JSON.stringify({
title: "REST Custom Note",
user: "YOUR_USER_ID",
tags: [],
tasks: [],
isPrivate: false
})
});
const data = await res.json();
const newNoteId = data.id;</pre>
<p><strong>3. Authentication Protocol:</strong></p>
<p>The parent application must send a <code>postMessage</code> to the iframe immediately after the <p>The parent application must send a <code>postMessage</code> to the iframe immediately after the
iframe loads (or whenever auth state changes).</p> iframe loads (or whenever auth state changes).</p>
<pre <pre
style="background: #f8f9fa; padding: 15px; border-radius: 4px; border: 1px solid #e9ecef; overflow-x: auto;"> style="background: #f8f9fa; padding: 15px; border-radius: 4px; border: 1px solid #e9ecef; overflow-x: auto; font-size: 12px;">
iframe.contentWindow.postMessage({ iframe.contentWindow.postMessage({
type: "TASGRID_AUTH", type: "TASGRID_AUTH",
token: "YOUR_POCKETBASE_TOKEN", token: "YOUR_POCKETBASE_TOKEN",
user: { /* optional PB user record */ } user: { /* optional PB user record */ }
}, "*");</pre> }, "*");</pre>
<p><strong>3. Responsiveness:</strong></p> <p><strong>4. Responsiveness:</strong></p>
<p>Both routes are designed to be fluid. Ensure your iframe container has defined dimensions; the <p>Both routes are designed to be fluid. Ensure your iframe container has defined dimensions; the
content will expand to fill it.</p> content will expand to fill it.</p>
</div> </div>
@@ -202,6 +248,43 @@ iframe.contentWindow.postMessage({
} }
} }
async function createNoteViaAPI() {
const title = document.getElementById('new-note-title').value.trim() || 'API Generated Note';
if (!pb.authStore.isValid) {
alert("Please log in first before creating a note via API.");
return;
}
statusEl.className = 'status';
statusEl.textContent = 'Creating note via API...';
statusEl.style.display = 'block';
try {
// Using PocketBase SDK to mimic a REST API call from sister app
const record = await pb.collection('notes').create({
title: title,
content: "<p>This note was created automatically via the API script!</p>",
tags: ["api_generated"],
isPrivate: false,
user: pb.authStore.model.id,
tasks: []
});
statusEl.className = 'status success';
statusEl.textContent = `Note created successfully (ID: ${record.id})! Loading iframe...`;
// Automatically set the new ID in the deep link input
document.getElementById('note-id-input').value = record.id;
// Automatically load it
loadSpecificNote();
} catch (err) {
statusEl.className = 'status error';
statusEl.textContent = 'Failed to create note: ' + err.message;
}
}
async function login() { async function login() {
const email = document.getElementById('email').value; const email = document.getElementById('email').value;
const password = document.getElementById('password').value; const password = document.getElementById('password').value;