2026-01-02 13:41:09 +00:00
|
|
|
// Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
2022-11-21 13:51:49 +00:00
|
|
|
|
2025-01-24 08:08:23 +00:00
|
|
|
import { keyBy } from 'lodash-es'
|
2024-05-17 13:31:19 +00:00
|
|
|
import { computed } from 'vue'
|
|
|
|
|
|
2024-11-12 21:13:22 +00:00
|
|
|
import type { ObjectAttribute } from '#shared/entities/object-attributes/types/store.ts'
|
|
|
|
|
import type { ObjectAttributeValue } from '#shared/graphql/types.ts'
|
2023-04-24 12:50:55 +00:00
|
|
|
import type { ObjectLike } from '#shared/types/utils.ts'
|
2025-01-24 08:08:23 +00:00
|
|
|
|
2025-11-10 15:42:05 +00:00
|
|
|
import { getLink, getValue, isEmpty, isInlineAttributeEditable } from './utils.ts'
|
2024-05-17 13:31:19 +00:00
|
|
|
|
2025-11-10 15:42:05 +00:00
|
|
|
import type { AttributeDeclaration, InlineEditable } from './types.ts'
|
2024-05-17 13:31:19 +00:00
|
|
|
import type { Dictionary } from 'ts-essentials'
|
|
|
|
|
import type { Component } from 'vue'
|
2022-11-21 13:51:49 +00:00
|
|
|
|
2025-01-24 08:08:23 +00:00
|
|
|
interface BaseObjectAttributeDisplayOptions {
|
2022-11-21 13:51:49 +00:00
|
|
|
object: ObjectLike
|
2025-01-24 08:08:23 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-11 17:45:28 +00:00
|
|
|
export interface ObjectAttributeDisplayOptions extends BaseObjectAttributeDisplayOptions {
|
2025-01-24 08:08:23 +00:00
|
|
|
attribute: ObjectAttribute
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 17:45:28 +00:00
|
|
|
export interface ObjectAttributesDisplayOptions extends BaseObjectAttributeDisplayOptions {
|
2025-01-24 08:08:23 +00:00
|
|
|
attributes: ObjectAttribute[]
|
2025-11-10 15:42:05 +00:00
|
|
|
skipAttributes?: string[]
|
|
|
|
|
inlineEditable?: InlineEditable
|
2025-10-02 14:03:42 +00:00
|
|
|
includeStatic?: boolean
|
2022-11-21 13:51:49 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-24 08:08:23 +00:00
|
|
|
export interface AttributeField {
|
2024-11-12 21:13:22 +00:00
|
|
|
attribute: ObjectAttribute
|
2022-11-21 13:51:49 +00:00
|
|
|
component: Component
|
|
|
|
|
value: unknown
|
2022-12-14 09:58:49 +00:00
|
|
|
link: Maybe<string>
|
2022-11-21 13:51:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const attributesDeclarations = import.meta.glob<AttributeDeclaration>(
|
|
|
|
|
'./attributes/Attribute*/index.ts',
|
|
|
|
|
{ eager: true, import: 'default' },
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const definitionsByType = Object.values(attributesDeclarations).reduce(
|
|
|
|
|
(acc, declaration) => {
|
|
|
|
|
declaration.dataTypes.forEach((type) => {
|
|
|
|
|
acc[type] = declaration.component
|
|
|
|
|
})
|
|
|
|
|
return acc
|
|
|
|
|
},
|
|
|
|
|
{} as Record<string, Component>,
|
|
|
|
|
)
|
|
|
|
|
|
2025-06-11 17:45:28 +00:00
|
|
|
export const useDisplayObjectAttribute = (options: ObjectAttributeDisplayOptions) => {
|
2022-11-21 13:51:49 +00:00
|
|
|
const attributesObject = computed<Dictionary<ObjectAttributeValue>>(() => {
|
|
|
|
|
return keyBy(options.object.objectAttributeValues || {}, 'attribute.name')
|
|
|
|
|
})
|
|
|
|
|
|
2025-01-24 08:08:23 +00:00
|
|
|
const field = computed<AttributeField>(() => {
|
|
|
|
|
const { attribute, object } = options
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
attribute,
|
|
|
|
|
component: definitionsByType[attribute.dataType],
|
2025-06-11 17:45:28 +00:00
|
|
|
value: getValue(attribute.name, object, attributesObject.value, attribute),
|
2025-01-24 08:08:23 +00:00
|
|
|
link: getLink(attribute.name, attributesObject.value),
|
2022-11-21 13:51:49 +00:00
|
|
|
}
|
2025-01-24 08:08:23 +00:00
|
|
|
})
|
|
|
|
|
return { field }
|
|
|
|
|
}
|
2022-12-14 09:58:49 +00:00
|
|
|
|
2025-06-11 17:45:28 +00:00
|
|
|
export const useDisplayObjectAttributes = (options: ObjectAttributesDisplayOptions) => {
|
2025-01-24 08:08:23 +00:00
|
|
|
const attributesObject = computed<Dictionary<ObjectAttributeValue>>(() => {
|
|
|
|
|
return keyBy(options.object.objectAttributeValues || {}, 'attribute.name')
|
|
|
|
|
})
|
2022-11-21 13:51:49 +00:00
|
|
|
|
|
|
|
|
const fields = computed<AttributeField[]>(() => {
|
|
|
|
|
return options.attributes
|
2025-10-02 14:03:42 +00:00
|
|
|
.filter((attribute) => options.includeStatic || !attribute.isStatic)
|
2025-01-24 08:08:23 +00:00
|
|
|
.map((attribute) => ({
|
2025-11-10 15:42:05 +00:00
|
|
|
attribute: {
|
|
|
|
|
...attribute,
|
|
|
|
|
id: `${attribute.name}-${options.object.internalId}`,
|
|
|
|
|
},
|
2025-01-24 08:08:23 +00:00
|
|
|
component: definitionsByType[attribute.dataType],
|
2025-06-11 17:45:28 +00:00
|
|
|
value: getValue(attribute.name, options.object, attributesObject.value, attribute),
|
2025-01-24 08:08:23 +00:00
|
|
|
link: getLink(attribute.name, attributesObject.value),
|
|
|
|
|
}))
|
2022-11-21 13:51:49 +00:00
|
|
|
.filter(({ attribute, value, component }) => {
|
|
|
|
|
if (!component) return false
|
|
|
|
|
|
2025-11-10 15:42:05 +00:00
|
|
|
if (isEmpty(value) && !isInlineAttributeEditable(attribute.name, options.inlineEditable)) {
|
2022-11-21 13:51:49 +00:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !options.skipAttributes?.includes(attribute.name)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
fields,
|
|
|
|
|
}
|
|
|
|
|
}
|