import { FunctionComponent, ReactNode, useCallback } from 'react'
import {
Component,
DataGridColumn,
DataGridColumnPublicProps,
DataGridOrderDirection,
Field,
FieldFallbackView,
FieldFallbackViewPublicProps,
QueryLanguage,
Stack,
SugaredRelativeSingleField,
Text,
wrapFilterInHasOnes,
} from '@contember/admin'
import { TextInput } from '@contember/ui'
import { Input } from '@contember/client'
function isUuid(value: string) {
return !!value.match(/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/)
}
export type UuidCellProps =
& DataGridColumnPublicProps
& FieldFallbackViewPublicProps
& SugaredRelativeSingleField
& {
disableOrder?: boolean
initialOrder?: DataGridOrderDirection
format?: (value: string | null) => ReactNode
initialFilter?: UuidFilterArtifacts
}
export type UuidFilterArtifacts = {
mode: 'matchesExactly'
query: string
nullCondition: boolean
}
export type GenericUuidCellFilterArtifacts = {
mode: 'matchesExactly'
query: string
}
export const GenericUuidCellFilter = <Filter extends GenericUuidCellFilterArtifacts>({ filter, setFilter }: {
filter: Filter
setFilter: (filter: Filter) => void
}) => {
const [value, setValue] = React.useState(filter.query)
return (
<>
<Stack gap={'small'}>
<TextInput
notNull
value={filter.query}
style={{ minWidth: '350px' }}
validationState={value && !isUuid(value) ? 'invalid' : 'valid'}
placeholder={'UUID'}
onChange={useCallback((currentValue?: string | null) => {
if (currentValue === null || currentValue === undefined) {
throw new Error('should not happen')
}
if (currentValue && isUuid(currentValue)) {
setFilter({
...filter,
query: currentValue,
})
}
setValue(currentValue)
}, [filter, setFilter, setValue])}
/>
{(value && !isUuid(value)) && (
<Text>This is not valid UUID</Text>
)}
</Stack>
</>
)
}
export const createGenericUserCellFilterCondition = (filter: GenericUuidCellFilterArtifacts) => {
const baseOperators = {
matchesExactly: 'eq',
}
let condition: Input.Condition<string> = {
[baseOperators[filter.mode]]: filter.query,
}
return condition
}
export const UuidCell: FunctionComponent<UuidCellProps> = Component(props => {
return (
<DataGridColumn<UuidFilterArtifacts>
{...props}
enableOrdering={!props.disableOrder as true}
getNewOrderBy={(newDirection, { environment }) =>
newDirection ? QueryLanguage.desugarOrderBy(`${props.field as string} ${newDirection}`, environment) : undefined
}
getNewFilter={(filter, { environment }) => {
if (filter.query === '' && filter.nullCondition === false) {
return undefined
}
let condition = filter.query !== '' ? createGenericUserCellFilterCondition(filter) : {}
if (filter.nullCondition) {
condition = {
or: [condition, { isNull: true }],
}
}
const desugared = QueryLanguage.desugarRelativeSingleField(props, environment)
return wrapFilterInHasOnes(desugared.hasOneRelationPath, {
[desugared.field]: condition,
})
}}
emptyFilter={{
mode: 'matchesExactly',
query: '',
nullCondition: false,
}}
filterRenderer={({ filter, setFilter, ...props }) => {
return (
<Stack horizontal align="center">
<GenericUuidCellFilter {...props} filter={filter} setFilter={setFilter} />
</Stack>
)
}}
>
<Field<string>
{...props}
format={value => {
if (value === null) {
return <FieldFallbackView fallback={props.fallback} fallbackStyle={props.fallbackStyle} />
}
if (props.format) {
return props.format(value as any)
}
return value
}}
/>
</DataGridColumn>
)
}, 'UuidCell')