mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			v0.27.2-be
			...
			v0.27.3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 3b8d7b8fba | ||
|  | 9fca7f09a5 | ||
|  | fd39d6b3a9 | ||
|  | a103886ea5 | ||
|  | 373408e401 | ||
|  | db44c1d8e6 | ||
|  | 95a34c9e2d | 
| @@ -18,6 +18,7 @@ Trilium Notes is a hierarchical note taking application with focus on building l | ||||
| * [Relation maps](https://github.com/zadam/trilium/wiki/Relation-map) for visualizing notes and their relations | ||||
| * [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases) | ||||
| * Scales well in both usability and performance upwards of 100 000 notes | ||||
| * Touch optimized [mobile frontend](https://github.com/zadam/trilium/wiki/Mobile-frontend) for smartphones and tablets | ||||
| * [Night theme](https://github.com/zadam/trilium/wiki/Themes) | ||||
| * [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) and [Markdown import & export](https://github.com/zadam/trilium/wiki/Markdown) | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "trilium", | ||||
|   "version": "0.27.1-beta", | ||||
|   "version": "0.27.2-beta", | ||||
|   "lockfileVersion": 1, | ||||
|   "requires": true, | ||||
|   "dependencies": { | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|   "name": "trilium", | ||||
|   "productName": "Trilium Notes", | ||||
|   "description": "Trilium Notes", | ||||
|   "version": "0.27.2-beta", | ||||
|   "version": "0.27.3", | ||||
|   "license": "AGPL-3.0-only", | ||||
|   "main": "electron.js", | ||||
|   "bin": { | ||||
|   | ||||
| @@ -158,7 +158,11 @@ class TreeCache { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         treeCache.childParentToBranch[childNoteId + '-' + newParentNoteId] = treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId]; | ||||
|         const branchId = treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId]; | ||||
|         const branch = await this.getBranch(branchId); | ||||
|         branch.parentNoteId = newParentNoteId; | ||||
|  | ||||
|         treeCache.childParentToBranch[childNoteId + '-' + newParentNoteId] = branchId; | ||||
|         delete treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId]; // this is correct because we know that oldParentId isn't same as newParentId | ||||
|  | ||||
|         // remove old associations | ||||
|   | ||||
| @@ -45,14 +45,23 @@ | ||||
| #header button { | ||||
|     padding: 1px 5px 1px 5px; | ||||
|     font-size: small; | ||||
|     margin-bottom: 2px; | ||||
|     margin-top: 2px; | ||||
|     margin-right: 8px; | ||||
| } | ||||
|  | ||||
| #history-navigation { | ||||
|     margin: 0 15px 0 5px; | ||||
|     position: relative; | ||||
|     top: 2px; | ||||
| } | ||||
|  | ||||
| #global-buttons { | ||||
|     display: flex; | ||||
|     justify-content: space-around; | ||||
|     padding: 10px 0 10px 0; | ||||
|     margin: 0 10px 0 16px; | ||||
|     border: 1px solid #ccc; | ||||
|     margin: 0 20px 0 10px; | ||||
|     border: 1px solid #ddd; | ||||
|     border-radius: 5px; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -155,17 +155,6 @@ span.fancytree-active:not(.fancytree-focused) .fancytree-title { | ||||
|     color: #337ab7 !important; | ||||
| } | ||||
|  | ||||
| #header-title { | ||||
|     padding: 5px 20px 5px 10px; | ||||
|     font-size: large; | ||||
|     font-weight: bold; | ||||
| } | ||||
|  | ||||
| #header .btn-sm { | ||||
|     margin-bottom: 2px; | ||||
|     margin-right: 8px; | ||||
| } | ||||
|  | ||||
| div.ui-tooltip { | ||||
|     max-width: 600px; | ||||
|     max-height: 600px; | ||||
| @@ -377,13 +366,8 @@ div.ui-tooltip { | ||||
|     height: 150px; | ||||
| } | ||||
|  | ||||
| #history-navigation { | ||||
|     margin: 0 20px 0 5px; | ||||
|     display: flex; | ||||
| } | ||||
|  | ||||
| .btn:not(.btn-primary):not(.btn-danger) { | ||||
|     border-color: #bbb; | ||||
|     border-color: #ddd; | ||||
|     background-color: #eee; | ||||
| } | ||||
|  | ||||
| @@ -544,7 +528,8 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th | ||||
|     max-height: 300px; | ||||
|     overflow: hidden; | ||||
|     color: black; | ||||
|     border: 1px solid #aaa; | ||||
|     border: 1px solid #ccc; | ||||
|     border-radius: 5px; | ||||
|     text-align: left; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| module.exports = { buildDate:"2019-01-04T23:33:32+01:00", buildRevision: "5d74dcd2564ff1341550ade1250aa9d790abc056" }; | ||||
| module.exports = { buildDate:"2019-01-05T22:48:11+01:00", buildRevision: "9fca7f09a564c719c834d38d76c3b595c8579b2a" }; | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| const sql = require('./sql'); | ||||
| const sqlInit = require('./sql_init'); | ||||
| const optionService = require('./options'); | ||||
| const dateUtils = require('./date_utils'); | ||||
| const syncTableService = require('./sync_table'); | ||||
| @@ -408,10 +409,12 @@ async function cleanupDeletedNotes() { | ||||
|     await sql.execute("UPDATE note_revisions SET content = NULL WHERE note_revisions.content IS NOT NULL AND noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1 AND notes.dateModified <= ?)", [dateUtils.dateStr(cutoffDate)]); | ||||
| } | ||||
|  | ||||
| // first cleanup kickoff 5 minutes after startup | ||||
| setTimeout(cls.wrap(cleanupDeletedNotes), 5 * 60 * 1000); | ||||
| sqlInit.dbReady.then(() => { | ||||
|     // first cleanup kickoff 5 minutes after startup | ||||
|     setTimeout(cls.wrap(cleanupDeletedNotes), 5 * 60 * 1000); | ||||
|  | ||||
| setInterval(cls.wrap(cleanupDeletedNotes), 4 * 3600 * 1000); | ||||
|     setInterval(cls.wrap(cleanupDeletedNotes), 4 * 3600 * 1000); | ||||
| }); | ||||
|  | ||||
| module.exports = { | ||||
|     createNewNote, | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|         <div id="history-navigation" style="display: none;"> | ||||
|             <a id="history-back-button" title="Go to previous note." class="icon-action jam jam-arrow-square-left"></a> | ||||
|  | ||||
|                 | ||||
|               | ||||
|  | ||||
|             <a id="history-forward-button" title="Go to next note." class="icon-action jam jam-arrow-square-right"></a> | ||||
|         </div> | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
|                 <div id="confirm-dialog-custom"></div> | ||||
|             </div> | ||||
|             <div class="modal-footer"> | ||||
|                 <button class="btn btn-default btn-sm" id="confirm-dialog-cancel-button">Cancel</button> | ||||
|                 <button class="btn btn-secondary btn-sm" id="confirm-dialog-cancel-button">Cancel</button> | ||||
|  | ||||
|                   | ||||
|  | ||||
|   | ||||
| @@ -108,7 +108,7 @@ | ||||
|                                 <div style="display: flex; justify-content: space-between;"> | ||||
|                                     <button class="btn btn-primary">Save</button> | ||||
|  | ||||
|                                     <button class="btn btn-default" type="button" data-help-page="Protected-notes">Help</button> | ||||
|                                     <button class="btn btn-secondary" type="button" data-help-page="Protected-notes">Help</button> | ||||
|                                 </div> | ||||
|                             </form> | ||||
|                         </div> | ||||
| @@ -125,7 +125,7 @@ | ||||
|                                 <div style="display: flex; justify-content: space-between;"> | ||||
|                                     <button class="btn btn-primary">Save</button> | ||||
|  | ||||
|                                     <button class="btn btn-default" type="button" data-help-page="Note-revisions">Help</button> | ||||
|                                     <button class="btn btn-secondary" type="button" data-help-page="Note-revisions">Help</button> | ||||
|                                 </div> | ||||
|                             </form> | ||||
|                         </div> | ||||
| @@ -154,7 +154,7 @@ | ||||
|                                 <div style="display: flex; justify-content: space-between;"> | ||||
|                                     <button class="btn btn-primary">Save</button> | ||||
|  | ||||
|                                     <button class="btn btn-default" type="button" data-help-page="Synchronization">Help</button> | ||||
|                                     <button class="btn btn-secondary" type="button" data-help-page="Synchronization">Help</button> | ||||
|                                 </div> | ||||
|                             </form> | ||||
|  | ||||
| @@ -164,24 +164,24 @@ | ||||
|  | ||||
|                             <p>This will test connection and handshake to the sync server. If sync server isn't initialized, this will set it up to sync with local document.</p> | ||||
|  | ||||
|                             <button id="test-sync-button" class="btn btn-default">Test sync</button> | ||||
|                             <button id="test-sync-button" class="btn btn-secondary">Test sync</button> | ||||
|                         </div> | ||||
|  | ||||
|                         <div id="advanced" class="tab-pane"> | ||||
|                             <h4 style="margin-top: 0px;">Sync</h4> | ||||
|                             <button id="force-full-sync-button" class="btn btn-default">Force full sync</button> | ||||
|                             <button id="force-full-sync-button" class="btn btn-secondary">Force full sync</button> | ||||
|  | ||||
|                             <br/> | ||||
|                             <br/> | ||||
|  | ||||
|                             <button id="fill-sync-rows-button" class="btn btn-default">Fill sync rows</button> | ||||
|                             <button id="fill-sync-rows-button" class="btn btn-secondary">Fill sync rows</button> | ||||
|  | ||||
|                             <br/> | ||||
|                             <br/> | ||||
|  | ||||
|                             <h4>Debugging</h4> | ||||
|  | ||||
|                             <button id="anonymize-button" class="btn btn-default">Save anonymized database</button><br/><br/> | ||||
|                             <button id="anonymize-button" class="btn btn-secondary">Save anonymized database</button><br/><br/> | ||||
|  | ||||
|                             <p>This action will create a new copy of the database and anonymise it (remove all note content and leave only structure and metadata) | ||||
|                                 for sharing online for debugging purposes without fear of leaking your personal data.</p> | ||||
| @@ -190,7 +190,7 @@ | ||||
|  | ||||
|                             <p>This will rebuild database which will typically result in smaller database file. No data will be actually changed.</p> | ||||
|  | ||||
|                             <button id="vacuum-database-button" class="btn btn-default">Vacuum database</button> | ||||
|                             <button id="vacuum-database-button" class="btn btn-secondary">Vacuum database</button> | ||||
|                         </div> | ||||
|  | ||||
|                         <div id="about" class="tab-pane"> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
| </head> | ||||
| <body> | ||||
| <div class="container"> | ||||
|     <div class="col-md-5 offset-md-3" style="padding-top: 25px;"> | ||||
|     <div class="col-xs-12 col-sm-10 col-md-6 col-lg-4 col-xl-4 mx-auto" style="padding-top: 25px;"> | ||||
|         <h1>Trilium login</h1> | ||||
|  | ||||
|         <% if (failedAuth) { %> | ||||
| @@ -60,6 +60,8 @@ | ||||
|         device = /Mobi/.test(navigator.userAgent) ? "mobile" : "desktop"; | ||||
|     } | ||||
|  | ||||
|     console.log("Setting device cookie to:", device); | ||||
|  | ||||
|     setCookie("trilium-device", device); | ||||
|  | ||||
|     function setCookie(name, value) { | ||||
|   | ||||
| @@ -2,113 +2,116 @@ | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> | ||||
|     <title>Setup</title> | ||||
| </head> | ||||
| <body> | ||||
| <div id="setup-dialog" style="width: 700px; margin: auto; padding-top: 50px; display:none; font-size: larger;"> | ||||
|     <h1>Trilium Notes setup</h1> | ||||
| <div class="container"> | ||||
|     <div id="setup-dialog" class="col-md-12 col-lg-8 col-xl-6 mx-auto" style="padding-top: 25px;"> | ||||
|         <h1>Trilium Notes setup</h1> | ||||
|  | ||||
|     <div class="alert alert-warning" id="alert" style="display: none;"> | ||||
|     </div> | ||||
|  | ||||
|     <div id="setup-type" data-bind="visible: step() == 'setup-type'" style="margin-top: 20px;"> | ||||
|         <div class="radio" style="margin-bottom: 15px;"> | ||||
|             <label><input type="radio" name="setup-type" value="new-document" data-bind="checked: setupType"> | ||||
|                 I'm a new user and I want to create new Trilium document for my notes</label> | ||||
|         </div> | ||||
|         <div class="radio" data-bind="if: instanceType == 'server'" style="margin-bottom: 15px;"> | ||||
|             <label><input type="radio" name="setup-type" value="sync-from-desktop" data-bind="checked: setupType"> | ||||
|                 I have desktop instance already and I want to setup sync with it</label> | ||||
|         </div> | ||||
|         <div class="radio" data-bind="if: instanceType == 'desktop'" style="margin-bottom: 15px;"> | ||||
|             <label><input type="radio" name="setup-type" value="sync-from-server" data-bind="checked: setupType"> | ||||
|                 I have server instance up and I want to setup sync with it</label> | ||||
|         <div class="alert alert-warning" id="alert" style="display: none;"> | ||||
|         </div> | ||||
|  | ||||
|         <button type="button" data-bind="disable: !setupTypeSelected(), click: selectSetupType" class="btn btn-primary">Next</button> | ||||
|     </div> | ||||
|         <div id="setup-type" data-bind="visible: step() == 'setup-type'" style="margin-top: 20px;"> | ||||
|             <div class="radio" style="margin-bottom: 15px;"> | ||||
|                 <label><input type="radio" name="setup-type" value="new-document" data-bind="checked: setupType"> | ||||
|                     I'm a new user and I want to create new Trilium document for my notes</label> | ||||
|             </div> | ||||
|             <div class="radio" data-bind="if: instanceType == 'server'" style="margin-bottom: 15px;"> | ||||
|                 <label><input type="radio" name="setup-type" value="sync-from-desktop" data-bind="checked: setupType"> | ||||
|                     I have desktop instance already and I want to setup sync with it</label> | ||||
|             </div> | ||||
|             <div class="radio" data-bind="if: instanceType == 'desktop'" style="margin-bottom: 15px;"> | ||||
|                 <label><input type="radio" name="setup-type" value="sync-from-server" data-bind="checked: setupType"> | ||||
|                     I have server instance up and I want to setup sync with it</label> | ||||
|             </div> | ||||
|  | ||||
|     <div data-bind="visible: step() == 'new-document'"> | ||||
|         <h2>New document</h2> | ||||
|  | ||||
|         <p>You're almost done with the setup. The last thing is to choose username and password using which you'll login to the application. | ||||
|             This password is also used for generating encryption key which encrypts protected notes.</p> | ||||
|  | ||||
|         <div class="form-group"> | ||||
|             <label for="username">Username</label> | ||||
|             <input type="text" class="form-control" data-bind="value: username" placeholder="Choose alphanumeric username"> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|             <label for="password1">Password</label> | ||||
|             <input type="password" class="form-control" data-bind="value: password1" placeholder="Password"> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|             <label for="password2">Repeat password</label> | ||||
|             <input type="password" class="form-control" data-bind="value: password2" placeholder="Password"> | ||||
|             <button type="button" data-bind="disable: !setupTypeSelected(), click: selectSetupType" class="btn btn-primary">Next</button> | ||||
|         </div> | ||||
|  | ||||
|         <button type="button" data-bind="click: back" class="btn btn-default">Back</button> | ||||
|         <div data-bind="visible: step() == 'new-document'"> | ||||
|             <h2>New document</h2> | ||||
|  | ||||
|           | ||||
|             <p>You're almost done with the setup. The last thing is to choose username and password using which you'll login to the application. | ||||
|                 This password is also used for generating encryption key which encrypts protected notes.</p> | ||||
|  | ||||
|         <button type="button" data-bind="click: finish" class="btn btn-primary">Finish setup</button> | ||||
|     </div> | ||||
|             <div class="form-group"> | ||||
|                 <label for="username">Username</label> | ||||
|                 <input type="text" class="form-control" data-bind="value: username" placeholder="Choose alphanumeric username"> | ||||
|             </div> | ||||
|             <div class="form-group"> | ||||
|                 <label for="password1">Password</label> | ||||
|                 <input type="password" class="form-control" data-bind="value: password1" placeholder="Password"> | ||||
|             </div> | ||||
|             <div class="form-group"> | ||||
|                 <label for="password2">Repeat password</label> | ||||
|                 <input type="password" class="form-control" data-bind="value: password2" placeholder="Password"> | ||||
|             </div> | ||||
|  | ||||
|     <div data-bind="visible: step() == 'sync-from-desktop'"> | ||||
|         <h2>Sync from Desktop</h2> | ||||
|             <button type="button" data-bind="click: back" class="btn btn-secondary">Back</button> | ||||
|  | ||||
|         <p>This setup needs to be initiated from the desktop instance:</p> | ||||
|               | ||||
|  | ||||
|         <ol> | ||||
|             <li>please open your desktop instance of Trilium Notes</li> | ||||
|             <li>click on Options button in the top right</li> | ||||
|             <li>click on Sync tab</li> | ||||
|             <li>configure server instance address to the: <span id="current-host"></span> and click save.</li> | ||||
|             <li>click on "Test sync" button</li> | ||||
|             <li>once you've done all this, click <a href="/">here</a></li> | ||||
|         </ol> | ||||
|  | ||||
|         <button type="button" data-bind="click: back" class="btn btn-default">Back</button> | ||||
|     </div> | ||||
|  | ||||
|     <div data-bind="visible: step() == 'sync-from-server'"> | ||||
|         <h2>Sync from Server</h2> | ||||
|  | ||||
|         <p>Please enter Trilium server address and credentials below. This will download the whole Trilium document from server and setup sync to it. Depending on the document size and your connection speed, this may take a while.</p> | ||||
|  | ||||
|         <div class="form-group"> | ||||
|             <label for="sync-server-host">Trilium server address</label> | ||||
|             <input type="text" id="syncServerHost" class="form-control" data-bind="value: syncServerHost" placeholder="https://<hostname>:<port>"> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|             <label for="sync-proxy">Proxy server (optional)</label> | ||||
|             <input type="text" id="sync-proxy" class="form-control" data-bind="value: syncProxy" placeholder="https://<hostname>:<port>"> | ||||
|  | ||||
|             <p><strong>Note:</strong> If you leave proxy setting blank, system proxy will be used (applies to desktop/electron build only)</p> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|             <label for="username">Username</label> | ||||
|             <input type="text" id="username" class="form-control" data-bind="value: username" placeholder="Username"> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|             <label for="password1">Password</label> | ||||
|             <input type="password" id="password1" class="form-control" data-bind="value: password1" placeholder="Password"> | ||||
|             <button type="button" data-bind="click: finish" class="btn btn-primary">Finish setup</button> | ||||
|         </div> | ||||
|  | ||||
|         <button type="button" data-bind="click: back" class="btn btn-default">Back</button> | ||||
|         <div data-bind="visible: step() == 'sync-from-desktop'"> | ||||
|             <h2>Sync from Desktop</h2> | ||||
|  | ||||
|           | ||||
|             <p>This setup needs to be initiated from the desktop instance:</p> | ||||
|  | ||||
|         <button type="button" data-bind="click: finish" class="btn btn-primary">Finish setup</button> | ||||
|     </div> | ||||
|             <ol> | ||||
|                 <li>please open your desktop instance of Trilium Notes</li> | ||||
|                 <li>click on Options button in the top right</li> | ||||
|                 <li>click on Sync tab</li> | ||||
|                 <li>configure server instance address to the: <span id="current-host"></span> and click save.</li> | ||||
|                 <li>click on "Test sync" button</li> | ||||
|                 <li>once you've done all this, click <a href="/">here</a></li> | ||||
|             </ol> | ||||
|  | ||||
|     <div data-bind="visible: step() == 'sync-in-progress'"> | ||||
|         <h2>Sync in progress</h2> | ||||
|             <button type="button" data-bind="click: back" class="btn btn-secondary">Back</button> | ||||
|         </div> | ||||
|  | ||||
|         <div class="alert alert-success">Sync has been correctly set up. It will take some time for the initial sync to finish. Once it's done, you'll be redirected to the login page.</div> | ||||
|         <div data-bind="visible: step() == 'sync-from-server'"> | ||||
|             <h2>Sync from Server</h2> | ||||
|  | ||||
|         <div data-bind="if: instanceType == 'desktop'"> | ||||
|             Outstanding sync items: <strong id="outstanding-syncs">N/A</strong> | ||||
|             <p>Please enter Trilium server address and credentials below. This will download the whole Trilium document from server and setup sync to it. Depending on the document size and your connection speed, this may take a while.</p> | ||||
|  | ||||
|             <div class="form-group"> | ||||
|                 <label for="sync-server-host">Trilium server address</label> | ||||
|                 <input type="text" id="syncServerHost" class="form-control" data-bind="value: syncServerHost" placeholder="https://<hostname>:<port>"> | ||||
|             </div> | ||||
|             <div class="form-group"> | ||||
|                 <label for="sync-proxy">Proxy server (optional)</label> | ||||
|                 <input type="text" id="sync-proxy" class="form-control" data-bind="value: syncProxy" placeholder="https://<hostname>:<port>"> | ||||
|  | ||||
|                 <p><strong>Note:</strong> If you leave proxy setting blank, system proxy will be used (applies to desktop/electron build only)</p> | ||||
|             </div> | ||||
|             <div class="form-group"> | ||||
|                 <label for="username">Username</label> | ||||
|                 <input type="text" id="username" class="form-control" data-bind="value: username" placeholder="Username"> | ||||
|             </div> | ||||
|             <div class="form-group"> | ||||
|                 <label for="password1">Password</label> | ||||
|                 <input type="password" id="password1" class="form-control" data-bind="value: password1" placeholder="Password"> | ||||
|             </div> | ||||
|  | ||||
|             <button type="button" data-bind="click: back" class="btn btn-secondary">Back</button> | ||||
|  | ||||
|               | ||||
|  | ||||
|             <button type="button" data-bind="click: finish" class="btn btn-primary">Finish setup</button> | ||||
|         </div> | ||||
|  | ||||
|         <div data-bind="visible: step() == 'sync-in-progress'"> | ||||
|             <h2>Sync in progress</h2> | ||||
|  | ||||
|             <div class="alert alert-success">Sync has been correctly set up. It will take some time for the initial sync to finish. Once it's done, you'll be redirected to the login page.</div> | ||||
|  | ||||
|             <div data-bind="if: instanceType == 'desktop'"> | ||||
|                 Outstanding sync items: <strong id="outstanding-syncs">N/A</strong> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user