]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Feature: support sorting sidebar saved views (#4381)
authorshamoon <4887959+shamoon@users.noreply.github.com>
Fri, 20 Oct 2023 02:41:01 +0000 (19:41 -0700)
committerGitHub <noreply@github.com>
Fri, 20 Oct 2023 02:41:01 +0000 (02:41 +0000)
18 files changed:
src-ui/messages.xlf
src-ui/src/app/components/admin/settings/settings.component.spec.ts
src-ui/src/app/components/admin/settings/settings.component.ts
src-ui/src/app/components/app-frame/app-frame.component.html
src-ui/src/app/components/app-frame/app-frame.component.scss
src-ui/src/app/components/app-frame/app-frame.component.spec.ts
src-ui/src/app/components/app-frame/app-frame.component.ts
src-ui/src/app/components/dashboard/dashboard.component.scss
src-ui/src/app/components/dashboard/dashboard.component.ts
src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html
src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html
src-ui/src/app/data/paperless-uisettings.ts
src-ui/src/app/services/rest/saved-view.service.spec.ts
src-ui/src/app/services/rest/saved-view.service.ts
src-ui/src/app/services/settings.service.spec.ts
src-ui/src/app/services/settings.service.ts
src-ui/src/styles.scss
src-ui/src/theme.scss

index 5ce123943fb2630ad200e7f91e0297b5e24b7fa6..fae11c3a8598df42ff6a084839c8cf04d28ecc03 100644 (file)
         </context-group>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="3894950702316166331" datatype="html">
         </context-group>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1685061484835793745" datatype="html">
         <source>Saved view &quot;<x id="PH" equiv-text="savedView.name"/>&quot; deleted.</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="3891152409365583719" datatype="html">
         <source>Settings saved</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="7217000812750597833" datatype="html">
         <source>Settings were saved successfully.</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="525012668859298131" datatype="html">
         <source>Settings were saved successfully. Reload is required to apply some changes.</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="8491974984518503778" datatype="html">
         <source>Reload now</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="3011185103048412841" datatype="html">
         <source>An error occurred while saving settings.</source>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="6839066544204061364" datatype="html">
         <source>Use system language</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="7729897675462249787" datatype="html">
         <source>Use date format of display language</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="5260584511980773458" datatype="html">
         <source>Error while storing settings on server.</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="2991443309752293110" datatype="html">
         </context-group>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="103921551219467537" datatype="html">
         </context-group>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="4555457172864212828" datatype="html">
         </context-group>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="6570363013146073520" datatype="html">
         <source>Open documents</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="5687256342387781369" datatype="html">
         <source>Close all</source>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="3897348120591552265" datatype="html">
         <source>Manage</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="7437910965833684826" datatype="html">
         <source>Correspondents</source>
         <context-group purpose="location">
           <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 purpose="location">
           <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 purpose="location">
           <context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context>
         <source>Tags</source>
         <context-group purpose="location">
           <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 purpose="location">
           <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 purpose="location">
           <context context-type="sourcefile">src/app/components/common/input/tags/tags.component.ts</context>
         <source>Document types</source>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="8835528846812581148" datatype="html">
         <source>Storage paths</source>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="4462691404891390153" datatype="html">
         <source>Consumption templates</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="5433675495457939071" datatype="html">
         <source>Templates</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1292737233370901804" datatype="html">
         <source>Mail</source>
         <context-group purpose="location">
           <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 purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="7844706011418789951" datatype="html">
         <source>Administration</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="5537285341303594392" datatype="html">
         <source>File Tasks<x id="START_TAG_SPAN_1" ctype="x-span_1" equiv-text="&lt;span *ngIf=&quot;tasksService.failedFileTasks.length &gt; 0&quot;&gt;"/><x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;badge bg-danger ms-2&quot;&gt;"/><x id="INTERPOLATION" equiv-text="{{tasksService.failedFileTasks.length}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/></source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1534029177398918729" datatype="html">
         <source>GitHub</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="4112664765954374539" datatype="html">
         <source>is available.</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1175891574282637937" datatype="html">
         <source>Click to view.</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="9811291095862612" datatype="html">
         <source>Paperless-ngx can automatically check for updates</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="894819944961861800" datatype="html">
         <source> How does this work? </source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="509090351011426949" datatype="html">
         <source>Update available</source>
         <context-group purpose="location">
           <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-group>
       </trans-unit>
         <source>An error occurred while saving update checking settings.</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="8700121026680200191" datatype="html">
         <source>Hello <x id="PH" equiv-text="this.settingsService.displayName"/>, welcome to Paperless-ngx</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="5334686081082652461" datatype="html">
         <source>Welcome to Paperless-ngx</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1325877348738783391" datatype="html">
         <source>Dashboard updated</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="3214475953924351473" datatype="html">
         <source>Error updating dashboard</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="2946624699882754313" datatype="html">
         <source>English (US)</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="7318555235181361185" datatype="html">
         <source>Afrikaans</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="6269202464699193298" datatype="html">
         <source>Arabic</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="3098941349689899577" datatype="html">
         <source>Belarusian</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1001043467371963032" datatype="html">
         <source>Catalan</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="2719780722934172508" datatype="html">
         <source>Czech</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="2924289692679201020" datatype="html">
         <source>Danish</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1858110241312746425" datatype="html">
         <source>German</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="7067741492320440272" datatype="html">
         <source>Greek</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="6987083569809053351" datatype="html">
         <source>English (GB)</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="5190825892106392539" datatype="html">
         <source>Spanish</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="861663369293303028" datatype="html">
         <source>Finnish</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="7633754075223722162" datatype="html">
         <source>French</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="2935232983274991580" datatype="html">
         <source>Italian</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1334425850005897370" datatype="html">
         <source>Luxembourgish</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="3071065188816255493" datatype="html">
         <source>Dutch</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="8069284467804715623" datatype="html">
         <source>Norwegian</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="792060551707690640" datatype="html">
         <source>Polish</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="9184513005098760425" datatype="html">
         <source>Portuguese (Brazil)</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="153799456510623899" datatype="html">
         <source>Portuguese</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="8118856427047826368" datatype="html">
         <source>Romanian</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="7137419789978325708" datatype="html">
         <source>Russian</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="9102963095355753902" datatype="html">
         <source>Slovak</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="4287008301409320881" datatype="html">
         <source>Slovenian</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="8608389829607915090" datatype="html">
         <source>Serbian</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="499386805970351976" datatype="html">
         <source>Swedish</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="5682359291233237791" datatype="html">
         <source>Turkish</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="3578644052206125685" datatype="html">
         <source>Ukrainian</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="4689443708886954687" datatype="html">
         <source>Chinese Simplified</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="4912706592792948707" datatype="html">
         <source>ISO 8601</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="313643372755303297" datatype="html">
         <source>Successfully completed one-time migratration of settings to the database!</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="5558341108007064934" datatype="html">
         <source>Unable to migrate settings to the database, please try saving manually.</source>
         <context-group purpose="location">
           <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>
       </trans-unit>
       <trans-unit id="1168781785897678748" datatype="html">
index 7ea025fe539b3c9901d98324b698cebcdd2c9641..73ac3c98afd05473db155799a31594ece2baf287 100644 (file)
@@ -180,11 +180,23 @@ describe('SettingsComponent', () => {
     activatedRoute.snapshot.fragment = '#notifications'
     const scrollSpy = jest.spyOn(viewportScroller, 'scrollToAnchor')
     component.ngOnInit()
-    expect(component.activeNavID).toEqual(3) // Users & Groups
+    expect(component.activeNavID).toEqual(3) // Notifications
     component.ngAfterViewInit()
     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', () => {
     completeSetup()
 
index 14528d76d50fadbd7c83ec9528328656f7480b3d..3a7f837f360e0cd529f5bcba5523803451689c2b 100644 (file)
@@ -194,6 +194,9 @@ export class SettingsComponent
         if (navIDKey) {
           this.activeNavID = SettingsNavIDs[navIDKey]
         }
+        if (this.activeNavID === SettingsNavIDs.SavedViews) {
+          this.settings.organizingSidebarSavedViews = true
+        }
       }
     })
   }
