Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ecd10ab
improved email tab
Corepex Jan 27, 2026
63e4736
changed properties
Corepex Jan 27, 2026
91052e1
added `tooltip` prop to `iconButton`
Corepex Jan 27, 2026
70ea6bf
added translations
Corepex Jan 27, 2026
20a42af
added tooltips to buttons
Corepex Jan 27, 2026
1fe8e5f
added sdk exports
Corepex Jan 27, 2026
087fcc5
added type column
Corepex Jan 27, 2026
d3b9c55
disable html and parameters button if thers none
Corepex Jan 27, 2026
a113f73
added enhanced caching
Corepex Jan 27, 2026
149e370
added variant icon
Corepex Jan 27, 2026
689175b
added tooltip translations
Corepex Jan 27, 2026
aa2dda7
added linter fixes
Corepex Jan 27, 2026
e3a8a3f
improved `ElementSubtypeIconCell` logic
Corepex Jan 27, 2026
9de346b
Apply eslint-fixer changes
Corepex Jan 27, 2026
d7336fd
Automatic frontend build
Corepex Jan 27, 2026
e64474b
removed weird logic
Corepex Jan 27, 2026
82047de
Apply eslint-fixer changes
Corepex Jan 27, 2026
27452c1
Automatic frontend build
Corepex Jan 27, 2026
ffb5e2c
improved tooltip
Corepex Jan 27, 2026
934bd7b
Automatic frontend build
Corepex Jan 27, 2026
69a41eb
changed icon color
Corepex Jan 28, 2026
59dd821
replaced strings with enum
Corepex Jan 28, 2026
a9fb398
Merge remote-tracking branch 'origin/gdpr-add-emails-tab' into gdpr-a…
Corepex Jan 28, 2026
c3ea8f6
fixed id column bug
Corepex Jan 28, 2026
d546890
Apply eslint-fixer changes
Corepex Jan 28, 2026
468a30c
Automatic frontend build
Corepex Jan 28, 2026
1578e2d
fixed sorting issue
Corepex Jan 28, 2026
fae5178
fixed imports
Corepex Jan 28, 2026
9c07edd
Apply eslint-fixer changes
Corepex Jan 28, 2026
37a361f
Automatic frontend build
Corepex Jan 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
12 changes: 9 additions & 3 deletions assets/js/src/core/app/api/pimcore/tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ export const tagNames = {
WIDGET_DETAIL: 'WIDGET_DETAIL',
USERS: 'USERS',
USER_DETAIL: 'USER_DETAIL',
USER_TREE: 'USER_TREE'
USER_TREE: 'USER_TREE',
GDPR_DATA: 'GDPR_DATA',
GDPR_DATA_DETAIL: 'GDPR_DATA_DETAIL'
}

