map: fix subtype filter dropping every measuring tool
This commit is contained in:
17
CHANGELOG.md
17
CHANGELOG.md
@@ -10,6 +10,14 @@ ADR-007 and ADR-002.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Configurable site timezone: a `site_timezone` site setting (default
|
||||
`America/New_York`, public-readable), editable in Settings > Site >
|
||||
Localization. Notification start/end times are entered and displayed in this
|
||||
zone, and daily-reset notification expiry is computed in it. A shared
|
||||
`frontend/src/utils/datetime.js` (Intl-based, DST-safe) does the conversion.
|
||||
|
||||
### Changed
|
||||
|
||||
- Asset detail pages (machines, PCs, printers, network devices, measuring
|
||||
@@ -24,6 +32,15 @@ ADR-007 and ADR-002.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Notification start/end times were off by the timezone offset (a 2:34 PM entry
|
||||
displayed as 6:34 PM). Times are now stored UTC and shown/entered in the site
|
||||
timezone; the calendar keys all-day events off the site-local day.
|
||||
- Kiosk displays showed a white screen on login: a legacy 32-bit kiosk
|
||||
installer's autostart kept relaunching Edge at a now-dead URL. The install's
|
||||
HKLM Run value was WOW64-redirected into `SOFTWARE\Wow6432Node\...\Run` and
|
||||
survived earlier cleanup. The `gea-shopfloor-display` dispatcher now purges
|
||||
the legacy autostarts every enforce cycle across both registry views, all
|
||||
user hives, Run/RunOnce/policy-Run, and every Startup folder.
|
||||
- List pages keep the current page (and search term) in the URL query, so
|
||||
paging to page 9, opening an item, and hitting browser Back returns to page 9
|
||||
instead of resetting to page 1. Applies to all 18 list views via a shared
|
||||
|
||||
@@ -97,6 +97,7 @@ import L from 'leaflet'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import { loadMapConfig, blueprintUrlFor, state as mapConfig } from '../composables/mapConfig'
|
||||
import { assetTypeLabel, assetDetailRoute } from '../utils/assetTypes'
|
||||
import { getSubtypeId } from '../utils/mapColors'
|
||||
import api from '../api'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -239,19 +240,6 @@ const visibleAssetTypes = computed(() => {
|
||||
return result
|
||||
})
|
||||
|
||||
// Get subtype ID from asset based on asset type
|
||||
function getSubtypeId(asset) {
|
||||
if (!asset.typedata) return null
|
||||
// Normalize network_device -> network device so the subtype id resolves.
|
||||
const typeLower = (asset.assettype || '').toLowerCase().replace(/_/g, ' ')
|
||||
if (typeLower === 'machine') return asset.typedata.machinetypeid
|
||||
if (typeLower === 'computer') return asset.typedata.computertypeid
|
||||
if (typeLower === 'network device') return asset.typedata.networkdevicetypeid
|
||||
if (typeLower === 'printer') return asset.typedata.printertypeid
|
||||
if (typeLower === 'measuring tool') return asset.typedata.measuringtooltypeid
|
||||
return null
|
||||
}
|
||||
|
||||
// Get visible subtypes when a type is selected
|
||||
const visibleSubtypes = computed(() => {
|
||||
if (!props.selectedAssetType) return {}
|
||||
|
||||
38
frontend/src/utils/mapColors.spec.js
Normal file
38
frontend/src/utils/mapColors.spec.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { getSubtypeId, resolveMarkerColor } from './mapColors'
|
||||
|
||||
// One case per asset type that carries a subtype. A missing branch here means
|
||||
// the map subtype filter silently drops every asset of that type.
|
||||
const cases = [
|
||||
['Machine', { machinetypeid: 3 }],
|
||||
['Computer', { computertypeid: 3 }],
|
||||
['Network Device', { networkdevicetypeid: 3 }],
|
||||
['network_device', { networkdevicetypeid: 3 }],
|
||||
['Printer', { printertypeid: 3 }],
|
||||
['Measuring Tool', { measuringtooltypeid: 3 }],
|
||||
]
|
||||
|
||||
describe('getSubtypeId', () => {
|
||||
it.each(cases)('resolves the subtype id for %s', (assettype, typedata) => {
|
||||
expect(getSubtypeId({ assettype, typedata })).toBe(3)
|
||||
})
|
||||
|
||||
it('returns null without typedata', () => {
|
||||
expect(getSubtypeId({ assettype: 'Machine' })).toBeNull()
|
||||
})
|
||||
|
||||
it('returns null for an asset type with no subtype table', () => {
|
||||
expect(getSubtypeId({ assettype: 'Furniture', typedata: {} })).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('resolveMarkerColor', () => {
|
||||
it('colors a measuring tool by its subtype when a type is selected', () => {
|
||||
const asset = { assettype: 'Measuring Tool', typedata: { measuringtooltypeid: 7 } }
|
||||
const color = resolveMarkerColor(asset, {
|
||||
selectedType: 'Measuring Tool',
|
||||
subtypeColors: { 7: '#00BCD4' },
|
||||
})
|
||||
expect(color).toBe('#00BCD4')
|
||||
})
|
||||
})
|
||||
@@ -85,6 +85,7 @@ import { useAuthStore } from '../stores/auth'
|
||||
import { loadMapConfig, state as mapConfig } from '../composables/mapConfig'
|
||||
import { exportMapPdf } from '../utils/mapPdf'
|
||||
import { assetTypeLabel, assetDetailRoute } from '../utils/assetTypes'
|
||||
import { getSubtypeId } from '../utils/mapColors'
|
||||
import { useToast } from '../composables/toast'
|
||||
const toast = useToast()
|
||||
|
||||
@@ -133,7 +134,8 @@ const subtypeLabel = computed(() => {
|
||||
'machine': 'All Machine Types',
|
||||
'computer': 'All Computer Types',
|
||||
'network device': 'All Device Types',
|
||||
'printer': 'All Printer Types'
|
||||
'printer': 'All Printer Types',
|
||||
'measuring tool': 'All Tool Types'
|
||||
}
|
||||
return labels[selectedType.value.toLowerCase().replace(/_/g, ' ')] || 'All Subtypes'
|
||||
})
|
||||
@@ -175,24 +177,12 @@ const filteredAssets = computed(() => {
|
||||
result = result.filter(a => a.assettype && a.assettype.toLowerCase() === selectedLower)
|
||||
}
|
||||
|
||||
// Filter by subtype (normalize network_device -> network device)
|
||||
// Filter by subtype. Uses the shared getSubtypeId helper so this stays in
|
||||
// step with the marker coloring - a local copy of the per-type id lookup went
|
||||
// stale and silently dropped every measuring tool.
|
||||
if (selectedSubtype.value) {
|
||||
const subtypeId = parseInt(selectedSubtype.value)
|
||||
const typeLower = (selectedType.value || '').toLowerCase().replace(/_/g, ' ')
|
||||
result = result.filter(a => {
|
||||
if (!a.typedata) return false
|
||||
// Check different ID fields based on asset type
|
||||
if (typeLower === 'machine') {
|
||||
return a.typedata.machinetypeid === subtypeId
|
||||
} else if (typeLower === 'computer') {
|
||||
return a.typedata.computertypeid === subtypeId
|
||||
} else if (typeLower === 'network device') {
|
||||
return a.typedata.networkdevicetypeid === subtypeId
|
||||
} else if (typeLower === 'printer') {
|
||||
return a.typedata.printertypeid === subtypeId
|
||||
}
|
||||
return false
|
||||
})
|
||||
result = result.filter(a => getSubtypeId(a) === subtypeId)
|
||||
}
|
||||
|
||||
// Filter by business unit
|
||||
|
||||
Reference in New Issue
Block a user