mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-15 01:28:30 +00:00
Introduced has file type filter
This commit is contained in:
parent
55aaec00bf
commit
a7918da273
8 changed files with 255 additions and 0 deletions
backend
src/baserow/contrib/database
tests/baserow/contrib/database/view
web-frontend
modules/database
test/unit/database
|
@ -112,6 +112,7 @@ class DatabaseConfig(AppConfig):
|
|||
LowerThanViewFilterType,
|
||||
ContainsViewFilterType,
|
||||
FilenameContainsViewFilterType,
|
||||
HasFileTypeViewFilterType,
|
||||
ContainsNotViewFilterType,
|
||||
BooleanViewFilterType,
|
||||
SingleSelectEqualViewFilterType,
|
||||
|
@ -123,6 +124,7 @@ class DatabaseConfig(AppConfig):
|
|||
view_filter_type_registry.register(EqualViewFilterType())
|
||||
view_filter_type_registry.register(NotEqualViewFilterType())
|
||||
view_filter_type_registry.register(FilenameContainsViewFilterType())
|
||||
view_filter_type_registry.register(HasFileTypeViewFilterType())
|
||||
view_filter_type_registry.register(ContainsViewFilterType())
|
||||
view_filter_type_registry.register(ContainsNotViewFilterType())
|
||||
view_filter_type_registry.register(HigherThanViewFilterType())
|
||||
|
|
|
@ -94,6 +94,32 @@ class FilenameContainsViewFilterType(ViewFilterType):
|
|||
return filename_contains_filter(*args)
|
||||
|
||||
|
||||
class HasFileTypeViewFilterType(ViewFilterType):
|
||||
"""
|
||||
The file field type column contains an array of objects with details related to
|
||||
the uploaded user files. Every object always contains the property `is_image`
|
||||
that indicates if the user file is an image. Using the Django contains lookup,
|
||||
we can check if there is at least one object where the `is_image` is True. If the
|
||||
filter value is `image`, there must at least be one object where the `is_image`
|
||||
is true. If the filter value is `document` there must at least be one object
|
||||
where the `is_image` is false. If an unsupported filter value is provided, we don't
|
||||
want to filter on anything.
|
||||
"""
|
||||
|
||||
type = "has_file_type"
|
||||
compatible_field_types = [FileFieldType.type]
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field):
|
||||
value = value.strip()
|
||||
is_image = value == "image"
|
||||
is_document = value == "document"
|
||||
|
||||
if is_document or is_image:
|
||||
return Q(**{f"{field_name}__contains": [{"is_image": is_image}]})
|
||||
else:
|
||||
return Q()
|
||||
|
||||
|
||||
class ContainsViewFilterType(ViewFilterType):
|
||||
"""
|
||||
The contains filter checks if the field value contains the provided filter value.
|
||||
|
|
|
@ -2334,6 +2334,107 @@ def test_filename_contains_filter_type(data_fixture):
|
|||
assert len(results) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_file_type(data_fixture):
|
||||
user = data_fixture.create_user()
|
||||
table = data_fixture.create_database_table(user=user)
|
||||
grid_view = data_fixture.create_grid_view(table=table)
|
||||
file_field = data_fixture.create_file_field(table=table)
|
||||
|
||||
handler = ViewHandler()
|
||||
model = table.get_model()
|
||||
|
||||
row_with_single_image = model.objects.create(
|
||||
**{
|
||||
f"field_{file_field.id}": [
|
||||
{"visible_name": "test_file.jpg", "is_image": True}
|
||||
],
|
||||
}
|
||||
)
|
||||
row_with_single_document = model.objects.create(
|
||||
**{
|
||||
f"field_{file_field.id}": [{"visible_name": "doc.doc", "is_image": False}],
|
||||
}
|
||||
)
|
||||
row_with_multiple_documents = model.objects.create(
|
||||
**{
|
||||
f"field_{file_field.id}": [
|
||||
{"visible_name": "test.doc", "is_image": False},
|
||||
{"visible_name": "test.txt", "is_image": False},
|
||||
{"visible_name": "test.doc", "is_image": False},
|
||||
{"visible_name": "test.txt", "is_image": False},
|
||||
],
|
||||
}
|
||||
)
|
||||
row_with_multiple_images = model.objects.create(
|
||||
**{
|
||||
f"field_{file_field.id}": [
|
||||
{"visible_name": "test.jpg", "is_image": True},
|
||||
{"visible_name": "test.png", "is_image": True},
|
||||
],
|
||||
}
|
||||
)
|
||||
row_with_single_image_and_multiple_documents = model.objects.create(
|
||||
**{
|
||||
f"field_{file_field.id}": [
|
||||
{"visible_name": "test_doc.doc", "is_image": False},
|
||||
{"visible_name": "test_doc.doc", "is_image": False},
|
||||
{"visible_name": "test_image.jpg", "is_image": True},
|
||||
{"visible_name": "test_doc.doc", "is_image": False},
|
||||
],
|
||||
}
|
||||
)
|
||||
row_with_single_document_and_multiple_images = model.objects.create(
|
||||
**{
|
||||
f"field_{file_field.id}": [
|
||||
{"visible_name": "image1.jpg", "is_image": True},
|
||||
{"visible_name": "image2.png", "is_image": True},
|
||||
{"visible_name": "doc.doc", "is_image": False},
|
||||
{"visible_name": "image3.jpg", "is_image": True},
|
||||
],
|
||||
}
|
||||
)
|
||||
model.objects.create(**{f"field_{file_field.id}": []})
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=grid_view,
|
||||
field=file_field,
|
||||
type="has_file_type",
|
||||
value="",
|
||||
)
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 7
|
||||
|
||||
view_filter.value = "image"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 4
|
||||
assert row_with_single_image.id in ids
|
||||
assert row_with_multiple_images.id in ids
|
||||
assert row_with_single_image_and_multiple_documents.id in ids
|
||||
assert row_with_single_document_and_multiple_images.id in ids
|
||||
|
||||
view_filter.value = "document"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 4
|
||||
assert row_with_single_document.id in ids
|
||||
assert row_with_multiple_documents.id in ids
|
||||
assert row_with_single_image_and_multiple_documents.id in ids
|
||||
assert row_with_single_document_and_multiple_images.id in ids
|
||||
|
||||
data_fixture.create_view_filter(
|
||||
view=grid_view,
|
||||
field=file_field,
|
||||
type="has_file_type",
|
||||
value="image",
|
||||
)
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 2
|
||||
assert row_with_single_image_and_multiple_documents.id in ids
|
||||
assert row_with_single_document_and_multiple_images.id in ids
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_link_row_preload_values(data_fixture, django_assert_num_queries):
|
||||
user = data_fixture.create_user()
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
* Fix minor error that could sometimes occur when a row and it's table/group/database
|
||||
were deleted in rapid succession.
|
||||
* Fix accidentally locking of too many rows in various tables during update operations.
|
||||
* Introduced the has file type filter.
|
||||
|
||||
## Released (2021-08-11)
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<Dropdown
|
||||
:value="filter.value"
|
||||
:show-search="false"
|
||||
:disabled="readOnly"
|
||||
class="filters__value-dropdown dropdown--tiny"
|
||||
@input="$emit('input', $event)"
|
||||
>
|
||||
<DropdownItem name="image" value="image"></DropdownItem>
|
||||
<DropdownItem name="document" value="document"></DropdownItem>
|
||||
</Dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ViewFilterTypeFileTypeDropdown',
|
||||
props: {
|
||||
filter: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
fields: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
primary: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -22,6 +22,7 @@ import {
|
|||
DateNotEqualViewFilterType,
|
||||
ContainsViewFilterType,
|
||||
FilenameContainsViewFilterType,
|
||||
HasFileTypeViewFilterType,
|
||||
ContainsNotViewFilterType,
|
||||
HigherThanViewFilterType,
|
||||
LowerThanViewFilterType,
|
||||
|
@ -91,6 +92,7 @@ export default (context) => {
|
|||
'viewFilter',
|
||||
new FilenameContainsViewFilterType(context)
|
||||
)
|
||||
app.$registry.register('viewFilter', new HasFileTypeViewFilterType(context))
|
||||
app.$registry.register('viewFilter', new ContainsNotViewFilterType(context))
|
||||
app.$registry.register('viewFilter', new HigherThanViewFilterType(context))
|
||||
app.$registry.register('viewFilter', new LowerThanViewFilterType(context))
|
||||
|
|
|
@ -9,6 +9,7 @@ import ViewFilterTypeTimeZone from '@baserow/modules/database/components/view/Vi
|
|||
import ViewFilterTypeLinkRow from '@baserow/modules/database/components/view/ViewFilterTypeLinkRow'
|
||||
import { trueString } from '@baserow/modules/database/utils/constants'
|
||||
import { isNumeric } from '@baserow/modules/core/utils/string'
|
||||
import ViewFilterTypeFileTypeDropdown from '@baserow/modules/database/components/view/ViewFilterTypeFileTypeDropdown'
|
||||
|
||||
export class ViewFilterType extends Registerable {
|
||||
/**
|
||||
|
@ -177,6 +178,45 @@ export class FilenameContainsViewFilterType extends ViewFilterType {
|
|||
}
|
||||
}
|
||||
|
||||
export class HasFileTypeViewFilterType extends ViewFilterType {
|
||||
static getType() {
|
||||
return 'has_file_type'
|
||||
}
|
||||
|
||||
getName() {
|
||||
return 'has file type'
|
||||
}
|
||||
|
||||
getExample() {
|
||||
return 'image | document'
|
||||
}
|
||||
|
||||
getInputComponent() {
|
||||
return ViewFilterTypeFileTypeDropdown
|
||||
}
|
||||
|
||||
getCompatibleFieldTypes() {
|
||||
return ['file']
|
||||
}
|
||||
|
||||
matches(rowValue, filterValue, field, fieldType) {
|
||||
const isImage = filterValue === 'image'
|
||||
const isDocument = filterValue === 'document'
|
||||
|
||||
if (!isImage && !isDocument) {
|
||||
return true
|
||||
}
|
||||
|
||||
for (let i = 0; i < rowValue.length; i++) {
|
||||
if (rowValue[i].is_image === isImage) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export class ContainsViewFilterType extends ViewFilterType {
|
||||
static getType() {
|
||||
return 'contains'
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
DateEqualViewFilterType,
|
||||
DateNotEqualViewFilterType,
|
||||
DateEqualsTodayViewFilterType,
|
||||
HasFileTypeViewFilterType,
|
||||
} from '@baserow/modules/database/viewFilters'
|
||||
|
||||
const dateBeforeCasesWithTimezone = [
|
||||
|
@ -400,4 +401,50 @@ describe('All Tests', () => {
|
|||
)
|
||||
expect(result).toBe(values.expected)
|
||||
})
|
||||
|
||||
test('HasFileType contains image', () => {
|
||||
expect(new HasFileTypeViewFilterType().matches([], '', {})).toBe(true)
|
||||
expect(new HasFileTypeViewFilterType().matches([], 'image', {})).toBe(false)
|
||||
expect(new HasFileTypeViewFilterType().matches([], 'document', {})).toBe(
|
||||
false
|
||||
)
|
||||
expect(
|
||||
new HasFileTypeViewFilterType().matches([{ is_image: true }], 'image', {})
|
||||
).toBe(true)
|
||||
expect(
|
||||
new HasFileTypeViewFilterType().matches(
|
||||
[{ is_image: true }],
|
||||
'document',
|
||||
{}
|
||||
)
|
||||
).toBe(false)
|
||||
expect(
|
||||
new HasFileTypeViewFilterType().matches(
|
||||
[{ is_image: false }],
|
||||
'image',
|
||||
{}
|
||||
)
|
||||
).toBe(false)
|
||||
expect(
|
||||
new HasFileTypeViewFilterType().matches(
|
||||
[{ is_image: false }],
|
||||
'document',
|
||||
{}
|
||||
)
|
||||
).toBe(true)
|
||||
expect(
|
||||
new HasFileTypeViewFilterType().matches(
|
||||
[{ is_image: true }, { is_image: false }],
|
||||
'image',
|
||||
{}
|
||||
)
|
||||
).toBe(true)
|
||||
expect(
|
||||
new HasFileTypeViewFilterType().matches(
|
||||
[{ is_image: true }, { is_image: false }],
|
||||
'document',
|
||||
{}
|
||||
)
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Add table
Reference in a new issue