Skip to content

Commit

Permalink
Table data object data type
Browse files Browse the repository at this point in the history
  • Loading branch information
markus-moser committed Dec 11, 2024
1 parent 0824a7d commit b370f58
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 50 deletions.
2 changes: 2 additions & 0 deletions assets/js/src/core/app/config/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ import { DynamicTypeObjectDataGeoPolygon } from '@Pimcore/modules/element/dynami
import { DynamicTypeObjectDataGeoPolyLine } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-geopolyline'
import { DynamicTypeObjectDataManyToManyRelation } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-many-to-many-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'
import { DynamicTypeObjectDataBlock } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-block'
import { DynamicTypeObjectDataLocalizedFields } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-localized-fields'
import { DynamicTypeGridCellAsset } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/asset/dynamic-type-grid-cell-asset'
Expand Down Expand Up @@ -259,6 +260,7 @@ container.bind(serviceIds['DynamicTypes/ObjectData/GeoBounds']).to(DynamicTypeOb
container.bind(serviceIds['DynamicTypes/ObjectData/GeoPolygon']).to(DynamicTypeObjectDataGeoPolygon).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/GeoPolyLine']).to(DynamicTypeObjectDataGeoPolyLine).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/ManyToManyRelation']).to(DynamicTypeObjectDataManyToManyRelation).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/Table']).to(DynamicTypeObjectDataTable).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/StructuredTable']).to(DynamicTypeObjectDataStructuredTable).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/Block']).to(DynamicTypeObjectDataBlock).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/LocalizedFields']).to(DynamicTypeObjectDataLocalizedFields).inSingletonScope()
Expand Down
1 change: 1 addition & 0 deletions assets/js/src/core/app/config/services/service-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export const serviceIds = {
'DynamicTypes/ObjectData/GeoPolygon': 'DynamicTypes/ObjectData/GeoPolygon',
'DynamicTypes/ObjectData/GeoPolyLine': 'DynamicTypes/ObjectData/GeoPolyLine',
'DynamicTypes/ObjectData/ManyToManyRelation': 'DynamicTypes/ObjectData/ManyToManyRelation',
'DynamicTypes/ObjectData/Table': 'DynamicTypes/ObjectData/Table',
'DynamicTypes/ObjectData/StructuredTable': 'DynamicTypes/ObjectData/StructuredTable',
'DynamicTypes/ObjectData/Block': 'DynamicTypes/ObjectData/Block',
'DynamicTypes/ObjectData/LocalizedFields': 'DynamicTypes/ObjectData/LocalizedFields',
Expand Down
102 changes: 52 additions & 50 deletions assets/js/src/core/components/grid/grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export interface ExtendedCellContext extends CellContext<any, any> {
modified?: boolean
}

export const Grid = ({ enableMultipleRowSelection = false, modifiedCells = [], sorting, manualSorting = false, enableSorting = false, enableRowSelection = false, selectedRows = {}, ...props }: GridProps): React.JSX.Element => {
export const Grid = ({ enableMultipleRowSelection = false, modifiedCells = [], sorting, manualSorting = false, enableSorting = false, hideColumnHeaders = false, enableRowSelection = false, selectedRows = {}, ...props }: GridProps): React.JSX.Element => {
const { t } = useTranslation()
const hashId = useCssComponentHash('table')
const { styles } = useStyles()
Expand Down Expand Up @@ -195,57 +195,59 @@ export const Grid = ({ enableMultipleRowSelection = false, modifiedCells = [], s
ref={ tableElement }
style={ { width: tableAutoWidth ? '100%' : table.getCenterTotalSize(), minWidth: table.getCenterTotalSize() } }
>
<thead className='ant-table-thead'>
{table.getHeaderGroups().map(headerGroup => (
<tr key={ headerGroup.id }>
{headerGroup.headers.map((header, index) => (
<th
className='ant-table-cell'
key={ header.id }
ref={ header.column.columnDef.meta?.autoWidth === true ? autoColumnRef : null }
style={
header.column.columnDef.meta?.autoWidth === true && !header.column.getIsResizing()
? {
width: 'auto',
minWidth: header.column.getSize()
}
: {
width: header.column.getSize(),
maxWidth: header.column.getSize()
}
}
>
<div className='grid__cell-content'>
<span>
{flexRender(
header.column.columnDef.header,
header.getContext()
{ hideColumnHeaders !== true && (
<thead className='ant-table-thead'>
{table.getHeaderGroups().map(headerGroup => (
<tr key={ headerGroup.id }>
{headerGroup.headers.map((header, index) => (
<th
className='ant-table-cell'
key={ header.id }
ref={ header.column.columnDef.meta?.autoWidth === true ? autoColumnRef : null }
style={
header.column.columnDef.meta?.autoWidth === true && !header.column.getIsResizing()
? {
width: 'auto',
minWidth: header.column.getSize()
}
: {
width: header.column.getSize(),
maxWidth: header.column.getSize()
}
}
>
<div className='grid__cell-content'>
<span>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</span>

{header.column.getCanSort() && (
<div className='grid__sorter'>
<SortButton
allowUnsorted={ sorting === undefined }
onSortingChange={ (value) => { updateSortDirection(header.column, value) } }
value={ getSortDirection(header.column) }
/>
</div>
)}
</span>

{header.column.getCanSort() && (
<div className='grid__sorter'>
<SortButton
allowUnsorted={ sorting === undefined }
onSortingChange={ (value) => { updateSortDirection(header.column, value) } }
value={ getSortDirection(header.column) }
/>
</div>
</div>

{props.resizable === true && header.column.getCanResize() && (
<Resizer
header={ header }
isResizing={ header.column.getIsResizing() }
table={ table }
/>
)}
</div>

{props.resizable === true && header.column.getCanResize() && (
<Resizer
header={ header }
isResizing={ header.column.getIsResizing() }
table={ table }
/>
)}
</th>
))}
</tr>
))}
</thead>
</th>
))}
</tr>
))}
</thead>
)}
<tbody className="ant-table-tbody">
{table.getRowModel().rows.length === 0 && (
<tr className={ 'ant-table-row' }>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* 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 from 'react'
import { Grid } from '@Pimcore/components/grid/grid'
import { type ColumnDef, createColumnHelper } from '@tanstack/react-table'
import {
type TableValue
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/components/table/table'

interface TableGridProps {
cols: number | null
rows: number | null
value: TableValue | null
onChange?: (value: TableValue | null) => void
}

export const TableGrid = (props: TableGridProps): React.JSX.Element => {
const columnHelper = createColumnHelper()

const cols = props.cols ?? 5
const rows = props.rows ?? 7

const columns: Array<ColumnDef<any>> = []
for (let i = 0; i < cols; i++) {
columns.push(
columnHelper.accessor('col-' + i, {
meta: {
type: 'text',
editable: true
}
})
)
}

const dataRows: Array<Record<string, string>> = []
for (let i = 0; i < rows; i++) {
const rowValues = {}
for (let j = 0; j < cols; j++) {
rowValues['col-' + j] = props.value?.[i]?.[j] ?? ''
}
dataRows.push(rowValues)
}

return (
<Grid

columns={ columns }
data={ dataRows }
hideColumnHeaders
onUpdateCellData={ (data) => {
const newDataRows = {
...dataRows,
[data.rowIndex]: {
...dataRows?.[data.rowIndex],
[data.columnId]: data.value
}
}

const newValue = Object.values(newDataRows).map(row => Object.values(row))
console.log('new value', newValue, newDataRows)
props.onChange?.(newValue)
} }
resizable
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* 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, useState } from 'react'
import { TableGrid } from './components/grid/grid'
import { Box } from '@Pimcore/components/box/box'
import { IconButton } from '@Pimcore/components/icon-button/icon-button'
import { Tooltip } from 'antd'
import { useTranslation } from 'react-i18next'
import { useFormModal } from '@Pimcore/components/modal/form-modal/hooks/use-form-modal'

export interface TableProps {
rows: number | null
cols: number | null
value?: TableValue | null
onChange?: (value: TableValue | null) => void
}

export type TableValue = string[][]

export const Table = (props: TableProps): React.JSX.Element => {
const [value, setValue] = useState<TableValue | null>(props.value ?? null)
const [key, setKey] = useState<number>(0)
const { t } = useTranslation()
const { confirm } = useFormModal()

const onChange = (value: TableValue | null): void => {
setValue(value)
}

useEffect(() => {
if (props.onChange !== undefined) {
props.onChange(value)
}
}, [value])

const emptyValue = (): void => {
if (value !== null) {
setValue([])
setKey(key + 1) // force re-render
}
}

return (
<>
<TableGrid
cols={ props.cols }
key={ key }
onChange={ onChange }
rows={ props.rows }
value={ value }
/>
<Box padding="extra-small">
<Tooltip title={ t('empty') }>
<IconButton
icon={ { value: 'trash' } }
onClick={ () => {
confirm({
title: t('empty'),
content: t('structured-table.empty.confirm'),
onOk: emptyValue
})
} }
type="default"
/>
</Tooltip>
</Box>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* 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 from 'react'
import {
type AbstractObjectDataDefinition, DynamicTypeObjectDataAbstract
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/dynamic-type-object-data-abstract'
import {
Table, type TableProps
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/components/table/table'

export type TableObjectDataDefinition = AbstractObjectDataDefinition & TableProps

export class DynamicTypeObjectDataTable extends DynamicTypeObjectDataAbstract {
id: string = 'table'

getObjectDataComponent (props: TableObjectDataDefinition): React.ReactElement<AbstractObjectDataDefinition> {
return (
<Table { ...props } />
)
}
}
2 changes: 2 additions & 0 deletions assets/js/src/core/modules/element/dynamic-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import { type DynamicTypeObjectDataGeoBounds } from '@Pimcore/modules/element/dy
import { type DynamicTypeObjectDataGeoPolygon } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-geopolygon'
import { type DynamicTypeObjectDataGeoPolyLine } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-geopolyline'
import { type DynamicTypeObjectDataManyToManyRelation } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-many-to-many-relation'
import { type DynamicTypeObjectDataTable } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-table'
import { type DynamicTypeObjectDataStructuredTable } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-structured-table'

import { type DynamicTypeObjectDataBlock } from './defintinitions/objects/data-related/types/dynamic-type-object-data-block'
Expand Down Expand Up @@ -227,6 +228,7 @@ moduleSystem.registerModule({
objectDataRegistry.registerDynamicType(container.get<DynamicTypeObjectDataGeoPolygon>(serviceIds['DynamicTypes/ObjectData/GeoPolygon']))
objectDataRegistry.registerDynamicType(container.get<DynamicTypeObjectDataGeoPolyLine>(serviceIds['DynamicTypes/ObjectData/GeoPolyLine']))
objectDataRegistry.registerDynamicType(container.get<DynamicTypeObjectDataManyToManyRelation>(serviceIds['DynamicTypes/ObjectData/ManyToManyRelation']))
objectDataRegistry.registerDynamicType(container.get<DynamicTypeObjectDataTable>(serviceIds['DynamicTypes/ObjectData/Table']))
objectDataRegistry.registerDynamicType(container.get<DynamicTypeObjectDataStructuredTable>(serviceIds['DynamicTypes/ObjectData/StructuredTable']))
objectDataRegistry.registerDynamicType(container.get<DynamicTypeObjectDataBlock>(serviceIds['DynamicTypes/ObjectData/Block']))
objectDataRegistry.registerDynamicType(container.get<DynamicTypeObjectDataLocalizedFields>(serviceIds['DynamicTypes/ObjectData/LocalizedFields']))
Expand Down
1 change: 1 addition & 0 deletions assets/js/src/core/types/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ export interface GridProps {
onSortingChange?: (sorting: SortingState) => void
setRowId?: (originalRow: any, index: number, parent: any) => string
autoWidth?: boolean
hideColumnHeaders?: boolean
}

0 comments on commit b370f58

Please sign in to comment.