Include saved views in global search

This commit is contained in:
shamoon 2024-04-19 11:02:13 -07:00
parent 05495794e8
commit 314e34c3b7
9 changed files with 721 additions and 551 deletions

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,9 @@
@if (type === DataType.Document) {
<i-bs width="1em" height="1em" name="pencil"></i-bs>
<span>&nbsp;<ng-container i18n>Open</ng-container></span>
} @else if (type === DataType.SavedView) {
<i-bs width="1em" height="1em" name="eye"></i-bs>
<span>&nbsp;<ng-container i18n>Open</ng-container></span>
} @else if (type === DataType.Workflow || type === DataType.CustomField || type === DataType.Group || type === DataType.User || type === DataType.MailAccount || type === DataType.MailRule) {
<i-bs width="1em" height="1em" name="pencil"></i-bs>
<span>&nbsp;<ng-container i18n>Edit</ng-container></span>
@ -41,7 +44,7 @@
<span>&nbsp;<ng-container i18n>Filter documents</ng-container></span>
}
</button>
@if (type !== DataType.Workflow && type !== DataType.CustomField && type !== DataType.Group && type !== DataType.User && type !== DataType.MailAccount && type !== DataType.MailRule) {
@if (type !== DataType.SavedView && type !== DataType.Workflow && type !== DataType.CustomField && type !== DataType.Group && type !== DataType.User && type !== DataType.MailAccount && type !== DataType.MailRule) {
<button #secondaryButton type="button" class="btn btn-sm btn-outline-primary d-flex"
(click)="secondaryAction(type, item); $event.stopPropagation()"
[disabled]="disableSecondaryButton(type, item)"
@ -69,6 +72,12 @@
<ng-container *ngTemplateOutlet="resultItemTemplate; context: {item: document, nameProp: 'title', type: DataType.Document, icon: 'file-text', date: document.added}"></ng-container>
}
}
@if (searchResults?.saved_views.length) {
<h6 class="dropdown-header" i18n="@@searchResults.saved_views">Saved Views</h6>
@for (saved_view of searchResults.saved_views; track saved_view.id) {
<ng-container *ngTemplateOutlet="resultItemTemplate; context: {item: saved_view, nameProp: 'name', type: DataType.SavedView, icon: 'funnel'}"></ng-container>
}
}
@if (searchResults?.tags.length) {
<h6 class="dropdown-header" i18n="@@searchResults.tags">Tags</h6>

View File

@ -51,6 +51,12 @@ const searchResults = {
custom_fields: [],
},
],
saved_views: [
{
id: 1,
name: 'TestSavedView',
},
],
correspondents: [
{
id: 1,

View File

@ -112,6 +112,9 @@ export class GlobalSearchComponent implements OnInit {
case DataType.Document:
this.router.navigate(['/documents', object.id])
return
case DataType.SavedView:
this.router.navigate(['/view', object.id])
return
case DataType.Correspondent:
filterRuleType = FILTER_HAS_CORRESPONDENT_ANY
break

View File

@ -1,5 +1,6 @@
export enum DataType {
Document = 'document',
SavedView = 'saved_view',
Correspondent = 'correspondent',
DocumentType = 'document_type',
StoragePath = 'storage_path',

View File

@ -15,10 +15,12 @@ import { User } from 'src/app/data/user'
import { Workflow } from 'src/app/data/workflow'
import { SettingsService } from '../settings.service'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { SavedView } from 'src/app/data/saved-view'
export interface GlobalSearchResult {
total: number
documents: Document[]
saved_views: SavedView[]
correspondents: Correspondent[]
document_types: DocumentType[]
storage_paths: StoragePath[]

View File

@ -21,6 +21,7 @@ from documents.models import CustomFieldInstance
from documents.models import Document
from documents.models import DocumentType
from documents.models import Note
from documents.models import SavedView
from documents.models import StoragePath
from documents.models import Tag
from documents.models import Workflow
@ -1171,10 +1172,17 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
StoragePath.objects.create(name="path 2", path="path2")
tag1 = Tag.objects.create(name="bank tag1")
Tag.objects.create(name="tag2")
user1 = User.objects.create_user("bank user1")
user1 = User.objects.create_superuser("bank user1")
User.objects.create_user("user2")
group1 = Group.objects.create(name="bank group1")
Group.objects.create(name="group2")
SavedView.objects.create(
name="bank view",
show_on_dashboard=True,
show_in_sidebar=True,
sort_field="",
owner=user1,
)
mail_account1 = MailAccount.objects.create(name="bank mail account 1")
mail_account2 = MailAccount.objects.create(name="mail account 2")
mail_rule1 = MailRule.objects.create(
@ -1198,10 +1206,13 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
workflow1 = Workflow.objects.create(name="bank workflow 1")
Workflow.objects.create(name="workflow 2")
self.client.force_authenticate(user1)
response = self.client.get("/api/search/?query=bank")
self.assertEqual(response.status_code, status.HTTP_200_OK)
results = response.data
self.assertEqual(len(results["documents"]), 2)
self.assertEqual(len(results["saved_views"]), 1)
self.assertNotEqual(results["documents"][0]["id"], d3.id)
self.assertNotEqual(results["documents"][1]["id"], d3.id)
self.assertEqual(results["correspondents"][0]["id"], correspondent1.id)

View File

@ -1135,7 +1135,13 @@ class GlobalSearchView(PassUserMixin):
)._get_query()
results = s.search(q, limit=OBJECT_LIMIT)
docs = docs | all_docs.filter(id__in=[r["id"] for r in results])
saved_views = (
SavedView.objects.filter(owner=request.user, name__icontains=query)[
:OBJECT_LIMIT
]
if request.user.has_perm("documents.view_savedview")
else []
)
tags = (
get_objects_for_user_owner_aware(request.user, "view_tag", Tag).filter(
name__icontains=query,
@ -1206,6 +1212,11 @@ class GlobalSearchView(PassUserMixin):
}
docs_serializer = DocumentSerializer(docs, many=True, context=context)
saved_views_serializer = SavedViewSerializer(
saved_views,
many=True,
context=context,
)
tags_serializer = TagSerializer(tags, many=True, context=context)
correspondents_serializer = CorrespondentSerializer(
correspondents,
@ -1244,6 +1255,7 @@ class GlobalSearchView(PassUserMixin):
return Response(
{
"total": len(docs)
+ len(saved_views)
+ len(tags)
+ len(correspondents)
+ len(document_types)
@ -1255,6 +1267,7 @@ class GlobalSearchView(PassUserMixin):
+ len(workflows)
+ len(custom_fields),
"documents": docs_serializer.data,
"saved_views": saved_views_serializer.data,
"tags": tags_serializer.data,
"correspondents": correspondents_serializer.data,
"document_types": document_types_serializer.data,

View File

@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-19 01:15-0700\n"
"POT-Creation-Date: 2024-04-19 11:01-0700\n"
"PO-Revision-Date: 2022-02-17 04:17\n"
"Last-Translator: \n"
"Language-Team: English\n"
@ -25,27 +25,27 @@ msgstr ""
msgid "owner"
msgstr ""
#: documents/models.py:53 documents/models.py:902
#: documents/models.py:53 documents/models.py:897
msgid "None"
msgstr ""
#: documents/models.py:54 documents/models.py:903
#: documents/models.py:54 documents/models.py:898
msgid "Any word"
msgstr ""
#: documents/models.py:55 documents/models.py:904
#: documents/models.py:55 documents/models.py:899
msgid "All words"
msgstr ""
#: documents/models.py:56 documents/models.py:905
#: documents/models.py:56 documents/models.py:900
msgid "Exact match"
msgstr ""
#: documents/models.py:57 documents/models.py:906
#: documents/models.py:57 documents/models.py:901
msgid "Regular expression"
msgstr ""
#: documents/models.py:58 documents/models.py:907
#: documents/models.py:58 documents/models.py:902
msgid "Fuzzy word"
msgstr ""
@ -53,20 +53,20 @@ msgstr ""
msgid "Automatic"
msgstr ""
#: documents/models.py:62 documents/models.py:397 documents/models.py:1223
#: documents/models.py:62 documents/models.py:397 documents/models.py:1218
#: paperless_mail/models.py:18 paperless_mail/models.py:93
msgid "name"
msgstr ""
#: documents/models.py:64 documents/models.py:963
#: documents/models.py:64 documents/models.py:958
msgid "match"
msgstr ""
#: documents/models.py:67 documents/models.py:966
#: documents/models.py:67 documents/models.py:961
msgid "matching algorithm"
msgstr ""
#: documents/models.py:72 documents/models.py:971
#: documents/models.py:72 documents/models.py:966
msgid "is insensitive"
msgstr ""
@ -615,246 +615,246 @@ msgstr ""
msgid "custom field instances"
msgstr ""
#: documents/models.py:910
#: documents/models.py:905
msgid "Consumption Started"
msgstr ""
#: documents/models.py:911
#: documents/models.py:906
msgid "Document Added"
msgstr ""
#: documents/models.py:912
#: documents/models.py:907
msgid "Document Updated"
msgstr ""
#: documents/models.py:915
#: documents/models.py:910
msgid "Consume Folder"
msgstr ""
#: documents/models.py:916
#: documents/models.py:911
msgid "Api Upload"
msgstr ""
#: documents/models.py:917
#: documents/models.py:912
msgid "Mail Fetch"
msgstr ""
#: documents/models.py:920
#: documents/models.py:915
msgid "Workflow Trigger Type"
msgstr ""
#: documents/models.py:932
#: documents/models.py:927
msgid "filter path"
msgstr ""
#: documents/models.py:937
#: documents/models.py:932
msgid ""
"Only consume documents with a path that matches this if specified. Wildcards "
"specified as * are allowed. Case insensitive."
msgstr ""
#: documents/models.py:944
#: documents/models.py:939
msgid "filter filename"
msgstr ""
#: documents/models.py:949 paperless_mail/models.py:148
#: documents/models.py:944 paperless_mail/models.py:148
msgid ""
"Only consume documents which entirely match this filename if specified. "
"Wildcards such as *.pdf or *invoice* are allowed. Case insensitive."
msgstr ""
#: documents/models.py:960
#: documents/models.py:955
msgid "filter documents from this mail rule"
msgstr ""
#: documents/models.py:976
#: documents/models.py:971
msgid "has these tag(s)"
msgstr ""
#: documents/models.py:984
#: documents/models.py:979
msgid "has this document type"
msgstr ""
#: documents/models.py:992
#: documents/models.py:987
msgid "has this correspondent"
msgstr ""
#: documents/models.py:996
#: documents/models.py:991
msgid "workflow trigger"
msgstr ""
#: documents/models.py:997
#: documents/models.py:992
msgid "workflow triggers"
msgstr ""
#: documents/models.py:1007
#: documents/models.py:1002
msgid "Assignment"
msgstr ""
#: documents/models.py:1011
#: documents/models.py:1006
msgid "Removal"
msgstr ""
#: documents/models.py:1015
#: documents/models.py:1010
msgid "Workflow Action Type"
msgstr ""
#: documents/models.py:1021
#: documents/models.py:1016
msgid "assign title"
msgstr ""
#: documents/models.py:1026
#: documents/models.py:1021
msgid ""
"Assign a document title, can include some placeholders, see documentation."
msgstr ""
#: documents/models.py:1035 paperless_mail/models.py:216
#: documents/models.py:1030 paperless_mail/models.py:216
msgid "assign this tag"
msgstr ""
#: documents/models.py:1044 paperless_mail/models.py:224
#: documents/models.py:1039 paperless_mail/models.py:224
msgid "assign this document type"
msgstr ""
#: documents/models.py:1053 paperless_mail/models.py:238
#: documents/models.py:1048 paperless_mail/models.py:238
msgid "assign this correspondent"
msgstr ""
#: documents/models.py:1062
#: documents/models.py:1057
msgid "assign this storage path"
msgstr ""
#: documents/models.py:1071
#: documents/models.py:1066
msgid "assign this owner"
msgstr ""
#: documents/models.py:1078
#: documents/models.py:1073
msgid "grant view permissions to these users"
msgstr ""
#: documents/models.py:1085
#: documents/models.py:1080
msgid "grant view permissions to these groups"
msgstr ""
#: documents/models.py:1092
#: documents/models.py:1087
msgid "grant change permissions to these users"
msgstr ""
#: documents/models.py:1099
#: documents/models.py:1094
msgid "grant change permissions to these groups"
msgstr ""
#: documents/models.py:1106
#: documents/models.py:1101
msgid "assign these custom fields"
msgstr ""
#: documents/models.py:1113
#: documents/models.py:1108
msgid "remove these tag(s)"
msgstr ""
#: documents/models.py:1118
#: documents/models.py:1113
msgid "remove all tags"
msgstr ""
#: documents/models.py:1125
#: documents/models.py:1120
msgid "remove these document type(s)"
msgstr ""
#: documents/models.py:1130
#: documents/models.py:1125
msgid "remove all document types"
msgstr ""
#: documents/models.py:1137
#: documents/models.py:1132
msgid "remove these correspondent(s)"
msgstr ""
#: documents/models.py:1142
#: documents/models.py:1137
msgid "remove all correspondents"
msgstr ""
#: documents/models.py:1149
#: documents/models.py:1144
msgid "remove these storage path(s)"
msgstr ""
#: documents/models.py:1154
#: documents/models.py:1149
msgid "remove all storage paths"
msgstr ""
#: documents/models.py:1161
#: documents/models.py:1156
msgid "remove these owner(s)"
msgstr ""
#: documents/models.py:1166
#: documents/models.py:1161
msgid "remove all owners"
msgstr ""
#: documents/models.py:1173
#: documents/models.py:1168
msgid "remove view permissions for these users"
msgstr ""
#: documents/models.py:1180
#: documents/models.py:1175
msgid "remove view permissions for these groups"
msgstr ""
#: documents/models.py:1187
#: documents/models.py:1182
msgid "remove change permissions for these users"
msgstr ""
#: documents/models.py:1194
#: documents/models.py:1189
msgid "remove change permissions for these groups"
msgstr ""
#: documents/models.py:1199
#: documents/models.py:1194
msgid "remove all permissions"
msgstr ""
#: documents/models.py:1206
#: documents/models.py:1201
msgid "remove these custom fields"
msgstr ""
#: documents/models.py:1211
#: documents/models.py:1206
msgid "remove all custom fields"
msgstr ""
#: documents/models.py:1215
#: documents/models.py:1210
msgid "workflow action"
msgstr ""
#: documents/models.py:1216
#: documents/models.py:1211
msgid "workflow actions"
msgstr ""
#: documents/models.py:1225 paperless_mail/models.py:95
#: documents/models.py:1220 paperless_mail/models.py:95
msgid "order"
msgstr ""
#: documents/models.py:1231
#: documents/models.py:1226
msgid "triggers"
msgstr ""
#: documents/models.py:1238
#: documents/models.py:1233
msgid "actions"
msgstr ""
#: documents/models.py:1241
#: documents/models.py:1236
msgid "enabled"
msgstr ""
#: documents/serialisers.py:115
#: documents/serialisers.py:114
#, python-format
msgid "Invalid regular expression: %(error)s"
msgstr ""
#: documents/serialisers.py:418
#: documents/serialisers.py:417
msgid "Invalid color."
msgstr ""
#: documents/serialisers.py:1148
#: documents/serialisers.py:1171
#, python-format
msgid "File type %(type)s not supported"
msgstr ""
#: documents/serialisers.py:1257
#: documents/serialisers.py:1280
msgid "Invalid variable detected."
msgstr ""
@ -1350,7 +1350,7 @@ msgstr ""
msgid "Chinese Simplified"
msgstr ""
#: paperless/urls.py:230
#: paperless/urls.py:236
msgid "Paperless-ngx administration"
msgstr ""