Complete LinkSyncServer and LinkSyncExtension implementation
LinkSyncServer: - Fix app.py imports, add CORS middleware, lifespan events - Create api/routes.py router aggregator - Create config/settings.py for centralized configuration - Rewrite models/base.py with proper relationships and serialization - Rewrite all API endpoints with real DB integration (auth, links, collections, sync, queries, tags) - Add admin endpoints (user management, stats, audit log) - Complete query parser with recursive descent and proper precedence - Complete query executor with set operations and field filters - Set up Alembic migrations with initial schema - Create web interface (templates, CSS, JS) - Add 42 passing tests (auth, links, collections, queries) - Add deploy.ps1 and deploy.sh scripts - Update README with deployment workflow LinkSyncExtension: - Create utils/api.js (REST client with retries, auth, error handling) - Create utils/sync.js (3 sync modes + conflict detection) - Create utils/collection.js (collection management) - Create utils/query-engine.js (client-side query parser) - Rewrite background.js (sync loop, bookmark events, message routing) - Rewrite popup.js (tabs, settings modal, notifications, CRUD) - Update popup.html (tabbed interface, query builder, modal) - Update popup.css (full redesign) - Create content/content.js (page metadata extraction) - Create options.html/js (dedicated settings page) - Generate icons (48x48, 96x96) - Update manifest.json (host permissions, content scripts, options) - Create AGENTS.md
This commit is contained in:
@@ -8,71 +8,151 @@
|
||||
<body>
|
||||
<header>
|
||||
<h1>LinkSync</h1>
|
||||
</header>
|
||||
|
||||
<section id="sync-status">
|
||||
<span id="sync-indicator"></span>
|
||||
<span id="last-sync"></span>
|
||||
</section>
|
||||
|
||||
<!-- Add/Edit Form -->
|
||||
<section id="bookmark-form">
|
||||
<h2>Add Bookmark</h2>
|
||||
<form id="bookmark-form">
|
||||
<div class="form-group">
|
||||
<label for="url">URL:</label>
|
||||
<input type="url" id="url" placeholder="https://example.com" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="title">Title:</label>
|
||||
<input type="text" id="title" placeholder="Page title">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Description:</label>
|
||||
<textarea id="description" rows="2"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">Notes:</label>
|
||||
<textarea id="notes" rows="2"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="tags">Tags:</label>
|
||||
<input type="text" id="tags" placeholder="work, personal, dev (comma-separated)">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="folder">Folder:</label>
|
||||
<input type="text" id="folder" placeholder="path/to/folder">
|
||||
</div>
|
||||
|
||||
<button type="submit" id="submit">Add Bookmark</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- Bookmark List -->
|
||||
<section id="bookmark-list">
|
||||
<h2>Bookmarks</h2>
|
||||
<div id="search-filter">
|
||||
<input type="text" id="search" placeholder="Search bookmarks...">
|
||||
<div id="sync-status">
|
||||
<span id="sync-indicator"></span>
|
||||
<span id="last-sync">Not synced yet</span>
|
||||
</div>
|
||||
<div id="bookmarks-container"></div>
|
||||
</header>
|
||||
|
||||
<div id="notification-container"></div>
|
||||
|
||||
<!-- Tabs -->
|
||||
<nav id="tabs">
|
||||
<button class="tab active" data-tab="bookmarks">Bookmarks</button>
|
||||
<button class="tab" data-tab="collections">Collections</button>
|
||||
<button class="tab" data-tab="query">Query</button>
|
||||
</nav>
|
||||
|
||||
<!-- Bookmarks Tab -->
|
||||
<section id="tab-bookmarks" class="tab-content active">
|
||||
<section id="bookmark-form">
|
||||
<h2>Add Bookmark</h2>
|
||||
<form id="add-bookmark-form">
|
||||
<div class="form-group">
|
||||
<label for="url">URL</label>
|
||||
<input type="url" id="url" placeholder="https://example.com" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="title">Title</label>
|
||||
<input type="text" id="title" placeholder="Page title">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<textarea id="description" rows="2" placeholder="Page description"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="notes">Notes</label>
|
||||
<textarea id="notes" rows="2" placeholder="Your notes"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="tags">Tags</label>
|
||||
<input type="text" id="tags" placeholder="work, personal, dev">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="folder">Folder</label>
|
||||
<input type="text" id="folder" placeholder="path/to/folder">
|
||||
</div>
|
||||
<button type="submit" id="submit-btn">Add Bookmark</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section id="bookmark-list">
|
||||
<div id="search-filter">
|
||||
<input type="text" id="search" placeholder="Search bookmarks...">
|
||||
</div>
|
||||
<div id="bookmarks-container">
|
||||
<p class="empty-state">Loading bookmarks...</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- Collections Panel -->
|
||||
<section id="collections-panel">
|
||||
<h2>Collections</h2>
|
||||
<div id="collections-list"></div>
|
||||
|
||||
<!-- Collections Tab -->
|
||||
<section id="tab-collections" class="tab-content">
|
||||
<section id="collections-panel">
|
||||
<h2>Collections</h2>
|
||||
<div id="collections-container">
|
||||
<p class="empty-state">Loading collections...</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Query Tab -->
|
||||
<section id="tab-query" class="tab-content">
|
||||
<section id="query-panel">
|
||||
<h2>Query Builder</h2>
|
||||
<div class="form-group">
|
||||
<label for="query-input">Expression</label>
|
||||
<input type="text" id="query-input" placeholder="('work', 'dev') OR tag:work">
|
||||
</div>
|
||||
<div class="query-actions">
|
||||
<button id="parse-btn" class="btn-small">Parse</button>
|
||||
<button id="execute-btn" class="btn-small btn-primary">Execute</button>
|
||||
</div>
|
||||
<div id="query-result"></div>
|
||||
<div class="query-help">
|
||||
<p>Syntax: <code>('term1', 'term2') OR tag:work AND url:example.com</code></p>
|
||||
<p>Precedence: <code>()</code> > XOR > AND > OR</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<button id="sync-btn">Sync Now</button>
|
||||
<button id="settings-btn">Settings</button>
|
||||
</footer>
|
||||
|
||||
|
||||
<!-- Settings Modal -->
|
||||
<div id="settings-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>Settings</h2>
|
||||
<button id="close-settings" class="close-btn">×</button>
|
||||
</div>
|
||||
<form id="settings-form">
|
||||
<div class="form-group">
|
||||
<label for="server-url">Server URL</label>
|
||||
<input type="url" id="server-url" placeholder="http://localhost:5000" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="api-key">API Key</label>
|
||||
<div class="input-with-toggle">
|
||||
<input type="password" id="api-key" placeholder="Your API key">
|
||||
<button type="button" id="toggle-key" class="toggle-btn">Show</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="sync-mode">Sync Mode</label>
|
||||
<select id="sync-mode">
|
||||
<option value="bi-directional">Bi-directional</option>
|
||||
<option value="browser-authoritative">Browser Authoritative</option>
|
||||
<option value="server-authoritative">Server Authoritative</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group checkbox-group">
|
||||
<label>
|
||||
<input type="checkbox" id="deletions">
|
||||
Enable deletions
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group checkbox-group">
|
||||
<label>
|
||||
<input type="checkbox" id="auto-sync">
|
||||
Auto-sync every 5 minutes
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-actions">
|
||||
<button type="button" id="test-connection" class="btn-small">Test Connection</button>
|
||||
<button type="submit" class="btn-primary">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="utils/api.js"></script>
|
||||
<script src="utils/sync.js"></script>
|
||||
<script src="utils/collection.js"></script>
|
||||
<script src="utils/query-engine.js"></script>
|
||||
<script src="utils/bookmark.js"></script>
|
||||
<script src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user