@elastic-suite/gally-admin-shared
Version:
Shared package for gally admin BO
294 lines (263 loc) • 7.46 kB
text/typescript
import {
IApi,
IApiSchemaOptions,
IField,
IHydraError,
IHydraLabelMember,
IHydraMember,
IHydraResponse,
IJsonldType,
IOptions,
IResource,
ISearchParameters,
ISourceFieldOption,
ISourceFieldOptionLabel,
} from '../types'
export class HydraError extends Error {
error: IHydraError
constructor(error: IHydraError) {
super(error['hydra:description'])
this.error = error
}
}
export function isJSonldType<T extends object>(
json: T | IJsonldType
): json is IJsonldType {
return '@type' in json
}
export function isHydraError<T extends IJsonldType>(
json: T | IHydraError
): json is IHydraError {
return json['@type'] === 'hydra:Error'
}
export function getResource(api: IApi, resourceName: string): IResource {
return api.find(
(resource) =>
resource.title === resourceName || resource.label === resourceName
)
}
export function getFieldName(property: string): string {
if (property.endsWith('[]')) {
return property.slice(0, -2)
}
if (property.endsWith('[between]')) {
return property.slice(0, -9)
}
return property
}
export function getField(resource: IResource, name: string): IField {
name = getFieldName(name)
return resource.supportedProperty.find((field) => {
return field.title === name || field?.gally?.alias === name
})
}
export function getFieldType(field: IField): string {
switch (field.property?.range?.['@id']) {
case 'http://www.w3.org/2001/XMLSchema#array':
return 'array'
case 'http://www.w3.org/2001/XMLSchema#integer':
return 'integer'
case 'http://www.w3.org/2001/XMLSchema#decimal':
case 'http://www.w3.org/2001/XMLSchema#float':
return 'float'
case 'http://www.w3.org/2001/XMLSchema#boolean':
return 'boolean'
case 'http://www.w3.org/2001/XMLSchema#date':
return 'date'
case 'http://www.w3.org/2001/XMLSchema#dateTime':
return 'dateTime'
default:
return 'text'
}
}
export function isReferenceField(field: IField): boolean {
return field.property['@type'] === 'http://www.w3.org/ns/hydra/core#Link'
}
export function getReferencedResource(api: IApi, field: IField): IResource {
return api.find((resource) => resource['@id'] === field.property.range['@id'])
}
export function getOptionsFromResource<T extends IHydraMember>(
response: IHydraResponse<T>
): IOptions<string | number> {
return response['hydra:member'].map((member) => ({
id: member.id,
label: member['@id'],
value: member.id,
}))
}
export function getOptionsFromLabelResource<T extends IHydraLabelMember>(
response: IHydraResponse<T>
): IOptions<string | number> {
return response['hydra:member'].map((member) => ({
id: member.id,
label: member.label,
value: member.id,
}))
}
export function getOptionsFromOptionResource(
optionLabelsResponse: IHydraResponse<ISourceFieldOption>,
localizedCatalogId = -1
): IOptions<string | number> {
return optionLabelsResponse['hydra:member'].map((option) => {
let label = option.defaultLabel
if (localizedCatalogId !== -1) {
label =
option.labels.find(
(label) => label.localizedCatalog.id === localizedCatalogId
)?.label ?? label
}
return {
id: option.code,
label,
value: option.code,
}
})
}
export function getOptionsFromOptionLabelResource(
optionLabelsResponse: IHydraResponse<ISourceFieldOptionLabel>
): IOptions<string | number> {
return optionLabelsResponse['hydra:member'].map((option) => ({
id: option.sourceFieldOption.code,
label: option.label,
value: option.sourceFieldOption.code,
}))
}
function convertValueForOpt(data: IApiSchemaOptions[]): IOptions<string> {
return data.flatMap(({ label, options }) =>
options.map((option) => ({
id: label,
value: option.value,
label: option.label,
}))
)
}
export function getOptionsFromApiSchema(
response: IHydraResponse<IApiSchemaOptions>
): IOptions<string | number> {
const res = response['hydra:member'].map(
({ label, value, code, options }) => ({
label,
value: value ?? code,
options,
})
)
return res.some(({ options }) => options) ? convertValueForOpt(res) : res
}
export function castFieldParameter(
field: IField,
value: string | string[]
): string | number | boolean | (string | number | boolean)[] {
if (value instanceof Array) {
return value.map(
(value) => castFieldParameter(field, value) as string | number | boolean
)
}
if (isReferenceField(field)) {
return Number(value)
}
switch (getFieldType(field)) {
case 'integer':
return value ? Number(value) : value
case 'boolean':
return value !== 'true' && value !== 'false' ? null : value === 'true'
default:
return value
}
}
export function isFieldValueValid(field: IField, value: unknown): boolean {
if (value instanceof Array) {
return value.every((value) => isFieldValueValid(field, value))
}
if (isReferenceField(field)) {
return typeof value === 'number' && !isNaN(value)
}
switch (getFieldType(field)) {
case 'integer':
return (typeof value === 'number' && !isNaN(value)) || value === ''
case 'boolean':
return typeof value === 'boolean'
default:
return typeof value === 'string'
}
}
export function getFilterParameters(
resource: IResource,
parameters: ISearchParameters
): ISearchParameters {
return Object.fromEntries(
Object.entries(parameters).reduce((acc, [key, value]) => {
const field = getField(resource, key)
if (field) {
const fieldValue = castFieldParameter(field, value as string | string[])
if (isFieldValueValid(field, fieldValue)) {
acc.push([key, fieldValue])
}
}
return acc
}, [])
)
}
function returnDefaultValue(val: unknown, defaultValue?: unknown): unknown {
return defaultValue !== undefined ? defaultValue : val
}
export function inputInitializer(input: string): unknown {
switch (input) {
case 'requestType':
case 'searchLimitations':
case 'categoryLimitations':
case 'optgroup':
case 'synonym':
case 'expansion':
return []
case 'ruleEngine':
return '{"type":"combination","operator":"all","value":"true","children":[]}'
case 'rangeDate':
return {
fromDate: null,
toDate: null,
}
case 'proportionalToAttribute':
return {
source_field_code: undefined,
boost_impact: undefined,
scale_factor: 1,
}
default:
return ''
}
}
export function valueInitializer(type: string, input?: string): unknown {
switch (type) {
case 'boolean':
return false
case 'array':
case 'select':
return []
case 'number':
case 'integer':
case 'float':
case 'slider':
return 0
case 'date':
case 'dateTime':
return null
default:
return input ? inputInitializer(input) : ''
}
}
export function initResourceData(resource: IResource): Record<string, unknown> {
const visibleChamp = Object.fromEntries(
resource.supportedProperty
.filter((property) => property?.gally?.visible)
.map((item) => {
return [
item.title,
returnDefaultValue(
valueInitializer(getFieldType(item), item?.gally?.input),
item.gally?.defaultValue
),
]
})
)
return visibleChamp
}