Skip to content

Commit

Permalink
Merge pull request #677 from contember/fix/headlessxx
Browse files Browse the repository at this point in the history
headless fixes
  • Loading branch information
matej21 committed Mar 13, 2024
2 parents 0329fd6 + 82fab8c commit 188f020
Show file tree
Hide file tree
Showing 17 changed files with 69 additions and 32 deletions.
2 changes: 2 additions & 0 deletions build/api/binding.api.md
Expand Up @@ -989,6 +989,8 @@ export interface InvalidInputPersistResult {
// (undocumented)
errors: ErrorAccessor.Error[];
// (undocumented)
response?: DataBindingTransactionResult;
// (undocumented)
type: 'invalidInput';
}

Expand Down
1 change: 1 addition & 0 deletions build/api/react-select.api.md
Expand Up @@ -78,6 +78,7 @@ export const SelectItemTrigger: React_2.ForwardRefExoticComponent<SelectItemTrig
export type SelectItemTriggerProps = {
children: ReactElement;
action?: 'select' | 'unselect' | 'toggle';
onClick?: (event: React_2.MouseEvent<HTMLElement>) => void;
};

// @public (undocumented)
Expand Down
2 changes: 2 additions & 0 deletions packages/binding/src/accessorTree/PersistResult.ts
@@ -1,5 +1,6 @@
import { ErrorAccessor } from '../accessors'
import { EntityId } from '../treeParameters'
import { DataBindingTransactionResult } from '../core'

