]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Change: make saved views manage its own component (#8423)
authorshamoon <4887959+shamoon@users.noreply.github.com>
Tue, 3 Dec 2024 19:09:02 +0000 (11:09 -0800)
committerGitHub <noreply@github.com>
Tue, 3 Dec 2024 19:09:02 +0000 (11:09 -0800)
14 files changed:
src-ui/e2e/admin/settings.spec.ts
src-ui/messages.xlf
src-ui/src/app/app-routing.module.ts
src-ui/src/app/app.component.ts
src-ui/src/app/app.module.ts
src-ui/src/app/components/admin/settings/settings.component.html
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/document-list/document-list.component.html
src-ui/src/app/components/manage/saved-views/saved-views.component.html [new file with mode: 0644]
src-ui/src/app/components/manage/saved-views/saved-views.component.scss [new file with mode: 0644]
src-ui/src/app/components/manage/saved-views/saved-views.component.spec.ts [new file with mode: 0644]
src-ui/src/app/components/manage/saved-views/saved-views.component.ts [new file with mode: 0644]

index 92c6918d91a00314b715747063167c8d6e7ba8d9..e90bd7d82367cf0adc29ec867fbd4a867fec19cc 100644 (file)
@@ -33,24 +33,3 @@ test('should apply appearance changes when set', async ({ page }) => {
   await page.getByLabel('Enable dark mode').click()
   await expect(page.locator('html')).toHaveAttribute('data-bs-theme', /dark/)
 })
-
-test('should toggle saved view options when set & saved', async ({ page }) => {
-  await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
-  await page.goto('/settings/savedviews')
-  await page.getByLabel('Show on dashboard').first().click()
-  await page.getByLabel('Show in sidebar').first().click()
-  const updatePromise = page.waitForRequest((request) => {
-    if (!request.url().includes('8')) return true // skip other saved views
-    const data = request.postDataJSON()
-    const isValid =
-      data['show_on_dashboard'] === true && data['show_in_sidebar'] === true
-    return (
-      isValid &&
-      request.method() === 'PATCH' &&
-      request.url().includes('/api/saved_views/')
-    )
-  })
-  await page.getByRole('button', { name: 'Save' }).scrollIntoViewIfNeeded()
-  await page.getByRole('button', { name: 'Save' }).click()
-  await updatePromise
-})
index 9f8cf01b1010e6288175f1c1fbb878c1f9ff3ddb..932a7318bf51b73f1fb1a69b032dfbba51b1d825 100644 (file)
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
           <context context-type="linenumber">2</context>
         </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">344</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">50</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">237</context>
+          <context context-type="linenumber">244</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">239</context>
+          <context context-type="linenumber">246</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2501522447884928778" datatype="html">
           <context context-type="linenumber">162</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="3909462337752654810" datatype="html">
-        <source>The dashboard can be used to show saved views, such as an &apos;Inbox&apos;. Those settings are found under Settings &gt; Saved Views once you have created some.</source>
+      <trans-unit id="5890330709052835856" datatype="html">
+        <source>The dashboard can be used to show saved views, such as an &apos;Inbox&apos;. Views are found under Manage &gt; Saved Views once you have created some.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
           <context context-type="linenumber">168</context>
           <context context-type="linenumber">4</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="1453710303796913192" datatype="html">
-        <source>Check out the settings for various tweaks to the web app and toggle settings for saved views.</source>
+      <trans-unit id="2755033621682206902" datatype="html">
+        <source>Check out the settings for various tweaks to the web app.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
           <context context-type="linenumber">230</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">424</context>
+          <context context-type="linenumber">349</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.html</context>
           <context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
           <context context-type="linenumber">21</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">73</context>
+        </context-group>
       </trans-unit>
       <trans-unit id="5079885666748292382" datatype="html">
         <source>Error retrieving config</source>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
-          <context context-type="linenumber">272</context>
+          <context context-type="linenumber">279</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">275</context>
+          <context context-type="linenumber">282</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2272120016352772836" datatype="html">
           <context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
           <context context-type="linenumber">36</context>
         </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">412</context>
-        </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
           <context context-type="linenumber">48</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">109</context>
+          <context context-type="linenumber">110</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
           <context context-type="linenumber">51</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">68</context>
+        </context-group>
       </trans-unit>
-      <trans-unit id="4999473193657330663" datatype="html">
-        <source>Options to customize appearance, notifications, saved views and more. Settings apply to the &lt;strong&gt;current user only&lt;/strong&gt;.</source>
+      <trans-unit id="1255048712725285892" datatype="html">
+        <source>Options to customize appearance, notifications and more. Settings apply to the &lt;strong&gt;current user only&lt;/strong&gt;.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
           <context context-type="linenumber">4</context>
           <context context-type="linenumber">152</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="5775451530782446954" datatype="html">
+        <source>Saved Views</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
+          <context context-type="linenumber">229</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">206</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="1595668988802980095" datatype="html">
+        <source>Show warning when closing saved views with unsaved changes</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
+          <context context-type="linenumber">232</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="8104421162933956065" datatype="html">
         <source>Notes</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">229</context>
+          <context context-type="linenumber">236</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">212</context>
+          <context context-type="linenumber">213</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/data/document.ts</context>
         <source>Enable notes</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">233</context>
+          <context context-type="linenumber">239</context>
         </context-group>
       </trans-unit>
       <trans-unit id="7314814725704332646" datatype="html">
         <source>Permissions</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">241</context>
+          <context context-type="linenumber">247</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/edit-dialog/group-edit-dialog/group-edit-dialog.component.html</context>
         <source>Default Permissions</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">244</context>
+          <context context-type="linenumber">250</context>
         </context-group>
       </trans-unit>
       <trans-unit id="8222269449891326545" datatype="html">
         <source> Settings apply to this user account for objects (Tags, Mail Rules, etc.) created via the web UI </source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">248,250</context>
+          <context context-type="linenumber">254,256</context>
         </context-group>
       </trans-unit>
       <trans-unit id="4292903881380648974" datatype="html">
         <source>Default Owner</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">255</context>
+          <context context-type="linenumber">261</context>
         </context-group>
       </trans-unit>
       <trans-unit id="734147282056744882" datatype="html">
         <source>Objects without an owner can be viewed and edited by all users</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">259</context>
+          <context context-type="linenumber">265</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
         <source>Default View Permissions</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">264</context>
+          <context context-type="linenumber">270</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2191775412581217688" datatype="html">
         <source>Users:</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">269</context>
+          <context context-type="linenumber">275</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">296</context>
+          <context context-type="linenumber">302</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
         <source>Groups:</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">279</context>
+          <context context-type="linenumber">285</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">306</context>
+          <context context-type="linenumber">312</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
         <source>Default Edit Permissions</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">291</context>
+          <context context-type="linenumber">297</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3728984448750213892" datatype="html">
         <source>Edit permissions also grant viewing permissions</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">315</context>
+          <context context-type="linenumber">321</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
         <source>Notifications</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">323</context>
+          <context context-type="linenumber">329</context>
         </context-group>
       </trans-unit>
       <trans-unit id="8545554728558600606" datatype="html">
         <source>Document processing</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">326</context>
+          <context context-type="linenumber">332</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3656786776644872398" datatype="html">
         <source>Show notifications when new documents are detected</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">330</context>
+          <context context-type="linenumber">336</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6057053428592387613" datatype="html">
         <source>Show notifications when document processing completes successfully</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">331</context>
+          <context context-type="linenumber">337</context>
         </context-group>
       </trans-unit>
       <trans-unit id="370315664367425513" datatype="html">
         <source>Show notifications when document processing fails</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">332</context>
+          <context context-type="linenumber">338</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6838309441164918531" datatype="html">
         <source>Suppress notifications on dashboard</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">333</context>
+          <context context-type="linenumber">339</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2741919327232918179" datatype="html">
         <source>This will suppress all messages about document processing status on the dashboard.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">333</context>
+          <context context-type="linenumber">339</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="472206565520537964" datatype="html">
-        <source>Saved views</source>
+      <trans-unit id="2159130950882492111" datatype="html">
+        <source>Cancel</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">341</context>
+          <context context-type="linenumber">350</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">98</context>
+          <context context-type="sourcefile">src/app/components/common/confirm-dialog/confirm-dialog.component.ts</context>
+          <context context-type="linenumber">44</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">103</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.html</context>
+          <context context-type="linenumber">27</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="1595668988802980095" datatype="html">
-        <source>Show warning when closing saved views with unsaved changes</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">347</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context>
+          <context context-type="linenumber">44</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="2123659921722214537" datatype="html">
-        <source>Views</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">351</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.html</context>
+          <context context-type="linenumber">29</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">70</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/group-edit-dialog/group-edit-dialog.component.html</context>
+          <context context-type="linenumber">19</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="4104807402967139762" datatype="html">
-        <source>Show on dashboard</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">364</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component.html</context>
+          <context context-type="linenumber">39</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
-          <context context-type="linenumber">10</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
+          <context context-type="linenumber">74</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="8689274715612276035" datatype="html">
-        <source>Show in sidebar</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">368</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component.html</context>
+          <context context-type="linenumber">78</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
-          <context context-type="linenumber">9</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html</context>
+          <context context-type="linenumber">30</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="3193976279273491157" datatype="html">
-        <source>Actions</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">372</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.html</context>
+          <context context-type="linenumber">56</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
-          <context context-type="linenumber">67</context>
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
+          <context context-type="linenumber">113</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">37</context>
+          <context context-type="sourcefile">src/app/components/common/permissions-dialog/permissions-dialog.component.html</context>
+          <context context-type="linenumber">25</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.html</context>
-          <context context-type="linenumber">23</context>
+          <context context-type="sourcefile">src/app/components/common/profile-edit-dialog/profile-edit-dialog.component.html</context>
+          <context context-type="linenumber">183</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.html</context>
-          <context context-type="linenumber">61</context>
+          <context context-type="sourcefile">src/app/components/common/select-dialog/select-dialog.component.html</context>
+          <context context-type="linenumber">12</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
-          <context context-type="linenumber">67</context>
+          <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
+          <context context-type="linenumber">4</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
-          <context context-type="linenumber">45</context>
+          <context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
+          <context context-type="linenumber">20</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
-          <context context-type="linenumber">107</context>
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">74</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/manage/custom-fields/custom-fields.component.html</context>
-          <context context-type="linenumber">19</context>
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
+          <context context-type="linenumber">59</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/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">33</context>
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
+          <context context-type="linenumber">62</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="1235706724900303689" datatype="html">
+        <source>Error retrieving users</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">100</context>
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
+          <context context-type="linenumber">181</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">43</context>
+          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
+          <context context-type="linenumber">51</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="3066660568529853846" datatype="html">
+        <source>Error retrieving groups</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">43</context>
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
+          <context context-type="linenumber">200</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">43</context>
+          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
+          <context context-type="linenumber">63</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/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">43</context>
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
+          <context context-type="linenumber">489</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/manage/workflows/workflows.component.html</context>
-          <context context-type="linenumber">21</context>
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
+          <context context-type="linenumber">493</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="7022070615528435141" datatype="html">
-        <source>Delete</source>
+      <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.html</context>
-          <context context-type="linenumber">374</context>
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
+          <context context-type="linenumber">494</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/trash/trash.component.html</context>
-          <context context-type="linenumber">72</context>
+          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
+          <context context-type="linenumber">504</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">81</context>
+          <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context>
+          <context context-type="linenumber">125</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="2991443309752293110" datatype="html">
+        <source>File Tasks</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.ts</context>
-          <context context-type="linenumber">59</context>
+          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
+          <context context-type="linenumber">2</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.ts</context>
-          <context context-type="linenumber">88</context>
+          <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
+          <context context-type="linenumber">267</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.html</context>
-          <context context-type="linenumber">38</context>
+          <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
+          <context context-type="linenumber">269</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="103921551219467537" datatype="html">
+        <source>Clear selection</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.html</context>
-          <context context-type="linenumber">76</context>
+          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
+          <context context-type="linenumber">9</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context>
-          <context context-type="linenumber">27</context>
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">8</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts</context>
-          <context context-type="linenumber">53</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">3</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
-          <context context-type="linenumber">45</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">3</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
-          <context context-type="linenumber">87</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/permissions-select/permissions-select.component.html</context>
-          <context context-type="linenumber">19</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/share-links-dropdown/share-links-dropdown.component.html</context>
-          <context context-type="linenumber">37</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
-          <context context-type="linenumber">24</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
-          <context context-type="linenumber">161</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.html</context>
-          <context context-type="linenumber">36</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.html</context>
-          <context context-type="linenumber">48</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">60</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">72</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">127</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">141</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">9</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">9</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">9</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">9</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">83</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">83</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">83</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">83</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">95</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">95</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">95</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">95</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
-          <context context-type="linenumber">210</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
-          <context context-type="linenumber">48</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
-          <context context-type="linenumber">59</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="6338800642797811873" datatype="html">
-        <source>Documents page size</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">385</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="4729108320774167624" datatype="html">
-        <source>Display as</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">388</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="1358239534403218079" datatype="html">
-        <source>Table</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">390</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="4236040382842528005" datatype="html">
-        <source>Small Cards</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">391</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="8569593958139569111" datatype="html">
-        <source>Large Cards</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">392</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="8461842260159597706" datatype="html">
-        <source>Show</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">396</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">17</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="5607669932062416162" datatype="html">
-        <source>Default</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">396</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
-          <context context-type="linenumber">117</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="7877440816920439876" datatype="html">
-        <source>No saved views defined.</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">405</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="2159130950882492111" datatype="html">
-        <source>Cancel</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
-          <context context-type="linenumber">425</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/confirm-dialog/confirm-dialog.component.ts</context>
-          <context context-type="linenumber">44</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.html</context>
-          <context context-type="linenumber">27</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context>
-          <context context-type="linenumber">44</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.html</context>
-          <context context-type="linenumber">29</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/group-edit-dialog/group-edit-dialog.component.html</context>
-          <context context-type="linenumber">19</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component.html</context>
-          <context context-type="linenumber">39</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.html</context>
-          <context context-type="linenumber">74</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component.html</context>
-          <context context-type="linenumber">78</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html</context>
-          <context context-type="linenumber">30</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.html</context>
-          <context context-type="linenumber">56</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
-          <context context-type="linenumber">113</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/permissions-dialog/permissions-dialog.component.html</context>
-          <context context-type="linenumber">25</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/profile-edit-dialog/profile-edit-dialog.component.html</context>
-          <context context-type="linenumber">183</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/common/select-dialog/select-dialog.component.html</context>
-          <context context-type="linenumber">12</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
-          <context context-type="linenumber">4</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
-          <context context-type="linenumber">20</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">62</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">65</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="1235706724900303689" datatype="html">
-        <source>Error retrieving users</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">193</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
-          <context context-type="linenumber">51</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="3066660568529853846" datatype="html">
-        <source>Error retrieving groups</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">212</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
-          <context context-type="linenumber">63</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="5610279464668232148" 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">431</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">569</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">573</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">574</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">584</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">125</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">618</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="2991443309752293110" datatype="html">
-        <source>File Tasks</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
-          <context context-type="linenumber">2</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">260</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">262</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="103921551219467537" datatype="html">
-        <source>Clear selection</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
-          <context context-type="linenumber">9</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">8</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">3</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">3</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
-          <context context-type="linenumber">3</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">3</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">239</context>
+          <context context-type="linenumber">240</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/data/document.ts</context>
           <context context-type="linenumber">66</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="3193976279273491157" datatype="html">
+        <source>Actions</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
+          <context context-type="linenumber">67</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">37</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.html</context>
+          <context context-type="linenumber">23</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.html</context>
+          <context context-type="linenumber">61</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
+          <context context-type="linenumber">67</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
+          <context context-type="linenumber">45</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
+          <context context-type="linenumber">107</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.html</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
+          <context context-type="linenumber">33</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
+          <context context-type="linenumber">100</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">43</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">43</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">43</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">43</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">28</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="8958063833276423847" datatype="html">
         <source>click for full output</source>
         <context-group purpose="location">
           <context context-type="linenumber">2</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">220</context>
+          <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
+          <context context-type="linenumber">227</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">230</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="3818027200170621545" datatype="html">
+        <source>Manage trashed documents that are pending deletion.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">4</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="3186604097120837257" datatype="html">
+        <source>Restore selected</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="8831459317888986184" datatype="html">
+        <source>Delete selected</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">14</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="8597030111956627342" datatype="html">
+        <source>Empty trash</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="991066160113599649" datatype="html">
+        <source>Remaining</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">36</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="7494361412465596264" datatype="html">
+        <source><x id="INTERPOLATION" equiv-text="{{ getDaysRemaining(document) }}"/> days</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">63</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="6770769801335635194" datatype="html">
+        <source>Restore</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">71</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">78</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="7022070615528435141" datatype="html">
+        <source>Delete</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">72</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
+          <context context-type="linenumber">81</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.ts</context>
+          <context context-type="linenumber">59</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.ts</context>
+          <context context-type="linenumber">88</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.html</context>
+          <context context-type="linenumber">38</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.html</context>
+          <context context-type="linenumber">76</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context>
+          <context context-type="linenumber">27</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts</context>
+          <context context-type="linenumber">53</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
+          <context context-type="linenumber">45</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
+          <context context-type="linenumber">87</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/common/permissions-select/permissions-select.component.html</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/common/share-links-dropdown/share-links-dropdown.component.html</context>
+          <context context-type="linenumber">37</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
+          <context context-type="linenumber">24</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
+          <context context-type="linenumber">161</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.html</context>
+          <context context-type="linenumber">36</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.html</context>
+          <context context-type="linenumber">48</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
+          <context context-type="linenumber">60</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
+          <context context-type="linenumber">72</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
+          <context context-type="linenumber">127</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
+          <context context-type="linenumber">141</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">83</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">83</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">83</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">223</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">83</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="3818027200170621545" datatype="html">
-        <source>Manage trashed documents that are pending deletion.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">4</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">95</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="3186604097120837257" datatype="html">
-        <source>Restore selected</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">11</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">95</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="8831459317888986184" datatype="html">
-        <source>Delete selected</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">14</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">95</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="8597030111956627342" datatype="html">
-        <source>Empty trash</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">17</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
+          <context context-type="linenumber">95</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="991066160113599649" datatype="html">
-        <source>Remaining</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">36</context>
+          <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
+          <context context-type="linenumber">210</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="7494361412465596264" datatype="html">
-        <source><x id="INTERPOLATION" equiv-text="{{ getDaysRemaining(document) }}"/> days</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">63</context>
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">30</context>
         </context-group>
-      </trans-unit>
-      <trans-unit id="6770769801335635194" datatype="html">
-        <source>Restore</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">71</context>
+          <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
+          <context context-type="linenumber">48</context>
         </context-group>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
-          <context context-type="linenumber">78</context>
+          <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
+          <context context-type="linenumber">59</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2308646316372333720" 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">251</context>
+          <context context-type="linenumber">258</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">253</context>
+          <context context-type="linenumber">260</context>
         </context-group>
       </trans-unit>
       <trans-unit id="4569276013106377105" 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">281</context>
+          <context context-type="linenumber">288</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">291</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="472206565520537964" datatype="html">
+        <source>Saved views</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
+          <context context-type="linenumber">98</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">284</context>
+          <context context-type="linenumber">103</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6988090220128974198" datatype="html">
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">194</context>
+          <context context-type="linenumber">195</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
           <context context-type="linenumber">199</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">204</context>
+        </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/custom-fields-dropdown/custom-fields-dropdown.component.html</context>
           <context context-type="linenumber">4</context>
         <source>Workflows</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
-          <context context-type="linenumber">206</context>
+          <context context-type="linenumber">213</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">208</context>
+          <context context-type="linenumber">215</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
         <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">213</context>
+          <context context-type="linenumber">220</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">216</context>
+          <context context-type="linenumber">223</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">231</context>
+          <context context-type="linenumber">238</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3008420115644088420" datatype="html">
         <source>Configuration</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.html</context>
-          <context context-type="linenumber">244</context>
+          <context context-type="linenumber">251</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">246</context>
+          <context context-type="linenumber">253</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">291</context>
+          <context context-type="linenumber">298</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">300,301</context>
+          <context context-type="linenumber">307,308</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">301</context>
+          <context context-type="linenumber">308</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">305</context>
+          <context context-type="linenumber">312</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">312,314</context>
+          <context context-type="linenumber">319,321</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">325</context>
+          <context context-type="linenumber">332</context>
         </context-group>
       </trans-unit>
       <trans-unit id="1542489069631984294" datatype="html">
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">248</context>
+          <context context-type="linenumber">249</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/data/document.ts</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">288</context>
+          <context context-type="linenumber">289</context>
         </context-group>
       </trans-unit>
       <trans-unit id="78870852467682010" datatype="html">
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">328</context>
+          <context context-type="linenumber">329</context>
         </context-group>
       </trans-unit>
       <trans-unit id="157572966557284263" datatype="html">
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">335</context>
+          <context context-type="linenumber">336</context>
         </context-group>
       </trans-unit>
       <trans-unit id="8911158217491828773" datatype="html">
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">191</context>
+          <context context-type="linenumber">192</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">181</context>
+          <context context-type="linenumber">182</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">221</context>
+          <context context-type="linenumber">222</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">230</context>
+          <context context-type="linenumber">231</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
           <context context-type="linenumber">59</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="5607669932062416162" datatype="html">
+        <source>Default</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
+          <context context-type="linenumber">117</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">52</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="6205355627445317276" datatype="html">
         <source>Content</source>
         <context-group purpose="location">
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">304</context>
+          <context context-type="linenumber">305</context>
         </context-group>
       </trans-unit>
       <trans-unit id="106713086593101376" datatype="html">
           <context context-type="linenumber">248</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="8461842260159597706" datatype="html">
+        <source>Show</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">52</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="5146398958364876914" datatype="html">
         <source>Sort</source>
         <context-group purpose="location">
           <context context-type="linenumber">46</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="2123659921722214537" datatype="html">
+        <source>Views</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
+          <context context-type="linenumber">70</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="1233494216161906927" datatype="html">
         <source>Save &quot;<x id="INTERPOLATION" equiv-text="{{list.activeSavedViewTitle}}"/>&quot;</source>
         <context-group purpose="location">
           <context context-type="linenumber">92</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="1450797155766668235" datatype="html">
+        <source>All saved views</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
+          <context context-type="linenumber">93</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="8786996283897742947" datatype="html">
         <source>{VAR_PLURAL, plural, =1 {Selected <x id="INTERPOLATION"/> of one document} other {Selected <x id="INTERPOLATION"/> of <x id="INTERPOLATION_1"/> documents}}</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">112</context>
+          <context context-type="linenumber">113</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6600548268163632449" datatype="html">
         <source>{VAR_PLURAL, plural, =1 {One document} other {<x id="INTERPOLATION"/> documents}}</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">116</context>
+          <context context-type="linenumber">117</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2243770355958919528" datatype="html">
         <source>(filtered)</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">118</context>
+          <context context-type="linenumber">119</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6849725902312323996" datatype="html">
         <source>Reset filters</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">123</context>
+          <context context-type="linenumber">124</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
         <source>Error while loading documents</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">139</context>
+          <context context-type="linenumber">140</context>
         </context-group>
       </trans-unit>
       <trans-unit id="494022736054110363" datatype="html">
         <source>Sort by ASN</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">168</context>
+          <context context-type="linenumber">169</context>
         </context-group>
       </trans-unit>
       <trans-unit id="7517688192215738656" datatype="html">
         <source>ASN</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">172</context>
+          <context context-type="linenumber">173</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
         <source>Sort by correspondent</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">177</context>
+          <context context-type="linenumber">178</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2066713941761361709" datatype="html">
         <source>Sort by title</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">186</context>
+          <context context-type="linenumber">187</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6232673011753681091" datatype="html">
         <source>Sort by owner</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">199</context>
+          <context context-type="linenumber">200</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3715596725146409911" datatype="html">
         <source>Owner</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">203</context>
+          <context context-type="linenumber">204</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/data/document.ts</context>
         <source>Sort by notes</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">208</context>
+          <context context-type="linenumber">209</context>
         </context-group>
       </trans-unit>
       <trans-unit id="5499001829734502606" datatype="html">
         <source>Sort by document type</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">217</context>
+          <context context-type="linenumber">218</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6213829731736042759" datatype="html">
         <source>Sort by storage path</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">226</context>
+          <context context-type="linenumber">227</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3406167410329973166" datatype="html">
         <source>Sort by created date</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">235</context>
+          <context context-type="linenumber">236</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3769035778779263084" datatype="html">
         <source>Sort by added date</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">244</context>
+          <context context-type="linenumber">245</context>
         </context-group>
       </trans-unit>
       <trans-unit id="4874754501044009042" datatype="html">
         <source>Sort by number of pages</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">253</context>
+          <context context-type="linenumber">254</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3817498941817715969" datatype="html">
         <source>Pages</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">257</context>
+          <context context-type="linenumber">258</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/data/document.ts</context>
         <source> Shared </source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">260,262</context>
+          <context context-type="linenumber">261,263</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2179847500064178686" datatype="html">
         <source>Edit document</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">296</context>
+          <context context-type="linenumber">297</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3420321797707163677" datatype="html">
         <source>Preview document</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">297</context>
+          <context context-type="linenumber">298</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2807800733729323332" datatype="html">
         <source>Yes</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">356</context>
+          <context context-type="linenumber">357</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/pipes/yes-no.pipe.ts</context>
         <source>No</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
-          <context context-type="linenumber">356</context>
+          <context context-type="linenumber">357</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/pipes/yes-no.pipe.ts</context>
           <context context-type="linenumber">3</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="8689274715612276035" datatype="html">
+        <source>Show in sidebar</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">24</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="4104807402967139762" datatype="html">
+        <source>Show on dashboard</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="6965614903949668392" datatype="html">
         <source>Filter rules error occurred while saving this view</source>
         <context-group purpose="location">
           <context context-type="linenumber">344</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="1930477323485553035" datatype="html">
+        <source>Customize the views of your documents.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">4</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="6338800642797811873" datatype="html">
+        <source>Documents page size</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">41</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="4729108320774167624" datatype="html">
+        <source>Display as</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">44</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="1358239534403218079" datatype="html">
+        <source>Table</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">46</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="4236040382842528005" datatype="html">
+        <source>Small Cards</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">47</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="8569593958139569111" datatype="html">
+        <source>Large Cards</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">48</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="7877440816920439876" datatype="html">
+        <source>No saved views defined.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
+          <context context-type="linenumber">61</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="5610279464668232148" 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/manage/saved-views/saved-views.component.ts</context>
+          <context context-type="linenumber">113</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="1660419335376265526" datatype="html">
+        <source>Views saved successfully.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.ts</context>
+          <context context-type="linenumber">138</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="1699877326523238632" datatype="html">
+        <source>Error while saving views.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.ts</context>
+          <context context-type="linenumber">143</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="5101757640976222639" datatype="html">
         <source>storage path</source>
         <context-group purpose="location">
index 8aacba8c868ce46c32dc9981101d11a1aec6d3e3..c2e86208ce869b04955d12a579aae8c36ca2d874 100644 (file)
@@ -27,6 +27,7 @@ import { UsersAndGroupsComponent } from './components/admin/users-groups/users-g
 import { CustomFieldsComponent } from './components/manage/custom-fields/custom-fields.component'
 import { ConfigComponent } from './components/admin/config/config.component'
 import { TrashComponent } from './components/admin/trash/trash.component'
+import { SavedViewsComponent } from './components/manage/saved-views/saved-views.component'
 
 export const routes: Routes = [
   { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
@@ -165,6 +166,10 @@ export const routes: Routes = [
         path: 'settings/usersgroups',
         redirectTo: '/usersgroups',
       },
+      {
+        path: 'settings/savedviews',
+        redirectTo: '/savedviews',
+      },
       {
         path: 'settings',
         component: SettingsComponent,
@@ -255,6 +260,17 @@ export const routes: Routes = [
           },
         },
       },
+      {
+        path: 'savedviews',
+        component: SavedViewsComponent,
+        canActivate: [PermissionsGuard],
+        data: {
+          requiredPermission: {
+            action: PermissionAction.View,
+            type: PermissionType.SavedView,
+          },
+        },
+      },
     ],
   },
 