@@ -275,11 +278,15 @@ export class SettingsComponent
       this.router
         .navigate(['settings', foundNavIDkey.toLowerCase()])
         .then((navigated) => {
+          this.settings.organizingSidebarSavedViews = false
           if (!navigated && this.isDirty) {
             this.activeNavID = navChangeEvent.activeId
           } else if (navigated && this.isDirty) {
             this.initialize()
           }
+          if (this.activeNavID === SettingsNavIDs.SavedViews) {
+            this.settings.organizingSidebarSavedViews = true
+          }
         })
   }
 
@@ -352,6 +359,7 @@ export class SettingsComponent
   ngOnDestroy() {
     if (this.isDirty) this.settings.updateAppearanceSettings() // in case user changed appearance but didnt save
     this.storeSub && this.storeSub.unsubscribe()
+    this.settings.organizingSidebarSavedViews = false
   }
 
   deleteSavedView(savedView: PaperlessSavedView) {
index cd78e0b1a531a606d3b904a6511ab3c3bfbce9af..c496ee4e78789eb2f8560663897ce28135eb0657 100644 (file)
           </li>
         </ul>
         <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>
             <div *ngIf="savedViewService.loading" class="spinner-border spinner-border-sm fw-normal ms-2" role="status"></div>
           </h6>
-          <ul class="nav flex-column mb-2">
-            <li class="nav-item w-100" *ngFor="let view of savedViewService.sidebarViews">
+          <ul class="nav flex-column mb-2" cdkDropList (cdkDropListDropped)="onDrop($event)">
+            <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">
                 <svg class="sidebaricon" fill="currentColor">
                   <use xlink:href="assets/bootstrap-icons.svg#funnel"/>
                 </svg><span>&nbsp;{{view.name}}</span>
               </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>
           </ul>
         </ng-container>
index 6877369a5b25c77d828daaafff240eb880ba6cee..500dd9ce14c9269c1b8f7ff6bbf5bb5be941c3d1 100644 (file)
@@ -169,6 +169,7 @@ main {
 
 .nav-item {
   position: relative;
+  list-style-type: none;
 
   &:hover .close {
     display: block;
@@ -310,3 +311,11 @@ main {
     opacity: 100%;
   }
 }
+
+.nav-item .position-absolute {
+  cursor: move;
+}
+
+::ng-deep .navItemDrag .position-absolute svg {
+  display: none;
+}
index c685413f3ccde07645eb3b95706ed10bfafa91c1..8de5ffef34ef2091017b3b1db20afb273a08dae4 100644 (file)
@@ -19,7 +19,7 @@ import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
 import { RemoteVersionService } from 'src/app/services/rest/remote-version.service'
 import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
 import { FormsModule, ReactiveFormsModule } from '@angular/forms'
-import { of } from 'rxjs'
+import { of, throwError } from 'rxjs'
 import { ToastService } from 'src/app/services/toast.service'
 import { environment } from 'src/environments/environment'
 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 { routes } from 'src/app/app-routing.module'
 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' }
 
 describe('AppFrameComponent', () => {
@@ -60,7 +100,19 @@ describe('AppFrameComponent', () => {
       ],
       providers: [
         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,
         RemoteVersionService,
         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()
+  })
 })
index 01c1345da8a2c8900fa19afe0b3d9929195bef96..d7a0932712bcb0be01a4751dcd3b56cecd754d24 100644 (file)
@@ -32,6 +32,13 @@ import {
   PermissionsService,
   PermissionType,
 } 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({
   selector: 'pngx-app-frame',
@@ -42,6 +49,17 @@ export class AppFrameComponent
   extends ComponentWithPermissions
   implements OnInit, ComponentCanDeactivate
 {
+  versionString = `${environment.appTitle} ${environment.version}`
+  appRemoteVersion: AppRemoteVersion
+
+  isMenuCollapsed: boolean = true
+
+  slimSidebarAnimating: boolean = false
+
+  searchField = new FormControl('')
+
+  sidebarViews: PaperlessSavedView[]
+
   constructor(
     public router: Router,
     private activatedRoute: ActivatedRoute,
@@ -63,7 +81,7 @@ export class AppFrameComponent
         PermissionType.SavedView
       )
     ) {
-      savedViewService.initialize()
+      this.savedViewService.initialize()
     }
   }
 
@@ -72,14 +90,11 @@ export class AppFrameComponent
       this.checkForUpdates()
     }
     this.tasksService.reload()
-  }
-
-  versionString = `${environment.appTitle} ${environment.version}`
-  appRemoteVersion: AppRemoteVersion
 
-  isMenuCollapsed: boolean = true
-
-  slimSidebarAnimating: boolean = false
+    this.savedViewService.listAll().subscribe(() => {
+      this.sidebarViews = this.savedViewService.sidebarViews
+    })
+  }
 
   toggleSlimSidebar(): void {
     this.slimSidebarAnimating = true
@@ -121,8 +136,6 @@ export class AppFrameComponent
     return !this.openDocumentsService.hasDirty()
   }
 
-  searchField = new FormControl('')
-
   get searchFieldEmpty(): boolean {
     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() {
     this.remoteVersionService
       .checkForUpdates()
index 6c2161957dd831b7030da13539acccf8ac834b2d..de41297eeaf1e465800e0332ad7296e32b3a74d1 100644 (file)
@@ -1,19 +1,3 @@
 .col-sidebar .row {
     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);
-    }
-}
index b39ce16635fe8fcd26b6660ada219b2b12db117d..4b585cb3250c62b7703a4abb6a39643a29033c3b 100644 (file)
@@ -29,22 +29,7 @@ export class DashboardComponent extends ComponentWithPermissions {
     super()
 
     this.savedViewService.listAll().subscribe(() => {
-      const sorted: number[] = this.settingsService.get(
-        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]
+      this.dashboardViews = this.savedViewService.dashboardViews
     })
   }
 
index f42100414c177eca5c293a5a1c9ec68b2f971039..60affe379fa6bc61967cb2be076ca82c35424f58 100644 (file)
@@ -17,7 +17,7 @@
         <div class="d-flex justify-content-between align-items-center my-2">
           <div class="progress flex-grow-1">
             <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"
               [ngbPopover]="getFileTypeName(filetype)"
               i18n-ngbPopover
index 63532813f7c378985e260899ca396fa163d56a6a..72d0ccd410e89364076d36323e63fbac58edead9 100644 (file)
@@ -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>
   <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>
index 2f1e9e230b79866e6b91970bcd945a7c3aa45410..a8ef0f87fe90bc54ffc3fa8b367fa408507176dd 100644 (file)
@@ -43,6 +43,8 @@ export const SETTINGS_KEYS = {
     'general-settings:saved-views:warn-on-unsaved-change',
   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',
   DEFAULT_PERMS_OWNER: 'general-settings:permissions:default-owner',
   DEFAULT_PERMS_VIEW_USERS: 'general-settings:permissions:default-view-users',
@@ -187,4 +189,9 @@ export const SETTINGS: PaperlessUiSetting[] = [
     type: 'array',
     default: [],
   },
+  {
+    key: SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER,
+    type: 'array',
+    default: [],
+  },
 ]
index 1e0c761aa5c4f4c55dd122646918521105a3e405..ffd2099ba4431d6dcff9d4eea88a6e0474d995c7 100644 (file)
@@ -4,6 +4,8 @@ import { TestBed } from '@angular/core/testing'
 import { environment } from 'src/environments/environment'
 import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec'
 import { SavedViewService } from './saved-view.service'
+import { SettingsService } from '../settings.service'
+import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
 
 let httpTestingController: HttpTestingController
 let service: SavedViewService
@@ -22,8 +24,8 @@ const saved_views = [
   {
     name: 'Saved View 2',
     id: 2,
-    show_on_dashboard: false,
-    show_in_sidebar: false,
+    show_on_dashboard: true,
+    show_in_sidebar: true,
     sort_field: 'name',
     sort_reverse: true,
     filter_rules: [],
@@ -32,6 +34,15 @@ const saved_views = [
     name: 'Saved View 3',
     id: 3,
     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,
     sort_field: 'name',
     sort_reverse: true,
@@ -43,6 +54,8 @@ const saved_views = [
 commonAbstractPaperlessServiceTests(endpoint, SavedViewService)
 
 describe(`Additional service tests for SavedViewService`, () => {
+  let settingsService
+
   it('should retrieve saved views and sort them', () => {
     service.initialize()
     const req = httpTestingController.expectOne(
@@ -51,9 +64,9 @@ describe(`Additional service tests for SavedViewService`, () => {
     req.flush({
       results: saved_views,
     })
-    expect(service.allViews).toHaveLength(3)
-    expect(service.dashboardViews).toHaveLength(2)
-    expect(service.sidebarViews).toHaveLength(1)
+    expect(service.allViews).toHaveLength(4)
+    expect(service.dashboardViews).toHaveLength(3)
+    expect(service.sidebarViews).toHaveLength(3)
   })
 
   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(() => {
     // Dont need to setup again
 
     httpTestingController = TestBed.inject(HttpTestingController)
     service = TestBed.inject(SavedViewService)
+    settingsService = TestBed.inject(SettingsService)
   })
 
   afterEach(() => {
index 307eaae10048289b938725aed1a2934a62804b57..bd0d9fb52308c559e704b053c47f49fe57587180 100644 (file)
@@ -5,6 +5,8 @@ import { tap } from 'rxjs/operators'
 import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'
 import { PermissionsService } from '../permissions.service'
 import { AbstractPaperlessService } from './abstract-paperless-service'
+import { SettingsService } from '../settings.service'
+import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
 
 @Injectable({
   providedIn: 'root',
@@ -12,7 +14,11 @@ import { AbstractPaperlessService } from './abstract-paperless-service'
 export class SavedViewService extends AbstractPaperlessService<PaperlessSavedView> {
   loading: boolean
 
-  constructor(http: HttpClient, permissionService: PermissionsService) {
+  constructor(
+    http: HttpClient,
+    permissionService: PermissionsService,
+    private settingsService: SettingsService
+  ) {
     super(http, 'saved_views')
   }
 
@@ -25,6 +31,7 @@ export class SavedViewService extends AbstractPaperlessService<PaperlessSavedVie
     this.listAll().subscribe((r) => {
       this.savedViews = r.results
       this.loading = false
+      this.settingsService.dashboardIsEmpty = this.dashboardViews.length === 0
     })
   }
 
@@ -34,12 +41,34 @@ export class SavedViewService extends AbstractPaperlessService<PaperlessSavedVie
     return this.savedViews
   }
 
-  get sidebarViews() {
-    return this.savedViews.filter((v) => v.show_in_sidebar)
+  get sidebarViews(): PaperlessSavedView[] {
+    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() {
-    return this.savedViews.filter((v) => v.show_on_dashboard)
+  get dashboardViews(): PaperlessSavedView[] {
+    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) {
index e7d13dffc3fd453f18b5ddcde9282a7f14070bf2..d0814bad9970835811865bf2e0ae59ed592ea352 100644 (file)
@@ -292,6 +292,14 @@ describe('SettingsService', () => {
       SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER,
       [1, 4]
     )
+    settingsService.updateSidebarViewsSort([
+      { id: 1 } as PaperlessSavedView,
+      { id: 4 } as PaperlessSavedView,
+    ])
+    expect(setSpy).toHaveBeenCalledWith(
+      SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER,
+      [1, 4]
+    )
     httpTestingController
       .expectOne(`${environment.apiBaseUrl}ui_settings/`)
       .flush(ui_settings)
index 6109135499216a639a66243cf1a7403f8604124a..e60304a0c58b81d0f4da57f8a4dddf8d8120366d 100644 (file)
@@ -24,7 +24,6 @@ import {
 } from '../data/paperless-uisettings'
 import { PaperlessUser } from '../data/paperless-user'
 import { PermissionsService } from './permissions.service'
-import { SavedViewService } from './rest/saved-view.service'
 import { ToastService } from './toast.service'
 import { PaperlessSavedView } from '../data/paperless-saved-view'
 
@@ -55,8 +54,11 @@ export class SettingsService {
     return this._renderer
   }
 
+  public dashboardIsEmpty: boolean = false
+
   public globalDropzoneEnabled: boolean = true
   public globalDropzoneActive: boolean = false
+  public organizingSidebarSavedViews: boolean = false
 
   constructor(
     rendererFactory: RendererFactory2,
@@ -66,7 +68,6 @@ export class SettingsService {
     @Inject(LOCALE_ID) private localeId: string,
     protected http: HttpClient,
     private toastService: ToastService,
-    private savedViewService: SavedViewService,
     private permissionsService: PermissionsService
   ) {
     this._renderer = rendererFactory.createRenderer(null, null)
@@ -515,11 +516,7 @@ export class SettingsService {
   }
 
   offerTour(): boolean {
-    return (
-      !this.savedViewService.loading &&
-      this.savedViewService.dashboardViews.length == 0 &&
-      !this.get(SETTINGS_KEYS.TOUR_COMPLETE)
-    )
+    return this.dashboardIsEmpty && !this.get(SETTINGS_KEYS.TOUR_COMPLETE)
   }
 
   completeTour() {
@@ -544,4 +541,11 @@ export class SettingsService {
     ])
     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()
+  }
 }
index 1bb96a6f63c56d498143788bd9310bf34b2a3ded..244fba8bb5c62080ec62ad8b1358a5ef74ce55d5 100644 (file)
@@ -642,3 +642,17 @@ code {
 .me-1px {
   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);
+}
index f415ed53770bfac4c1bde09c2f2c7d546c39db15..095b83d20a89daf9cf99b906229fe5fd42a52b58 100644 (file)
@@ -226,7 +226,7 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='htt
   }
 
   .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-border-color: var(--pngx-bg-darker);
   }