export interface NothingToPersistPersistResult {
type: 'nothingToPersist'
Expand All @@ -14,6 +15,7 @@ export interface JustSuccessPersistResult {
export interface InvalidInputPersistResult {
type: 'invalidInput'
errors: ErrorAccessor.Error[]
response?: DataBindingTransactionResult
}

export interface InvalidResponseResult {
Expand Down
3 changes: 2 additions & 1 deletion packages/binding/src/core/DataBinding.ts
Expand Up @@ -163,7 +163,7 @@ export class DataBinding<Node> {
}
}

if (Object.values(response.data).every(it => it.ok)) {
if (response.ok && Object.values(response.data).every(it => it.ok)) {
return await this.processSuccessfulPersistResult(response, operations, onPersistSuccess)
} else {
if (response.errorMessage) {
Expand All @@ -177,6 +177,7 @@ export class DataBinding<Node> {
this.persistFail({
errors: this.accessorErrorManager.getErrors(),
type: 'invalidInput',
response,
})

}
Expand Down
7 changes: 5 additions & 2 deletions packages/playground/admin/app/pages/select.tsx
Expand Up @@ -3,7 +3,7 @@ import { Binding, PersistButton } from '../../lib/components/binding'
import { EntitySubTree } from '@contember/interface'
import * as React from 'react'
import { Field } from '@contember/react-binding'
import { MultiSelectField, SelectField, SortableMultiSelectField } from '../../lib/components/form'
import { InputField, MultiSelectField, SelectField, SortableMultiSelectField } from '../../lib/components/form'


export const hasOne = () => <>
Expand All @@ -13,7 +13,10 @@ export const hasOne = () => <>
</Slots.Actions>
<EntitySubTree entity={'SelectRoot(unique=unique)'} setOnCreate={'(unique=unique)'}>
<div className={'space-y-4'}>
<SelectField field={'hasOne'} options={'SelectValue'} filterField={'name'} label="Has one value">
<SelectField field={'hasOne'} options={'SelectValue'} filterField={'name'} label="Has one value" createNewForm={<>
<InputField field="name"/>
<InputField field="slug"/>
</>}>
<Field field={'name'} />
</SelectField>
</div>
Expand Down
Expand Up @@ -38,6 +38,7 @@ export const usePersistErrorHandler = () => {
<ToastContent
title={dict.persist.invalidInputError}
description={<ul>{errorList.map((it, i) => <li key={i}>{it}</li>)}</ul>}
details={result.response?.errorMessage}
/>, {
type: 'error',
})
Expand Down
7 changes: 5 additions & 2 deletions packages/playground/admin/lib/components/datagrid/columns.tsx
Expand Up @@ -3,7 +3,7 @@ import { ReactNode } from 'react'
import {
DataViewEnumFieldTooltip,
DataViewRelationFieldTooltip,
DataViewTextFilter,
DataViewTextFilter, DefaultDataViewBooleanFilter, DefaultDataViewDateFilter,
DefaultDataViewEnumFilter,
DefaultDataViewNumberFilter,
DefaultDataViewRelationFilter,
Expand All @@ -15,6 +15,7 @@ import {
createBooleanFilter,
createDateFilter,
createEnumFilter,
createHasManyFilter,
createHasOneFilter,
createNumberRangeFilter,
createTextFilter,
Expand Down Expand Up @@ -126,7 +127,7 @@ export const createHasManyColumn = ({ field, label, tooltipActions, filterOption
),
header: label,
hidingName: field,
filterHandler: createHasOneFilter(field),
filterHandler: createHasManyFilter(field),
filterToolbar: filterOptions && (
<DefaultDataViewRelationFilter
name={field}
Expand Down Expand Up @@ -174,6 +175,7 @@ export const createDateColumn = ({ field, label, ...args }: DataViewDateColumnAr
hidingName: field,
sortingField: field,
filterHandler: createDateFilter(field),
filterToolbar: <DefaultDataViewDateFilter name={field} label={label} />,
...args,
}
}
Expand All @@ -193,6 +195,7 @@ export const createBooleanColumn = ({ field, label, ...args }: DataViewBooleanCo
hidingName: field,
sortingField: field,
filterHandler: createBooleanFilter(field),
filterToolbar: <DefaultDataViewBooleanFilter name={field} label={label} />,
...args,
}
}
Expand Down
Expand Up @@ -99,7 +99,7 @@ const DataViewEnumFilterSelect = ({ name, options, label }: {
<PopoverTrigger asChild>
<DataViewFilterSelectTriggerUI>{label}</DataViewFilterSelectTriggerUI>
</PopoverTrigger>
<PopoverContent>
<PopoverContent className="p-2">
<div className={'relative flex flex-col gap-2'}>
{Object.entries(options).map(([value, label]) => (
<DataViewEnumFilterSelectItem value={value} key={value} filterFactory={filterFactory}>
Expand Down
Expand Up @@ -102,7 +102,7 @@ const DataViewRelationFilterSelect = ({ name, children, options, filterField, la
</DataViewRelationFilterSelectItem>
</SelectListInner>
</DataView>
<div className="px-4 py-2">
<div>
<DataViewNullFilter name={name} />
</div>
</SelectPopoverContent>
Expand Down
2 changes: 1 addition & 1 deletion packages/playground/admin/lib/components/datagrid/grid.tsx
Expand Up @@ -89,7 +89,7 @@ export const DefaultDataGrid = ({ columns, tile, lastColumnActions, firstColumnA
>
<DataViewBody toolbar={<>
<DataGridToolbarFilters columns={columns} />
<div className="ml-auto">
<div className="ml-auto flex gap-2">
{tile && <DataViewLayoutSwitcher />}
<DataGridToolbarColumns columns={columns} />
</div>
Expand Down
21 changes: 12 additions & 9 deletions packages/playground/admin/lib/components/select/create-new.tsx
Expand Up @@ -13,15 +13,18 @@ export const CreateEntityDialog = ({ trigger, children }: { trigger: ReactElemen
{trigger}
</AlertDialogTrigger>
<AlertDialogContent>
<SelectNewItem children={children} />
<AlertDialogFooter>
<AlertDialogCancel>{dict.select.cancelNew}</AlertDialogCancel>
<AlertDialogAction asChild>
<SelectItemTrigger>
<Button>{dict.select.confirmNew}</Button>
</SelectItemTrigger>
</AlertDialogAction>
</AlertDialogFooter>
<SelectNewItem>
{children}
<AlertDialogFooter>
<AlertDialogCancel>{dict.select.cancelNew}</AlertDialogCancel>
<AlertDialogAction asChild>
<SelectItemTrigger>
<Button>{dict.select.confirmNew}</Button>
</SelectItemTrigger>
</AlertDialogAction>
</AlertDialogFooter>

</SelectNewItem>
</AlertDialogContent>
</AlertDialog>
)
Expand Down
6 changes: 2 additions & 4 deletions packages/playground/admin/lib/components/select/list.tsx
Expand Up @@ -18,11 +18,9 @@ export const SelectListInner = ({ children, filterToolbar }: SelectListProps) =>
return (
<DataViewKeyboardEventHandler>
<div className={'flex flex-col gap-4 group-data-[side="top"]:flex-col-reverse'}>
{filterToolbar && <div className={'px-4'}>
{filterToolbar}
</div>}
{filterToolbar}
<ScrollArea className={'max-h-96'}>
<div className={'flex flex-col gap-1 px-1'}>
<div className={'flex flex-col gap-1'}>
<DataViewLoaderState refreshing>
<DataViewLoaderOverlay />
</DataViewLoaderState>
Expand Down
9 changes: 5 additions & 4 deletions packages/playground/admin/lib/components/select/ui.tsx
Expand Up @@ -5,6 +5,7 @@ import * as React from 'react'
import { CheckIcon, PlusIcon, XIcon } from 'lucide-react'
import { PopoverContent } from '../ui/popover'
import { dict } from '../../../lib/dict'
import { forwardRef } from 'react'

export const SelectInputUI = uic(InputLike, {
baseClass: 'cursor-pointer hover:border-gray-400 relative flex gap-2 flex-wrap py-1 pr-6',
Expand All @@ -14,12 +15,12 @@ export const SelectInputActionsUI = uic('div', {
})

export const SelectListItemUI = uic(Button, {
baseClass: 'w-full text-left justify-start gap-1 data-[highlighted]:bg-gray-200 group pl-1',
baseClass: 'w-full text-left justify-start gap-1 data-[highlighted]:bg-gray-200 data-[selected]:bg-gray-100 group relative',
defaultProps: {
variant: 'ghost',
size: 'sm',
},
beforeChildren: <CheckIcon className="h-3 w-3 opacity-0 group-data-[selected]:opacity-100"/>,
afterChildren: <CheckIcon className="h-3 w-3 opacity-0 group-data-[selected]:opacity-100 ml-auto"/>,
})

export const SelectDefaultPlaceholderUI = () => <span className={'text-gray-400'}>{dict.select.placeholder}</span>
Expand All @@ -43,8 +44,8 @@ export const MultiSelectItemRemoveButtonUI = uic('button', {
})

export const SelectPopoverContent = uic(PopoverContent, {
baseClass: 'p-0 py-1 group w-[max(16rem,var(--radix-popover-trigger-width))]',
baseClass: 'group w-[max(16rem,var(--radix-popover-trigger-width))]',
})


export const SelectCreateNewTrigger = () => <Button variant="outline" size="icon"><PlusIcon className="w-3 h-3" /></Button>
export const SelectCreateNewTrigger = forwardRef<HTMLButtonElement, {}>((props, ref) => <Button variant="outline" size="icon" ref={ref} {...props}><PlusIcon className="w-3 h-3" /></Button>)
19 changes: 18 additions & 1 deletion packages/playground/admin/lib/components/ui/toast/toast.tsx
Expand Up @@ -4,17 +4,29 @@ import { X } from 'lucide-react'
import { uic } from '../../../../lib/utils/uic'
import { ReactNode } from 'react'
import { ToasterProvider, useToasts } from './toaster'
import { dict } from '../../../dict'

export const ToastContent = ({ title, description, action }: {
export const ToastContent = ({ title, description, action, details }: {
title?: ReactNode
description?: ReactNode
action?: ReactNode
details?: ReactNode
}) => {
const [open, setOpen] = React.useState(false)

return <>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && <ToastDescription>{description}</ToastDescription>}
{details ? (
open ? (
<code className="p-1 bg-gray-50 border rounded font-mono text-xs">{details}</code>
) : (
<div>
<button onClick={() => setOpen(true)} className="text-sm text-gray-400 underline">{dict.toast.showDetails}</button>
</div>
)
) : null}
</div>
{action}
</>
Expand Down Expand Up @@ -49,6 +61,11 @@ const Toast = uic(ToastPrimitives.Root, {
variant: 'info',
},
displayName: 'Toast',
defaultProps: {
style: {
userSelect: 'auto',
},
},
})

const ToastClose = uic(ToastPrimitives.Close, {
Expand Down
5 changes: 4 additions & 1 deletion packages/playground/admin/lib/dict.ts
Expand Up @@ -13,12 +13,15 @@ export const dict = {
},
persist: {
persistButton: 'Save data',
invalidInputError: 'Invalid input',
invalidInputError: 'Failed to save data',
invalidResponseError: 'Invalid response',
invalidResponseErrorDetails: 'The server returned an invalid response. Please try again later.',
success: 'Successfully saved',
afterPersistError: 'Something wrong has happened after the data were persisted. Please refresh the page.',
},
toast: {
showDetails: 'Show details',
},
datagrid: {
na: 'N/A',
dateStart: 'Start',
Expand Down
2 changes: 1 addition & 1 deletion packages/react-dataview/src/filterTypes/hasOne.ts
Expand Up @@ -16,7 +16,7 @@ export const createHasOneFilter = (field: SugaredRelativeSingleEntity['field']):
inclusionConditions.push({ isNull: filter.nullCondition })
}
if (filter.notId?.length) {
exclusionConditions.push({ notIn: filter.notId })
exclusionConditions.push({ or: [{ notIn: filter.notId }, { isNull: true }] })
}
if (filter.nullCondition === false) {
exclusionConditions.push({ isNull: false })
Expand Down
10 changes: 6 additions & 4 deletions packages/react-select/src/components/SelectItemTrigger.tsx
Expand Up @@ -6,14 +6,16 @@ import { useEntity } from '@contember/react-binding'
export type SelectItemTriggerProps = {
children: ReactElement
action?: 'select' | 'unselect' | 'toggle'
onClick?: (event: React.MouseEvent<HTMLElement>) => void
}

export const SelectItemTrigger = forwardRef<HTMLElement, SelectItemTriggerProps>(({ action, ...props }: SelectItemTriggerProps, ref) => {
const handleSelect = useSelectHandleSelect()
const entity = useEntity()
const onClick = useCallback(() => {
const onClickProp = props.onClick
const onClick = useCallback((e: React.MouseEvent<HTMLElement>) => {
handleSelect?.(entity, action)
}, [action, entity, handleSelect])

return <Slot onClick={onClick} {...props} ref={ref} />
onClickProp?.(e)
}, [action, entity, handleSelect, onClickProp])
return <Slot {...props} onClick={onClick} ref={ref} />
})

0 comments on commit 188f020

Please sign in to comment.