feat: filters script setup
continuous-integration/drone/pr Build is passing
Details
continuous-integration/drone/pr Build is passing
Details
This commit is contained in:
parent
4c0ce26f2d
commit
15f532d37a
|
@ -20,7 +20,7 @@
|
||||||
:overflow="true"
|
:overflow="true"
|
||||||
variant="hint-modal"
|
variant="hint-modal"
|
||||||
>
|
>
|
||||||
<filters
|
<Filters
|
||||||
:has-title="true"
|
:has-title="true"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
ref="filters"
|
ref="filters"
|
||||||
|
@ -30,14 +30,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, ref, watch} from 'vue'
|
import {computed, ref, watch, type PropType} from 'vue'
|
||||||
|
|
||||||
import Filters from '@/components/list/partials/filters.vue'
|
import Filters from '@/components/list/partials/filters.vue'
|
||||||
|
|
||||||
import {getDefaultParams} from '@/composables/taskList'
|
import {getDefaultParams} from '@/composables/taskList'
|
||||||
|
import type {IParams} from '@/types/IParams'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
|
type: Object as PropType<IParams>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -63,15 +65,15 @@ watch(
|
||||||
const hasFilters = computed(() => {
|
const hasFilters = computed(() => {
|
||||||
// this.value also contains the page parameter which we don't want to include in filters
|
// this.value also contains the page parameter which we don't want to include in filters
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
const {filter_by, filter_value, filter_comparator, filter_concat, s} = value.value
|
const {filterBy, filterValue, filterComparator, filterConcat, s} = value.value
|
||||||
const def = {...getDefaultParams()}
|
const def = {...getDefaultParams()}
|
||||||
|
|
||||||
const params = {filter_by, filter_value, filter_comparator, filter_concat, s}
|
const params = {filterBy, filterValue, filterComparator, filterConcat, s}
|
||||||
const defaultParams = {
|
const defaultParams = {
|
||||||
filter_by: def.filter_by,
|
filterBy: def.filterBy,
|
||||||
filter_value: def.filter_value,
|
filterValue: def.filterValue,
|
||||||
filter_comparator: def.filter_comparator,
|
filterComparator: def.filterComparator,
|
||||||
filter_concat: def.filter_concat,
|
filterConcat: def.filterConcat,
|
||||||
s: s ? def.s : undefined,
|
s: s ? def.s : undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,52 +1,63 @@
|
||||||
import {ref, shallowReactive, watch, computed} from 'vue'
|
import {ref, shallowReactive, watch, computed, type Ref} from 'vue'
|
||||||
import {useRoute} from 'vue-router'
|
import {useRoute} from 'vue-router'
|
||||||
|
|
||||||
import TaskCollectionService from '@/services/taskCollection'
|
import TaskCollectionService from '@/services/taskCollection'
|
||||||
import type { ITask } from '@/modelTypes/ITask'
|
|
||||||
|
import type {ITask} from '@/modelTypes/ITask'
|
||||||
|
import type {IList} from '@/modelTypes/IList'
|
||||||
|
import type {IParams, OrderBy, SortBy} from '@/types/IParams'
|
||||||
|
|
||||||
// FIXME: merge with DEFAULT_PARAMS in filters.vue
|
// FIXME: merge with DEFAULT_PARAMS in filters.vue
|
||||||
export const getDefaultParams = () => ({
|
export const getDefaultParams = () => ({
|
||||||
sort_by: ['position', 'id'],
|
sortBy: ['position', 'id'],
|
||||||
order_by: ['asc', 'desc'],
|
orderBy: ['asc', 'desc'],
|
||||||
filter_by: ['done'],
|
filterBy: ['done'],
|
||||||
filter_value: ['false'],
|
filterValue: ['false'],
|
||||||
filter_comparator: ['equals'],
|
filterComparator: ['equals'],
|
||||||
filter_concat: 'and',
|
filterConcat: 'and',
|
||||||
})
|
} as IParams)
|
||||||
|
|
||||||
const SORT_BY_DEFAULT = {
|
type FilterSortOrderMap = Partial<{[key in SortBy]: OrderBy }>
|
||||||
|
|
||||||
|
const SORT_BY_DEFAULT: FilterSortOrderMap = {
|
||||||
id: 'desc',
|
id: 'desc',
|
||||||
}
|
} as const
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This mixin provides a base set of methods and properties to get tasks on a list.
|
* This mixin provides a base set of methods and properties to get tasks on a list.
|
||||||
*/
|
*/
|
||||||
export function useTaskList(listId, sortByDefault = SORT_BY_DEFAULT) {
|
export function useTaskList(listId: Ref<IList['id']>, sortByDefault = SORT_BY_DEFAULT) {
|
||||||
const params = ref({...getDefaultParams()})
|
const params = ref({...getDefaultParams()})
|
||||||
|
|
||||||
const search = ref('')
|
const search = ref('')
|
||||||
const page = ref(1)
|
const page = ref(1)
|
||||||
|
|
||||||
const sortBy = ref({ ...sortByDefault })
|
const sortBy = ref<FilterSortOrderMap>({ ...sortByDefault })
|
||||||
|
|
||||||
// This makes sure an id sort order is always sorted last.
|
// This makes sure an id sort order is always sorted last.
|
||||||
// When tasks would be sorted first by id and then by whatever else was specified, the id sort takes
|
// When tasks would be sorted first by id and then by whatever else was specified, the id sort takes
|
||||||
// precedence over everything else, making any other sort columns pretty useless.
|
// precedence over everything else, making any other sort columns pretty useless.
|
||||||
function formatSortOrder(params) {
|
function formatSortOrder(params: IParams) {
|
||||||
let hasIdFilter = false
|
const sortEntries = Object.entries(sortBy.value)
|
||||||
const sortKeys = Object.keys(sortBy.value)
|
const sortKeys: SortBy[] = []
|
||||||
for (const s of sortKeys) {
|
const orderByValue: OrderBy[] = []
|
||||||
if (s === 'id') {
|
let idFilterValue
|
||||||
sortKeys.splice(s, 1)
|
sortEntries.forEach(([key, value], index) => {
|
||||||
hasIdFilter = true
|
if (key === 'id') {
|
||||||
break
|
idFilterValue = value
|
||||||
|
sortEntries.splice(index, 1)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
sortKeys.push(key as SortBy)
|
||||||
if (hasIdFilter) {
|
orderByValue.push(value)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (idFilterValue) {
|
||||||
sortKeys.push('id')
|
sortKeys.push('id')
|
||||||
}
|
}
|
||||||
params.sort_by = sortKeys
|
|
||||||
params.order_by = sortKeys.map(s => sortBy.value[s])
|
params.sortBy = sortKeys
|
||||||
|
params.orderBy = orderByValue
|
||||||
|
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import {camelCase} from 'camel-case'
|
import {camelCase} from 'camel-case'
|
||||||
import {snakeCase} from 'snake-case'
|
import {snakeCase} from 'snake-case'
|
||||||
|
|
||||||
|
export {
|
||||||
|
camelCase,
|
||||||
|
snakeCase,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms field names to camel case.
|
* Transforms field names to camel case.
|
||||||
* @param object
|
* @param object
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export function parseDateOrString(rawValue: string | undefined, fallback: any): string | Date {
|
export function parseDateOrString(rawValue: string | undefined, fallback: null) {
|
||||||
if (typeof rawValue === 'undefined') {
|
if (typeof rawValue === 'undefined') {
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ export function findById<T extends {id: string | number}>(array : T[], id : stri
|
||||||
return array.find(({id: currentId}) => currentId === id)
|
return array.find(({id: currentId}) => currentId === id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function includesById(array: [], id: string | number) {
|
export function includesById(array: any[], id: string | number) {
|
||||||
return array.some(({id: currentId}) => currentId === id)
|
return array.some(({id: currentId}) => currentId === id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import type {IAbstract} from './IAbstract'
|
import type {IAbstract} from './IAbstract'
|
||||||
import type {IUser} from './IUser'
|
import type {IUser} from './IUser'
|
||||||
import type {IFilter} from '@/types/IFilter'
|
import type {IParams} from '@/types/IParams'
|
||||||
|
|
||||||
export interface ISavedFilter extends IAbstract {
|
export interface ISavedFilter extends IAbstract {
|
||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
filters: IFilter
|
filters: IParams
|
||||||
|
|
||||||
owner: IUser
|
owner: IUser
|
||||||
created: Date
|
created: Date
|
||||||
|
|
|
@ -186,7 +186,7 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
|
||||||
* This one here is the default one, usually the service definitions for a model will override this.
|
* This one here is the default one, usually the service definitions for a model will override this.
|
||||||
*/
|
*/
|
||||||
modelFactory(data : Partial<Model>) {
|
modelFactory(data : Partial<Model>) {
|
||||||
return new AbstractModel(data)
|
return data as Model
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,9 +1,32 @@
|
||||||
|
import type { Priority } from '@/constants/priorities'
|
||||||
|
|
||||||
export interface IFilter {
|
export interface IFilter {
|
||||||
sortBy: ('done' | 'id')[]
|
// where
|
||||||
orderBy: ('asc' | 'desc')[]
|
listId: string
|
||||||
filterBy: 'done'[]
|
|
||||||
filterValue: 'false'[]
|
// what
|
||||||
filterComparator: 'equals'[]
|
assignees: string
|
||||||
filterConcat: 'and'
|
done: boolean,
|
||||||
filterIncludeNulls: boolean
|
dueDate: string
|
||||||
}
|
endDate: string
|
||||||
|
labels: string
|
||||||
|
namespace: string
|
||||||
|
percentDone: number
|
||||||
|
priority: Priority
|
||||||
|
reminders: string
|
||||||
|
startDate: string
|
||||||
|
|
||||||
|
// filter meta
|
||||||
|
requireAllFilters: boolean
|
||||||
|
|
||||||
|
// toggle what
|
||||||
|
usePercentDone: boolean
|
||||||
|
usePriority: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IFilterToggles {
|
||||||
|
usePercentDone: boolean
|
||||||
|
usePriority: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IFilterKey = keyof IFilter
|
|
@ -0,0 +1,38 @@
|
||||||
|
import type { ITask } from '@/modelTypes/ITask'
|
||||||
|
|
||||||
|
export type SortBy =
|
||||||
|
| 'id'
|
||||||
|
| 'title'
|
||||||
|
| 'description'
|
||||||
|
| 'done'
|
||||||
|
| 'doneAt'
|
||||||
|
| 'dueDate'
|
||||||
|
| 'createdById'
|
||||||
|
| 'listId'
|
||||||
|
| 'repeatAfter'
|
||||||
|
| 'priority'
|
||||||
|
| 'start_date'
|
||||||
|
| 'end_date'
|
||||||
|
| 'hex_color'
|
||||||
|
| 'percent_done'
|
||||||
|
| 'uid'
|
||||||
|
| 'created'
|
||||||
|
| 'updated'
|
||||||
|
| 'position'
|
||||||
|
|
||||||
|
export type OrderBy = 'asc' | 'desc'
|
||||||
|
export type FilterComparator = 'equals' | 'greater' | 'greaterEquals' | 'less' | 'lessEquals' | 'like' |'in'
|
||||||
|
|
||||||
|
export type FilterBy = keyof ITask | 'namespace'
|
||||||
|
export type FilterValue = 'false' | string | number | boolean | Date | {dateFrom: string | Date, dateTo: string | Date}
|
||||||
|
|
||||||
|
export interface IParams {
|
||||||
|
sortBy: SortBy[]
|
||||||
|
orderBy: OrderBy[]
|
||||||
|
filterBy: FilterBy[]
|
||||||
|
filterValue: FilterValue[]
|
||||||
|
filterComparator: FilterComparator[]
|
||||||
|
filterConcat: 'and' | 'or'
|
||||||
|
filterIncludeNulls: boolean
|
||||||
|
s: '' // search
|
||||||
|
}
|
|
@ -226,7 +226,7 @@ const {
|
||||||
|
|
||||||
|
|
||||||
const isAlphabeticalSorting = computed(() => {
|
const isAlphabeticalSorting = computed(() => {
|
||||||
return params.value.sort_by.find(sortBy => sortBy === ALPHABETICAL_SORT) !== undefined
|
return params.value.sortBy.find(sortBy => sortBy === ALPHABETICAL_SORT) !== undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
const firstNewPosition = computed(() => {
|
const firstNewPosition = computed(() => {
|
||||||
|
|
Reference in New Issue