Skip to content

Commit

Permalink
Project autocomplete (#3944)
Browse files Browse the repository at this point in the history
* Project autocomplete

* Fixing linting

---------

Co-authored-by: Will Sheldon <[email protected]>
  • Loading branch information
kevgliss and wssheldon authored Nov 7, 2023
1 parent d2f3276 commit 7f512b6
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 13 deletions.
3 changes: 3 additions & 0 deletions src/dispatch/static/dispatch/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ declare module '@vue/runtime-core' {
AnimatedNumber: typeof import('./src/components/AnimatedNumber.vue')['default']
AppDrawer: typeof import('./src/components/AppDrawer.vue')['default']
AppToolbar: typeof import('./src/components/AppToolbar.vue')['default']
AutoComplete: typeof import('./src/components/AutoComplete.vue')['default']
BaseCombobox: typeof import('./src/components/BaseCombobox.vue')['default']
BasicLayout: typeof import('./src/components/layouts/BasicLayout.vue')['default']
ColorPickerInput: typeof import('./src/components/ColorPickerInput.vue')['default']
Expand All @@ -25,7 +26,9 @@ declare module '@vue/runtime-core' {
MonacoEditor: typeof import('./src/components/MonacoEditor.vue')['default']
NotificationSnackbarsWrapper: typeof import('./src/components/NotificationSnackbarsWrapper.vue')['default']
PageHeader: typeof import('./src/components/PageHeader.vue')['default']
ParticipantAutoComplete: typeof import('./src/components/ParticipantAutoComplete.vue')['default']
ParticipantSelect: typeof import('./src/components/ParticipantSelect.vue')['default']
ProjectAutoComplete: typeof import('./src/components/ProjectAutoComplete.vue')['default']
Refresh: typeof import('./src/components/Refresh.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Expand Down
6 changes: 3 additions & 3 deletions src/dispatch/static/dispatch/src/case/DetailsTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
/>
</v-col>
<v-col cols="6">
<project-select v-model="project" />
<project-auto-complete v-model="project" />
</v-col>
<v-col cols="6">
<case-type-select v-model="case_type" :project="project" />
Expand Down Expand Up @@ -131,8 +131,8 @@ import CaseSeveritySelect from "@/case/severity/CaseSeveritySelect.vue"
import CaseTypeSelect from "@/case/type/CaseTypeSelect.vue"
import DateTimePickerMenu from "@/components/DateTimePickerMenu.vue"
import IncidentFilterCombobox from "@/incident/IncidentFilterCombobox.vue"
import ProjectAutoComplete from "@/project/ProjectAutoComplete.vue"
import ParticipantSelect from "@/components/ParticipantSelect.vue"
import ProjectSelect from "@/project/ProjectSelect.vue"
import TagFilterAutoComplete from "@/tag/TagFilterAutoComplete.vue"
export default {
Expand All @@ -151,7 +151,7 @@ export default {
DateTimePickerMenu,
IncidentFilterCombobox,
ParticipantSelect,
ProjectSelect,
ProjectAutoComplete,
TagFilterAutoComplete,
},
Expand Down
153 changes: 153 additions & 0 deletions src/dispatch/static/dispatch/src/components/AutoComplete.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<template>
<v-autocomplete
:items="items"
:label="label"
:loading="loading"
clearable
:item-title="title"
:item-value="identifier"
return-object
:hide-no-data="false"
v-model:search="search"
v-model="selectedModel"
@update:model-value="handleClear"
>
<template #no-data>
<v-list-item v-if="!loading">
<v-list-item-title>
No {{ resource }} matching {{}}<strong>"{{ search }}".</strong>
</v-list-item-title>
</v-list-item>
</template>
<template #item="{ props, item }">
<slot name="item" :props="props" :item="item">
<v-list-item v-bind="props" :title="item.title" :subtitle="item.raw[subtitle]" />
</slot>
</template>
<template #append-item v-if="items.length < total.value">
<v-list-item @click="loadMore">
<v-list-item-subtitle> Load More </v-list-item-subtitle>
</v-list-item>
</template>
</v-autocomplete>
</template>

<script>
import { ref, watch, toRefs, onMounted } from "vue"
import { initials } from "@/filters"
import { debounce } from "lodash"
import API from "@/api"
export default {
name: "AutoComplete",
props: {
resource: {
type: String,
required: true,
},
title: {
type: String,
default: "name",
},
identifier: {
type: String,
default: "id",
},
subtitle: {
type: String,
default: "description",
},
label: {
type: String,
default: "Select",
},
modelValue: {
type: Object,
default: () => ({}),
},
},
emits: ["update:modelValue"],
setup(props, { emit }) {
const { resource, modelValue } = toRefs(props)
let loading = ref(false)
let items = ref([])
let numItems = ref(10)
let currentPage = ref(1)
let total = ref(0)
let selectedModel = ref(modelValue.value)
let search = ref(modelValue.value ? modelValue.value[props.title.value] : "")
let debouncedGetData = debounce((searchVal, page = currentPage.value) => {
loading.value = true
API.get(`/${resource.value}`, {
params: {
q: searchVal,
sortBy: ["name"],
descending: [false],
itemsPerPage: numItems.value * page,
},
}).then((response) => {
items.value = response.data.items
total.value = response.data.total
loading.value = false
})
}, 300)
onMounted(() => {
debouncedGetData(search.value)
})
const handleClear = (newValue) => {
if (!newValue) {
items.value = []
search.value = ""
selectedModel.value = null
numItems.value = 10
currentPage.value = 1
}
}
const loadMore = () => {
currentPage.value++
numItems.value += 10
debouncedGetData(search.value)
}
watch(search, (newVal, oldVal) => {
if (oldVal !== newVal) {
numItems.value = 10
currentPage.value = 1
debouncedGetData(newVal)
}
})
watch(selectedModel, (newVal) => {
emit(
"update:modelValue",
newVal
? items.value.find(
(item) => item[props.identifier.value] == newVal[props.identifier.value]
)
: null
)
})
watch(modelValue, (newValue) => {
selectedModel.value = newValue
search.value = newValue ? newValue[props.title] : ""
})
return {
initials,
items,
loading,
handleClear,
loadMore,
selectedModel,
search,
total,
}
},
}
</script>
14 changes: 4 additions & 10 deletions src/dispatch/static/dispatch/src/components/ParticipantSelect.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<v-autocomplete
:items="items"
:label="labelProp"
:label="label"
:loading="loading"
v-model:search="search"
clearable
Expand All @@ -12,7 +12,7 @@
chips
:hide-no-data="false"
v-model="participant"
@update:modelValue="handleClear"
@update:model-value="handleClear"
>
<template #no-data>
<v-list-item v-if="!loading">
Expand Down Expand Up @@ -41,7 +41,7 @@
</template>

<script>
import { ref, watch, toRefs, onMounted } from "vue"
import { ref, watch, onMounted } from "vue"
import { initials } from "@/filters"
import { debounce } from "lodash"
Expand All @@ -50,8 +50,7 @@ import IndividualApi from "@/individual/api"
export default {
name: "ParticipantSelect",
props: {
labelProp: {
// Define the labelProp
label: {
type: String,
default: "Participant",
},
Expand All @@ -61,11 +60,8 @@ export default {
},
},
setup(props) {
const { labelProp } = toRefs(props) // toRefs make props reactive
let loading = ref(false)
let items = ref([])
console.log(items)
let numItems = ref(10)
let participant = ref({ ...props.initialValue })
let currentPage = ref(1)
Expand All @@ -84,7 +80,6 @@ export default {
}
await IndividualApi.getAll(filterOptions).then((response) => {
console.log(response.data.items)
items.value = response.data.items.map(function (x) {
return { individual: x }
})
Expand Down Expand Up @@ -127,7 +122,6 @@ export default {
handleClear,
initials,
items,
labelProp,
loading,
loadMore,
participant,
Expand Down
53 changes: 53 additions & 0 deletions src/dispatch/static/dispatch/src/project/ProjectAutoComplete.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<AutoComplete
resource="projects"
title="name"
identifier="id"
subtitle="description"
v-model="internalModelValue"
:label="label"
/>
</template>

<script>
import { ref, watch } from "vue"
import AutoComplete from "@/components/AutoComplete.vue"
export default {
name: "ProjectAutoComplete",
components: {
AutoComplete,
},
props: {
modelValue: {
type: Object,
default: () => ({}),
},
label: {
type: String,
default: "Project",
},
},
emits: ["update:modelValue"],
setup(props, { emit }) {
const internalModelValue = ref(props.modelValue)
watch(
() => props.modelValue,
(newVal) => {
internalModelValue.value = newVal
}
)
watch(internalModelValue, (newVal) => {
if (newVal !== props.modelValue) {
emit("update:modelValue", newVal)
}
})
return {
internalModelValue,
}
},
}
</script>

0 comments on commit 7f512b6

Please sign in to comment.