index 7ce6d94945976c3150dbe8a5184e2f252fae72c7..594f972a96a4e38a921e1dfef21a673a9850ceb8 100644 (file)
@@ -165,7 +165,7 @@ export class AppComponent implements OnInit, OnDestroy {
       [
         {
           anchorId: 'tour.dashboard',
-          content: $localize`The dashboard can be used to show saved views, such as an 'Inbox'. Those settings are found under Settings > Saved Views once you have created some.`,
+          content: $localize`The dashboard can be used to show saved views, such as an 'Inbox'. Views are found under Manage > Saved Views once you have created some.`,
           route: '/dashboard',
           delayAfterNavigation: 500,
           isOptional: false,
@@ -227,7 +227,7 @@ export class AppComponent implements OnInit, OnDestroy {
         },
         {
           anchorId: 'tour.settings',
-          content: $localize`Check out the settings for various tweaks to the web app and toggle settings for saved views.`,
+          content: $localize`Check out the settings for various tweaks to the web app.`,
           route: '/settings',
           backdropConfig: {
             offset: 0,
index 702a8dc6a6561bf75cb41783e44f719415355acb..68124d5411518da1f8d662e36e38c6add231569e 100644 (file)
@@ -132,6 +132,7 @@ import { HotkeyDialogComponent } from './components/common/hotkey-dialog/hotkey-
 import { DeletePagesConfirmDialogComponent } from './components/common/confirm-dialog/delete-pages-confirm-dialog/delete-pages-confirm-dialog.component'
 import { TrashComponent } from './components/admin/trash/trash.component'
 import { EntriesComponent } from './components/common/input/entries/entries.component'
+import { SavedViewsComponent } from './components/manage/saved-views/saved-views.component'
 import {
   airplane,
   archive,
@@ -235,6 +236,7 @@ import {
   trash,
   uiRadios,
   upcScan,
+  windowStack,
   x,
   xCircle,
   xLg,
@@ -343,6 +345,7 @@ const icons = {
   trash,
   uiRadios,
   upcScan,
+  windowStack,
   x,
   xCircle,
   xLg,
@@ -524,6 +527,7 @@ function initializeApp(settings: SettingsService) {
     DeletePagesConfirmDialogComponent,
     TrashComponent,
     EntriesComponent,
+    SavedViewsComponent,
   ],
   bootstrap: [AppComponent],
   imports: [
index 827f61d7857ba41283e8de7e0df7c46812805ed9..d798e1defbc19214417f68a1cbf164a4532c4089 100644 (file)
@@ -1,7 +1,7 @@
 <pngx-page-header
   title="Settings"
   i18n-title
-  info="Options to customize appearance, notifications, saved views and more. Settings apply to the <strong>current user only</strong>."
+  info="Options to customize appearance, notifications and more. Settings apply to the <strong>current user only</strong>."
   i18n-info
   >
   <button class="btn btn-sm btn-outline-primary" (click)="tourService.start()">
           </div>
         </div>
 
-        <h4 class="mt-4" i18n>Notes</h4>
+        <h4 class="mt-4" i18n>Saved Views</h4>
+        <div class="row mb-3">
+          <div class="offset-md-3 col">
+            <pngx-input-check i18n-title title="Show warning when closing saved views with unsaved changes" formControlName="savedViewsWarnOnUnsavedChange"></pngx-input-check>
+          </div>
+        </div>
 
+        <h4 class="mt-4" i18n>Notes</h4>
         <div class="row mb-3">
           <div class="offset-md-3 col">
             <pngx-input-check i18n-title title="Enable notes" formControlName="notesEnabled"></pngx-input-check>
 
       </ng-template>
     </li>
-
-    <li [ngbNavItem]="SettingsNavIDs.SavedViews" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.SavedView }">
-      <a ngbNavLink i18n>Saved views</a>
-      <ng-template ngbNavContent>
-
-        <h4 i18n>Settings</h4>
-        <div class="row mb-3">
-          <div class="offset-md-3 col">
-            <pngx-input-check i18n-title title="Show warning when closing saved views with unsaved changes" formControlName="savedViewsWarnOnUnsavedChange"></pngx-input-check>
-          </div>
-        </div>
-
-        <h4 i18n>Views</h4>
-        <ul class="list-group" formGroupName="savedViews">
-
-          @for (view of savedViews; track view) {
-            <li class="list-group-item py-3">
-            <div [formGroupName]="view.id">
-              <div class="row">
-                <div class="col">
-                  <pngx-input-text title="Name" formControlName="name"></pngx-input-text>
-                </div>
-                <div class="col">
-                  <div class="form-check form-switch mt-3">
-                    <input type="checkbox" class="form-check-input" id="show_on_dashboard_{{view.id}}" formControlName="show_on_dashboard">
-                    <label class="form-check-label" for="show_on_dashboard_{{view.id}}" i18n>Show on dashboard</label>
-                  </div>
-                  <div class="form-check form-switch">
-                    <input type="checkbox" class="form-check-input" id="show_in_sidebar_{{view.id}}" formControlName="show_in_sidebar">
-                    <label class="form-check-label" for="show_in_sidebar_{{view.id}}" i18n>Show in sidebar</label>
-                  </div>
-                </div>
-                <div class="col-auto">
-                  <label class="form-label" for="name_{{view.id}}" i18n>Actions</label>
-                  <pngx-confirm-button
-                    label="Delete"
-                    i18n-label
-                    (confirm)="deleteSavedView(view)"
-                    *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.SavedView }"
-                    buttonClasses="btn-sm btn-outline-danger form-control"
-                    iconName="trash">
-                  </pngx-confirm-button>
-                </div>
-              </div>
-              <div class="row">
-                <div class="col">
-                  <pngx-input-number i18n-title title="Documents page size" [showAdd]="false" formControlName="page_size"></pngx-input-number>
-                </div>
-                <div class="col">
-                  <label class="form-label" for="display_mode_{{view.id}}" i18n>Display as</label>
-                  <select class="form-select" formControlName="display_mode">
-                    <option [ngValue]="DisplayMode.TABLE" i18n>Table</option>
-                    <option [ngValue]="DisplayMode.SMALL_CARDS" i18n>Small Cards</option>
-                    <option [ngValue]="DisplayMode.LARGE_CARDS" i18n>Large Cards</option>
-                  </select>
-                </div>
-                  @if (displayFields) {
-                    <pngx-input-drag-drop-select i18n-title title="Show" i18n-emptyText emptyText="Default" [items]="displayFields" formControlName="display_fields"></pngx-input-drag-drop-select>
-                  }
-                </div>
-            </div>
-            </li>
-          }
-
-          @if (savedViews && savedViews.length === 0) {
-            <li class="list-group-item">
-              <div i18n>No saved views defined.</div>
-            </li>
-          }
-
-          @if (!savedViews) {
-            <li class="list-group-item">
-              <div class="spinner-border spinner-border-sm fw-normal ms-2 me-auto" role="status"></div>
-              <div class="visually-hidden" i18n>Loading...</div>
-            </li>
-          }
-
-        </ul>
-
-      </ng-template>
-    </li>
   </ul>
 
   <div [ngbNavOutlet]="nav" class="border-start border-end border-bottom p-3 mb-3 shadow-sm"></div>
index bd9fe5664dd147acd45e9c2ff52d2df00137e2e4..b6f863163f70c382d55832b1cb22475766dd2073 100644 (file)
@@ -15,7 +15,6 @@ import {
 import { NgSelectModule } from '@ng-select/ng-select'
 import { of, throwError } from 'rxjs'
 import { routes } from 'src/app/app-routing.module'
-import { SavedView } from 'src/app/data/saved-view'
 import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
 import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
 import { PermissionsGuard } from 'src/app/guards/permissions.guard'
@@ -52,10 +51,6 @@ import { DragDropSelectComponent } from '../../common/input/drag-drop-select/dra
 import { DragDropModule } from '@angular/cdk/drag-drop'
 import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
 
-const savedViews = [
-  { id: 1, name: 'view1', show_in_sidebar: true, show_on_dashboard: true },
-  { id: 2, name: 'view2', show_in_sidebar: false, show_on_dashboard: false },
-]
 const users = [
   { id: 1, username: 'user1', is_superuser: false },
   { id: 2, username: 'user2', is_superuser: false },
@@ -70,7 +65,6 @@ describe('SettingsComponent', () => {
   let fixture: ComponentFixture<SettingsComponent>
   let router: Router
   let settingsService: SettingsService
-  let savedViewService: SavedViewService
   let activatedRoute: ActivatedRoute
   let viewportScroller: ViewportScroller
   let toastService: ToastService
@@ -139,7 +133,6 @@ describe('SettingsComponent', () => {
       .spyOn(permissionsService, 'currentUserOwnsObject')
       .mockReturnValue(true)
     groupService = TestBed.inject(GroupService)
-    savedViewService = TestBed.inject(SavedViewService)
   })
 
   function completeSetup(excludeService = null) {
@@ -161,15 +154,6 @@ describe('SettingsComponent', () => {
         })
       )
     }
-    if (excludeService !== savedViewService) {
-      jest.spyOn(savedViewService, 'listAll').mockReturnValue(
-        of({
-          all: savedViews.map((v) => v.id),
-          count: savedViews.length,
-          results: (savedViews as SavedView[]).concat([]),
-        })
-      )
-    }
 
     fixture = TestBed.createComponent(SettingsComponent)
     component = fixture.componentInstance
@@ -184,8 +168,6 @@ describe('SettingsComponent', () => {
     expect(navigateSpy).toHaveBeenCalledWith(['settings', 'permissions'])
     tabButtons[2].nativeElement.dispatchEvent(new MouseEvent('click'))
     expect(navigateSpy).toHaveBeenCalledWith(['settings', 'notifications'])
-    tabButtons[3].nativeElement.dispatchEvent(new MouseEvent('click'))
-    expect(navigateSpy).toHaveBeenCalledWith(['settings', 'savedviews'])
 
     const initSpy = jest.spyOn(component, 'initialize')
     component.isDirty = true // mock dirty
@@ -213,90 +195,8 @@ describe('SettingsComponent', () => {
     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()
-
-    const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
-    tabButtons[3].nativeElement.dispatchEvent(new MouseEvent('click'))
-    fixture.detectChanges()
-
-    const toastErrorSpy = jest.spyOn(toastService, 'showError')
-    const toastSpy = jest.spyOn(toastService, 'show')
-    const savedViewPatchSpy = jest.spyOn(savedViewService, 'patchMany')
-
-    const toggle = fixture.debugElement.query(
-      By.css('.form-check.form-switch input')
-    )
-    toggle.nativeElement.checked = true
-    toggle.nativeElement.dispatchEvent(new Event('change'))
-
-    // saved views error first
-    savedViewPatchSpy.mockReturnValueOnce(
-      throwError(() => new Error('unable to save saved views'))
-    )
-    component.saveSettings()
-    expect(toastErrorSpy).toHaveBeenCalled()
-    expect(savedViewPatchSpy).toHaveBeenCalled()
-    toastSpy.mockClear()
-    toastErrorSpy.mockClear()
-    savedViewPatchSpy.mockClear()
-
-    // succeed saved views
-    savedViewPatchSpy.mockReturnValueOnce(of(savedViews as SavedView[]))
-    component.saveSettings()
-    expect(toastErrorSpy).not.toHaveBeenCalled()
-    expect(savedViewPatchSpy).toHaveBeenCalled()
-  })
-
-  it('should update only patch saved views that have changed', () => {
-    completeSetup()
-
-    const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
-    tabButtons[3].nativeElement.dispatchEvent(new MouseEvent('click'))
-    fixture.detectChanges()
-
-    const patchSpy = jest.spyOn(savedViewService, 'patchMany')
-    component.saveSettings()
-    expect(patchSpy).not.toHaveBeenCalled()
-
-    const view = savedViews[0]
-    const toggle = fixture.debugElement.query(
-      By.css('.form-check.form-switch input')
-    )
-    toggle.nativeElement.checked = true
-    toggle.nativeElement.dispatchEvent(new Event('change'))
-    // register change
-    component.savedViewGroup.get(view.id.toString()).value[
-      'show_on_dashboard'
-    ] = !view.show_on_dashboard
-    fixture.detectChanges()
-
-    component.saveSettings()
-    expect(patchSpy).toHaveBeenCalledWith([
-      {
-        id: view.id,
-        name: view.name,
-        show_in_sidebar: view.show_in_sidebar,
-        show_on_dashboard: !view.show_on_dashboard,
-      },
-    ])
-  })
-
   it('should support save local settings updating appearance settings and calling API, show error', () => {
     completeSetup()
-    jest.spyOn(savedViewService, 'patchMany').mockReturnValue(of([]))
     const toastErrorSpy = jest.spyOn(toastService, 'showError')
     const toastSpy = jest.spyOn(toastService, 'show')
     const storeSpy = jest.spyOn(settingsService, 'storeSettings')
@@ -326,7 +226,6 @@ describe('SettingsComponent', () => {
 
   it('should offer reload if settings changes require', () => {
     completeSetup()
-    jest.spyOn(savedViewService, 'patchMany').mockReturnValue(of([]))
     let toast: Toast
     toastService.getToasts().subscribe((t) => (toast = t[0]))
     component.initialize(true) // reset
@@ -361,18 +260,6 @@ describe('SettingsComponent', () => {
     component.clearThemeColor()
   })
 
-  it('should support delete saved view', () => {
-    completeSetup()
-    const toastSpy = jest.spyOn(toastService, 'showInfo')
-    const deleteSpy = jest.spyOn(savedViewService, 'delete')
-    deleteSpy.mockReturnValue(of(true))
-    component.deleteSavedView(savedViews[0] as SavedView)
-    expect(deleteSpy).toHaveBeenCalled()
-    expect(toastSpy).toHaveBeenCalledWith(
-      `Saved view "${savedViews[0].name}" deleted.`
-    )
-  })
-
   it('should show errors on load if load users failure', () => {
     const toastErrorSpy = jest.spyOn(toastService, 'showError')
     jest
index c08a869e2f42bca8b2b0dffaae8177cae4c19c9d..de6d34a2a0ae6ee191ce2fe1a268d28f71d4568a 100644 (file)
@@ -26,7 +26,6 @@ import {
   tap,
 } from 'rxjs'
 import { Group } from 'src/app/data/group'
-import { SavedView } from 'src/app/data/saved-view'
 import { GlobalSearchType, SETTINGS_KEYS } from 'src/app/data/ui-settings'
 import { User } from 'src/app/data/user'
 import { DocumentListViewService } from 'src/app/services/document-list-view.service'
@@ -36,7 +35,6 @@ import {
   PermissionType,
 } from 'src/app/services/permissions.service'
 import { GroupService } from 'src/app/services/rest/group.service'
-import { SavedViewService } from 'src/app/services/rest/saved-view.service'
 import { UserService } from 'src/app/services/rest/user.service'
 import {
   SettingsService,
@@ -50,7 +48,6 @@ import {
   SystemStatusItemStatus,
   SystemStatus,
 } from 'src/app/data/system-status'
-import { DisplayMode } from 'src/app/data/document'
 
 enum SettingsNavIDs {
   General = 1,
@@ -75,9 +72,6 @@ export class SettingsComponent
   implements OnInit, AfterViewInit, OnDestroy, DirtyComponent
 {
   activeNavID: number
-  DisplayMode = DisplayMode
-
-  savedViewGroup = new FormGroup({})
 
   settingsForm = new FormGroup({
     bulkEditConfirmationDialogs: new FormControl(null),
@@ -110,14 +104,9 @@ export class SettingsComponent
     notificationsConsumerSuppressOnDashboard: new FormControl(null),
 
     savedViewsWarnOnUnsavedChange: new FormControl(null),
-    savedViews: this.savedViewGroup,
   })
 
-  savedViews: SavedView[]
   SettingsNavIDs = SettingsNavIDs
-  get displayFields() {
-    return this.settings.allDisplayFields
-  }
 
   store: BehaviorSubject<any>
   storeSub: Subscription
@@ -152,7 +141,6 @@ export class SettingsComponent
   }
 
   constructor(
-    public savedViewService: SavedViewService,
     private documentListViewService: DocumentListViewService,
     private toastService: ToastService,
     private settings: SettingsService,
@@ -214,18 +202,6 @@ export class SettingsComponent
         })
     }
 
-    if (
-      this.permissionsService.currentUserCan(
-        PermissionAction.View,
-        PermissionType.SavedView
-      )
-    ) {
-      this.savedViewService.listAll().subscribe((r) => {
-        this.savedViews = r.results
-        this.initialize(false)
-      })
-    }
-
     this.activatedRoute.paramMap.subscribe((paramMap) => {
       const section = paramMap.get('section')
       if (section) {
@@ -235,9 +211,6 @@ export class SettingsComponent
         if (navIDKey) {
           this.activeNavID = SettingsNavIDs[navIDKey]
         }
-        if (this.activeNavID === SettingsNavIDs.SavedViews) {
-          this.settings.organizingSidebarSavedViews = true
-        }
       }
     })
   }
@@ -314,7 +287,6 @@ export class SettingsComponent
       ),
       searchDbOnly: this.settings.get(SETTINGS_KEYS.SEARCH_DB_ONLY),
       searchLink: this.settings.get(SETTINGS_KEYS.SEARCH_FULL_TYPE),
-      savedViews: {},
     }
   }
 
@@ -327,15 +299,11 @@ 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
-          }
         })
   }
 
@@ -346,34 +314,6 @@ export class SettingsComponent
 
     let storeData = this.getCurrentSettings()
 
-    if (this.savedViews) {
-      this.emptyGroup(this.savedViewGroup)
-
-      for (let view of this.savedViews) {
-        storeData.savedViews[view.id.toString()] = {
-          id: view.id,
-          name: view.name,
-          show_on_dashboard: view.show_on_dashboard,
-          show_in_sidebar: view.show_in_sidebar,
-          page_size: view.page_size,
-          display_mode: view.display_mode,
-          display_fields: view.display_fields,
-        }
-        this.savedViewGroup.addControl(
-          view.id.toString(),
-          new FormGroup({
-            id: new FormControl(null),
-            name: new FormControl(null),
-            show_on_dashboard: new FormControl(null),
-            show_in_sidebar: new FormControl(null),
-            page_size: new FormControl(null),
-            display_mode: new FormControl(null),
-            display_fields: new FormControl([]),
-          })
-        )
-      }
-    }
-
     this.store = new BehaviorSubject(storeData)
 
     this.storeSub = this.store.asObservable().subscribe((state) => {
@@ -413,32 +353,12 @@ export class SettingsComponent
     }
   }
 
-  private emptyGroup(group: FormGroup) {
-    Object.keys(group.controls).forEach((key) => group.removeControl(key))
-  }
-
   ngOnDestroy() {
     if (this.isDirty) this.settings.updateAppearanceSettings() // in case user changed appearance but didn't save
     this.storeSub && this.storeSub.unsubscribe()
-    this.settings.organizingSidebarSavedViews = false
   }
 
-  deleteSavedView(savedView: SavedView) {
-    this.savedViewService.delete(savedView).subscribe(() => {
-      this.savedViewGroup.removeControl(savedView.id.toString())
-      this.savedViews.splice(this.savedViews.indexOf(savedView), 1)
-      this.toastService.showInfo(
-        $localize`Saved view "${savedView.name}" deleted.`
-      )
-      this.savedViewService.clearCache()
-      this.savedViewService.listAll().subscribe((r) => {
-        this.savedViews = r.results
-        this.initialize(true)
-      })
-    })
-  }
-
-  private saveLocalSettings() {
+  public saveSettings() {
     this.savePending = true
     const reloadRequired =
       this.settingsForm.value.displayLanguage !=
@@ -600,31 +520,6 @@ export class SettingsComponent
     return new Date()
   }
 
-  saveSettings() {
-    // only patch views that have actually changed
-    const changed: SavedView[] = []
-    Object.values(this.savedViewGroup.controls)
-      .filter((g: FormGroup) => !g.pristine)
-      .forEach((group: FormGroup) => {
-        changed.push(group.value)
-      })
-    if (changed.length > 0) {
-      this.savedViewService.patchMany(changed).subscribe({
-        next: () => {
-          this.saveLocalSettings()
-        },
-        error: (error) => {
-          this.toastService.showError(
-            $localize`Error while storing settings on server.`,
-            error
-          )
-        },
-      })
-    } else {
-      this.saveLocalSettings()
-    }
-  }
-
   reset() {
     this.settingsForm.patchValue(this.store.getValue())
   }
index f69b5246a59801810fabae85a3ec024294f7a871..c9192df6a15b5b16e6c44eba6c7da424beeec327 100644 (file)
                 <i-bs class="me-1" name="ui-radios"></i-bs><span>&nbsp;<ng-container i18n>Custom Fields</ng-container></span>
               </a>
             </li>
+            <li class="nav-item app-link" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.SavedView }">
+              <a class="nav-link" routerLink="savedviews" routerLinkActive="active" (click)="closeMenu()"
+                ngbPopover="Custom Fields" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
+                container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
+                <i-bs class="me-1" name="window-stack"></i-bs><span>&nbsp;<ng-container i18n>Saved Views</ng-container></span>
+              </a>
+            </li>
             <li class="nav-item app-link"
               *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Workflow }"
               tourAnchor="tour.workflows">
index ebe3536e58b6ec7fe5408d52d0aae6a030b73489..fdf3e24ed7613970d7096eccb273a43e325a02f2 100644 (file)
@@ -90,6 +90,7 @@
         }
       </div>
       <button ngbDropdownItem (click)="saveViewConfigAs()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.SavedView }" i18n>Save as...</button>
+      <a ngbDropdownItem routerLink="/savedviews" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.SavedView }" i18n>All saved views</a>
     </div>
   </div>
 
diff --git a/src-ui/src/app/components/manage/saved-views/saved-views.component.html b/src-ui/src/app/components/manage/saved-views/saved-views.component.html
new file mode 100644 (file)
index 0000000..58111fa
--- /dev/null
@@ -0,0 +1,75 @@
+<pngx-page-header
+  title="Saved Views"
+  i18n-title
+  info="Customize the views of your documents."
+  i18n-info
+  >
+</pngx-page-header>
+<form [formGroup]="savedViewsForm" (ngSubmit)="save()">
+  <ul class="list-group mb-3" formGroupName="savedViews">
+    @for (view of savedViews; track view) {
+      <li class="list-group-item py-3">
+      <div [formGroupName]="view.id">
+        <div class="row">
+          <div class="col">
+            <pngx-input-text title="Name" formControlName="name"></pngx-input-text>
+          </div>
+          <div class="col">
+            <div class="form-check form-switch mt-3">
+              <input type="checkbox" class="form-check-input" id="show_on_dashboard_{{view.id}}" formControlName="show_on_dashboard">
+              <label class="form-check-label" for="show_on_dashboard_{{view.id}}" i18n>Show on dashboard</label>
+            </div>
+            <div class="form-check form-switch">
+              <input type="checkbox" class="form-check-input" id="show_in_sidebar_{{view.id}}" formControlName="show_in_sidebar">
+              <label class="form-check-label" for="show_in_sidebar_{{view.id}}" i18n>Show in sidebar</label>
+            </div>
+          </div>
+          <div class="col-auto">
+            <label class="form-label" for="name_{{view.id}}" i18n>Actions</label>
+            <pngx-confirm-button
+              label="Delete"
+              i18n-label
+              (confirm)="deleteSavedView(view)"
+              *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.SavedView }"
+              buttonClasses="btn-sm btn-outline-danger form-control"
+              iconName="trash">
+            </pngx-confirm-button>
+          </div>
+        </div>
+        <div class="row">
+          <div class="col">
+            <pngx-input-number i18n-title title="Documents page size" [showAdd]="false" formControlName="page_size"></pngx-input-number>
+          </div>
+          <div class="col">
+            <label class="form-label" for="display_mode_{{view.id}}" i18n>Display as</label>
+            <select class="form-select" formControlName="display_mode">
+              <option [ngValue]="DisplayMode.TABLE" i18n>Table</option>
+              <option [ngValue]="DisplayMode.SMALL_CARDS" i18n>Small Cards</option>
+              <option [ngValue]="DisplayMode.LARGE_CARDS" i18n>Large Cards</option>
+            </select>
+          </div>
+            @if (displayFields) {
+              <pngx-input-drag-drop-select i18n-title title="Show" i18n-emptyText emptyText="Default" [items]="displayFields" formControlName="display_fields"></pngx-input-drag-drop-select>
+            }
+          </div>
+      </div>
+      </li>
+    }
+
+    @if (savedViews && savedViews.length === 0) {
+      <li class="list-group-item">
+        <div i18n>No saved views defined.</div>
+      </li>
+    }
+
+    @if (!savedViews) {
+      <li class="list-group-item">
+        <div class="spinner-border spinner-border-sm fw-normal ms-2 me-auto" role="status"></div>
+        <div class="visually-hidden" i18n>Loading...</div>
+      </li>
+    }
+  </ul>
+
+  <button type="submit" class="btn btn-primary mb-2" [disabled]="(isDirty$ | async) === false" i18n>Save</button>
+  <button type="button" (click)="reset()" class="btn btn-secondary ms-2 mb-2" [disabled]="(isDirty$ | async) === false" i18n>Cancel</button>
+</form>
diff --git a/src-ui/src/app/components/manage/saved-views/saved-views.component.scss b/src-ui/src/app/components/manage/saved-views/saved-views.component.scss
new file mode 100644 (file)
index 0000000..5d4e87f
--- /dev/null
@@ -0,0 +1,3 @@
+:host {
+  display: block;
+}
diff --git a/src-ui/src/app/components/manage/saved-views/saved-views.component.spec.ts b/src-ui/src/app/components/manage/saved-views/saved-views.component.spec.ts
new file mode 100644 (file)
index 0000000..aaa7743
--- /dev/null
@@ -0,0 +1,165 @@
+import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
+import { provideHttpClientTesting } from '@angular/common/http/testing'
+import { ComponentFixture, TestBed } from '@angular/core/testing'
+import { ReactiveFormsModule, FormsModule } from '@angular/forms'
+import { By } from '@angular/platform-browser'
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
+import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
+import { of, throwError } from 'rxjs'
+import { SavedView } from 'src/app/data/saved-view'
+import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
+import { PermissionsGuard } from 'src/app/guards/permissions.guard'
+import { PermissionsService } from 'src/app/services/permissions.service'
+import { SavedViewService } from 'src/app/services/rest/saved-view.service'
+import { ToastService } from 'src/app/services/toast.service'
+import { ConfirmButtonComponent } from '../../common/confirm-button/confirm-button.component'
+import { CheckComponent } from '../../common/input/check/check.component'
+import { DragDropSelectComponent } from '../../common/input/drag-drop-select/drag-drop-select.component'
+import { NumberComponent } from '../../common/input/number/number.component'
+import { SelectComponent } from '../../common/input/select/select.component'
+import { TextComponent } from '../../common/input/text/text.component'
+import { PageHeaderComponent } from '../../common/page-header/page-header.component'
+import { SavedViewsComponent } from './saved-views.component'
+import { DragDropModule } from '@angular/cdk/drag-drop'
+
+const savedViews = [
+  { id: 1, name: 'view1', show_in_sidebar: true, show_on_dashboard: true },
+  { id: 2, name: 'view2', show_in_sidebar: false, show_on_dashboard: false },
+]
+
+describe('SavedViewsComponent', () => {
+  let component: SavedViewsComponent
+  let fixture: ComponentFixture<SavedViewsComponent>
+  let savedViewService: SavedViewService
+  let toastService: ToastService
+
+  beforeEach(async () => {
+    TestBed.configureTestingModule({
+      declarations: [
+        SavedViewsComponent,
+        PageHeaderComponent,
+        IfPermissionsDirective,
+        CheckComponent,
+        SelectComponent,
+        TextComponent,
+        NumberComponent,
+        ConfirmButtonComponent,
+        DragDropSelectComponent,
+      ],
+      imports: [
+        NgbModule,
+        NgxBootstrapIconsModule.pick(allIcons),
+        ReactiveFormsModule,
+        FormsModule,
+        DragDropModule,
+      ],
+      providers: [
+        {
+          provide: PermissionsService,
+          useValue: {
+            currentUserCan: () => true,
+          },
+        },
+        PermissionsGuard,
+        provideHttpClient(withInterceptorsFromDi()),
+        provideHttpClientTesting(),
+      ],
+    }).compileComponents()
+
+    savedViewService = TestBed.inject(SavedViewService)
+    toastService = TestBed.inject(ToastService)
+    fixture = TestBed.createComponent(SavedViewsComponent)
+    component = fixture.componentInstance
+
+    jest.spyOn(savedViewService, 'listAll').mockReturnValue(
+      of({
+        all: savedViews.map((v) => v.id),
+        count: savedViews.length,
+        results: (savedViews as SavedView[]).concat([]),
+      })
+    )
+
+    fixture.detectChanges()
+  })
+
+  it('should support save saved views, show error', () => {
+    const toastErrorSpy = jest.spyOn(toastService, 'showError')
+    const toastSpy = jest.spyOn(toastService, 'show')
+    const savedViewPatchSpy = jest.spyOn(savedViewService, 'patchMany')
+
+    const toggle = fixture.debugElement.query(
+      By.css('.form-check.form-switch input')
+    )
+    toggle.nativeElement.checked = true
+    toggle.nativeElement.dispatchEvent(new Event('change'))
+
+    // saved views error first
+    savedViewPatchSpy.mockReturnValueOnce(
+      throwError(() => new Error('unable to save saved views'))
+    )
+    component.save()
+    expect(toastErrorSpy).toHaveBeenCalled()
+    expect(savedViewPatchSpy).toHaveBeenCalled()
+    toastSpy.mockClear()
+    toastErrorSpy.mockClear()
+    savedViewPatchSpy.mockClear()
+
+    // succeed saved views
+    savedViewPatchSpy.mockReturnValueOnce(of(savedViews as SavedView[]))
+    component.save()
+    expect(toastErrorSpy).not.toHaveBeenCalled()
+    expect(savedViewPatchSpy).toHaveBeenCalled()
+  })
+
+  it('should update only patch saved views that have changed', () => {
+    const patchSpy = jest.spyOn(savedViewService, 'patchMany')
+    component.save()
+    expect(patchSpy).not.toHaveBeenCalled()
+
+    const view = savedViews[0]
+    const toggle = fixture.debugElement.query(
+      By.css('.form-check.form-switch input')
+    )
+    toggle.nativeElement.checked = true
+    toggle.nativeElement.dispatchEvent(new Event('change'))
+    // register change
+    component.savedViewsForm.get('savedViews').get(view.id.toString()).value[
+      'show_on_dashboard'
+    ] = !view.show_on_dashboard
+    fixture.detectChanges()
+
+    component.save()
+    expect(patchSpy).toHaveBeenCalledWith([
+      {
+        id: view.id,
+        name: view.name,
+        show_in_sidebar: view.show_in_sidebar,
+        show_on_dashboard: !view.show_on_dashboard,
+      },
+    ])
+  })
+
+  it('should support delete saved view', () => {
+    const toastSpy = jest.spyOn(toastService, 'showInfo')
+    const deleteSpy = jest.spyOn(savedViewService, 'delete')
+    deleteSpy.mockReturnValue(of(true))
+    component.deleteSavedView(savedViews[0] as SavedView)
+    expect(deleteSpy).toHaveBeenCalled()
+    expect(toastSpy).toHaveBeenCalledWith(
+      `Saved view "${savedViews[0].name}" deleted.`
+    )
+  })
+
+  it('should support reset', () => {
+    const view = savedViews[0]
+    component.savedViewsForm.get('savedViews').get(view.id.toString()).value[
+      'show_on_dashboard'
+    ] = !view.show_on_dashboard
+    component.reset()
+    expect(
+      component.savedViewsForm.get('savedViews').get(view.id.toString()).value[
+        'show_on_dashboard'
+      ]
+    ).toEqual(view.show_on_dashboard)
+  })
+})
diff --git a/src-ui/src/app/components/manage/saved-views/saved-views.component.ts b/src-ui/src/app/components/manage/saved-views/saved-views.component.ts
new file mode 100644 (file)
index 0000000..dc09c71
--- /dev/null
@@ -0,0 +1,150 @@
+import { Component, OnDestroy, OnInit } from '@angular/core'
+import { FormControl, FormGroup } from '@angular/forms'
+import { SavedView } from 'src/app/data/saved-view'
+import { SavedViewService } from 'src/app/services/rest/saved-view.service'
+import { SettingsService } from 'src/app/services/settings.service'
+import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
+import { DisplayMode } from 'src/app/data/document'
+import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs'
+import { dirtyCheck } from '@ngneat/dirty-check-forms'
+import { ToastService } from 'src/app/services/toast.service'
+
+@Component({
+  selector: 'pngx-saved-views',
+  templateUrl: './saved-views.component.html',
+  styleUrl: './saved-views.component.scss',
+})
+export class SavedViewsComponent
+  extends ComponentWithPermissions
+  implements OnInit, OnDestroy
+{
+  DisplayMode = DisplayMode
+
+  public savedViews: SavedView[]
+  private savedViewsGroup = new FormGroup({})
+  public savedViewsForm: FormGroup = new FormGroup({
+    savedViews: this.savedViewsGroup,
+  })
+
+  private store: BehaviorSubject<any>
+  private storeSub: Subscription
+  public isDirty$: Observable<boolean>
+  private isDirty: boolean = false
+  private unsubscribeNotifier: Subject<any> = new Subject()
+  private savePending: boolean = false
+
+  get displayFields() {
+    return this.settings.allDisplayFields
+  }
+
+  constructor(
+    private savedViewService: SavedViewService,
+    private settings: SettingsService,
+    private toastService: ToastService
+  ) {
+    super()
+  }
+
+  ngOnInit(): void {
+    this.settings.organizingSidebarSavedViews = true
+
+    this.savedViewService.listAll().subscribe((r) => {
+      this.savedViews = r.results
+      this.initialize()
+    })
+  }
+
+  ngOnDestroy(): void {
+    this.settings.organizingSidebarSavedViews = false
+    this.unsubscribeNotifier.next(this)
+    this.unsubscribeNotifier.complete()
+    this.storeSub.unsubscribe()
+  }
+
+  private initialize() {
+    this.emptyGroup(this.savedViewsGroup)
+
+    let storeData = {
+      savedViews: {},
+    }
+
+    for (let view of this.savedViews) {
+      storeData.savedViews[view.id.toString()] = {
+        id: view.id,
+        name: view.name,
+        show_on_dashboard: view.show_on_dashboard,
+        show_in_sidebar: view.show_in_sidebar,
+        page_size: view.page_size,
+        display_mode: view.display_mode,
+        display_fields: view.display_fields,
+      }
+      this.savedViewsGroup.addControl(
+        view.id.toString(),
+        new FormGroup({
+          id: new FormControl(null),
+          name: new FormControl(null),
+          show_on_dashboard: new FormControl(null),
+          show_in_sidebar: new FormControl(null),
+          page_size: new FormControl(null),
+          display_mode: new FormControl(null),
+          display_fields: new FormControl([]),
+        })
+      )
+    }
+
+    this.store = new BehaviorSubject(storeData)
+    this.storeSub = this.store.asObservable().subscribe((state) => {
+      this.savedViewsForm.patchValue(state, { emitEvent: false })
+    })
+
+    // Initialize dirtyCheck
+    this.isDirty$ = dirtyCheck(this.savedViewsForm, this.store.asObservable())
+  }
+
+  public reset() {
+    this.savedViewsForm.patchValue(this.store.getValue())
+  }
+
+  public deleteSavedView(savedView: SavedView) {
+    this.savedViewService.delete(savedView).subscribe(() => {
+      this.savedViewsGroup.removeControl(savedView.id.toString())
+      this.savedViews.splice(this.savedViews.indexOf(savedView), 1)
+      this.toastService.showInfo(
+        $localize`Saved view "${savedView.name}" deleted.`
+      )
+      this.savedViewService.clearCache()
+      this.savedViewService.listAll().subscribe((r) => {
+        this.savedViews = r.results
+        this.initialize()
+      })
+    })
+  }
+
+  private emptyGroup(group: FormGroup) {
+    Object.keys(group.controls).forEach((key) => group.removeControl(key))
+  }
+
+  public save() {
+    // only patch views that have actually changed
+    const changed: SavedView[] = []
+    Object.values(this.savedViewsGroup.controls)
+      .filter((g: FormGroup) => !g.pristine)
+      .forEach((group: FormGroup) => {
+        changed.push(group.value)
+      })
+    if (changed.length) {
+      this.savedViewService.patchMany(changed).subscribe({
+        next: () => {
+          this.toastService.showInfo($localize`Views saved successfully.`)
+          this.store.next(this.savedViewsForm.value)
+        },
+        error: (error) => {
+          this.toastService.showError(
+            $localize`Error while saving views.`,
+            error
+          )
+        },
+      })
+    }
+  }
+}