proper typing

This commit is contained in:
andrewwallacespeckle
2025-08-15 15:29:44 +01:00
parent e7ee9f0e97
commit 85e1b5fac4
4 changed files with 37 additions and 41 deletions
@@ -7,7 +7,7 @@
>
<div
class="col-span-1 truncate text-body-3xs mr-2 font-medium text-foreground-2"
:title="(kvp.key as string)"
:title="kvp.key"
>
{{ kvp.key }}
</div>
@@ -66,14 +66,10 @@ import { LayoutMenu, type LayoutMenuItem } from '@speckle/ui-components'
import { Ellipsis } from 'lucide-vue-next'
import { useFilterUtilities } from '~~/lib/viewer/composables/ui'
import { useInjectedViewer } from '~~/lib/viewer/composables/setup'
import type { KeyValuePair } from '~/components/viewer/selection/types'
const props = defineProps<{
kvp: Record<string, unknown> & {
key: string
value: unknown
units?: string
backendPath?: string
}
kvp: KeyValuePair
}>()
const showActionsMenu = ref(false)
@@ -86,38 +82,28 @@ const {
const isUrlString = (v: unknown) => typeof v === 'string' && VALID_HTTP_URL.test(v)
const isCopyable = (kvp: Record<string, unknown>) => {
const isCopyable = (kvp: KeyValuePair) => {
return kvp.value !== null && kvp.value !== undefined && typeof kvp.value !== 'object'
}
const isFilterable = (kvp: Record<string, unknown>) => {
return isKvpFilterable(
kvp as Record<string, unknown> & { key: string; backendPath?: string },
availableFilters.value
)
const isFilterable = (kvp: KeyValuePair) => {
return isKvpFilterable(kvp, availableFilters.value)
}
const getDisabledReason = (kvp: Record<string, unknown>) => {
return getFilterDisabledReason(
kvp as Record<string, unknown> & { key: string; backendPath?: string },
availableFilters.value
)
const getDisabledReason = (kvp: KeyValuePair) => {
return getFilterDisabledReason(kvp, availableFilters.value)
}
const handleFilterByProperty = (kvp: Record<string, unknown>) => {
applyKvpFilter(
kvp as Record<string, unknown> & { key: string; backendPath?: string },
availableFilters.value
)
const handleFilterByProperty = (kvp: KeyValuePair) => {
applyKvpFilter(kvp, availableFilters.value)
}
const handleCopy = async (kvp: Record<string, unknown>) => {
const handleCopy = async (kvp: KeyValuePair) => {
const { copy } = useClipboard()
if (isCopyable(kvp)) {
const keyName = kvp.key as string
await copy(kvp.value as string, {
successMessage: `${keyName} copied to clipboard`,
failureMessage: `Failed to copy ${keyName} to clipboard`
successMessage: `${kvp.key} copied to clipboard`,
failureMessage: `Failed to copy ${kvp.key} to clipboard`
})
}
}
@@ -97,6 +97,7 @@ import type { SpeckleObject } from '~~/lib/viewer/helpers/sceneExplorer'
import { getHeaderAndSubheaderForSpeckleObject } from '~~/lib/object-sidebar/helpers'
import { useInjectedViewerState } from '~~/lib/viewer/composables/setup'
import { useHighlightedObjectsUtilities } from '~/lib/viewer/composables/ui'
import type { KeyValuePair } from '~/components/viewer/selection/types'
const {
ui: {
@@ -194,20 +195,19 @@ const ignoredProps = [
]
const keyValuePairs = computed(() => {
const kvps = [] as (Record<string, unknown> & {
key: string
value: unknown
backendPath?: string
})[]
const kvps: KeyValuePair[] = []
// handle revit paramters
if (props.title === 'parameters') {
const paramKeys = Object.keys(props.object)
for (const prop of paramKeys) {
const param = props.object[prop] as Record<string, unknown>
if (!param) continue
const param = props.object[prop]
if (!param || typeof param !== 'object' || param === null) continue
if (!('name' in param) || typeof param.name !== 'string') continue
if (!('value' in param)) continue
kvps.push({
key: param.name as string,
key: param.name,
type: typeof param.value,
innerType: null,
arrayLength: null,
@@ -0,0 +1,10 @@
export type KeyValuePair = {
key: string
value: unknown
units?: string
type?: string
innerType?: string | null
arrayLength?: number | null
arrayPreview?: string | null
backendPath?: string
}
@@ -388,11 +388,11 @@ export function useFilterUtilities(
* Determines if a key-value pair is filterable (with smart matching for nested properties)
*/
const isKvpFilterable = (
kvp: Record<string, unknown> & { key: string; backendPath?: string },
kvp: { key: string; backendPath?: string },
availableFilters: PropertyInfo[] | null | undefined
): boolean => {
// Use backendPath if available, otherwise fall back to display key
const backendKey = (kvp.backendPath as string | undefined) || (kvp.key as string)
const backendKey = kvp.backendPath || kvp.key
// First check direct match
const directMatch = availableFilters?.some((f) => f.key === backendKey)
@@ -415,10 +415,10 @@ export function useFilterUtilities(
* Gets a detailed reason why a property is disabled for filtering
*/
const getFilterDisabledReason = (
kvp: Record<string, unknown> & { key: string; backendPath?: string },
kvp: { key: string; backendPath?: string },
availableFilters: PropertyInfo[] | null | undefined
): string => {
const backendKey = (kvp.backendPath as string | undefined) || (kvp.key as string)
const backendKey = kvp.backendPath || kvp.key
const availableKeys = availableFilters?.map((f) => f.key) || []
// Check if it's not in available filters
@@ -451,11 +451,11 @@ export function useFilterUtilities(
* Applies a filter for a key-value pair (with smart matching)
*/
const applyKvpFilter = (
kvp: Record<string, unknown> & { key: string; backendPath?: string },
kvp: { key: string; backendPath?: string },
availableFilters: PropertyInfo[] | null | undefined
): void => {
// Use backendPath if available, otherwise fall back to display key
const backendKey = (kvp.backendPath as string | undefined) || (kvp.key as string)
const backendKey = kvp.backendPath || kvp.key
// First try direct match
let filter = availableFilters?.find((f: PropertyInfo) => f.key === backendKey)