-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat: add tag-linked document dialog with linked/unlinked tabs, search, status filter, pagination, and batch link/unlink support via new docs-tag delete API #4835
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -395,13 +395,17 @@ class Query(serializers.Serializer): | |
| tag_ids = serializers.ListField(child=serializers.UUIDField(), allow_null=True, required=False, | ||
| allow_empty=True) | ||
| no_tag = serializers.BooleanField(required=False, default=False, allow_null=True) | ||
| tag_ids = serializers.ListField(child=serializers.UUIDField(),allow_null=True,required=False,allow_empty=True) | ||
| no_tag = serializers.BooleanField(required=False,default=False, allow_null=True) | ||
| tag_exclude = serializers.BooleanField(required=False,default=False, allow_null=True) | ||
|
|
||
| def get_query_set(self): | ||
| query_set = QuerySet(model=Document) | ||
| query_set = query_set.filter(**{'knowledge_id': self.data.get("knowledge_id")}) | ||
|
|
||
| tag_ids = self.data.get('tag_ids') | ||
| no_tag = self.data.get('no_tag') | ||
| tag_exclude = self.data.get('tag_exclude') | ||
| if 'name' in self.data and self.data.get('name') is not None: | ||
| query_set = query_set.filter(**{'name__icontains': self.data.get('name')}) | ||
| if 'hit_handling_method' in self.data and self.data.get('hit_handling_method') not in [None, '']: | ||
|
|
@@ -419,7 +423,10 @@ def get_query_set(self): | |
| query_set = query_set.exclude(id__in=tagged_doc_ids) | ||
| elif tag_ids: | ||
| matched_doc_ids = QuerySet(DocumentTag).filter(tag_id__in=tag_ids).values_list('document_id', flat=True) | ||
| query_set = query_set.filter(id__in=matched_doc_ids) | ||
| if tag_exclude: | ||
| query_set = query_set.exclude(id__in=matched_doc_ids) | ||
| else: | ||
| query_set = query_set.filter(id__in=matched_doc_ids) | ||
|
|
||
| if 'status' in self.data and self.data.get('status') is not None: | ||
| task_type = self.data.get('task_type') | ||
|
|
@@ -1605,6 +1612,40 @@ def delete_tags(self): | |
| tag_id__in=tag_ids | ||
| ).delete() | ||
|
|
||
| class DeleteDocsTag(serializers.Serializer): | ||
| workspace_id = serializers.CharField(required=True, label=_('workspace id')) | ||
| knowledge_id = serializers.UUIDField(required=True, label=_('knowledge id')) | ||
| tag_id = serializers.UUIDField(required=True, label=_('tag id')) | ||
|
|
||
| def is_valid(self, *, raise_exception=False): | ||
| super().is_valid(raise_exception=True) | ||
| workspace_id = self.data.get('workspace_id') | ||
| query_set = QuerySet(Knowledge).filter(id=self.data.get('knowledge_id')) | ||
| if workspace_id and workspace_id != 'None': | ||
| query_set = query_set.filter(workspace_id=workspace_id) | ||
| if not query_set.exists(): | ||
| raise AppApiException(500, _('Knowledge id does not exist')) | ||
| if not QuerySet(Tag).filter( | ||
| id=self.data.get('tag_id'), | ||
| knowledge_id=self.data.get('knowledge_id') | ||
| ).exists(): | ||
| raise AppApiException(500, _('Tag id does not exist')) | ||
|
|
||
| def batch_delete_docs_tag(self, instance,with_valid=True): | ||
| if with_valid: | ||
| BatchSerializer(data=instance).is_valid(model=Document, raise_exception=True) | ||
| self.is_valid(raise_exception=True) | ||
| knowledge_id = self.data.get('knowledge_id') | ||
| tag_id=self.data.get('tag_id') | ||
| doc_id_list = instance.get("id_list") | ||
|
|
||
| valid_doc_count = Document.objects.filter(id__in=doc_id_list, knowledge_id=knowledge_id).count() | ||
| if valid_doc_count != len(doc_id_list): | ||
| raise AppApiException(500, _('Document id does not belong to current knowledge')) | ||
|
|
||
| DocumentTag.objects.filter(document_id__in=doc_id_list,tag_id=tag_id).delete() | ||
|
|
||
| return True | ||
| class ReplaceSourceFile(serializers.Serializer): | ||
| workspace_id = serializers.CharField(required=True, label=_('workspace id')) | ||
| knowledge_id = serializers.UUIDField(required=True, label=_('knowledge id')) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The provided code has several issues and inefficiencies that can be improved:
Here's an updated version of the code with these improvements: from django.core.exceptions import ObjectDoesNotExist
from rest_framework import serializers
class Query(serializers.ModelSerializer):
# ... existing field definitions ...
def get_query_set(self):
queryset = Document.objects.all()
if knowledge_id := self.data.get('knowledge_id'):
queryset = queryset.filter(knowledge_id=knowledge_id)
name = self.data.get('name')
if name:
queryset = queryset.filter(name__icontains=name)
hit_handling_method = self.data.get('hit_handling_method')
if task_type := self.data.get('task_type'): # Assuming 'task_type' is related
if hit_handling_method == 'exclude':
# Implement exclude logic here
pass
elif hit_handling_method == 'include':
# Implement include logic here
pass
if tags := self.data.get('tags'):
if isinstance(tags, list):
queryset = queryset.filter(tag_id__in=tags)
else:
queryset = queryset.filter(pk=tags) # If tags is a single document ID
if statuses := self.data.get('statuses'):
if isinstance(statuses, list):
queryset = queryset.filter(status=statuses[0])
else:
queryset = queryset.filter(status=str(statuses)) # If it's a string representation
return queryset.distinct()
# ... other serializers ...Key Improvements:
This should make the code more readable, maintainable, and efficient. Make sure to adjust the implementation details of |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -579,6 +579,54 @@ export const iconMap: any = { | |
| ]) | ||
| }, | ||
| }, | ||
| 'app-unlink': { | ||
| iconReader: () => { | ||
| return h('i', [ | ||
| h( | ||
| 'svg', | ||
| { | ||
| style: { height: '100%', width: '100%' }, | ||
| viewBox: '0 0 16 16', | ||
| fill: 'none', | ||
| xmlns: 'http://www.w3.org/2000/svg', | ||
| }, | ||
| [ | ||
| h('g', { 'clip-path': 'url(#clip0_10754_9765)' }, [ | ||
| h('path', { | ||
| d: 'M1.23567 0.764126L0.76429 1.23549C0.634122 1.36565 0.634122 1.57668 0.76429 1.70685L13.9629 14.905C14.0931 15.0351 14.3042 15.0351 14.4343 14.905L14.9057 14.4336C15.0359 14.3034 15.0359 14.0924 14.9057 13.9622L1.70705 0.764126C1.57688 0.633963 1.36584 0.633963 1.23567 0.764126Z', | ||
| fill: '#3370FF', | ||
| }), | ||
| h('path', { | ||
| d: 'M9.77756 6.94871V3.33311C9.77756 3.22403 9.69895 3.1333 9.59528 3.11448L9.55534 3.1109H5.93959L4.60626 1.77762H9.55534C10.3858 1.77762 11.0643 2.42839 11.1086 3.24777L11.1109 3.33311V8.28199L9.77756 6.94871Z', | ||
| fill: '#3370FF', | ||
| }), | ||
| h('path', { | ||
| d: 'M0.888669 3.71681V8.66623L0.890971 8.75157C0.93528 9.57095 1.61375 10.2217 2.44422 10.2217H4.17756C4.32483 10.2217 4.44422 10.1023 4.44422 9.95506V9.15509C4.44422 9.00782 4.32483 8.88844 4.17756 8.88844H2.44422L2.40428 8.88486C2.30061 8.86604 2.222 8.77531 2.222 8.66623V5.05009L0.888669 3.71681Z', | ||
| fill: '#3370FF', | ||
| }), | ||
| h('path', { | ||
| d: 'M5.33311 8.16107V12.6661L5.33542 12.7514C5.37972 13.5708 6.0582 14.2216 6.88867 14.2216H11.3938L10.0605 12.8883H6.88867L6.84872 12.8847C6.74506 12.8659 6.66645 12.7751 6.66645 12.6661V9.49435L5.33311 8.16107Z', | ||
| fill: '#3370FF', | ||
| }), | ||
| h('path', { | ||
| d: 'M8.60626 5.77746L8.88867 6.05986V6.04411C8.88867 5.89684 8.76928 5.77746 8.622 5.77746H8.60626Z', | ||
| fill: '#3370FF', | ||
| }), | ||
| h('path', { | ||
| d: 'M15.5542 12.7251L14.222 11.393V7.33295C14.222 7.22386 14.1434 7.13313 14.0397 7.11431L13.9998 7.11073H12.2664C12.1192 7.11073 11.9998 6.99135 11.9998 6.84408V6.04411C11.9998 5.89684 12.1192 5.77746 12.2664 5.77746H13.9998C14.8303 5.77746 15.5087 6.42822 15.553 7.2476L15.5553 7.33295V12.6661C15.5553 12.6858 15.555 12.7055 15.5542 12.7251Z', | ||
| fill: '#3370FF', | ||
| }), | ||
| ]), | ||
| h('defs', [ | ||
| h('clipPath', { id: 'clip0_10754_9765' }, [ | ||
| h('rect', { width: '16', height: '15.9993', fill: 'white' }), | ||
| ]), | ||
| ]), | ||
| ], | ||
| ), | ||
| ]) | ||
| }, | ||
| }, | ||
| // 动态加载的图标 | ||
| ...dynamicIcons, | ||
| } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code looks mostly correct but has a few improvements to make it more efficient and maintainable:
Here's the revised and cleaned-up version of the code: // ...
export const iconsMap: any = {
// Other entries...
'AppUnlink': {
iconReader: () => {
return h('i', [
h(
'svg',
{
style: { height: '100%', width: '100%' },
viewBox: '0 0 16 16',
fill: 'none',
xmlns: 'http://www.w3.org/2000/svg',
},
[
h('g', { clipPath: 'url(#clip0_10754_9765)' }, [
// SVG path data...
]),
h('defs', [
h('clipPath', { id: 'clip0_10754_9765' }, [
h('rect', { width: '16', height: '15.9993', fill: 'white' }),
]),
]),
],
),
]);
},
},
// dynamic loading icons remains unchanged
};
// ...These changes enhance clarity and reduce redundancy while maintaining functionality. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The provided code appears to be part of an API implementation using FastAPI frameworks in Python. I've reviewed the changes made:
BatchSerializerfromknowledge.serializers.common.Suggestions for further improvement:
Code snippet corrections implemented:
This review focuses on the specific areas mentioned in the question, aiming to improve readability, correctness, and maintainability of the codebase.