export const providingTags = {
Expand Down Expand Up @@ -134,7 +136,9 @@ export const providingTags = {
WIDGET_DETAIL: (id: string, widgetType: string) => [{ type: tagNames.WIDGET_DETAIL, id, widgetType }],
USERS: () => [tagNames.USERS],
USER_DETAIL: (id: number) => [{ type: tagNames.USER_DETAIL, id }],
USER_TREE: () => [tagNames.USER_TREE]
USER_TREE: () => [tagNames.USER_TREE],
GDPR_DATA: (providerKey: string) => [{ type: tagNames.GDPR_DATA, id: providerKey }],
GDPR_DATA_DETAIL: (providerKey: string, id: number) => [{ type: tagNames.GDPR_DATA_DETAIL, id: `${providerKey}-${id}` }]
}

export const invalidatingTags = {
Expand Down Expand Up @@ -194,7 +198,9 @@ export const invalidatingTags = {
WIDGETS: () => [tagNames.WIDGETS],
USERS: () => [tagNames.USERS],
USER_DETAIL: (id: number) => [{ type: tagNames.USER_DETAIL, id }],
USER_TREE: () => [tagNames.USER_TREE]
USER_TREE: () => [tagNames.USER_TREE],
GDPR_DATA: (providerKey: string) => [{ type: tagNames.GDPR_DATA, id: providerKey }],
GDPR_DATA_DETAIL: (providerKey: string, id: number) => [{ type: tagNames.GDPR_DATA_DETAIL, id: `${providerKey}-${id}` }]
}

const elementUnspecificDataTag = tagNames.AVAILABLE_TAGS
Expand Down
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 @@ -57,6 +57,7 @@ import { DynamicTypeFieldFilterMultiselect } from '@Pimcore/modules/element/dyna
import { DynamicTypeFieldFilterString } from '@Pimcore/modules/element/dynamic-types/definitions/field-filters/types/string/dynamic-type-field-filter-string'
import { DynamicTypeGridCellRegistry } from '@Pimcore/modules/element/dynamic-types/definitions/grid-cell/dynamic-type-grid-cell-registry'
import { DynamicTypeGridCellDependencyTypeIcon } from '@Pimcore/modules/element/dynamic-types/definitions/grid-cell/types/_dependencies/dynamic-type-grid-cell-dependency-type-icon'
import { DynamicTypeGridCellElementSubtypeIcon } from '@Pimcore/modules/element/dynamic-types/definitions/grid-cell/types/element-subtype-icon/dynamic-type-grid-cell-element-subtype-icon'
import { DynamicTypeGridCellAssetCustomMetadataIcon } from '@Pimcore/modules/element/dynamic-types/definitions/grid-cell/types/_meta-data/dynamic-type-grid-cell-asset-custom-metadata-icon'
import { DynamicTypeGridCellAssetCustomMetadataValue } from '@Pimcore/modules/element/dynamic-types/definitions/grid-cell/types/_meta-data/dynamic-type-grid-cell-asset-custom-metadata-value'
import { DynamicTypeGridCellPropertyIcon } from '@Pimcore/modules/element/dynamic-types/definitions/grid-cell/types/_properties/dynamic-type-grid-cell-property-icon'
Expand Down Expand Up @@ -412,6 +413,7 @@ container.bind(serviceIds['DynamicTypes/GridCell/AssetPreview']).to(DynamicTypeG
container.bind(serviceIds['DynamicTypes/GridCell/AssetActions']).to(DynamicTypeGridCellAssetActions).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/DataObjectActions']).to(DynamicTypeGridCellDataObjectActions).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/DependencyTypeIcon']).to(DynamicTypeGridCellDependencyTypeIcon).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/ElementSubtypeIcon']).to(DynamicTypeGridCellElementSubtypeIcon).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/AssetCustomMetadataIcon']).to(DynamicTypeGridCellAssetCustomMetadataIcon).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/AssetCustomMetadataValue']).to(DynamicTypeGridCellAssetCustomMetadataValue).inSingletonScope()
container.bind(serviceIds['DynamicTypes/GridCell/PropertyIcon']).to(DynamicTypeGridCellPropertyIcon).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 @@ -159,6 +159,7 @@ export const serviceIds = {
'DynamicTypes/GridCell/AssetActions': 'DynamicTypes/GridCell/AssetActions',
'DynamicTypes/GridCell/DataObjectActions': 'DynamicTypes/GridCell/DataObjectActions',
'DynamicTypes/GridCell/DependencyTypeIcon': 'DynamicTypes/GridCell/DependencyTypeIcon',
'DynamicTypes/GridCell/ElementSubtypeIcon': 'DynamicTypes/GridCell/ElementSubtypeIcon',
'DynamicTypes/GridCell/AssetCustomMetadataIcon': 'DynamicTypes/GridCell/AssetCustomMetadataIcon',
'DynamicTypes/GridCell/AssetCustomMetadataValue': 'DynamicTypes/GridCell/AssetCustomMetadataValue',
'DynamicTypes/GridCell/PropertyIcon': 'DynamicTypes/GridCell/PropertyIcon',
Expand Down
5 changes: 5 additions & 0 deletions assets/js/src/core/assets/icons/code.inline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 15 additions & 1 deletion assets/js/src/core/components/icon-button/icon-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ import React, { forwardRef } from 'react'
import cn from 'classnames'
import { Button, type ButtonProps } from '../button/button'
import { Icon, type IconProps } from '../icon/icon'
import { Tooltip } from '../tooltip/tooltip'
import { useStyles } from './icon-button.styles'
import { type SizeType } from 'antd/es/config-provider/SizeContext'
import { type TooltipProps } from 'antd'

export interface IconButtonProps extends Omit<ButtonProps, 'icon' | 'variant'> {
icon: IconProps
tooltip?: TooltipProps
theme?: 'primary' | 'secondary'
variant?: 'minimal' | 'static'
size?: SizeType
Expand All @@ -33,6 +36,7 @@ const Component = (props: IconButtonProps, ref): React.JSX.Element => {
variant,
size,
className,
tooltip,
...buttonProps
} = props

Expand All @@ -59,7 +63,7 @@ const Component = (props: IconButtonProps, ref): React.JSX.Element => {
}
}

return (
const button = (
<Button
type={ type }
{ ...buttonProps }
Expand All @@ -69,6 +73,16 @@ const Component = (props: IconButtonProps, ref): React.JSX.Element => {
<Icon { ...iconWithSize } />
</Button>
)

if (tooltip !== undefined) {
return (
<Tooltip { ...tooltip }>
{button}
</Tooltip>
)
}

return button
}

export const IconButton = forwardRef(Component)
6 changes: 3 additions & 3 deletions assets/js/src/core/modules/app/utils/sort-filter-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import { type SortingState } from '@tanstack/react-table'
import { type SortFilter } from '../types/sort-filter'
import { isNil } from 'lodash'

export function transformToSortingState (sortFilter: SortFilter): SortingState {
export function transformToSortFilter (sortFilter: SortFilter): SortingState {
return [{
id: sortFilter.key,
desc: sortFilter.direction === 'DESC'
}]
}

export function transformToSortFilter (sorting: SortingState | null): SortFilter | null {
export function transformToSortingState (sorting: SortingState | null): SortFilter | undefined {
if (isNil(sorting) || sorting.length === 0) {
return null
return undefined
}

return {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

import { createStyles } from 'antd-style'

export const useStyle = createStyles(({ token, css }) => {
return {
cell: css`
.pimcore-icon {
color: ${token.Colors.Neutral.Icon.colorIcon};
}
`
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

import { type DefaultCellProps } from '@Pimcore/components/grid/columns/default-cell'
import { IconView } from '@Pimcore/components/grid/columns/views/icon/icon-view'
import { Tooltip } from '@Pimcore/components/tooltip/tooltip'
import { type ElementType } from '@Pimcore/types/enums/element/element-type'
import { capitalize } from 'lodash'
import React from 'react'
import { useStyle } from './element-subtype-icon-cell.styles'

export interface ElementSubtypeIconCellProps extends DefaultCellProps {
elementType: ElementType
}

export const ElementSubtypeIconCell = (props: ElementSubtypeIconCellProps): React.JSX.Element => {
const { styles } = useStyle()
const subtype = props.getValue() ?? props.row.original.subType

function renderCell (): React.JSX.Element {
switch (subtype) {
case 'image':
return <IconView value={ 'image' } />
case 'video':
return <IconView value={ 'video' } />
case 'audio':
return <IconView value={ 'audio' } />
case 'document':
return <IconView value={ 'document' } />
case 'archive':
case 'folder':
return <IconView value={ 'folder' } />
case 'page':
return <IconView value={ 'file' } />
case 'snippet':
return <IconView value={ 'snippet' } />
case 'email':
return <IconView value={ 'mail' } />
case 'link':
return <IconView value={ 'hardlink' } />
case 'object':
case 'dataObject':
case 'data-object':
return <IconView value={ 'data-object' } />
case 'variant':
return <IconView value={ 'data-object-variant' } />
default:
return <IconView value={ props.elementType } />
}
}

return (
<div className={ styles.cell }>
<Tooltip title={ capitalize(String(subtype)) }>
{renderCell()}
</Tooltip>
</div >
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

import React, { type ReactElement } from 'react'
import { type AbstractGridCellDefinition, DynamicTypeGridCellAbstract } from '../../dynamic-type-grid-cell-abstract'
import { injectable } from 'inversify'
import { ElementSubtypeIconCell, type ElementSubtypeIconCellProps } from '../../components/element-subtype-icon-cell/element-subtype-icon-cell'
import { type ElementType } from '@Pimcore/types/enums/element/element-type'

export interface ElementSubtypeIconGridCellConfig {
elementType: ElementType
}

@injectable()
export class DynamicTypeGridCellElementSubtypeIcon extends DynamicTypeGridCellAbstract {
readonly id = 'element-subtype-icon'

getGridCellComponent (props: AbstractGridCellDefinition): ReactElement<AbstractGridCellDefinition> {
const config = props.column.columnDef.meta?.config as ElementSubtypeIconGridCellConfig | undefined

if (config?.elementType === undefined) {
throw new Error('ElementSubtypeIconCell requires elementType in column meta config')
}

const cellProps: ElementSubtypeIconCellProps = {
...props,
elementType: config.elementType
}

return <ElementSubtypeIconCell { ...cellProps } />
}
}
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 @@ -38,6 +38,7 @@ import { type DynamicTypeGridCellOpenElement } from './definitions/grid-cell/typ
import { type DynamicTypeGridCellAssetPreview } from './definitions/grid-cell/types/asset-preview/dynamic-type-grid-cell-asset-preview'
import { type DynamicTypeGridCellAssetActions } from './definitions/grid-cell/types/asset-actions/dynamic-type-grid-cell-asset-preview'
import { type DynamicTypeGridCellDependencyTypeIcon } from './definitions/grid-cell/types/_dependencies/dynamic-type-grid-cell-dependency-type-icon'
import { type DynamicTypeGridCellElementSubtypeIcon } from './definitions/grid-cell/types/element-subtype-icon/dynamic-type-grid-cell-element-subtype-icon'
import { type DynamicTypeGridCellAssetCustomMetadataIcon } from './definitions/grid-cell/types/_meta-data/dynamic-type-grid-cell-asset-custom-metadata-icon'
import { type DynamicTypeGridCellAssetCustomMetadataValue } from './definitions/grid-cell/types/_meta-data/dynamic-type-grid-cell-asset-custom-metadata-value'
import { type DynamicTypeGridCellPropertyIcon } from './definitions/grid-cell/types/_properties/dynamic-type-grid-cell-property-icon'
Expand Down Expand Up @@ -282,6 +283,7 @@ moduleSystem.registerModule({
GridCellRegistry.registerDynamicType(container.get<DynamicTypeGridCellAssetActions>(serviceIds['DynamicTypes/GridCell/AssetActions']))
GridCellRegistry.registerDynamicType(container.get<DynamicTypeGridCellDataObjectActions>(serviceIds['DynamicTypes/GridCell/DataObjectActions']))
GridCellRegistry.registerDynamicType(container.get<DynamicTypeGridCellDependencyTypeIcon>(serviceIds['DynamicTypes/GridCell/DependencyTypeIcon']))
GridCellRegistry.registerDynamicType(container.get<DynamicTypeGridCellElementSubtypeIcon>(serviceIds['DynamicTypes/GridCell/ElementSubtypeIcon']))
GridCellRegistry.registerDynamicType(container.get<DynamicTypeGridCellAssetCustomMetadataIcon>(serviceIds['DynamicTypes/GridCell/AssetCustomMetadataIcon']))
GridCellRegistry.registerDynamicType(container.get<DynamicTypeGridCellAssetCustomMetadataValue>(serviceIds['DynamicTypes/GridCell/AssetCustomMetadataValue']))
GridCellRegistry.registerDynamicType(container.get<DynamicTypeGridCellPropertyIcon>(serviceIds['DynamicTypes/GridCell/PropertyIcon']))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ export const EmailCard = ({ emails }: EmailCardProps): React.JSX.Element => {
{
label: t('widget.email-log.tab.html'),
key: 'html',
children: <EmailPreview email={ email } />
children: <EmailPreview id={ email.id } />
},
{
label: t('widget.email-log.tab.parameters'),
key: 'parameters',
children: <ParametersTab email={ email } />
children: <ParametersTab id={ email.id } />
}
]

Expand Down Expand Up @@ -78,10 +78,10 @@ export const EmailCard = ({ emails }: EmailCardProps): React.JSX.Element => {
gap={ 4 }
>
{email.hasError && (
<Icon
className={ styles.errorIcon }
value="close-filled"
/>
<Icon
className={ styles.errorIcon }
value="close-filled"
/>
)}
<span>{formatDateTime({ timestamp: email.sentDate, dateStyle: 'short', timeStyle: 'short' })}</span>
</Flex>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import { useStyles } from './email-preview.styles'
import { useTranslation } from 'react-i18next'

interface EmailPreviewProps {
email: EmailLog
id: EmailLog['id']
height?: number
}

export const EmailPreview = ({ email, height = 650 }: EmailPreviewProps): React.JSX.Element => {
export const EmailPreview = ({ id, height = 650 }: EmailPreviewProps): React.JSX.Element => {
const { t } = useTranslation()
const { styles } = useStyles()
const { data, isLoading } = useEmailLogGetHtmlQuery({ id: email.id })
const { data, isLoading } = useEmailLogGetHtmlQuery({ id })

return (
<Content
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ export const ForwardModal = ({ email, ...props }: ForwardModalProps): React.JSX.
</Form>

<EmailPreview
email={ email }
height={ 300 }
id={ email.id }
/>
</Flex>
</Modal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ import React from 'react'
import { useTranslation } from 'react-i18next'

interface ParametersTabProps {
email: EmailLog
id: EmailLog['id']
}

interface ExtendedEmailLogParameters extends EmailLogParameters {
computedValue: string | EmailLogObjectParameterData | null
}

export const ParametersTab = ({ email }: ParametersTabProps): React.JSX.Element => {
export const ParametersTab = ({ id }: ParametersTabProps): React.JSX.Element => {
const { t } = useTranslation()
const { data, isLoading } = useEmailLogGetParamsQuery({ id: email.id })
const { data, isLoading } = useEmailLogGetParamsQuery({ id })

const columnHelper = createColumnHelper<ExtendedEmailLogParameters>()
const columns: Array<ColumnDef<ExtendedEmailLogParameters>> = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,25 @@
* @license Pimcore Open Core License (POCL)
*/

import { useAppDispatch } from '@Pimcore/app/store'
import { type ElementType } from '@Pimcore/types/enums/element/element-type'
import { IconButton } from '@sdk/components'
import { useDelete } from '@sdk/modules/element'
import React, { useState } from 'react'
import { api } from '@Pimcore/modules/email/emails-api-slice-enhanced'
import { invalidatingTags } from '@Pimcore/app/api/pimcore/tags'

interface DeleteButtonProps extends Omit<React.ComponentProps<typeof IconButton>, 'id' | 'icon'> {
id: number
elementType: ElementType
providerKey: string
label: string
}

export const DeleteButton = ({ id, elementType, label, onClick, ...iconButtonProps }: DeleteButtonProps): React.JSX.Element => {
export const DeleteButton = ({ id, elementType, label, providerKey, onClick, ...iconButtonProps }: DeleteButtonProps): React.JSX.Element => {
const { deleteElement } = useDelete(elementType)
const [isDeleting, setIsDeleting] = useState<boolean>(false)
const dispatch = useAppDispatch()

return (
<IconButton
Expand All @@ -32,6 +37,12 @@ export const DeleteButton = ({ id, elementType, label, onClick, ...iconButtonPro
setIsDeleting(true)
deleteElement(id, label, undefined, () => {
setIsDeleting(false)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be better in the slice - enhanced ticket created #2848

dispatch(
api.util.invalidateTags(
invalidatingTags.GDPR_DATA(providerKey)
)
)
})
onClick?.(e)
} }
Expand Down
Loading