Compare commits
3 Commits
main
...
fix/saved-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7d39b6f1a | ||
|
|
88873aec85 | ||
|
|
44f9e1fe8d |
@@ -27,6 +27,7 @@ in {
|
||||
|
||||
go = {
|
||||
enable = true;
|
||||
enableHardeningWorkaround = true;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -65,7 +65,11 @@ import {useRoute} from 'vue-router'
|
||||
import type {TaskFilterParams} from '@/services/taskCollection'
|
||||
import {useLabelStore} from '@/stores/labels'
|
||||
import {useProjectStore} from '@/stores/projects'
|
||||
import {FILTER_OPERATORS, transformFilterStringForApi, transformFilterStringFromApi} from '@/helpers/filters'
|
||||
import {
|
||||
hasFilterQuery,
|
||||
transformFilterStringForApi,
|
||||
transformFilterStringFromApi,
|
||||
} from '@/helpers/filters'
|
||||
import FilterInputDocs from '@/components/project/partials/FilterInputDocs.vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
@@ -161,8 +165,7 @@ function change(event: 'blur' | 'modelValue' | 'always') {
|
||||
let s = ''
|
||||
|
||||
// When the filter does not contain any filter tokens, assume a simple search and redirect the input
|
||||
const hasFilterQueries = FILTER_OPERATORS.find(o => filter.includes(o)) || false
|
||||
if (!hasFilterQueries) {
|
||||
if (!hasFilterQuery(filter)) {
|
||||
s = filter
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type {IProjectView} from '@/modelTypes/IProjectView'
|
||||
import type {IFilter} from '@/modelTypes/ISavedFilter'
|
||||
import XButton from '@/components/input/Button.vue'
|
||||
import FilterInput from '@/components/project/partials/FilterInput.vue'
|
||||
import {ref, onBeforeMount} from 'vue'
|
||||
import {transformFilterStringForApi, transformFilterStringFromApi} from '@/helpers/filters'
|
||||
import {onBeforeMount, ref} from 'vue'
|
||||
import {hasFilterQuery, transformFilterStringForApi, transformFilterStringFromApi} from '@/helpers/filters'
|
||||
import {useLabelStore} from '@/stores/labels'
|
||||
import {useProjectStore} from '@/stores/projects'
|
||||
import FilterInputDocs from '@/components/project/partials/FilterInputDocs.vue'
|
||||
@@ -28,18 +29,24 @@ const labelStore = useLabelStore()
|
||||
const projectStore = useProjectStore()
|
||||
|
||||
onBeforeMount(() => {
|
||||
const transform = (filterString: string) => transformFilterStringFromApi(
|
||||
filterString,
|
||||
labelId => labelStore.getLabelById(labelId)?.title || null,
|
||||
projectId => projectStore.projects[projectId]?.title || null,
|
||||
)
|
||||
const transformFilterToString = (filter: IFilter): string => {
|
||||
if (filter.s !== '') {
|
||||
return filter.s
|
||||
}
|
||||
|
||||
return transformFilterStringFromApi(
|
||||
filter.filter,
|
||||
labelId => labelStore.getLabelById(labelId)?.title || null,
|
||||
projectId => projectStore.projects[projectId]?.title || null,
|
||||
)
|
||||
}
|
||||
|
||||
const transformed = {
|
||||
...props.modelValue,
|
||||
filter: transform(props.modelValue.filter),
|
||||
filter: transformFilterToString(props.modelValue.filter),
|
||||
bucketConfiguration: props.modelValue.bucketConfiguration.map(bc => ({
|
||||
title: bc.title,
|
||||
filter: transform(bc.filter),
|
||||
filter: transformFilterToString(bc.filter),
|
||||
})),
|
||||
}
|
||||
|
||||
@@ -49,21 +56,31 @@ onBeforeMount(() => {
|
||||
})
|
||||
|
||||
function save() {
|
||||
const transformFilter = (filterQuery: string) => transformFilterStringForApi(
|
||||
filterQuery,
|
||||
labelTitle => labelStore.getLabelByExactTitle(labelTitle)?.id || null,
|
||||
projectTitle => {
|
||||
const found = projectStore.findProjectByExactname(projectTitle)
|
||||
return found?.id || null
|
||||
},
|
||||
)
|
||||
const transformFilterForApi = (filterQuery: string): IFilter => {
|
||||
const filterString = transformFilterStringForApi(
|
||||
filterQuery,
|
||||
labelTitle => labelStore.getLabelByExactTitle(labelTitle)?.id || null,
|
||||
projectTitle => {
|
||||
const found = projectStore.findProjectByExactname(projectTitle)
|
||||
return found?.id || null
|
||||
},
|
||||
)
|
||||
const filter: IFilter = {}
|
||||
if (hasFilterQuery(filterString)) {
|
||||
filter.filter = filterString
|
||||
} else {
|
||||
filter.s = filterString
|
||||
}
|
||||
|
||||
return filter
|
||||
}
|
||||
|
||||
emit('update:modelValue', {
|
||||
...view.value,
|
||||
filter: transformFilter(view.value?.filter),
|
||||
filter: transformFilterForApi(view.value?.filter || ''),
|
||||
bucketConfiguration: view.value?.bucketConfiguration.map(bc => ({
|
||||
title: bc.title,
|
||||
filter: transformFilter(bc.filter),
|
||||
filter: transformFilterForApi(bc.filter || ''),
|
||||
})),
|
||||
})
|
||||
}
|
||||
@@ -231,7 +248,7 @@ function handleBubbleSave() {
|
||||
<XButton
|
||||
variant="secondary"
|
||||
icon="plus"
|
||||
@click="() => view.bucketConfiguration.push({title: '', filter: ''})"
|
||||
@click="() => view.bucketConfiguration.push({title: '', filter: {filter: ''}})"
|
||||
>
|
||||
{{ $t('project.kanban.addBucket') }}
|
||||
</XButton>
|
||||
|
||||
@@ -60,6 +60,10 @@ export const FILTER_JOIN_OPERATOR = [
|
||||
|
||||
export const FILTER_OPERATORS_REGEX = '(<|>|<=|>=|=|!=|not in|in)'
|
||||
|
||||
export function hasFilterQuery(filter: string): boolean {
|
||||
return FILTER_OPERATORS.find(o => filter.includes(o)) || false
|
||||
}
|
||||
|
||||
export function getFilterFieldRegexPattern(field: string): RegExp {
|
||||
return new RegExp('(' + field + '\\s*' + FILTER_OPERATORS_REGEX + '\\s*)([\'"]?)([^\'"&|()<]+\\1?)?', 'ig')
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type {IAbstract} from './IAbstract'
|
||||
import type {IProject} from '@/modelTypes/IProject'
|
||||
import type {IFilters} from '@/modelTypes/ISavedFilter'
|
||||
|
||||
export const PROJECT_VIEW_KINDS = {
|
||||
LIST: 'list',
|
||||
@@ -20,7 +21,7 @@ export type ProjectViewBucketConfigurationMode = typeof PROJECT_VIEW_BUCKET_CONF
|
||||
|
||||
export interface IProjectViewBucketConfiguration {
|
||||
title: string
|
||||
filter: string
|
||||
filter: IFilters
|
||||
}
|
||||
|
||||
export interface IProjectView extends IAbstract {
|
||||
@@ -29,7 +30,7 @@ export interface IProjectView extends IAbstract {
|
||||
projectId: IProject['id']
|
||||
viewKind: ProjectViewKind
|
||||
|
||||
filter: string
|
||||
filter: IFilters
|
||||
position: number
|
||||
|
||||
bucketConfigurationMode: ProjectViewBucketConfigurationMode
|
||||
|
||||
@@ -2,7 +2,7 @@ import type {IAbstract} from './IAbstract'
|
||||
import type {IUser} from './IUser'
|
||||
|
||||
// FIXME: what makes this different from TaskFilterParams?
|
||||
interface Filters {
|
||||
export interface IFilters {
|
||||
sort_by: ('start_date' | 'done' | 'id' | 'position')[],
|
||||
order_by: ('asc' | 'desc')[],
|
||||
filter: string,
|
||||
@@ -14,7 +14,7 @@ export interface ISavedFilter extends IAbstract {
|
||||
id: number
|
||||
title: string
|
||||
description: string
|
||||
filters: Filters
|
||||
filters: IFilters
|
||||
|
||||
owner: IUser
|
||||
created: Date
|
||||
|
||||
@@ -7,7 +7,13 @@ export default class ProjectViewModel extends AbstractModel<IProjectView> implem
|
||||
projectId = 0
|
||||
viewKind: ProjectViewKind = 'list'
|
||||
|
||||
filter = ''
|
||||
filter: IProjectView['filters'] = {
|
||||
sort_by: ['done', 'id'],
|
||||
order_by: ['asc', 'desc'],
|
||||
filter: 'done = false',
|
||||
filter_include_nulls: true,
|
||||
s: '',
|
||||
}
|
||||
position = 0
|
||||
|
||||
bucketConfiguration = []
|
||||
|
||||
83
pkg/migration/20241118123644.go
Normal file
83
pkg/migration/20241118123644.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-present Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type taskCollection20241118123644 struct {
|
||||
Filter string `query:"filter" json:"filter"`
|
||||
}
|
||||
|
||||
type projectViews20241118123644New struct {
|
||||
ID int64 `xorm:"autoincr not null unique pk" json:"id" param:"view"`
|
||||
Filter *taskCollection20241118123644 `xorm:"json null default null" query:"filter" json:"filter"`
|
||||
}
|
||||
|
||||
func (*projectViews20241118123644New) TableName() string {
|
||||
return "project_views"
|
||||
}
|
||||
|
||||
type projectViews20241118123644 struct {
|
||||
ID int64 `xorm:"autoincr not null unique pk" json:"id" param:"view"`
|
||||
Filter string `xorm:"json null default null" query:"filter" json:"filter"`
|
||||
}
|
||||
|
||||
func (*projectViews20241118123644) TableName() string {
|
||||
return "project_views"
|
||||
}
|
||||
|
||||
func init() {
|
||||
migrations = append(migrations, &xormigrate.Migration{
|
||||
ID: "20241118123644",
|
||||
Description: "change filter format",
|
||||
Migrate: func(tx *xorm.Engine) (err error) {
|
||||
oldViews := []*projectViews20241118123644{}
|
||||
|
||||
err = tx.Where("filter != '' AND filter IS NOT NULL").Find(&oldViews)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = tx.Sync(projectViews20241118123644New{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, view := range oldViews {
|
||||
newView := &projectViews20241118123644New{
|
||||
ID: view.ID,
|
||||
Filter: &taskCollection20241118123644{
|
||||
Filter: view.Filter,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = tx.Where("id = ?", view.ID).Update(newView)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
Rollback: func(tx *xorm.Engine) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
95
pkg/migration/20241119115012.go
Normal file
95
pkg/migration/20241119115012.go
Normal file
@@ -0,0 +1,95 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-present Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type projectView20241119115012BucketConfiguration struct {
|
||||
Title string `json:"title"`
|
||||
Filter string `json:"filter"`
|
||||
}
|
||||
|
||||
type projectView20241119115012 struct {
|
||||
ID int64 `xorm:"autoincr not null unique pk" json:"id" param:"view"`
|
||||
BucketConfiguration []*projectView20241119115012BucketConfiguration `xorm:"json" json:"bucket_configuration"`
|
||||
}
|
||||
|
||||
func (projectView20241119115012) TableName() string {
|
||||
return "project_views"
|
||||
}
|
||||
|
||||
type projectView20241119115012BucketConfigurationNew struct {
|
||||
Title string `json:"title"`
|
||||
Filter *taskCollection20241118123644 `json:"filter"`
|
||||
}
|
||||
|
||||
type projectView20241119115012New struct {
|
||||
ID int64 `xorm:"autoincr not null unique pk" json:"id" param:"view"`
|
||||
BucketConfiguration []*projectView20241119115012BucketConfigurationNew `xorm:"json" json:"bucket_configuration"`
|
||||
}
|
||||
|
||||
func (projectView20241119115012New) TableName() string {
|
||||
return "project_views"
|
||||
}
|
||||
|
||||
func init() {
|
||||
migrations = append(migrations, &xormigrate.Migration{
|
||||
ID: "20241119115012",
|
||||
Description: "change bucket filter format",
|
||||
Migrate: func(tx *xorm.Engine) (err error) {
|
||||
oldViews := []*projectView20241119115012{}
|
||||
|
||||
err = tx.Where("bucket_configuration_mode = 2").Find(&oldViews)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = tx.Sync(projectView20241119115012New{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, view := range oldViews {
|
||||
newView := &projectView20241119115012New{
|
||||
ID: view.ID,
|
||||
}
|
||||
|
||||
for _, configuration := range view.BucketConfiguration {
|
||||
newView.BucketConfiguration = append(newView.BucketConfiguration, &projectView20241119115012BucketConfigurationNew{
|
||||
Title: configuration.Title,
|
||||
Filter: &taskCollection20241118123644{
|
||||
Filter: configuration.Filter,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_, err = tx.Where("id = ?", view.ID).Update(newView)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
Rollback: func(tx *xorm.Engine) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -230,7 +230,14 @@ func GetTasksInBucketsForView(s *xorm.Session, view *ProjectView, projects []*Pr
|
||||
|
||||
var bucketFilter = taskPropertyBucketID + " = " + strconv.FormatInt(id, 10)
|
||||
if view.BucketConfigurationMode == BucketConfigurationModeFilter {
|
||||
bucketFilter = "(" + view.BucketConfiguration[id].Filter + ")"
|
||||
bucketFilter = ""
|
||||
if view.BucketConfiguration[id].Filter.Filter != "" {
|
||||
bucketFilter = "(" + view.BucketConfiguration[id].Filter.Filter + ")"
|
||||
}
|
||||
|
||||
if view.BucketConfiguration[id].Filter.Search != "" {
|
||||
opts.search = view.BucketConfiguration[id].Filter.Search
|
||||
}
|
||||
}
|
||||
|
||||
var filterString string
|
||||
|
||||
@@ -136,7 +136,7 @@ var FavoritesPseudoProject = Project{
|
||||
Title: "List",
|
||||
ViewKind: ProjectViewKindList,
|
||||
Position: 100,
|
||||
Filter: "done = false",
|
||||
Filter: &TaskCollection{Filter: "done = false"},
|
||||
},
|
||||
{
|
||||
ID: -2,
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/web"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
@@ -115,8 +116,8 @@ func (p *BucketConfigurationModeKind) UnmarshalJSON(bytes []byte) error {
|
||||
}
|
||||
|
||||
type ProjectViewBucketConfiguration struct {
|
||||
Title string `json:"title"`
|
||||
Filter string `json:"filter"`
|
||||
Title string `json:"title"`
|
||||
Filter *TaskCollection `json:"filter"`
|
||||
}
|
||||
|
||||
type ProjectView struct {
|
||||
@@ -130,7 +131,7 @@ type ProjectView struct {
|
||||
ViewKind ProjectViewKind `xorm:"not null" json:"view_kind"`
|
||||
|
||||
// The filter query to match tasks by. Check out https://vikunja.io/docs/filters for a full explanation.
|
||||
Filter string `xorm:"text null default null" query:"filter" json:"filter"`
|
||||
Filter *TaskCollection `xorm:"json null default null" query:"filter" json:"filter"`
|
||||
// The position of this view in the list. The list of all views will be sorted by this parameter.
|
||||
Position float64 `xorm:"double null" json:"position"`
|
||||
|
||||
@@ -273,6 +274,24 @@ func (pv *ProjectView) Create(s *xorm.Session, a web.Auth) (err error) {
|
||||
}
|
||||
|
||||
func createProjectView(s *xorm.Session, p *ProjectView, a web.Auth, createBacklogBucket bool, addExistingTasksToView bool) (err error) {
|
||||
if p.Filter != nil && p.Filter.Filter != "" {
|
||||
_, err = getTaskFiltersFromFilterString(p.Filter.Filter, p.Filter.FilterTimezone)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if p.BucketConfigurationMode == BucketConfigurationModeFilter {
|
||||
for _, configuration := range p.BucketConfiguration {
|
||||
if configuration.Filter != nil && configuration.Filter.Filter != "" {
|
||||
_, err = getTaskFiltersFromFilterString(configuration.Filter.Filter, configuration.Filter.FilterTimezone)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.ID = 0
|
||||
_, err = s.Insert(p)
|
||||
if err != nil {
|
||||
@@ -348,6 +367,13 @@ func addTasksToView(s *xorm.Session, a web.Auth, pv *ProjectView, b *Bucket) (er
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /projects/{project}/views/{id} [post]
|
||||
func (pv *ProjectView) Update(s *xorm.Session, _ web.Auth) (err error) {
|
||||
if pv.Filter != nil && pv.Filter.Filter != "" {
|
||||
_, err = getTaskFiltersFromFilterString(pv.Filter.Filter, pv.Filter.FilterTimezone)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the project view exists
|
||||
_, err = GetProjectViewByIDAndProject(s, pv.ID, pv.ProjectID)
|
||||
if err != nil {
|
||||
@@ -428,7 +454,9 @@ func CreateDefaultViewsForProject(s *xorm.Session, project *Project, a web.Auth,
|
||||
Position: 100,
|
||||
}
|
||||
if createDefaultListFilter {
|
||||
list.Filter = "done = false"
|
||||
list.Filter = &TaskCollection{
|
||||
Filter: "done = false",
|
||||
}
|
||||
}
|
||||
err = createProjectView(s, list, a, createBacklogBucket, true)
|
||||
if err != nil {
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestSavedFilter_Create(t *testing.T) {
|
||||
vals := map[string]interface{}{
|
||||
"title": "'test'",
|
||||
"description": "'Lorem Ipsum dolor sit amet'",
|
||||
"filters": "'{\"sort_by\":null,\"order_by\":null,\"filter\":\"\",\"filter_include_nulls\":false}'",
|
||||
"filters": `'{"s":"","sort_by":null,"order_by":null,"filter":"","filter_include_nulls":false}'`,
|
||||
"owner_id": 1,
|
||||
}
|
||||
// Postgres can't compare json values directly, see https://dba.stackexchange.com/a/106290/210721
|
||||
|
||||
@@ -32,6 +32,8 @@ type TaskCollection struct {
|
||||
ProjectID int64 `param:"project" json:"-"`
|
||||
ProjectViewID int64 `param:"view" json:"-"`
|
||||
|
||||
Search string `query:"s" json:"s"`
|
||||
|
||||
// The query parameter to sort by. This is for ex. done, priority, etc.
|
||||
SortBy []string `query:"sort_by" json:"sort_by"`
|
||||
SortByArr []string `query:"sort_by[]" json:"-"`
|
||||
@@ -181,6 +183,10 @@ func getRelevantProjectsFromCollection(s *xorm.Session, a web.Auth, tf *TaskColl
|
||||
}
|
||||
|
||||
func getFilterValueForBucketFilter(filter string, view *ProjectView) (newFilter string, err error) {
|
||||
if view.BucketConfigurationMode != BucketConfigurationModeFilter {
|
||||
return filter, nil
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`bucket_id\s*=\s*(\d+)`)
|
||||
|
||||
match := re.FindStringSubmatch(filter)
|
||||
@@ -195,7 +201,7 @@ func getFilterValueForBucketFilter(filter string, view *ProjectView) (newFilter
|
||||
|
||||
for id, bucket := range view.BucketConfiguration {
|
||||
if id == bucketID {
|
||||
return re.ReplaceAllString(filter, `(`+bucket.Filter+`)`), nil
|
||||
return re.ReplaceAllString(filter, `(`+bucket.Filter.Filter+`)`), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,21 +283,34 @@ func (tf *TaskCollection) ReadAll(s *xorm.Session, a web.Auth, search string, pa
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
if view.Filter != "" {
|
||||
if tf.Filter != "" {
|
||||
tf.Filter = "(" + tf.Filter + ") && (" + view.Filter + ")"
|
||||
} else {
|
||||
tf.Filter = view.Filter
|
||||
if view.Filter != nil {
|
||||
if view.Filter.Filter != "" {
|
||||
if tf.Filter != "" {
|
||||
tf.Filter = "(" + tf.Filter + ") && (" + view.Filter.Filter + ")"
|
||||
} else {
|
||||
tf.Filter = view.Filter.Filter
|
||||
}
|
||||
tf.FilterIncludeNulls = view.Filter.FilterIncludeNulls
|
||||
}
|
||||
|
||||
if view.Filter.FilterTimezone != "" {
|
||||
tf.FilterTimezone = view.Filter.FilterTimezone
|
||||
}
|
||||
|
||||
if view.Filter.FilterIncludeNulls {
|
||||
tf.FilterIncludeNulls = view.Filter.FilterIncludeNulls
|
||||
}
|
||||
|
||||
if view.Filter.Search != "" {
|
||||
search = view.Filter.Search
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(tf.Filter, taskPropertyBucketID) {
|
||||
filteringForBucket = true
|
||||
if view.BucketConfigurationMode == BucketConfigurationModeFilter {
|
||||
tf.Filter, err = getFilterValueForBucketFilter(tf.Filter, view)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
tf.Filter, err = getFilterValueForBucketFilter(tf.Filter, view)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user