-
Notifications
You must be signed in to change notification settings - Fork 0
Conversation
This new menu section includes a button to add new annotations and lists already-existing annotations
…isualization Now is possible to jump between different saved positions (annotations) and to actually delete one. Also added the coordinates of the camera and of the pivot point (to be fixed)
add annotationPanel.css file and just inserted the css code to make the original annotation button not visible in the toolbar
…ions add an increasing number to each new annotation created. As for now, only in the sidebar (jstree)
…tations add an increasing number to each new annotation created. Now works also in the live scene (for each UUID)
…rom the sidebar it is now possible to double-click on a saved position's name to rename it. The update is cascaded to the live-scene elements
This fix solves the NotFoundError, throwed whenever there was an attempt of removing an already removed target
fixed behaviour conflict triggered by "Add a new location" button
…r label placement to update Before of this fix, whenever there was the creation of a new saved position, it had Placeholder values from potree's build, that were updated only after the creation/deletion of another position. Now plaeholder value is substituted by "---" and there is a eventListener that waits for the label to be placed before updating its values
…all refactor Now it is possible to see the Annotation Description in the sidebar, and if double-clicked, it can be edited. The Annotation is mirrored in the liev scene object. Lastly, there is a small refactor of the code to have some helpers
The data is sent by API to the small express server and stored in a json. the objects in the json will be fetched when opening the app and displayed
- made it possible to click everywhere on the single annotation panel to open it, and not only on the toggle triangle - added a small pencil icon to indicate the possibility to edit the title text - switched “camera coordinates” with “saved point coordinates” in the annotation panel - made it that the coordinates are listed below the “type of coordinate” title, and are on different lines
…up-4/MolloyExplorer into 4-save-camera-positions-us5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks really good, and the movement between the annotations are really smooth, good job!
Just two things I noticed:
- When I try to move to either annotation 3 and 4, it zooms out quite far (as shown on the picture below). If I do the same for annotation 1 and 2, the camera moves closer to them, as intended. Not sure if the camera behaviour for 3 and 4 is intended, or if it might be related to the fact that the other areas are smaller?
- Also noticed that the textbox can be dragged outside of the gray area. I don't think it is a big issue as of now, but if you have time it could maybe be fixed.
WalkthroughAdds a Potree annotations sidebar (UI + CSS), client-side persistence with autosave and optional server save, a small Express server endpoint and npm script, a Vite dev proxy, and an initial annotations JSON plus README updates. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as "Annotations Panel"
participant Viewer as "Potree Viewer"
participant Persist as "Annotation Persistence"
participant Server
User->>UI: Click "Add Location"
UI->>Viewer: Capture camera & marker position
Viewer-->>UI: Live annotation created
UI->>Persist: Register new annotation
Persist->>localStorage: Debounced snapshot
Persist->>Server: POST /api/annotations (debounced)
Server-->>Persist: { saved: true, path }
Persist->>UI: Refresh list / emit update
sequenceDiagram
participant UI as "Annotations Panel"
participant Viewer as "Potree Viewer"
participant Persist as "Annotation Persistence"
UI->>UI: Inline edit title/description
UI->>Viewer: Update live annotation object
Viewer-->>Persist: annotation_changed event
Persist->>Persist: Mark dirty & debounce snapshot
Persist->>localStorage: Save snapshot
Persist->>UI: Confirm persisted state / refresh
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
[pre_merge_check_pass] The pull request implements most core coding objectives from issue #4. The annotation tool, list, and properties have been moved to a dedicated "Saved Locations" sidebar section (annotationPanel.js, annotationPanel.css), delete functionality is implemented (visible in CSS and code structure), and the travel button between locations is added. The Express server with API endpoint stores annotation data with folder support, and the persistence module serializes all required fields: Name, Description, Camera Position, Camera Target, and Position. However, the PR description does not explicitly clarify whether folder creation and folder-selection UI during annotation creation are fully implemented, though the code infrastructure (folders property, serializeGrouped logic) suggests these features may be partially present. | ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
♻️ Duplicate comments (1)
src/AnnotationControl/annotationPanel.js (1)
1-1: Docstring consistency.Docs style varies across helpers (e.g., _getJSTree, _getJSTreeInstance, _findLiveAnnotationByUUID). Align placement/format with the rest.
🧹 Nitpick comments (10)
server.js (3)
36-38: File writes are not atomic and lack backups.Direct
writeFileSynccan corrupt the file if the process crashes mid-write. Consider atomic writes (write to temp file, then rename) to ensure data integrity.Example atomic write pattern:
const tempFile = annotationsFile + '.tmp' await fs.promises.writeFile(tempFile, data, 'utf8') await fs.promises.rename(tempFile, annotationsFile)
26-44: No authentication or rate limiting on the save endpoint.Any client can repeatedly overwrite annotation data. Consider adding rate limiting and authentication mechanisms for production deployments.
29-34: Basic validation may allow malformed data.The validation only checks for the presence of
foldersas an object but doesn't validate its structure or content depth. Consider adding schema validation (e.g., with a library like Joi or Zod) to ensure data integrity.src/AnnotationControl/annotationPanel.js (3)
69-75: Prevent double initialization (buttons/listeners duplication).Calling initAnnotationsPanel multiple times will add duplicate listeners and “Add a location” buttons.
if (!targetContainer) { console.warn( 'Annotations list container not found and dynamic injection failed' ) return } + // Prevent double-initialization + if (targetContainer.dataset.annPanelInitialized === '1') { + updateAnnotationsList() + return + } ... createAddButton() updateAnnotationsList() initAnnotationPersistence(viewer) + // Mark initialized + try { targetContainer.dataset.annPanelInitialized = '1' } catch {}Also applies to: 991-1009
570-572: Avoid magic placeholder coordinates.Hard-coding PLACEHOLDER_POS couples UI to dataset-specific values. Prefer a semantic check (e.g., wait until ann.marker exists and differs from default) or hide until a live marker position is available.
919-990: US:5 verification: folder selection on create.Create button doesn’t prompt/select a folder; new annotations default to ‘General’. If folder selection is required at creation time, point me to where it’s implemented or we should add it.
src/AnnotationControl/persistence.js (4)
2-3: Make endpoints and autosave configurable.Allow callers to pass saveUrl/jsonUrl/autosave. Keeps dev/prod flexible.
-export function initAnnotationPersistence(viewer, options = {}) { - const jsonUrl = options.jsonUrl || '/annotations/annotations.json' +export function initAnnotationPersistence(viewer, options = {}) { + const jsonUrl = options.jsonUrl || '/annotations/annotations.json' ... - const saveUrl = defaultSaveUrl - const autosave = true + const saveUrl = options.saveUrl || defaultSaveUrl + const autosave = options.autosave ?? trueAlso applies to: 16-20
84-84: Reduce console noise (guard with debug).Wrap this log with a debug flag or remove before release.
53-62: Note: grouping only by top-level children.serializeGrouped iterates root children only. If nested annotations matter, consider a recursive walk or confirm folders are always one level.
64-81: Offline fallback: consider versioning.When schema changes (e.g., new cameraTarget), consider bumping version or handling both formats during load.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
README.md(2 hunks)index.html(1 hunks)package.json(1 hunks)public/annotations/annotations.json(1 hunks)server.js(1 hunks)src/AnnotationControl/annotationPanel.css(1 hunks)src/AnnotationControl/annotationPanel.js(1 hunks)src/AnnotationControl/persistence.js(1 hunks)src/potreeViewer.js(2 hunks)vite.config.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/AnnotationControl/persistence.js (1)
server.js (1)
data(37-37)
src/AnnotationControl/annotationPanel.js (1)
src/AnnotationControl/persistence.js (2)
root(151-151)initAnnotationPersistence(1-276)
src/potreeViewer.js (1)
src/AnnotationControl/annotationPanel.js (1)
initAnnotationsPanel(20-1010)
🪛 GitHub Actions: Prettier
src/AnnotationControl/annotationPanel.js
[warning] 1-1: Code style issues found in the above file. Run Prettier with --write to fix.
🔇 Additional comments (11)
vite.config.js (1)
1-14: LGTM! Development proxy configuration is correct.The proxy setup correctly routes
/apirequests to the backend server. Thesecure: falsesetting is acceptable for local development but should not be used in production (this config is dev-only).public/annotations/annotations.json (1)
1-4: LGTM! Clean initial state for annotations storage.The structure with a version field supports future schema evolution, and the empty folders object is an appropriate starting point.
README.md (2)
25-29: LGTM! Clear server setup instructions.The server instructions are well-placed and easy to follow.
41-49: LGTM! Helpful structural documentation.The Structure section provides valuable context about the Potree integration and version management.
index.html (1)
41-41: LGTM! Stylesheet link properly added.The annotation panel CSS is correctly linked and positioned with other stylesheets.
src/potreeViewer.js (2)
1-1: LGTM! Clean import following existing patterns.The import is consistent with other control panel imports.
41-41: LGTM! Proper initialization placement.The annotation panel is initialized alongside other panels in the correct location within the GUI setup callback.
src/AnnotationControl/annotationPanel.css (2)
1-10: Heavy use of !important to override third-party styles.While necessary to hide Potree's annotation icon, the multiple
!importantdeclarations make this rule brittle. Ensure this selector remains stable across Potree versions.Verify this selector continues to work after Potree updates by checking the button-icon class and annotation.svg path remain unchanged in the Potree build.
12-365: LGTM! Comprehensive and accessible UI styling.The stylesheet provides:
- Clean visual hierarchy and spacing
- Smooth transitions and interactions
- Proper focus states for accessibility
- Responsive hover and active states
package.json (1)
14-17: Dependencies are secure and free from known vulnerabilities.Verification confirms that express ^4.21.1 and cors ^2.8.5 are not affected by any known vulnerabilities in the GitHub advisory database. Both versions exceed the minimum patched versions for all reported issues. No action required.
src/AnnotationControl/annotationPanel.js (1)
995-1009: Prettier formatting issues resolved.Prettier successfully ran and fixed formatting issues in the file. The changes are ready to commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with the comments Klein left :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (1)
src/AnnotationControl/annotationPanel.js (1)
563-570: Consider making the placeholder position configurable.The hardcoded
PLACEHOLDER_POS = [589748.27, 231444.54, 753.675]is specific to your current dataset or Potree configuration. If you use a different point cloud or Potree version, this constant may not match the actual placeholder, causing valid coordinates to be hidden or placeholder coordinates to be displayed.Consider one of these approaches:
- Pass as an option to
initAnnotationsPanel(viewer, { placeholderPos: [...] }).- Detect dynamically by checking if a newly created annotation has these exact coordinates before placement.
- Use a configurable epsilon and document the expected placeholder for your project.
Example:
+ const PLACEHOLDER_POS = (viewer.config && viewer.config.annotationPlaceholder) + || [589748.27, 231444.54, 753.675]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/AnnotationControl/annotationPanel.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/AnnotationControl/annotationPanel.js (1)
src/AnnotationControl/persistence.js (2)
root(151-151)initAnnotationPersistence(1-276)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (3)
src/AnnotationControl/annotationPanel.js (3)
347-371: Enable Jump when either point or camera is available.
setViewalready guards oncamPos. Don’t disable Jump when point is missing but camera exists.- // Enable or disable jump button depending on whether we have a saved point position + // Enable Jump when either a saved point OR a camera position exists try { - if (pointPos && Array.isArray(pointPos) && pointPos.length === 3) { + const canJumpByPoint = + pointPos && Array.isArray(pointPos) && pointPos.length === 3 + const canJumpByCam = + cam && Array.isArray(cam) && cam.length === 3 + if (canJumpByPoint || canJumpByCam) { jumpBtn.disabled = false jumpBtn.classList.remove('jump-disabled') } else { jumpBtn.disabled = true jumpBtn.classList.add('jump-disabled') } } catch (e) {}Also applies to: 593-601
703-711: Prevent double-commit from blur + keydown in inline editors.Both editors can fire twice (blur and keydown). Add a small “finished” guard.
- function finishInlineEditForUUID(commit) { + let finished = false + function finishInlineEditForUUID(commit) { + if (finished) return + finished = true const newText = commit ? input.value.trim() || oldText : oldText // restore label- function finishInlineDescriptionEdit(commit) { + let finished = false + function finishInlineDescriptionEdit(commit) { + if (finished) return + finished = true const newText = commit ? ta.value.trim() || '' : oldTextAlso applies to: 804-817
342-351: Make toggle control accessible (button + aria-expanded).Use a real button for the triangle toggle and update
aria-expandedon state changes.- const toggle = document.createElement('span') - toggle.className = 'toggle-triangle' - toggle.title = 'Toggle details' + const toggle = document.createElement('button') + toggle.type = 'button' + toggle.className = 'toggle-triangle' + toggle.title = 'Toggle details' + toggle.setAttribute('aria-expanded', 'false')- // Otherwise toggle the row - row.classList.toggle('open') + // Otherwise toggle the row + row.classList.toggle('open') + try { + toggle.setAttribute( + 'aria-expanded', + row.classList.contains('open') ? 'true' : 'false' + ) + } catch (e) {}toggle.addEventListener('click', (ev) => { ev.stopPropagation() - row.classList.toggle('open') + row.classList.toggle('open') + try { + toggle.setAttribute( + 'aria-expanded', + row.classList.contains('open') ? 'true' : 'false' + ) + } catch (e) {} })Also applies to: 496-501, 504-510
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/AnnotationControl/annotationPanel.js(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-23T17:13:41.544Z
Learnt from: franmagn
PR: TDT4290-group-4/MolloyExplorer#38
File: src/AnnotationControl/annotationPanel.js:346-369
Timestamp: 2025-10-23T17:13:41.544Z
Learning: In the MolloyExplorer project's saved locations/annotations feature (src/AnnotationControl/annotationPanel.js and related files), the team has decided to ignore `cameraTarget` and only use `cameraPosition` and `pointPosition` (also referred to as annotation position) when jumping between saved locations.
Applied to files:
src/AnnotationControl/annotationPanel.js
🪛 GitHub Actions: Prettier
src/AnnotationControl/annotationPanel.js
[warning] 1-1: Code style issues found in src/AnnotationControl/annotationPanel.js. Run 'npx prettier --write' to fix.
🔇 Additional comments (3)
src/AnnotationControl/annotationPanel.js (3)
1000-1003: US:5 acceptance: verify export schema includes Camera Target, or document the deviation.Issue #4 requires “Camera Target” in export. The team decision is to ignore
cameraTarget. Please confirm the acceptance criteria were updated or ensure persistence includes a placeholder/derived target. Based on learnings.Would you like me to scan the persistence layer and server endpoint to validate the JSON shape?
1-1: Prettier warning in CI.Run: npx prettier --write src/AnnotationControl/annotationPanel.js
879-897: Bug: earlyreturnaborts live updates when jQuery is missing.
returninside the try exits_commitEditedNameentirely, skipping live annotation updates and UI refresh.function _commitEditedName(uuid, name) { if (!uuid) return // update jsTree node text try { - if (!window.jQuery) return - const tree = window.jQuery('#jstree_scene').jstree && window.jQuery('#jstree_scene').jstree() - if (tree) { + if (window.jQuery) { + const tree = + window.jQuery('#jstree_scene').jstree && + window.jQuery('#jstree_scene').jstree() + if (tree) { const annotationsRoot = tree.get_json('annotations') if (annotationsRoot && annotationsRoot.children) { const node = annotationsRoot.children.find( (c) => (c.data && c.data.uuid) === uuid ) if (node) { _renameJSTreeNode(node.id, name) node.text = name } } - } + } + } } catch (e) {}Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (5)
src/AnnotationControl/annotationPanel.js (5)
57-66: Fix unguarded$reference before jQuery check.Line 59 uses
$directly before checking ifwindow.jQueryexists on line 60, which will throw aReferenceErrorif jQuery isn't loaded.Apply this diff to guard the first check:
header.addEventListener('click', () => { - if ($(menu).accordion && $(menu).data('uiAccordion')) return - if (window.jQuery) { + if ( + window.jQuery && + window.jQuery(menu).accordion && + window.jQuery(menu).data('uiAccordion') + ) { + return + } + if (window.jQuery) { const $p = window.jQuery(panel) $p.is(':visible') ? $p.slideUp(350) : $p.slideDown(350) return } + // Fallback: toggle via style when jQuery unavailable + panel.style.display = panel.style.display === 'none' ? '' : 'none' })
930-1024: Prevent duplicate buttons and event listeners on re-initialization.If
initAnnotationsPanelis called multiple times, it will create duplicate "Add" buttons and register multiple event listeners, leading to memory leaks and unexpected behavior.Apply these diffs:
1. Guard button creation (in
createAddButton):function createAddButton() { + // Prevent duplicate buttons + const host = targetContainer.parentElement + if (host && host.querySelector('.annotation-add-button')) return + const btn = document.createElement('button')2. Guard event listener registration:
// Listen to Potree's annotation events to auto-refresh the list - if (viewer.scene && viewer.scene.annotations) { + if ( + viewer.scene && + viewer.scene.annotations && + !viewer.__annoPanelListeners + ) { + viewer.__annoPanelListeners = true viewer.scene.annotations.addEventListener( 'annotation_added', updateAnnotationsList ) viewer.scene.annotations.addEventListener( 'annotation_removed', updateAnnotationsList ) viewer.scene.annotations.addEventListener( 'annotation_changed', updateAnnotationsList ) }
185-206: Unify onwindow.jQueryinstead of mixingwindow.$and$.The function checks
window.$(line 187) but then uses$.jstreeand$('#jstree_scene')which may not be available. Standardize onwindow.jQuery.Apply this diff:
function _renameJSTreeNode(nodeId, text) { try { - if (window.$ && $.jstree) { - if ($.jstree.reference) { - const ref = $.jstree.reference(nodeId) + if (window.jQuery && (window.jQuery.fn.jstree || window.jQuery.jstree)) { + if (window.jQuery.jstree && window.jQuery.jstree.reference) { + const ref = window.jQuery.jstree.reference(nodeId) if (ref && typeof ref.rename_node === 'function') { ref.rename_node(nodeId, text) return } } // fallback to global selector - if ($('#jstree_scene') && $('#jstree_scene').jstree) { + const $el = window.jQuery('#jstree_scene') + if ($el && $el.jstree) { try { - $('#jstree_scene').jstree('rename_node', nodeId, text) + $el.jstree('rename_node', nodeId, text) return } catch (e) {} } } } catch (e) { // ignore rename failures } }
990-1002: Guard$usage in delayed jsTree access.Line 992 uses
$without checking if jQuery is available, which will throw aReferenceErrorif jQuery isn't loaded.Apply this diff:
setTimeout(() => { - let tree = $('#jstree_scene').jstree && $('#jstree_scene').jstree() - if (!tree || !annotation) return + if (!annotation) return + if (!window.jQuery) { + updateAnnotationsList() + return + } + const $el = window.jQuery('#jstree_scene') + const tree = $el && $el.jstree ? $el.jstree() : null + if (!tree) { + updateAnnotationsList() + return + } // Persist captured camera info on the annotation object so it will be available in the jsTree node data try { if (camPos) annotation.cameraPosition = camPos } catch (e) { console.warn('Could not attach camera info to annotation', e) } updateAnnotationsList() }, 200) // A short delay for Potree/jsTree to update
118-141: Replace$withwindow.jQueryfor consistency after guard checks.After verifying
window.jQueryexists, the code still uses the$alias which may be undefined innoConflictmode or other edge cases. Usewindow.jQueryconsistently.Apply this diff:
function _getJSTree() { try { if (!window.jQuery) return null - return $('#jstree_scene').jstree && $('#jstree_scene').jstree() + const $el = window.jQuery('#jstree_scene') + return $el && $el.jstree ? $el.jstree() : null } catch (e) { return null } } function _getJSTreeInstance() { try { if (!window.jQuery || !window.jQuery.jstree) return null - return ( - ($('#jstree_scene').jstree && $('#jstree_scene').jstree(true)) || - (typeof $.jstree !== 'undefined' && - $.jstree.reference && - $.jstree.reference('#jstree_scene')) || - null - ) + const $el = window.jQuery('#jstree_scene') + return ( + ($el && $el.jstree && $el.jstree(true)) || + (window.jQuery.jstree.reference && + window.jQuery.jstree.reference('#jstree_scene')) || + null + ) } catch (e) { return null } }
🧹 Nitpick comments (2)
src/AnnotationControl/annotationPanel.js (2)
573-580: Document the placeholder position constant.The hardcoded
PLACEHOLDER_POSappears to be Potree's default pre-placement coordinate. Consider extracting it to a named constant at the module level with a comment explaining its source and the Potree version it's valid for. This aids maintainability if Potree is upgraded.Example:
+// Potree's default placeholder coordinates before an annotation is actually placed +// (specific to the current Potree version in use) +const POTREE_PLACEHOLDER_POSITION = [589748.27, 231444.54, 753.675] + export function initAnnotationsPanel(viewer) { // ... existing code ... function approxEqual(a, b, eps = 1e-3) { if (!a || !b || a.length !== b.length) return false for (let i = 0; i < a.length; i++) if (Math.abs(Number(a[i]) - Number(b[i])) > eps) return false return true } - const PLACEHOLDER_POS = [589748.27, 231444.54, 753.675] - if (pointPos && approxEqual(pointPos, PLACEHOLDER_POS)) pointPos = null + if (pointPos && approxEqual(pointPos, POTREE_PLACEHOLDER_POSITION)) pointPos = null
20-1025: Consider extracting helper utilities for better modularity.The 1025-line file with deeply nested helpers works correctly but could benefit from extracting stable utility functions (e.g.,
vecToArray, jQuery helpers, UUID indexing) to a separate module or to module-level scope. This would improve testability and readability, particularly for the 363-lineupdateAnnotationsListfunction.This is a nice-to-have improvement for future refactoring, not a blocker.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/AnnotationControl/annotationPanel.js(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-23T17:13:41.544Z
Learnt from: franmagn
PR: TDT4290-group-4/MolloyExplorer#38
File: src/AnnotationControl/annotationPanel.js:346-369
Timestamp: 2025-10-23T17:13:41.544Z
Learning: In the MolloyExplorer project's saved locations/annotations feature (src/AnnotationControl/annotationPanel.js and related files), the team has decided to ignore `cameraTarget` and only use `cameraPosition` and `pointPosition` (also referred to as annotation position) when jumping between saved locations.
Applied to files:
src/AnnotationControl/annotationPanel.js
🧬 Code graph analysis (1)
src/AnnotationControl/annotationPanel.js (1)
src/AnnotationControl/persistence.js (2)
root(151-151)initAnnotationPersistence(1-276)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Issue number
Closes #4
Description
Testing steps
When testing this feature, remember to run "npm install", start the server in a separate terminal using "npm run server" and you also have to restart the dev server with "npm run dev". Then go to the "Saved locations" section in the sidebar and try saving, editing and deleting annotations
Screenshots (optional)
Summary by CodeRabbit
New Features
Style
Chores
Documentation