Rudimentary searching
This commit is contained in:
@@ -56,12 +56,10 @@
|
|||||||
emit-value
|
emit-value
|
||||||
map-options
|
map-options
|
||||||
input-debounce="250"
|
input-debounce="250"
|
||||||
@new-value="addTag"
|
|
||||||
:options="skillTagOptions"
|
:options="skillTagOptions"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="$id"
|
option-value="$id"
|
||||||
@filter="filterSkillTags"
|
@filter="filterSkillTags"
|
||||||
new-value-mode="add-unique"
|
|
||||||
>
|
>
|
||||||
</q-select>
|
</q-select>
|
||||||
</div>
|
</div>
|
||||||
@@ -159,7 +157,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref, Ref } from 'vue';
|
import { computed, reactive, ref, Ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useTaskStore, TASKSTATUS } from 'src/stores/task';
|
import { useTaskStore, TASKSTATUS } from 'src/stores/task';
|
||||||
import type { TaskTag, SkillTag, Task } from 'src/stores/task';
|
import type { TaskTag, SkillTag, Task } from 'src/stores/task';
|
||||||
@@ -194,24 +192,33 @@ const boatList = ref<Boat[]>(useBoatStore().boats);
|
|||||||
const skillTagOptions = ref<SkillTag[]>(taskStore.skillTags);
|
const skillTagOptions = ref<SkillTag[]>(taskStore.skillTags);
|
||||||
const taskTagOptions = ref<TaskTag[]>(taskStore.taskTags);
|
const taskTagOptions = ref<TaskTag[]>(taskStore.taskTags);
|
||||||
|
|
||||||
function filterSkillTags(val: string, update: (cb: () => void) => void): void {
|
const filterSkillTags = computed(
|
||||||
return filterTags(skillTagOptions, taskStore.skillTags, val, update);
|
() =>
|
||||||
}
|
(val: string, update: (cb: () => void) => void): void => {
|
||||||
function filterTaskTags(val: string, update: (cb: () => void) => void): void {
|
return filterTags(skillTagOptions, taskStore.skillTags, val, update);
|
||||||
return filterTags(taskTagOptions, taskStore.taskTags, val, update);
|
}
|
||||||
}
|
);
|
||||||
function filterTasks(val: string, update: (cb: () => void) => void): void {
|
const filterTaskTags = computed(
|
||||||
if (val === '') {
|
() =>
|
||||||
update(() => {
|
(val: string, update: (cb: () => void) => void): void => {
|
||||||
tasks = taskStore.tasks;
|
return filterTags(taskTagOptions, taskStore.taskTags, val, update);
|
||||||
});
|
}
|
||||||
return;
|
);
|
||||||
}
|
const filterTasks = computed(
|
||||||
|
() =>
|
||||||
|
(val: string, update: (cb: () => void) => void): void => {
|
||||||
|
if (val === '') {
|
||||||
|
update(() => {
|
||||||
|
tasks = taskStore.tasks;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
update(() => {
|
update(() => {
|
||||||
tasks = taskStore.filterTasksByTitle(val);
|
tasks = taskStore.filterTasksByTitle(val);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function filterTags(
|
function filterTags(
|
||||||
optionVar: Ref<(SkillTag | TaskTag)[] | undefined>,
|
optionVar: Ref<(SkillTag | TaskTag)[] | undefined>,
|
||||||
@@ -233,9 +240,6 @@ function filterTags(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTag(tag: string) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Method to update the model in ISO 8601 format
|
// Method to update the model in ISO 8601 format
|
||||||
const updateDateISO = (value: string) => {
|
const updateDateISO = (value: string) => {
|
||||||
modifiedTask.due_date = date.formatDate(value, 'YYYY-MM-DD');
|
modifiedTask.due_date = date.formatDate(value, 'YYYY-MM-DD');
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<q-table
|
<q-table
|
||||||
:rows="tasks"
|
:rows="tasks"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
:grid="$q.screen.xs"
|
||||||
dense
|
dense
|
||||||
row-key="$id"
|
row-key="$id"
|
||||||
flatten
|
flatten
|
||||||
@@ -11,7 +12,7 @@
|
|||||||
selection="multiple"
|
selection="multiple"
|
||||||
v-model:selected="selected"
|
v-model:selected="selected"
|
||||||
:filter="searchFilter"
|
:filter="searchFilter"
|
||||||
:filter-method="filterByTitle"
|
:filter-method="filterRows"
|
||||||
@row-click="onRowClick"
|
@row-click="onRowClick"
|
||||||
>
|
>
|
||||||
<template v-slot:top>
|
<template v-slot:top>
|
||||||
@@ -30,7 +31,42 @@
|
|||||||
@click="deleteTasks"
|
@click="deleteTasks"
|
||||||
/>
|
/>
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-input flatten debounce="300" color="primary" v-model="searchFilter">
|
<q-select
|
||||||
|
style="width: 250px"
|
||||||
|
multiple
|
||||||
|
use-chips
|
||||||
|
clearable
|
||||||
|
label="Skills Filter"
|
||||||
|
input-debounce="250"
|
||||||
|
:options="skillTagOptions"
|
||||||
|
v-model="searchFilter.skillTags"
|
||||||
|
option-label="name"
|
||||||
|
option-value="$id"
|
||||||
|
>
|
||||||
|
</q-select>
|
||||||
|
<q-select
|
||||||
|
style="width: 250px"
|
||||||
|
multiple
|
||||||
|
use-chips
|
||||||
|
clearable
|
||||||
|
label="Tag Filter"
|
||||||
|
input-debounce="250"
|
||||||
|
:options="taskTagOptions"
|
||||||
|
v-model="searchFilter.taskTags"
|
||||||
|
option-label="name"
|
||||||
|
option-value="$id"
|
||||||
|
>
|
||||||
|
<template v-slot: prepend>
|
||||||
|
<q-icon name="wrench"></q-icon>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
<q-space />
|
||||||
|
<q-input
|
||||||
|
flatten
|
||||||
|
debounce="300"
|
||||||
|
color="primary"
|
||||||
|
v-model="searchFilter.title"
|
||||||
|
>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-icon name="search" />
|
<q-icon name="search" />
|
||||||
</template>
|
</template>
|
||||||
@@ -75,8 +111,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, ref } from 'vue';
|
import { computed, defineProps, ref } from 'vue';
|
||||||
import { useTaskStore, Task } from 'src/stores/task';
|
import { useTaskStore, Task, SkillTag, TaskTag } from 'src/stores/task';
|
||||||
import { QTableProps, date, useQuasar } from 'quasar';
|
import { QTableProps, date, useQuasar } from 'quasar';
|
||||||
import { useBoatStore } from 'src/stores/boat';
|
import { useBoatStore } from 'src/stores/boat';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
@@ -129,7 +165,7 @@ const columns = <QTableProps['columns']>[
|
|||||||
label: 'Boat',
|
label: 'Boat',
|
||||||
field: (row) =>
|
field: (row) =>
|
||||||
useBoatStore().boats.find((boat) => boat.$id === row.boat)?.name,
|
useBoatStore().boats.find((boat) => boat.$id === row.boat)?.name,
|
||||||
sortable: false,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'volunteers',
|
name: 'volunteers',
|
||||||
@@ -164,27 +200,45 @@ const columns = <QTableProps['columns']>[
|
|||||||
|
|
||||||
const props = defineProps<{ tasks: Task[] }>();
|
const props = defineProps<{ tasks: Task[] }>();
|
||||||
const taskStore = useTaskStore();
|
const taskStore = useTaskStore();
|
||||||
const searchFilter = ref('');
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
|
|
||||||
|
const searchFilter = ref({
|
||||||
|
title: '',
|
||||||
|
skillTags: <SkillTag[]>[],
|
||||||
|
taskTags: <TaskTag[]>[],
|
||||||
|
});
|
||||||
|
|
||||||
|
const skillTagOptions = ref<SkillTag[]>(taskStore.skillTags);
|
||||||
|
const taskTagOptions = ref<TaskTag[]>(taskStore.taskTags);
|
||||||
|
|
||||||
function onRowClick(evt: Event, row: Task) {
|
function onRowClick(evt: Event, row: Task) {
|
||||||
console.log(row);
|
console.log(row);
|
||||||
router.push({ name: 'edit-task', params: { id: row.$id } });
|
router.push({ name: 'edit-task', params: { id: row.$id } });
|
||||||
}
|
}
|
||||||
|
// TODO: Implement server side search
|
||||||
const filterByTitle = (
|
const filterRows = computed(
|
||||||
rows: readonly Task[],
|
() => (rows: readonly Task[], terms: any, cols: any, cellValueFn: any) => {
|
||||||
terms: any,
|
let result = rows;
|
||||||
cols: any,
|
result = rows.filter((row) =>
|
||||||
cellValueFn: any
|
terms.title
|
||||||
) => {
|
? row.title.toLowerCase().includes(terms.title.toLowerCase())
|
||||||
console.log(terms);
|
: true
|
||||||
return terms
|
);
|
||||||
? rows.filter((row) =>
|
result = result.filter((row) =>
|
||||||
row.title.toLowerCase().includes(terms.toLowerCase())
|
terms.skillTags.length > 0
|
||||||
)
|
? row.required_skills.some((req_skill) =>
|
||||||
: rows;
|
terms.skillTags.map((t) => t.$id).includes(req_skill)
|
||||||
};
|
)
|
||||||
|
: true
|
||||||
|
);
|
||||||
|
result = result.filter((row) =>
|
||||||
|
terms.taskTags.length > 0
|
||||||
|
? row.tags.some((tag) => terms.taskTags.map((t) => t.$id).includes(tag))
|
||||||
|
: true
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function deleteTasks() {
|
function deleteTasks() {
|
||||||
confirmDelete(selected.value);
|
confirmDelete(selected.value);
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<toolbar-component pageTitle="Tasks" />
|
<toolbar-component pageTitle="Tasks" />
|
||||||
<q-page padding>
|
<q-page padding>
|
||||||
<TaskListComponent v-if="$q.screen.lt.sm" :tasks="taskStore.tasks" />
|
<TaskTableComponent :tasks="taskStore.tasks" />
|
||||||
<TaskTableComponent v-else :tasks="taskStore.tasks" />
|
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useTaskStore } from 'stores/task';
|
import { useTaskStore } from 'stores/task';
|
||||||
import ToolbarComponent from 'src/components/ToolbarComponent.vue';
|
import ToolbarComponent from 'src/components/ToolbarComponent.vue';
|
||||||
import TaskListComponent from 'src/components/task/TaskListComponent.vue';
|
|
||||||
import TaskTableComponent from 'src/components/task/TaskTableComponent.vue';
|
import TaskTableComponent from 'src/components/task/TaskTableComponent.vue';
|
||||||
|
|
||||||
const taskStore = useTaskStore();
|
const taskStore = useTaskStore();
|
||||||
|
|||||||
Reference in New Issue
Block a user