Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add advanced many to many object relation data object type #910

Merged
merged 23 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fafd3c3
Add advanced many to many object relation data object type
markus-moser Jan 21, 2025
7be2a3a
Apply eslint-fixer changes
markus-moser Jan 21, 2025
1a8735a
Automatic frontend build
markus-moser Jan 21, 2025
d01c820
Handle existing editable column types
markus-moser Jan 21, 2025
18b597f
Merge remote-tracking branch 'origin/advanced-object-relation' into a…
markus-moser Jan 21, 2025
9419bec
Automatic frontend build
markus-moser Jan 21, 2025
b1cc881
Remove useless condition
markus-moser Jan 22, 2025
80d1d2a
Merge remote-tracking branch 'origin/advanced-object-relation' into a…
markus-moser Jan 22, 2025
cca1007
Automatic frontend build
markus-moser Jan 22, 2025
3004c05
Integrate value conversion into hook
markus-moser Jan 22, 2025
118faa9
Automatic frontend build
markus-moser Jan 22, 2025
c2c91f7
Fix handling changed data
markus-moser Jan 22, 2025
f174ed0
Merge remote-tracking branch 'origin/advanced-object-relation' into a…
markus-moser Jan 22, 2025
5181fda
Automatic frontend build
markus-moser Jan 22, 2025
3764049
Delete item based on rowIndex instead of type/id (preparation for mul…
markus-moser Jan 22, 2025
ec22330
Merge remote-tracking branch 'origin/advanced-object-relation' into a…
markus-moser Jan 22, 2025
31c4038
Automatic frontend build
markus-moser Jan 22, 2025
0fc9749
Add multiple assignments check
markus-moser Jan 22, 2025
5f34d70
Merge remote-tracking branch 'origin/advanced-object-relation' into a…
markus-moser Jan 22, 2025
8cfc61a
Automatic frontend build
markus-moser Jan 22, 2025
403482e
Implement multi-select column types and fix select styling
markus-moser Jan 22, 2025
ff8983c
Merge remote-tracking branch 'origin/advanced-object-relation' into a…
markus-moser Jan 22, 2025
e905781
Automatic frontend build
markus-moser Jan 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions assets/js/src/core/app/config/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { DynamicTypeGridCellRegistry } from '@Pimcore/modules/element/dynamic-ty
import { DynamicTypeGridCellTextarea } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/textarea/dynamic-type-grid-cell-text'
import { DynamicTypeGridCellNumber } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/number/dynamic-type-grid-cell-number'
import { DynamicTypeGridCellSelect } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/select/dynamic-type-grid-cell-select'
import { DynamicTypeGridCellMultiSelect } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/multi-select/dynamic-type-grid-cell-multi-select'
import { DynamicTypeGridCellCheckbox } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/checkbox/dynamic-type-grid-cell-checkbox'
import { DynamicTypeGridCellDate } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/date/dynamic-type-grid-cell-date'
import { DynamicTypeGridCellTime } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/time/dynamic-type-grid-cell-time'
Expand Down Expand Up @@ -118,6 +119,7 @@ import { DynamicTypeObjectDataGeoPolyLine } from '@Pimcore/modules/element/dynam
import { DynamicTypeObjectDataManyToOneRelation } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-many-to-one-relation'
import { DynamicTypeObjectDataManyToManyRelation } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-many-to-many-relation'
import { DynamicTypeObjectDataManyToManyObjectRelation } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-many-to-many-object-relation'
import { DynamicTypeObjectDataAdvancedManyToManyObjectRelation } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-advanced-many-to-many-object-relation'
import { DynamicTypeObjectDataReverseObjectRelation } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-reverse-object-relation'
import { DynamicTypeObjectDataStructuredTable } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-structured-table'
import { DynamicTypeObjectDataTable } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-table'
Expand Down Expand Up @@ -181,6 +183,7 @@ container.bind(serviceIds['DynamicTypes/GridCell/Text']).to(DynamicTypeGridCellT
container.bind(serviceIds['DynamicTypes/GridCell/Textarea']).to(DynamicTypeGridCellTextarea).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/Number']).to(DynamicTypeGridCellNumber).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/Select']).to(DynamicTypeGridCellSelect).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/MultiSelect']).to(DynamicTypeGridCellMultiSelect).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/Checkbox']).to(DynamicTypeGridCellCheckbox).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/Date']).to(DynamicTypeGridCellDate).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/Time']).to(DynamicTypeGridCellTime).inSingletonScope()
Expand Down Expand Up @@ -274,6 +277,7 @@ container.bind(serviceIds['DynamicTypes/ObjectData/GeoPolyLine']).to(DynamicType
container.bind(serviceIds['DynamicTypes/ObjectData/ManyToOneRelation']).to(DynamicTypeObjectDataManyToOneRelation).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/ManyToManyRelation']).to(DynamicTypeObjectDataManyToManyRelation).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/ManyToManyObjectRelation']).to(DynamicTypeObjectDataManyToManyObjectRelation).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/AdvancedManyToManyObjectRelation']).to(DynamicTypeObjectDataAdvancedManyToManyObjectRelation).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/ReverseObjectRelation']).to(DynamicTypeObjectDataReverseObjectRelation).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/Table']).to(DynamicTypeObjectDataTable).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/StructuredTable']).to(DynamicTypeObjectDataStructuredTable).inSingletonScope()
Expand Down
2 changes: 2 additions & 0 deletions assets/js/src/core/app/config/services/service-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const serviceIds = {
'DynamicTypes/GridCell/Textarea': 'DynamicTypes/GridCell/Textarea',
'DynamicTypes/GridCell/Number': 'DynamicTypes/GridCell/Number',
'DynamicTypes/GridCell/Select': 'DynamicTypes/GridCell/Select',
'DynamicTypes/GridCell/MultiSelect': 'DynamicTypes/GridCell/MultiSelect',
'DynamicTypes/GridCell/Checkbox': 'DynamicTypes/GridCell/Checkbox',
'DynamicTypes/GridCell/Date': 'DynamicTypes/GridCell/Date',
'DynamicTypes/GridCell/Time': 'DynamicTypes/GridCell/Time',
Expand Down Expand Up @@ -153,6 +154,7 @@ export const serviceIds = {
'DynamicTypes/ObjectData/ManyToOneRelation': 'DynamicTypes/ObjectData/ManyToOneRelation',
'DynamicTypes/ObjectData/ManyToManyRelation': 'DynamicTypes/ObjectData/ManyToManyRelation',
'DynamicTypes/ObjectData/ManyToManyObjectRelation': 'DynamicTypes/ObjectData/ManyToManyObjectRelation',
'DynamicTypes/ObjectData/AdvancedManyToManyObjectRelation': 'DynamicTypes/ObjectData/AdvancedManyToManyObjectRelation',
'DynamicTypes/ObjectData/ReverseObjectRelation': 'DynamicTypes/ObjectData/ReverseObjectRelation',
'DynamicTypes/ObjectData/Table': 'DynamicTypes/ObjectData/Table',
'DynamicTypes/ObjectData/StructuredTable': 'DynamicTypes/ObjectData/StructuredTable',
Expand Down
2 changes: 1 addition & 1 deletion assets/js/src/core/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const Select = forwardRef<RefSelectProps, SelectProps>(({ customIcon, cus
const isStatusWarning = status === 'warning'
const isStatusError = status === 'error'

const selectContainerClassNames = cn(styles.selectContainer, {
const selectContainerClassNames = cn('studio-select', styles.selectContainer, {
[styles.selectContainerWarning]: isStatusWarning,
[styles.selectContainerError]: isStatusError,
[styles.selectContainerWithClear]: allowClear === true && isSelected
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import { createStyles } from 'antd-style'

export const useStyles = createStyles(({ css }) => {
return {
'multi-select-cell': css`
padding: 4px;

.ant-select, .studio-select {
width: 100%;
}
`
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import React, { useEffect, useRef, useState } from 'react'
import { type RefSelectProps } from 'antd/es/select'
import cn from 'classnames'
import { useEditMode } from '@Pimcore/components/grid/edit-mode/use-edit-mode'
import { Select } from '@Pimcore/components/select/select'
import { useStyles } from './multi-select-cell.styles'
import { type DefaultCellProps } from '@Pimcore/components/grid/columns/default-cell'
import {
type SelectOptionType
} from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/components/select/select-cell'

export interface MultiSelectCellConfig {
options: string[] | SelectOptionType[]
}
export const MultiSelectCell = (props: DefaultCellProps): React.JSX.Element => {
const { styles } = useStyles()
const { column, getValue } = props
const { isInEditMode, disableEditMode, fireOnUpdateCellDataEvent } = useEditMode(props)
const [open, setOpen] = useState<boolean>(false)
const config = column.columnDef.meta?.config as MultiSelectCellConfig | undefined
const element = useRef<RefSelectProps>(null)

useEffect(() => {
if (isInEditMode) {
element.current?.focus()
setOpen(true)
}
}, [isInEditMode])

const value: [] = Array.isArray(getValue()) ? getValue() : []

if (config === undefined) {
return <>{ value.join(', ') }</>
}

const options: SelectOptionType[] = config.options.map((value: string | object) => (
typeof value === 'object' ? value : { label: value, value }
))

const displayOptions = value.map((value: string) => {
const option = options.find((option: SelectOptionType) => option.value === value)
return option?.displayValue ?? option?.label ?? value
})
const displayValue = displayOptions.join(', ')

if (!isInEditMode) {
return (
<div className={ [styles['multi-select-cell'], 'default-cell__content'].join(' ') }>
{ displayValue }
</div>
)
}

return (
<div className={ cn(styles['multi-select-cell'], 'default-cell__content') }>
<Select
mode="multiple"
onBlur={ disableEditMode }
onChange={ onChange }
open={ open }
options={ options }
popupMatchSelectWidth={ false }
ref={ element }
value={ value }
/>
</div>
)

function onChange (value: string): void {
fireOnUpdateCellDataEvent(value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const useStyles = createStyles(({ css }) => {
'select-cell': css`
padding: 4px;

.ant-select {
.ant-select, .studio-select {
width: 100%;
}
`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import React, { type ReactElement } from 'react'
import { type AbstractGridCellDefinition, DynamicTypeGridCellAbstract } from '../../dynamic-type-grid-cell-abstract'
import { injectable } from 'inversify'
import {
MultiSelectCell
} from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/components/multi-select/multi-select-cell'

@injectable()
export class DynamicTypeGridCellMultiSelect extends DynamicTypeGridCellAbstract {
readonly id = 'multi-select'

getGridCellComponent (props: AbstractGridCellDefinition): ReactElement<AbstractGridCellDefinition> {
return <MultiSelectCell { ...props } />
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import React, { useEffect } from 'react'
import {
ManyToManyObjectRelation,
type VisibleFieldDefinition
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/components/many-to-many-object-relation/many-to-many-object-relation'
import type {
ManyToManyRelationValue,
ManyToManyRelationValueItem
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/components/many-to-many-relation/hooks/use-value'
import _ from 'lodash'
import { Alert } from '@Pimcore/components/alert/alert'
import {
type AdvancedManyToManyRelationValue
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/helpers/relations/types/advanced-many-to-many-relation'
import {
useConvertRelationEditableColumns
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/helpers/relations/hooks/use-convert-relation-editable-columns'

export interface AdvancedManyToManyObjectRelationClassDefinitionProps {
allowToClearRelation: boolean
allowMultipleAssignments: boolean
maxItems: number | null
pathFormatterClass: string | null
width: number | string | null
height: number | string | null
visibleFieldDefinitions?: Record<string, VisibleFieldDefinition> | null
allowedClassId: string | null
columns?: RelationColumnDefinition[] | null
name: string[]
}

export interface RelationColumnDefinition {
type?: string
position: number
key: string
label?: string
width?: number
value?: string
}

export interface AdvancedManyToManyObjectRelationProps extends AdvancedManyToManyObjectRelationClassDefinitionProps {
disabled?: boolean
value?: AdvancedManyToManyRelationValue | null
onChange?: (value?: AdvancedManyToManyRelationValue | null) => void
enrichRowData?: (row: ManyToManyRelationValueItem) => ManyToManyRelationValueItem & Record<string, any>
}

export const AdvancedManyToManyObjectRelation = (props: AdvancedManyToManyObjectRelationProps): React.JSX.Element => {
const fieldName = props.name[props.name.length - 1]
const { columnDefinition, onUpdateCellData, convertToManyToManyRelationValue, convertToAdvancedManyToManyRelationValue } = useConvertRelationEditableColumns(props.columns ?? [], fieldName, props.value, props.onChange)

useEffect(() => {
}, [props.value])

if (_.isEmpty(props.allowedClassId)) {
return (
<Alert
message="Allowed class definition is missing in field configuration."
type="warning"
/>
)
}

const onChange = (value?: ManyToManyRelationValue | null): void => {
props.onChange?.(convertToAdvancedManyToManyRelationValue(value))
}

return (
<ManyToManyObjectRelation
{ ...props }
allowedClasses={ [String(props.allowedClassId)] }
columnDefinition={ columnDefinition }
dataObjectsAllowed
onChange={ onChange }
onUpdateCellData={ onUpdateCellData }
value={ convertToManyToManyRelationValue(props.value) }
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
enrichRowData,
visibleFieldsToColumnDefinitions
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/components/many-to-many-object-relation/utils/column-definition'
import { type OnUpdateCellDataEvent } from '@Pimcore/types/components/types'

export interface ManyToManyObjectRelationClassDefinitionProps {
allowToClearRelation: boolean
Expand All @@ -51,6 +52,7 @@ export interface ManyToManyObjectRelationProps extends IRelationAllowedTypesData
columnDefinition?: Array<ColumnDef<any>>
enrichRowData?: (row: ManyToManyRelationValueItem) => ManyToManyRelationValueItem & Record<string, any>
hint?: React.ReactNode | null
onUpdateCellData?: (event: OnUpdateCellDataEvent) => void
}

export const ManyToManyObjectRelation = (props: ManyToManyObjectRelationProps): React.JSX.Element => {
Expand Down Expand Up @@ -95,7 +97,7 @@ export const ManyToManyObjectRelation = (props: ManyToManyObjectRelationProps):
return (
<ManyToManyRelation
{ ...props }
columnDefinition={ columnDefinition }
columnDefinition={ [...columnDefinition, ...(props.columnDefinition ?? [])] }
dataObjectsAllowed={ !_.isEmpty(props.allowedClasses) }
enrichRowData={ (row: ManyToManyRelationValueItem) => enrichRowData(visibleFieldDefinitions, row) }
// isLoading // todo: set this prop while loading the column definition data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,19 @@ import cn from 'classnames'
import { useDownload } from '@Pimcore/modules/asset/actions/download/use-download'
import { toCssDimension } from '@Pimcore/utils/css'
import { Content } from '@Pimcore/components/content/content'
import { type OnUpdateCellDataEvent } from '@Pimcore/types/components/types'

interface ManyToManyRelationGridProps {
value?: ManyToManyRelationValue | null
deleteItem: (id: number, type: string) => void
deleteItem: (rowIndex: number) => void
assetInlineDownloadAllowed: boolean
disabled?: boolean
width: number | string | null
height: number | string | null
enrichRowData?: (row: ManyToManyRelationValueItem) => ManyToManyRelationValueItem & Record<string, any>
columnDefinition?: Array<ColumnDef<any>>
hint?: React.ReactNode | null
onUpdateCellData?: (event: OnUpdateCellDataEvent) => void
}

export const ManyToManyRelationGrid = forwardRef(function ManyToManyRelationGrid (props: ManyToManyRelationGridProps, ref: MutableRefObject<HTMLDivElement>): React.JSX.Element {
Expand Down Expand Up @@ -89,6 +91,7 @@ export const ManyToManyRelationGrid = forwardRef(function ManyToManyRelationGrid
header: t('actions'),
size: 110,
cell: (info) => {
const rowIndex = info.row.index
const rowValue = info.row.original as ManyToManyRelationValueItem

const buttons: ReactElement[] = []
Expand Down Expand Up @@ -152,7 +155,7 @@ export const ManyToManyRelationGrid = forwardRef(function ManyToManyRelationGrid
} }
/>,
onOk: () => {
props.deleteItem(rowValue.id, rowValue.type)
props.deleteItem(rowIndex)
}
})
} }
Expand Down Expand Up @@ -208,6 +211,7 @@ export const ManyToManyRelationGrid = forwardRef(function ManyToManyRelationGrid
autoWidth
columns={ columns }
data={ getDataArray() }
onUpdateCellData={ props.onUpdateCellData }
resizable
/>
{ props.hint }
Expand Down
Loading
Loading