mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Feature: support sorting sidebar saved views (#4381)
This commit is contained in:
		| @@ -421,11 +421,11 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">207</context> |           <context context-type="linenumber">218</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">210</context> |           <context context-type="linenumber">221</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="3894950702316166331" datatype="html"> |       <trans-unit id="3894950702316166331" datatype="html"> | ||||||
| @@ -511,11 +511,11 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">185</context> |           <context context-type="linenumber">196</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">188</context> |           <context context-type="linenumber">199</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1685061484835793745" datatype="html"> |       <trans-unit id="1685061484835793745" datatype="html"> | ||||||
| @@ -1355,67 +1355,67 @@ | |||||||
|         <source>Saved view "<x id="PH" equiv-text="savedView.name"/>" deleted.</source> |         <source>Saved view "<x id="PH" equiv-text="savedView.name"/>" deleted.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">362</context> |           <context context-type="linenumber">370</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="3891152409365583719" datatype="html"> |       <trans-unit id="3891152409365583719" datatype="html"> | ||||||
|         <source>Settings saved</source> |         <source>Settings saved</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">484</context> |           <context context-type="linenumber">492</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="7217000812750597833" datatype="html"> |       <trans-unit id="7217000812750597833" datatype="html"> | ||||||
|         <source>Settings were saved successfully.</source> |         <source>Settings were saved successfully.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">485</context> |           <context context-type="linenumber">493</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="525012668859298131" datatype="html"> |       <trans-unit id="525012668859298131" datatype="html"> | ||||||
|         <source>Settings were saved successfully. Reload is required to apply some changes.</source> |         <source>Settings were saved successfully. Reload is required to apply some changes.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">489</context> |           <context context-type="linenumber">497</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="8491974984518503778" datatype="html"> |       <trans-unit id="8491974984518503778" datatype="html"> | ||||||
|         <source>Reload now</source> |         <source>Reload now</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">490</context> |           <context context-type="linenumber">498</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="3011185103048412841" datatype="html"> |       <trans-unit id="3011185103048412841" datatype="html"> | ||||||
|         <source>An error occurred while saving settings.</source> |         <source>An error occurred while saving settings.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">500</context> |           <context context-type="linenumber">508</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context> | ||||||
|           <context context-type="linenumber">104</context> |           <context context-type="linenumber">114</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="6839066544204061364" datatype="html"> |       <trans-unit id="6839066544204061364" datatype="html"> | ||||||
|         <source>Use system language</source> |         <source>Use system language</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">508</context> |           <context context-type="linenumber">516</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="7729897675462249787" datatype="html"> |       <trans-unit id="7729897675462249787" datatype="html"> | ||||||
|         <source>Use date format of display language</source> |         <source>Use date format of display language</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">515</context> |           <context context-type="linenumber">523</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="5260584511980773458" datatype="html"> |       <trans-unit id="5260584511980773458" datatype="html"> | ||||||
|         <source>Error while storing settings on server.</source> |         <source>Error while storing settings on server.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> |           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context> | ||||||
|           <context context-type="linenumber">538</context> |           <context context-type="linenumber">546</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="2991443309752293110" datatype="html"> |       <trans-unit id="2991443309752293110" datatype="html"> | ||||||
| @@ -1426,7 +1426,7 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">199</context> |           <context context-type="linenumber">210</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="103921551219467537" datatype="html"> |       <trans-unit id="103921551219467537" datatype="html"> | ||||||
| @@ -1635,11 +1635,11 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">192</context> |           <context context-type="linenumber">203</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">195</context> |           <context context-type="linenumber">206</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="4555457172864212828" datatype="html"> |       <trans-unit id="4555457172864212828" datatype="html"> | ||||||
| @@ -1969,11 +1969,11 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">214</context> |           <context context-type="linenumber">225</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">217</context> |           <context context-type="linenumber">228</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="6570363013146073520" datatype="html"> |       <trans-unit id="6570363013146073520" datatype="html"> | ||||||
| @@ -2026,36 +2026,36 @@ | |||||||
|         <source>Open documents</source> |         <source>Open documents</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">107</context> |           <context context-type="linenumber">118</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="5687256342387781369" datatype="html"> |       <trans-unit id="5687256342387781369" datatype="html"> | ||||||
|         <source>Close all</source> |         <source>Close all</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">123</context> |           <context context-type="linenumber">134</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">126</context> |           <context context-type="linenumber">137</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="3897348120591552265" datatype="html"> |       <trans-unit id="3897348120591552265" datatype="html"> | ||||||
|         <source>Manage</source> |         <source>Manage</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">133</context> |           <context context-type="linenumber">144</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="7437910965833684826" datatype="html"> |       <trans-unit id="7437910965833684826" datatype="html"> | ||||||
|         <source>Correspondents</source> |         <source>Correspondents</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">137</context> |           <context context-type="linenumber">148</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">140</context> |           <context context-type="linenumber">151</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context> |           <context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context> | ||||||
| @@ -2066,11 +2066,11 @@ | |||||||
|         <source>Tags</source> |         <source>Tags</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">144</context> |           <context context-type="linenumber">155</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">147</context> |           <context context-type="linenumber">158</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/common/input/tags/tags.component.ts</context> |           <context context-type="sourcefile">src/app/components/common/input/tags/tags.component.ts</context> | ||||||
| @@ -2097,102 +2097,116 @@ | |||||||
|         <source>Document types</source> |         <source>Document types</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">151</context> |           <context context-type="linenumber">162</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">154</context> |           <context context-type="linenumber">165</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="8835528846812581148" datatype="html"> |       <trans-unit id="8835528846812581148" datatype="html"> | ||||||
|         <source>Storage paths</source> |         <source>Storage paths</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">158</context> |           <context context-type="linenumber">169</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">161</context> |           <context context-type="linenumber">172</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="4462691404891390153" datatype="html"> |       <trans-unit id="4462691404891390153" datatype="html"> | ||||||
|         <source>Consumption templates</source> |         <source>Consumption templates</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">165</context> |           <context context-type="linenumber">176</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="5433675495457939071" datatype="html"> |       <trans-unit id="5433675495457939071" datatype="html"> | ||||||
|         <source>Templates</source> |         <source>Templates</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">168</context> |           <context context-type="linenumber">179</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1292737233370901804" datatype="html"> |       <trans-unit id="1292737233370901804" datatype="html"> | ||||||
|         <source>Mail</source> |         <source>Mail</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">172</context> |           <context context-type="linenumber">183</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">175</context> |           <context context-type="linenumber">186</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="7844706011418789951" datatype="html"> |       <trans-unit id="7844706011418789951" datatype="html"> | ||||||
|         <source>Administration</source> |         <source>Administration</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">181</context> |           <context context-type="linenumber">192</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="5537285341303594392" datatype="html"> |       <trans-unit id="5537285341303594392" datatype="html"> | ||||||
|         <source>File Tasks<x id="START_TAG_SPAN_1" ctype="x-span_1" equiv-text="<span *ngIf="tasksService.failedFileTasks.length > 0">"/><x id="START_TAG_SPAN" ctype="x-span" equiv-text="<span class="badge bg-danger ms-2">"/><x id="INTERPOLATION" equiv-text="{{tasksService.failedFileTasks.length}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="</span>"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="</span>"/></source> |         <source>File Tasks<x id="START_TAG_SPAN_1" ctype="x-span_1" equiv-text="<span *ngIf="tasksService.failedFileTasks.length > 0">"/><x id="START_TAG_SPAN" ctype="x-span" equiv-text="<span class="badge bg-danger ms-2">"/><x id="INTERPOLATION" equiv-text="{{tasksService.failedFileTasks.length}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="</span>"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="</span>"/></source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">203</context> |           <context context-type="linenumber">214</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1534029177398918729" datatype="html"> |       <trans-unit id="1534029177398918729" datatype="html"> | ||||||
|         <source>GitHub</source> |         <source>GitHub</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">223</context> |           <context context-type="linenumber">234</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="4112664765954374539" datatype="html"> |       <trans-unit id="4112664765954374539" datatype="html"> | ||||||
|         <source>is available.</source> |         <source>is available.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">229</context> |           <context context-type="linenumber">240</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1175891574282637937" datatype="html"> |       <trans-unit id="1175891574282637937" datatype="html"> | ||||||
|         <source>Click to view.</source> |         <source>Click to view.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">229</context> |           <context context-type="linenumber">240</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="9811291095862612" datatype="html"> |       <trans-unit id="9811291095862612" datatype="html"> | ||||||
|         <source>Paperless-ngx can automatically check for updates</source> |         <source>Paperless-ngx can automatically check for updates</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">233</context> |           <context context-type="linenumber">244</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="894819944961861800" datatype="html"> |       <trans-unit id="894819944961861800" datatype="html"> | ||||||
|         <source> How does this work? </source> |         <source> How does this work? </source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|           <context context-type="linenumber">240,242</context> |           <context context-type="linenumber">251,253</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="509090351011426949" datatype="html"> |       <trans-unit id="509090351011426949" datatype="html"> | ||||||
|         <source>Update available</source> |         <source>Update available</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context> | ||||||
|  |           <context context-type="linenumber">262</context> | ||||||
|  |         </context-group> | ||||||
|  |       </trans-unit> | ||||||
|  |       <trans-unit id="1542489069631984294" datatype="html"> | ||||||
|  |         <source>Sidebar views updated</source> | ||||||
|  |         <context-group purpose="location"> | ||||||
|  |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context> | ||||||
|  |           <context context-type="linenumber">248</context> | ||||||
|  |         </context-group> | ||||||
|  |       </trans-unit> | ||||||
|  |       <trans-unit id="3547923076537026828" datatype="html"> | ||||||
|  |         <source>Error updating sidebar views</source> | ||||||
|  |         <context-group purpose="location"> | ||||||
|  |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context> | ||||||
|           <context context-type="linenumber">251</context> |           <context context-type="linenumber">251</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
| @@ -2200,7 +2214,7 @@ | |||||||
|         <source>An error occurred while saving update checking settings.</source> |         <source>An error occurred while saving update checking settings.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context> |           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context> | ||||||
|           <context context-type="linenumber">237</context> |           <context context-type="linenumber">272</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="8700121026680200191" datatype="html"> |       <trans-unit id="8700121026680200191" datatype="html"> | ||||||
| @@ -3612,28 +3626,28 @@ | |||||||
|         <source>Hello <x id="PH" equiv-text="this.settingsService.displayName"/>, welcome to Paperless-ngx</source> |         <source>Hello <x id="PH" equiv-text="this.settingsService.displayName"/>, welcome to Paperless-ngx</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> |           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> | ||||||
|           <context context-type="linenumber">53</context> |           <context context-type="linenumber">38</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="5334686081082652461" datatype="html"> |       <trans-unit id="5334686081082652461" datatype="html"> | ||||||
|         <source>Welcome to Paperless-ngx</source> |         <source>Welcome to Paperless-ngx</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> |           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> | ||||||
|           <context context-type="linenumber">55</context> |           <context context-type="linenumber">40</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1325877348738783391" datatype="html"> |       <trans-unit id="1325877348738783391" datatype="html"> | ||||||
|         <source>Dashboard updated</source> |         <source>Dashboard updated</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> |           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> | ||||||
|           <context context-type="linenumber">86</context> |           <context context-type="linenumber">71</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="3214475953924351473" datatype="html"> |       <trans-unit id="3214475953924351473" datatype="html"> | ||||||
|         <source>Error updating dashboard</source> |         <source>Error updating dashboard</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> |           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> | ||||||
|           <context context-type="linenumber">89</context> |           <context context-type="linenumber">74</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="2946624699882754313" datatype="html"> |       <trans-unit id="2946624699882754313" datatype="html"> | ||||||
| @@ -5999,224 +6013,224 @@ | |||||||
|         <source>English (US)</source> |         <source>English (US)</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">154</context> |           <context context-type="linenumber">155</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="7318555235181361185" datatype="html"> |       <trans-unit id="7318555235181361185" datatype="html"> | ||||||
|         <source>Afrikaans</source> |         <source>Afrikaans</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">160</context> |           <context context-type="linenumber">161</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="6269202464699193298" datatype="html"> |       <trans-unit id="6269202464699193298" datatype="html"> | ||||||
|         <source>Arabic</source> |         <source>Arabic</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">166</context> |           <context context-type="linenumber">167</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="3098941349689899577" datatype="html"> |       <trans-unit id="3098941349689899577" datatype="html"> | ||||||
|         <source>Belarusian</source> |         <source>Belarusian</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">172</context> |           <context context-type="linenumber">173</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1001043467371963032" datatype="html"> |       <trans-unit id="1001043467371963032" datatype="html"> | ||||||
|         <source>Catalan</source> |         <source>Catalan</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">178</context> |           <context context-type="linenumber">179</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="2719780722934172508" datatype="html"> |       <trans-unit id="2719780722934172508" datatype="html"> | ||||||
|         <source>Czech</source> |         <source>Czech</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">184</context> |           <context context-type="linenumber">185</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="2924289692679201020" datatype="html"> |       <trans-unit id="2924289692679201020" datatype="html"> | ||||||
|         <source>Danish</source> |         <source>Danish</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">190</context> |           <context context-type="linenumber">191</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1858110241312746425" datatype="html"> |       <trans-unit id="1858110241312746425" datatype="html"> | ||||||
|         <source>German</source> |         <source>German</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">196</context> |           <context context-type="linenumber">197</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="7067741492320440272" datatype="html"> |       <trans-unit id="7067741492320440272" datatype="html"> | ||||||
|         <source>Greek</source> |         <source>Greek</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">202</context> |           <context context-type="linenumber">203</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="6987083569809053351" datatype="html"> |       <trans-unit id="6987083569809053351" datatype="html"> | ||||||
|         <source>English (GB)</source> |         <source>English (GB)</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">208</context> |           <context context-type="linenumber">209</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="5190825892106392539" datatype="html"> |       <trans-unit id="5190825892106392539" datatype="html"> | ||||||
|         <source>Spanish</source> |         <source>Spanish</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">214</context> |           <context context-type="linenumber">215</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="861663369293303028" datatype="html"> |       <trans-unit id="861663369293303028" datatype="html"> | ||||||
|         <source>Finnish</source> |         <source>Finnish</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">220</context> |           <context context-type="linenumber">221</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="7633754075223722162" datatype="html"> |       <trans-unit id="7633754075223722162" datatype="html"> | ||||||
|         <source>French</source> |         <source>French</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">226</context> |           <context context-type="linenumber">227</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="2935232983274991580" datatype="html"> |       <trans-unit id="2935232983274991580" datatype="html"> | ||||||
|         <source>Italian</source> |         <source>Italian</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">232</context> |           <context context-type="linenumber">233</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1334425850005897370" datatype="html"> |       <trans-unit id="1334425850005897370" datatype="html"> | ||||||
|         <source>Luxembourgish</source> |         <source>Luxembourgish</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">238</context> |           <context context-type="linenumber">239</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="3071065188816255493" datatype="html"> |       <trans-unit id="3071065188816255493" datatype="html"> | ||||||
|         <source>Dutch</source> |         <source>Dutch</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">244</context> |           <context context-type="linenumber">245</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="8069284467804715623" datatype="html"> |       <trans-unit id="8069284467804715623" datatype="html"> | ||||||
|         <source>Norwegian</source> |         <source>Norwegian</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">250</context> |           <context context-type="linenumber">251</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="792060551707690640" datatype="html"> |       <trans-unit id="792060551707690640" datatype="html"> | ||||||
|         <source>Polish</source> |         <source>Polish</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">256</context> |           <context context-type="linenumber">257</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="9184513005098760425" datatype="html"> |       <trans-unit id="9184513005098760425" datatype="html"> | ||||||
|         <source>Portuguese (Brazil)</source> |         <source>Portuguese (Brazil)</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">262</context> |           <context context-type="linenumber">263</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="153799456510623899" datatype="html"> |       <trans-unit id="153799456510623899" datatype="html"> | ||||||
|         <source>Portuguese</source> |         <source>Portuguese</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">268</context> |           <context context-type="linenumber">269</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="8118856427047826368" datatype="html"> |       <trans-unit id="8118856427047826368" datatype="html"> | ||||||
|         <source>Romanian</source> |         <source>Romanian</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">274</context> |           <context context-type="linenumber">275</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="7137419789978325708" datatype="html"> |       <trans-unit id="7137419789978325708" datatype="html"> | ||||||
|         <source>Russian</source> |         <source>Russian</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">280</context> |           <context context-type="linenumber">281</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="9102963095355753902" datatype="html"> |       <trans-unit id="9102963095355753902" datatype="html"> | ||||||
|         <source>Slovak</source> |         <source>Slovak</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">286</context> |           <context context-type="linenumber">287</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="4287008301409320881" datatype="html"> |       <trans-unit id="4287008301409320881" datatype="html"> | ||||||
|         <source>Slovenian</source> |         <source>Slovenian</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">292</context> |           <context context-type="linenumber">293</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="8608389829607915090" datatype="html"> |       <trans-unit id="8608389829607915090" datatype="html"> | ||||||
|         <source>Serbian</source> |         <source>Serbian</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">298</context> |           <context context-type="linenumber">299</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="499386805970351976" datatype="html"> |       <trans-unit id="499386805970351976" datatype="html"> | ||||||
|         <source>Swedish</source> |         <source>Swedish</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">304</context> |           <context context-type="linenumber">305</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="5682359291233237791" datatype="html"> |       <trans-unit id="5682359291233237791" datatype="html"> | ||||||
|         <source>Turkish</source> |         <source>Turkish</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">310</context> |           <context context-type="linenumber">311</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="3578644052206125685" datatype="html"> |       <trans-unit id="3578644052206125685" datatype="html"> | ||||||
|         <source>Ukrainian</source> |         <source>Ukrainian</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">316</context> |           <context context-type="linenumber">317</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="4689443708886954687" datatype="html"> |       <trans-unit id="4689443708886954687" datatype="html"> | ||||||
|         <source>Chinese Simplified</source> |         <source>Chinese Simplified</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">322</context> |           <context context-type="linenumber">323</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="4912706592792948707" datatype="html"> |       <trans-unit id="4912706592792948707" datatype="html"> | ||||||
|         <source>ISO 8601</source> |         <source>ISO 8601</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">339</context> |           <context context-type="linenumber">340</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="313643372755303297" datatype="html"> |       <trans-unit id="313643372755303297" datatype="html"> | ||||||
|         <source>Successfully completed one-time migratration of settings to the database!</source> |         <source>Successfully completed one-time migratration of settings to the database!</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">458</context> |           <context context-type="linenumber">459</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="5558341108007064934" datatype="html"> |       <trans-unit id="5558341108007064934" datatype="html"> | ||||||
|         <source>Unable to migrate settings to the database, please try saving manually.</source> |         <source>Unable to migrate settings to the database, please try saving manually.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> |           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||||
|           <context context-type="linenumber">459</context> |           <context context-type="linenumber">460</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1168781785897678748" datatype="html"> |       <trans-unit id="1168781785897678748" datatype="html"> | ||||||
|   | |||||||
| @@ -180,11 +180,23 @@ describe('SettingsComponent', () => { | |||||||
|     activatedRoute.snapshot.fragment = '#notifications' |     activatedRoute.snapshot.fragment = '#notifications' | ||||||
|     const scrollSpy = jest.spyOn(viewportScroller, 'scrollToAnchor') |     const scrollSpy = jest.spyOn(viewportScroller, 'scrollToAnchor') | ||||||
|     component.ngOnInit() |     component.ngOnInit() | ||||||
|     expect(component.activeNavID).toEqual(3) // Users & Groups |     expect(component.activeNavID).toEqual(3) // Notifications | ||||||
|     component.ngAfterViewInit() |     component.ngAfterViewInit() | ||||||
|     expect(scrollSpy).toHaveBeenCalledWith('#notifications') |     expect(scrollSpy).toHaveBeenCalledWith('#notifications') | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|  |   it('should enable organizing of sidebar saved views even on direct navigation', () => { | ||||||
|  |     completeSetup() | ||||||
|  |     jest | ||||||
|  |       .spyOn(activatedRoute, 'paramMap', 'get') | ||||||
|  |       .mockReturnValue(of(convertToParamMap({ section: 'savedviews' }))) | ||||||
|  |     activatedRoute.snapshot.fragment = '#savedviews' | ||||||
|  |     component.ngOnInit() | ||||||
|  |     expect(component.activeNavID).toEqual(4) // Saved Views | ||||||
|  |     component.ngAfterViewInit() | ||||||
|  |     expect(settingsService.organizingSidebarSavedViews).toBeTruthy() | ||||||
|  |   }) | ||||||
|  |  | ||||||
|   it('should support save saved views, show error', () => { |   it('should support save saved views, show error', () => { | ||||||
|     completeSetup() |     completeSetup() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -194,6 +194,9 @@ export class SettingsComponent | |||||||
|         if (navIDKey) { |         if (navIDKey) { | ||||||
|           this.activeNavID = SettingsNavIDs[navIDKey] |           this.activeNavID = SettingsNavIDs[navIDKey] | ||||||
|         } |         } | ||||||
|  |         if (this.activeNavID === SettingsNavIDs.SavedViews) { | ||||||
|  |           this.settings.organizingSidebarSavedViews = true | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| @@ -275,11 +278,15 @@ export class SettingsComponent | |||||||
|       this.router |       this.router | ||||||
|         .navigate(['settings', foundNavIDkey.toLowerCase()]) |         .navigate(['settings', foundNavIDkey.toLowerCase()]) | ||||||
|         .then((navigated) => { |         .then((navigated) => { | ||||||
|  |           this.settings.organizingSidebarSavedViews = false | ||||||
|           if (!navigated && this.isDirty) { |           if (!navigated && this.isDirty) { | ||||||
|             this.activeNavID = navChangeEvent.activeId |             this.activeNavID = navChangeEvent.activeId | ||||||
|           } else if (navigated && this.isDirty) { |           } else if (navigated && this.isDirty) { | ||||||
|             this.initialize() |             this.initialize() | ||||||
|           } |           } | ||||||
|  |           if (this.activeNavID === SettingsNavIDs.SavedViews) { | ||||||
|  |             this.settings.organizingSidebarSavedViews = true | ||||||
|  |           } | ||||||
|         }) |         }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -352,6 +359,7 @@ export class SettingsComponent | |||||||
|   ngOnDestroy() { |   ngOnDestroy() { | ||||||
|     if (this.isDirty) this.settings.updateAppearanceSettings() // in case user changed appearance but didnt save |     if (this.isDirty) this.settings.updateAppearanceSettings() // in case user changed appearance but didnt save | ||||||
|     this.storeSub && this.storeSub.unsubscribe() |     this.storeSub && this.storeSub.unsubscribe() | ||||||
|  |     this.settings.organizingSidebarSavedViews = false | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   deleteSavedView(savedView: PaperlessSavedView) { |   deleteSavedView(savedView: PaperlessSavedView) { | ||||||
|   | |||||||
| @@ -87,17 +87,28 @@ | |||||||
|           </li> |           </li> | ||||||
|         </ul> |         </ul> | ||||||
|         <ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.SavedView }"> |         <ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.SavedView }"> | ||||||
|           <h6 class="sidebar-heading px-3 mt-3 mb-1 text-muted" *ngIf='savedViewService.loading || savedViewService.sidebarViews.length > 0'> |           <h6 class="sidebar-heading px-3 mt-3 mb-1 text-muted" *ngIf='savedViewService.loading || sidebarViews?.length > 0'> | ||||||
|             <span i18n>Saved views</span> |             <span i18n>Saved views</span> | ||||||
|             <div *ngIf="savedViewService.loading" class="spinner-border spinner-border-sm fw-normal ms-2" role="status"></div> |             <div *ngIf="savedViewService.loading" class="spinner-border spinner-border-sm fw-normal ms-2" role="status"></div> | ||||||
|           </h6> |           </h6> | ||||||
|           <ul class="nav flex-column mb-2"> |           <ul class="nav flex-column mb-2" cdkDropList (cdkDropListDropped)="onDrop($event)"> | ||||||
|             <li class="nav-item w-100" *ngFor="let view of savedViewService.sidebarViews"> |             <li class="nav-item w-100" *ngFor="let view of sidebarViews" | ||||||
|  |               cdkDrag | ||||||
|  |               [cdkDragDisabled]="!settingsService.organizingSidebarSavedViews" | ||||||
|  |               cdkDragPreviewContainer="parent" | ||||||
|  |               cdkDragPreviewClass="navItemDrag" | ||||||
|  |               (cdkDragStarted)="onDragStart($event)" | ||||||
|  |               (cdkDragEnded)="onDragEnd($event)"> | ||||||
|               <a class="nav-link" [class.text-truncate]="!slimSidebarEnabled" routerLink="view/{{view.id}}" routerLinkActive="active" (click)="closeMenu()" [ngbPopover]="view.name" [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim"> |               <a class="nav-link" [class.text-truncate]="!slimSidebarEnabled" routerLink="view/{{view.id}}" routerLinkActive="active" (click)="closeMenu()" [ngbPopover]="view.name" [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim"> | ||||||
|                 <svg class="sidebaricon" fill="currentColor"> |                 <svg class="sidebaricon" fill="currentColor"> | ||||||
|                   <use xlink:href="assets/bootstrap-icons.svg#funnel"/> |                   <use xlink:href="assets/bootstrap-icons.svg#funnel"/> | ||||||
|                 </svg><span> {{view.name}}</span> |                 </svg><span> {{view.name}}</span> | ||||||
|               </a> |               </a> | ||||||
|  |               <div *ngIf="settingsService.organizingSidebarSavedViews" class="position-absolute end-0 top-0 px-3 py-2" [class.me-n3]="slimSidebarEnabled" cdkDragHandle> | ||||||
|  |                 <svg class="sidebaricon text-muted" fill="currentColor"> | ||||||
|  |                   <use xlink:href="assets/bootstrap-icons.svg#grip-vertical"/> | ||||||
|  |                 </svg> | ||||||
|  |               </div> | ||||||
|             </li> |             </li> | ||||||
|           </ul> |           </ul> | ||||||
|         </ng-container> |         </ng-container> | ||||||
|   | |||||||
| @@ -169,6 +169,7 @@ main { | |||||||
|  |  | ||||||
| .nav-item { | .nav-item { | ||||||
|   position: relative; |   position: relative; | ||||||
|  |   list-style-type: none; | ||||||
|  |  | ||||||
|   &:hover .close { |   &:hover .close { | ||||||
|     display: block; |     display: block; | ||||||
| @@ -310,3 +311,11 @@ main { | |||||||
|     opacity: 100%; |     opacity: 100%; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .nav-item .position-absolute { | ||||||
|  |   cursor: move; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ::ng-deep .navItemDrag .position-absolute svg { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings' | |||||||
| import { RemoteVersionService } from 'src/app/services/rest/remote-version.service' | import { RemoteVersionService } from 'src/app/services/rest/remote-version.service' | ||||||
| import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' | import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' | ||||||
| import { FormsModule, ReactiveFormsModule } from '@angular/forms' | import { FormsModule, ReactiveFormsModule } from '@angular/forms' | ||||||
| import { of } from 'rxjs' | import { of, throwError } from 'rxjs' | ||||||
| import { ToastService } from 'src/app/services/toast.service' | import { ToastService } from 'src/app/services/toast.service' | ||||||
| import { environment } from 'src/environments/environment' | import { environment } from 'src/environments/environment' | ||||||
| import { OpenDocumentsService } from 'src/app/services/open-documents.service' | import { OpenDocumentsService } from 'src/app/services/open-documents.service' | ||||||
| @@ -30,7 +30,47 @@ import { DocumentListViewService } from 'src/app/services/document-list-view.ser | |||||||
| import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type' | import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type' | ||||||
| import { routes } from 'src/app/app-routing.module' | import { routes } from 'src/app/app-routing.module' | ||||||
| import { PermissionsGuard } from 'src/app/guards/permissions.guard' | import { PermissionsGuard } from 'src/app/guards/permissions.guard' | ||||||
|  | import { CdkDragDrop } from '@angular/cdk/drag-drop' | ||||||
|  | import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' | ||||||
|  |  | ||||||
|  | const saved_views = [ | ||||||
|  |   { | ||||||
|  |     name: 'Saved View 0', | ||||||
|  |     id: 0, | ||||||
|  |     show_on_dashboard: true, | ||||||
|  |     show_in_sidebar: true, | ||||||
|  |     sort_field: 'name', | ||||||
|  |     sort_reverse: true, | ||||||
|  |     filter_rules: [], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     name: 'Saved View 1', | ||||||
|  |     id: 1, | ||||||
|  |     show_on_dashboard: false, | ||||||
|  |     show_in_sidebar: false, | ||||||
|  |     sort_field: 'name', | ||||||
|  |     sort_reverse: true, | ||||||
|  |     filter_rules: [], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     name: 'Saved View 2', | ||||||
|  |     id: 2, | ||||||
|  |     show_on_dashboard: true, | ||||||
|  |     show_in_sidebar: true, | ||||||
|  |     sort_field: 'name', | ||||||
|  |     sort_reverse: true, | ||||||
|  |     filter_rules: [], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     name: 'Saved View 3', | ||||||
|  |     id: 3, | ||||||
|  |     show_on_dashboard: true, | ||||||
|  |     show_in_sidebar: true, | ||||||
|  |     sort_field: 'name', | ||||||
|  |     sort_reverse: true, | ||||||
|  |     filter_rules: [], | ||||||
|  |   }, | ||||||
|  | ] | ||||||
| const document = { id: 2, title: 'Hello world' } | const document = { id: 2, title: 'Hello world' } | ||||||
|  |  | ||||||
| describe('AppFrameComponent', () => { | describe('AppFrameComponent', () => { | ||||||
| @@ -60,7 +100,19 @@ describe('AppFrameComponent', () => { | |||||||
|       ], |       ], | ||||||
|       providers: [ |       providers: [ | ||||||
|         SettingsService, |         SettingsService, | ||||||
|         SavedViewService, |         { | ||||||
|  |           provide: SavedViewService, | ||||||
|  |           useValue: { | ||||||
|  |             initialize: () => {}, | ||||||
|  |             listAll: () => | ||||||
|  |               of({ | ||||||
|  |                 all: [saved_views.map((v) => v.id)], | ||||||
|  |                 count: saved_views.length, | ||||||
|  |                 results: saved_views, | ||||||
|  |               }), | ||||||
|  |             sidebarViews: saved_views.filter((v) => v.show_in_sidebar), | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|         PermissionsService, |         PermissionsService, | ||||||
|         RemoteVersionService, |         RemoteVersionService, | ||||||
|         IfPermissionsDirective, |         IfPermissionsDirective, | ||||||
| @@ -269,4 +321,45 @@ describe('AppFrameComponent', () => { | |||||||
|       }, |       }, | ||||||
|     ]) |     ]) | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|  |   it('should disable global dropzone on start drag + drop, re-enable after', () => { | ||||||
|  |     expect(settingsService.globalDropzoneEnabled).toBeTruthy() | ||||||
|  |     component.onDragStart(null) | ||||||
|  |     expect(settingsService.globalDropzoneEnabled).toBeFalsy() | ||||||
|  |     component.onDragEnd(null) | ||||||
|  |     expect(settingsService.globalDropzoneEnabled).toBeTruthy() | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   it('should update saved view sorting on drag + drop, show info', () => { | ||||||
|  |     const settingsSpy = jest.spyOn(settingsService, 'updateSidebarViewsSort') | ||||||
|  |     const toastSpy = jest.spyOn(toastService, 'showInfo') | ||||||
|  |     jest.spyOn(settingsService, 'storeSettings').mockReturnValue(of(true)) | ||||||
|  |     component.onDrop({ previousIndex: 0, currentIndex: 1 } as CdkDragDrop< | ||||||
|  |       PaperlessSavedView[] | ||||||
|  |     >) | ||||||
|  |     expect(settingsSpy).toHaveBeenCalledWith([ | ||||||
|  |       saved_views[2], | ||||||
|  |       saved_views[0], | ||||||
|  |       saved_views[3], | ||||||
|  |     ]) | ||||||
|  |     expect(toastSpy).toHaveBeenCalled() | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   it('should update saved view sorting on drag + drop, show error', () => { | ||||||
|  |     jest.spyOn(settingsService, 'get').mockImplementation((key) => { | ||||||
|  |       if (key === SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER) return [] | ||||||
|  |     }) | ||||||
|  |     fixture.destroy() | ||||||
|  |     fixture = TestBed.createComponent(AppFrameComponent) | ||||||
|  |     component = fixture.componentInstance | ||||||
|  |     fixture.detectChanges() | ||||||
|  |     const toastSpy = jest.spyOn(toastService, 'showError') | ||||||
|  |     jest | ||||||
|  |       .spyOn(settingsService, 'storeSettings') | ||||||
|  |       .mockReturnValue(throwError(() => new Error('unable to save'))) | ||||||
|  |     component.onDrop({ previousIndex: 0, currentIndex: 2 } as CdkDragDrop< | ||||||
|  |       PaperlessSavedView[] | ||||||
|  |     >) | ||||||
|  |     expect(toastSpy).toHaveBeenCalled() | ||||||
|  |   }) | ||||||
| }) | }) | ||||||
|   | |||||||
| @@ -32,6 +32,13 @@ import { | |||||||
|   PermissionsService, |   PermissionsService, | ||||||
|   PermissionType, |   PermissionType, | ||||||
| } from 'src/app/services/permissions.service' | } from 'src/app/services/permissions.service' | ||||||
|  | import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' | ||||||
|  | import { | ||||||
|  |   CdkDragStart, | ||||||
|  |   CdkDragEnd, | ||||||
|  |   CdkDragDrop, | ||||||
|  |   moveItemInArray, | ||||||
|  | } from '@angular/cdk/drag-drop' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'pngx-app-frame', |   selector: 'pngx-app-frame', | ||||||
| @@ -42,6 +49,17 @@ export class AppFrameComponent | |||||||
|   extends ComponentWithPermissions |   extends ComponentWithPermissions | ||||||
|   implements OnInit, ComponentCanDeactivate |   implements OnInit, ComponentCanDeactivate | ||||||
| { | { | ||||||
|  |   versionString = `${environment.appTitle} ${environment.version}` | ||||||
|  |   appRemoteVersion: AppRemoteVersion | ||||||
|  |  | ||||||
|  |   isMenuCollapsed: boolean = true | ||||||
|  |  | ||||||
|  |   slimSidebarAnimating: boolean = false | ||||||
|  |  | ||||||
|  |   searchField = new FormControl('') | ||||||
|  |  | ||||||
|  |   sidebarViews: PaperlessSavedView[] | ||||||
|  |  | ||||||
|   constructor( |   constructor( | ||||||
|     public router: Router, |     public router: Router, | ||||||
|     private activatedRoute: ActivatedRoute, |     private activatedRoute: ActivatedRoute, | ||||||
| @@ -63,7 +81,7 @@ export class AppFrameComponent | |||||||
|         PermissionType.SavedView |         PermissionType.SavedView | ||||||
|       ) |       ) | ||||||
|     ) { |     ) { | ||||||
|       savedViewService.initialize() |       this.savedViewService.initialize() | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -72,15 +90,12 @@ export class AppFrameComponent | |||||||
|       this.checkForUpdates() |       this.checkForUpdates() | ||||||
|     } |     } | ||||||
|     this.tasksService.reload() |     this.tasksService.reload() | ||||||
|  |  | ||||||
|  |     this.savedViewService.listAll().subscribe(() => { | ||||||
|  |       this.sidebarViews = this.savedViewService.sidebarViews | ||||||
|  |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   versionString = `${environment.appTitle} ${environment.version}` |  | ||||||
|   appRemoteVersion: AppRemoteVersion |  | ||||||
|  |  | ||||||
|   isMenuCollapsed: boolean = true |  | ||||||
|  |  | ||||||
|   slimSidebarAnimating: boolean = false |  | ||||||
|  |  | ||||||
|   toggleSlimSidebar(): void { |   toggleSlimSidebar(): void { | ||||||
|     this.slimSidebarAnimating = true |     this.slimSidebarAnimating = true | ||||||
|     this.slimSidebarEnabled = !this.slimSidebarEnabled |     this.slimSidebarEnabled = !this.slimSidebarEnabled | ||||||
| @@ -121,8 +136,6 @@ export class AppFrameComponent | |||||||
|     return !this.openDocumentsService.hasDirty() |     return !this.openDocumentsService.hasDirty() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   searchField = new FormControl('') |  | ||||||
|  |  | ||||||
|   get searchFieldEmpty(): boolean { |   get searchFieldEmpty(): boolean { | ||||||
|     return this.searchField.value.trim().length == 0 |     return this.searchField.value.trim().length == 0 | ||||||
|   } |   } | ||||||
| @@ -218,6 +231,27 @@ export class AppFrameComponent | |||||||
|       }) |       }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   onDragStart(event: CdkDragStart) { | ||||||
|  |     this.settingsService.globalDropzoneEnabled = false | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   onDragEnd(event: CdkDragEnd) { | ||||||
|  |     this.settingsService.globalDropzoneEnabled = true | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   onDrop(event: CdkDragDrop<PaperlessSavedView[]>) { | ||||||
|  |     moveItemInArray(this.sidebarViews, event.previousIndex, event.currentIndex) | ||||||
|  |  | ||||||
|  |     this.settingsService.updateSidebarViewsSort(this.sidebarViews).subscribe({ | ||||||
|  |       next: () => { | ||||||
|  |         this.toastService.showInfo($localize`Sidebar views updated`) | ||||||
|  |       }, | ||||||
|  |       error: (e) => { | ||||||
|  |         this.toastService.showError($localize`Error updating sidebar views`, e) | ||||||
|  |       }, | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   private checkForUpdates() { |   private checkForUpdates() { | ||||||
|     this.remoteVersionService |     this.remoteVersionService | ||||||
|       .checkForUpdates() |       .checkForUpdates() | ||||||
|   | |||||||
| @@ -1,19 +1,3 @@ | |||||||
| .col-sidebar .row { | .col-sidebar .row { | ||||||
|     top: 3.5rem; |     top: 3.5rem; | ||||||
| } | } | ||||||
|  |  | ||||||
| :host ::ng-deep { |  | ||||||
|     .cdk-drag-placeholder { |  | ||||||
|       opacity: .5; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* Animate items as they're being sorted. */ |  | ||||||
|     .cdk-drop-list-dragging .cdk-drag { |  | ||||||
|       transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* Animate an item that has been dropped. */ |  | ||||||
|     .cdk-drag-animating { |  | ||||||
|       transition: transform 300ms cubic-bezier(0, 0, 0.2, 1); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -29,22 +29,7 @@ export class DashboardComponent extends ComponentWithPermissions { | |||||||
|     super() |     super() | ||||||
|  |  | ||||||
|     this.savedViewService.listAll().subscribe(() => { |     this.savedViewService.listAll().subscribe(() => { | ||||||
|       const sorted: number[] = this.settingsService.get( |       this.dashboardViews = this.savedViewService.dashboardViews | ||||||
|         SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER |  | ||||||
|       ) |  | ||||||
|       this.dashboardViews = |  | ||||||
|         sorted?.length > 0 |  | ||||||
|           ? sorted |  | ||||||
|               .map((id) => |  | ||||||
|                 this.savedViewService.dashboardViews.find((v) => v.id === id) |  | ||||||
|               ) |  | ||||||
|               .concat( |  | ||||||
|                 this.savedViewService.dashboardViews.filter( |  | ||||||
|                   (v) => !sorted.includes(v.id) |  | ||||||
|                 ) |  | ||||||
|               ) |  | ||||||
|               .filter((v) => v) |  | ||||||
|           : [...this.savedViewService.dashboardViews] |  | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ | |||||||
|         <div class="d-flex justify-content-between align-items-center my-2"> |         <div class="d-flex justify-content-between align-items-center my-2"> | ||||||
|           <div class="progress flex-grow-1"> |           <div class="progress flex-grow-1"> | ||||||
|             <div *ngFor="let filetype of statistics?.document_file_type_counts; let i = index; let last = last" |             <div *ngFor="let filetype of statistics?.document_file_type_counts; let i = index; let last = last" | ||||||
|               class="progress-bar bg-primary text-primary-contrast" |               class="progress-bar bg-primary" | ||||||
|               role="progressbar" |               role="progressbar" | ||||||
|               [ngbPopover]="getFileTypeName(filetype)" |               [ngbPopover]="getFileTypeName(filetype)" | ||||||
|               i18n-ngbPopover |               i18n-ngbPopover | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| <ngb-alert class="pe-3" type="primary" [dismissible]="true" (closed)="dismiss.emit(true)"> | <ngb-alert class="pe-3 text-primary-contrast" type="primary" [dismissible]="true" (closed)="dismiss.emit(true)"> | ||||||
|   <h4 class="alert-heading"><ng-container i18n>Paperless-ngx is running!</ng-container> 🎉</h4> |   <h4 class="alert-heading"><ng-container i18n>Paperless-ngx is running!</ng-container> 🎉</h4> | ||||||
|   <p i18n>You're ready to start uploading documents! Explore the various features of this web app on your own, or start a quick tour using the button below.</p> |   <p i18n>You're ready to start uploading documents! Explore the various features of this web app on your own, or start a quick tour using the button below.</p> | ||||||
|   <p i18n>More detail on how to use and configure Paperless-ngx is always available in the <a href="https://docs.paperless-ngx.com" target="_blank">documentation</a>.</p> |   <p i18n>More detail on how to use and configure Paperless-ngx is always available in the <a href="https://docs.paperless-ngx.com" target="_blank">documentation</a>.</p> | ||||||
|   | |||||||
| @@ -43,6 +43,8 @@ export const SETTINGS_KEYS = { | |||||||
|     'general-settings:saved-views:warn-on-unsaved-change', |     'general-settings:saved-views:warn-on-unsaved-change', | ||||||
|   DASHBOARD_VIEWS_SORT_ORDER: |   DASHBOARD_VIEWS_SORT_ORDER: | ||||||
|     'general-settings:saved-views:dashboard-views-sort-order', |     'general-settings:saved-views:dashboard-views-sort-order', | ||||||
|  |   SIDEBAR_VIEWS_SORT_ORDER: | ||||||
|  |     'general-settings:saved-views:sidebar-views-sort-order', | ||||||
|   TOUR_COMPLETE: 'general-settings:tour-complete', |   TOUR_COMPLETE: 'general-settings:tour-complete', | ||||||
|   DEFAULT_PERMS_OWNER: 'general-settings:permissions:default-owner', |   DEFAULT_PERMS_OWNER: 'general-settings:permissions:default-owner', | ||||||
|   DEFAULT_PERMS_VIEW_USERS: 'general-settings:permissions:default-view-users', |   DEFAULT_PERMS_VIEW_USERS: 'general-settings:permissions:default-view-users', | ||||||
| @@ -187,4 +189,9 @@ export const SETTINGS: PaperlessUiSetting[] = [ | |||||||
|     type: 'array', |     type: 'array', | ||||||
|     default: [], |     default: [], | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     key: SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER, | ||||||
|  |     type: 'array', | ||||||
|  |     default: [], | ||||||
|  |   }, | ||||||
| ] | ] | ||||||
|   | |||||||
| @@ -4,6 +4,8 @@ import { TestBed } from '@angular/core/testing' | |||||||
| import { environment } from 'src/environments/environment' | import { environment } from 'src/environments/environment' | ||||||
| import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec' | import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec' | ||||||
| import { SavedViewService } from './saved-view.service' | import { SavedViewService } from './saved-view.service' | ||||||
|  | import { SettingsService } from '../settings.service' | ||||||
|  | import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings' | ||||||
|  |  | ||||||
| let httpTestingController: HttpTestingController | let httpTestingController: HttpTestingController | ||||||
| let service: SavedViewService | let service: SavedViewService | ||||||
| @@ -22,8 +24,8 @@ const saved_views = [ | |||||||
|   { |   { | ||||||
|     name: 'Saved View 2', |     name: 'Saved View 2', | ||||||
|     id: 2, |     id: 2, | ||||||
|     show_on_dashboard: false, |     show_on_dashboard: true, | ||||||
|     show_in_sidebar: false, |     show_in_sidebar: true, | ||||||
|     sort_field: 'name', |     sort_field: 'name', | ||||||
|     sort_reverse: true, |     sort_reverse: true, | ||||||
|     filter_rules: [], |     filter_rules: [], | ||||||
| @@ -32,6 +34,15 @@ const saved_views = [ | |||||||
|     name: 'Saved View 3', |     name: 'Saved View 3', | ||||||
|     id: 3, |     id: 3, | ||||||
|     show_on_dashboard: true, |     show_on_dashboard: true, | ||||||
|  |     show_in_sidebar: true, | ||||||
|  |     sort_field: 'name', | ||||||
|  |     sort_reverse: true, | ||||||
|  |     filter_rules: [], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     name: 'Saved View 4', | ||||||
|  |     id: 4, | ||||||
|  |     show_on_dashboard: false, | ||||||
|     show_in_sidebar: false, |     show_in_sidebar: false, | ||||||
|     sort_field: 'name', |     sort_field: 'name', | ||||||
|     sort_reverse: true, |     sort_reverse: true, | ||||||
| @@ -43,6 +54,8 @@ const saved_views = [ | |||||||
| commonAbstractPaperlessServiceTests(endpoint, SavedViewService) | commonAbstractPaperlessServiceTests(endpoint, SavedViewService) | ||||||
|  |  | ||||||
| describe(`Additional service tests for SavedViewService`, () => { | describe(`Additional service tests for SavedViewService`, () => { | ||||||
|  |   let settingsService | ||||||
|  |  | ||||||
|   it('should retrieve saved views and sort them', () => { |   it('should retrieve saved views and sort them', () => { | ||||||
|     service.initialize() |     service.initialize() | ||||||
|     const req = httpTestingController.expectOne( |     const req = httpTestingController.expectOne( | ||||||
| @@ -51,9 +64,9 @@ describe(`Additional service tests for SavedViewService`, () => { | |||||||
|     req.flush({ |     req.flush({ | ||||||
|       results: saved_views, |       results: saved_views, | ||||||
|     }) |     }) | ||||||
|     expect(service.allViews).toHaveLength(3) |     expect(service.allViews).toHaveLength(4) | ||||||
|     expect(service.dashboardViews).toHaveLength(2) |     expect(service.dashboardViews).toHaveLength(3) | ||||||
|     expect(service.sidebarViews).toHaveLength(1) |     expect(service.sidebarViews).toHaveLength(3) | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|   it('should support patchMany', () => { |   it('should support patchMany', () => { | ||||||
| @@ -67,11 +80,36 @@ describe(`Additional service tests for SavedViewService`, () => { | |||||||
|     }) |     }) | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|  |   it('should sort dashboard views', () => { | ||||||
|  |     service['savedViews'] = saved_views | ||||||
|  |     jest.spyOn(settingsService, 'get').mockImplementation((key) => { | ||||||
|  |       if (key === SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER) return [3, 1, 2] | ||||||
|  |     }) | ||||||
|  |     expect(service.dashboardViews).toEqual([ | ||||||
|  |       saved_views[2], | ||||||
|  |       saved_views[0], | ||||||
|  |       saved_views[1], | ||||||
|  |     ]) | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   it('should sort sidebar views', () => { | ||||||
|  |     service['savedViews'] = saved_views | ||||||
|  |     jest.spyOn(settingsService, 'get').mockImplementation((key) => { | ||||||
|  |       if (key === SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER) return [3, 1, 2] | ||||||
|  |     }) | ||||||
|  |     expect(service.sidebarViews).toEqual([ | ||||||
|  |       saved_views[2], | ||||||
|  |       saved_views[0], | ||||||
|  |       saved_views[1], | ||||||
|  |     ]) | ||||||
|  |   }) | ||||||
|  |  | ||||||
|   beforeEach(() => { |   beforeEach(() => { | ||||||
|     // Dont need to setup again |     // Dont need to setup again | ||||||
|  |  | ||||||
|     httpTestingController = TestBed.inject(HttpTestingController) |     httpTestingController = TestBed.inject(HttpTestingController) | ||||||
|     service = TestBed.inject(SavedViewService) |     service = TestBed.inject(SavedViewService) | ||||||
|  |     settingsService = TestBed.inject(SettingsService) | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|   afterEach(() => { |   afterEach(() => { | ||||||
|   | |||||||
| @@ -5,6 +5,8 @@ import { tap } from 'rxjs/operators' | |||||||
| import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' | import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' | ||||||
| import { PermissionsService } from '../permissions.service' | import { PermissionsService } from '../permissions.service' | ||||||
| import { AbstractPaperlessService } from './abstract-paperless-service' | import { AbstractPaperlessService } from './abstract-paperless-service' | ||||||
|  | import { SettingsService } from '../settings.service' | ||||||
|  | import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings' | ||||||
|  |  | ||||||
| @Injectable({ | @Injectable({ | ||||||
|   providedIn: 'root', |   providedIn: 'root', | ||||||
| @@ -12,7 +14,11 @@ import { AbstractPaperlessService } from './abstract-paperless-service' | |||||||
| export class SavedViewService extends AbstractPaperlessService<PaperlessSavedView> { | export class SavedViewService extends AbstractPaperlessService<PaperlessSavedView> { | ||||||
|   loading: boolean |   loading: boolean | ||||||
|  |  | ||||||
|   constructor(http: HttpClient, permissionService: PermissionsService) { |   constructor( | ||||||
|  |     http: HttpClient, | ||||||
|  |     permissionService: PermissionsService, | ||||||
|  |     private settingsService: SettingsService | ||||||
|  |   ) { | ||||||
|     super(http, 'saved_views') |     super(http, 'saved_views') | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -25,6 +31,7 @@ export class SavedViewService extends AbstractPaperlessService<PaperlessSavedVie | |||||||
|     this.listAll().subscribe((r) => { |     this.listAll().subscribe((r) => { | ||||||
|       this.savedViews = r.results |       this.savedViews = r.results | ||||||
|       this.loading = false |       this.loading = false | ||||||
|  |       this.settingsService.dashboardIsEmpty = this.dashboardViews.length === 0 | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -34,12 +41,34 @@ export class SavedViewService extends AbstractPaperlessService<PaperlessSavedVie | |||||||
|     return this.savedViews |     return this.savedViews | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   get sidebarViews() { |   get sidebarViews(): PaperlessSavedView[] { | ||||||
|     return this.savedViews.filter((v) => v.show_in_sidebar) |     const sidebarViews = this.savedViews.filter((v) => v.show_in_sidebar) | ||||||
|  |  | ||||||
|  |     const sorted: number[] = this.settingsService.get( | ||||||
|  |       SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     return sorted?.length > 0 | ||||||
|  |       ? sorted | ||||||
|  |           .map((id) => sidebarViews.find((v) => v.id === id)) | ||||||
|  |           .concat(sidebarViews.filter((v) => !sorted.includes(v.id))) | ||||||
|  |           .filter((v) => v) | ||||||
|  |       : [...sidebarViews] | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   get dashboardViews() { |   get dashboardViews(): PaperlessSavedView[] { | ||||||
|     return this.savedViews.filter((v) => v.show_on_dashboard) |     const dashboardViews = this.savedViews.filter((v) => v.show_on_dashboard) | ||||||
|  |  | ||||||
|  |     const sorted: number[] = this.settingsService.get( | ||||||
|  |       SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     return sorted?.length > 0 | ||||||
|  |       ? sorted | ||||||
|  |           .map((id) => dashboardViews.find((v) => v.id === id)) | ||||||
|  |           .concat(dashboardViews.filter((v) => !sorted.includes(v.id))) | ||||||
|  |           .filter((v) => v) | ||||||
|  |       : [...dashboardViews] | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   create(o: PaperlessSavedView) { |   create(o: PaperlessSavedView) { | ||||||
|   | |||||||
| @@ -292,6 +292,14 @@ describe('SettingsService', () => { | |||||||
|       SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER, |       SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER, | ||||||
|       [1, 4] |       [1, 4] | ||||||
|     ) |     ) | ||||||
|  |     settingsService.updateSidebarViewsSort([ | ||||||
|  |       { id: 1 } as PaperlessSavedView, | ||||||
|  |       { id: 4 } as PaperlessSavedView, | ||||||
|  |     ]) | ||||||
|  |     expect(setSpy).toHaveBeenCalledWith( | ||||||
|  |       SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER, | ||||||
|  |       [1, 4] | ||||||
|  |     ) | ||||||
|     httpTestingController |     httpTestingController | ||||||
|       .expectOne(`${environment.apiBaseUrl}ui_settings/`) |       .expectOne(`${environment.apiBaseUrl}ui_settings/`) | ||||||
|       .flush(ui_settings) |       .flush(ui_settings) | ||||||
|   | |||||||
| @@ -24,7 +24,6 @@ import { | |||||||
| } from '../data/paperless-uisettings' | } from '../data/paperless-uisettings' | ||||||
| import { PaperlessUser } from '../data/paperless-user' | import { PaperlessUser } from '../data/paperless-user' | ||||||
| import { PermissionsService } from './permissions.service' | import { PermissionsService } from './permissions.service' | ||||||
| import { SavedViewService } from './rest/saved-view.service' |  | ||||||
| import { ToastService } from './toast.service' | import { ToastService } from './toast.service' | ||||||
| import { PaperlessSavedView } from '../data/paperless-saved-view' | import { PaperlessSavedView } from '../data/paperless-saved-view' | ||||||
|  |  | ||||||
| @@ -55,8 +54,11 @@ export class SettingsService { | |||||||
|     return this._renderer |     return this._renderer | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public dashboardIsEmpty: boolean = false | ||||||
|  |  | ||||||
|   public globalDropzoneEnabled: boolean = true |   public globalDropzoneEnabled: boolean = true | ||||||
|   public globalDropzoneActive: boolean = false |   public globalDropzoneActive: boolean = false | ||||||
|  |   public organizingSidebarSavedViews: boolean = false | ||||||
|  |  | ||||||
|   constructor( |   constructor( | ||||||
|     rendererFactory: RendererFactory2, |     rendererFactory: RendererFactory2, | ||||||
| @@ -66,7 +68,6 @@ export class SettingsService { | |||||||
|     @Inject(LOCALE_ID) private localeId: string, |     @Inject(LOCALE_ID) private localeId: string, | ||||||
|     protected http: HttpClient, |     protected http: HttpClient, | ||||||
|     private toastService: ToastService, |     private toastService: ToastService, | ||||||
|     private savedViewService: SavedViewService, |  | ||||||
|     private permissionsService: PermissionsService |     private permissionsService: PermissionsService | ||||||
|   ) { |   ) { | ||||||
|     this._renderer = rendererFactory.createRenderer(null, null) |     this._renderer = rendererFactory.createRenderer(null, null) | ||||||
| @@ -515,11 +516,7 @@ export class SettingsService { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   offerTour(): boolean { |   offerTour(): boolean { | ||||||
|     return ( |     return this.dashboardIsEmpty && !this.get(SETTINGS_KEYS.TOUR_COMPLETE) | ||||||
|       !this.savedViewService.loading && |  | ||||||
|       this.savedViewService.dashboardViews.length == 0 && |  | ||||||
|       !this.get(SETTINGS_KEYS.TOUR_COMPLETE) |  | ||||||
|     ) |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   completeTour() { |   completeTour() { | ||||||
| @@ -544,4 +541,11 @@ export class SettingsService { | |||||||
|     ]) |     ]) | ||||||
|     return this.storeSettings() |     return this.storeSettings() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   updateSidebarViewsSort(sidebarViews: PaperlessSavedView[]): Observable<any> { | ||||||
|  |     this.set(SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER, [ | ||||||
|  |       ...new Set(sidebarViews.map((v) => v.id)), | ||||||
|  |     ]) | ||||||
|  |     return this.storeSettings() | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -642,3 +642,17 @@ code { | |||||||
| .me-1px { | .me-1px { | ||||||
|   margin-right: 1px !important; |   margin-right: 1px !important; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .cdk-drag-placeholder { | ||||||
|  |   opacity: .5; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Animate items as they're being sorted. */ | ||||||
|  | .cdk-drop-list-dragging .cdk-drag { | ||||||
|  |   transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Animate an item that has been dropped. */ | ||||||
|  | .cdk-drag-animating { | ||||||
|  |   transition: transform 300ms cubic-bezier(0, 0, 0.2, 1); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -226,7 +226,7 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='htt | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   .alert-primary { |   .alert-primary { | ||||||
|     --bs-alert-color: var(--pngx-primary-text-contrast); |     --bs-alert-color: var(--bs-primary); | ||||||
|     --bs-alert-bg: var(--pngx-primary-darken-27); |     --bs-alert-bg: var(--pngx-primary-darken-27); | ||||||
|     --bs-alert-border-color: var(--pngx-bg-darker); |     --bs-alert-border-color: var(--pngx-bg-darker); | ||||||
|   } |   } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon