Warranty form: vendor combobox + clearer "Lookup source" label
- Vendor is now a datalist combobox seeded from the site vendor catalog (/api/vendors), so users pick a known vendor instead of retyping it, while still allowing free text. Kept as a string, not an FK, to keep the warranty plugin decoupled from core. - Renamed the "Provider" select to "Lookup source" with helper text. It was confusingly synonymous with Vendor; it actually means where coverage data comes from (manual entry vs a maker's warranty API that supports Refresh).
This commit is contained in:
@@ -82,16 +82,22 @@
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Vendor *</label>
|
||||
<input v-model="form.vendor" type="text" class="form-control" maxlength="100" required />
|
||||
<input v-model="form.vendor" type="text" class="form-control" maxlength="100" required
|
||||
list="warranty-vendor-list" placeholder="e.g. Dell" />
|
||||
<datalist id="warranty-vendor-list">
|
||||
<option v-for="name in vendorNames" :key="name" :value="name" />
|
||||
</datalist>
|
||||
<small class="muted">Who backs the warranty. Pick a known vendor or type a new one.</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Provider</label>
|
||||
<label>Lookup source</label>
|
||||
<select v-model="form.provider" class="form-control">
|
||||
<option value="manual">Manual</option>
|
||||
<option value="dell">Dell</option>
|
||||
<option value="lenovo">Lenovo</option>
|
||||
<option value="hp">HP</option>
|
||||
<option value="manual">Manual entry</option>
|
||||
<option value="dell">Dell (auto-refresh)</option>
|
||||
<option value="lenovo">Lenovo (auto-refresh)</option>
|
||||
<option value="hp">HP (auto-refresh)</option>
|
||||
</select>
|
||||
<small class="muted">Where coverage data comes from. Non-manual sources can be refreshed from the maker's warranty API.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
@@ -155,7 +161,7 @@
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { colorStyle } from '@/utils/colorStyle'
|
||||
import { warrantyApi, assetsApi } from '../../api'
|
||||
import { warrantyApi, assetsApi, vendorsApi } from '../../api'
|
||||
import { useToast } from '../../composables/toast'
|
||||
import { apiError } from '../../utils/apiError'
|
||||
|
||||
@@ -196,6 +202,8 @@ const form = ref(blankForm())
|
||||
const selectedAssets = ref([])
|
||||
const assetQuery = ref('')
|
||||
const assetResults = ref([])
|
||||
// Suggestions for the Vendor combobox, pulled from the site vendor catalog.
|
||||
const vendorNames = ref([])
|
||||
|
||||
function blankForm() {
|
||||
return { vendor: '', provider: 'manual', servicetag: '', servicelevel: '', startdate: '', enddate: '', notes: '' }
|
||||
@@ -215,6 +223,7 @@ function assetLink(a) {
|
||||
|
||||
onMounted(async () => {
|
||||
await loadData()
|
||||
loadVendors()
|
||||
// Deep-link from an asset detail page: open the add modal pre-linked to it.
|
||||
const addfor = route.query.addfor
|
||||
if (addfor) {
|
||||
@@ -229,6 +238,18 @@ onMounted(async () => {
|
||||
}
|
||||
})
|
||||
|
||||
async function loadVendors() {
|
||||
// Best-effort: the combobox still accepts free text if this fails.
|
||||
try {
|
||||
const response = await vendorsApi.list({ per_page: 1000 })
|
||||
const rows = response.data.data
|
||||
const list = Array.isArray(rows) ? rows : (rows.items || [])
|
||||
vendorNames.value = list.map(v => v.vendor || v.name).filter(Boolean).sort()
|
||||
} catch (err) {
|
||||
vendorNames.value = []
|
||||
}
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user