From 927fd98174f60091d8b603166a20c4761b2645b1 Mon Sep 17 00:00:00 2001 From: idaiv <138690998+idaiv@users.noreply.github.com> Date: Tue, 21 Jul 2026 09:07:48 +0000 Subject: [PATCH 1/3] Revert "Scope full-height tab rules to own panes (fix nested-tabs collapse) (#3903)" This reverts commit 337700d9092bd341508082ce73fc2338179f7da1. --- .../src/core/components/tabs/tabs.styles.tsx | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/assets/js/src/core/components/tabs/tabs.styles.tsx b/assets/js/src/core/components/tabs/tabs.styles.tsx index 21bedf18d6..17a39987e1 100644 --- a/assets/js/src/core/components/tabs/tabs.styles.tsx +++ b/assets/js/src/core/components/tabs/tabs.styles.tsx @@ -130,26 +130,22 @@ export const useStyles = createStyles(({ token, css }) => { flex-direction: column; height: 100%; - /* Scope to this tabs' OWN panes via direct-child combinators. Plain - descendant selectors here leak into any nested (e.g. an editor - whose body is itself tabbed), turning their content into a 0-height - position:absolute box and hiding the fields. */ - > .ant-tabs-content-holder { + .ant-tabs-content-holder { flex: 1; min-height: 0; position: relative; overflow: hidden; + } - > .ant-tabs-content { - position: absolute; - inset: 0; + .ant-tabs-content { + position: absolute; + inset: 0; + } - > .ant-tabs-tabpane { - position: relative; - height: 100%; - overflow: hidden; - } - } + .ant-tabs-tabpane { + position: relative; + height: 100%; + overflow: hidden; } } From bbfc4371e12d606b11e51047c37197a1c81c653b Mon Sep 17 00:00:00 2001 From: idaiv <138690998+idaiv@users.noreply.github.com> Date: Tue, 21 Jul 2026 09:08:19 +0000 Subject: [PATCH 2/3] Revert "[Studio UI] Fix full-height tabs and compact tab spacing (#3884)" This reverts commit 827edf844f00fda284098ffdc2737eec7d4d9fc8. --- .github/workflows/frontend-build-pr.yaml | 1 - .github/workflows/{docs.yml => new-docs.yml} | 0 ...hp-cs-fixer.yaml => new-php-cs-fixer.yaml} | 0 ...r-export.yaml => new-poeditor-export.yaml} | 0 ...analysis.yaml => new-static-analysis.yaml} | 0 CONTRIBUTING.md | 84 +---------- .../components/many-to-many-relation/grid.tsx | 1 - .../hooks/use-columns.tsx | 135 +++++++++--------- .../many-to-many-relation.tsx | 2 - .../core/components/modal/modal.styles.tsx | 2 +- .../dynamic-group/dynamic-group-content.tsx | 2 +- .../dynamic-group-item.styles.ts | 8 -- .../src/core/components/pipeline/pipeline.tsx | 3 +- .../components/divider/divider.styles.ts | 7 +- .../stack-list/stack-list-item.styles.tsx | 13 +- .../components/stack-list/stack-list-item.tsx | 2 +- .../src/core/components/tabs/tabs.styles.tsx | 39 +---- .../tabs/grid-config/grid-config-list.tsx | 62 ++------ .../advanced-column-form.tsx | 60 ++++---- .../preview/preview-item-selection.tsx | 43 +----- .../preview/preview-loader.styles.ts | 19 --- .../preview/preview-loader.tsx | 13 +- .../preview/preview.styles.ts | 19 --- .../advanced-column-form/preview/preview.tsx | 8 +- .../tabs/grid-config/grid-config-list.tsx | 74 ++-------- .../grid-config/grid-config-modal.styles.ts | 1 - .../tabs/grid-config/grid-config-modal.tsx | 11 +- .../advanced-many-to-many-object-relation.tsx | 1 - .../advanced-many-to-many-relation.tsx | 1 - .../many-to-many-object-relation.tsx | 1 - .../reverse-object-relation.tsx | 1 - ...-advanced-many-to-many-object-relation.tsx | 4 - ...ct-data-advanced-many-to-many-relation.tsx | 4 - ...ject-data-many-to-many-object-relation.tsx | 4 - ...type-object-data-many-to-many-relation.tsx | 4 - ...-type-object-data-many-to-one-relation.tsx | 4 - ...pe-object-data-reverse-object-relation.tsx | 4 - .../relation-field/relation-field.tsx | 5 +- .../workflow/hooks/use-submit-workflow.ts | 31 ++-- .../workflow/hooks/use-workflow-action.ts | 4 +- .../hooks/use-workflow-modal-state.ts | 22 --- .../workflow/modal/workflow-modal.tsx | 4 +- .../editor-workflow-subject-bridge.tsx | 56 -------- .../workflow/provider/workflow-provider.tsx | 31 +--- .../workflow/types/workflow-types.ts | 12 -- .../add-column-controls.tsx | 2 +- .../fields-to-add-panel.styles.ts | 6 +- .../fields-to-add-panel.tsx | 3 - assets/js/src/sdk/modules/element/index.ts | 28 ---- build-dist/build-4ad71b48c45c.zip | Bin 4421502 -> 0 bytes translations/studio.en.yaml | 37 +++-- 51 files changed, 190 insertions(+), 688 deletions(-) rename .github/workflows/{docs.yml => new-docs.yml} (100%) rename .github/workflows/{php-cs-fixer.yaml => new-php-cs-fixer.yaml} (100%) rename .github/workflows/{poeditor-export.yaml => new-poeditor-export.yaml} (100%) rename .github/workflows/{static-analysis.yaml => new-static-analysis.yaml} (100%) delete mode 100644 assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-loader.styles.ts delete mode 100644 assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview.styles.ts delete mode 100644 assets/js/src/core/modules/element/editor/shared-components/workflow/hooks/use-workflow-modal-state.ts delete mode 100644 assets/js/src/core/modules/element/editor/shared-components/workflow/provider/editor-workflow-subject-bridge.tsx delete mode 100644 build-dist/build-4ad71b48c45c.zip diff --git a/.github/workflows/frontend-build-pr.yaml b/.github/workflows/frontend-build-pr.yaml index 8fd735a60d..402789f1b4 100644 --- a/.github/workflows/frontend-build-pr.yaml +++ b/.github/workflows/frontend-build-pr.yaml @@ -4,7 +4,6 @@ on: push: branches: - "[0-9]+.[0-9]+" - - "[0-9]+.x" - "feature-*" - "nightly" # TEMP (remove before merge): regenerate build-dist/build-.zip on every push to diff --git a/.github/workflows/docs.yml b/.github/workflows/new-docs.yml similarity index 100% rename from .github/workflows/docs.yml rename to .github/workflows/new-docs.yml diff --git a/.github/workflows/php-cs-fixer.yaml b/.github/workflows/new-php-cs-fixer.yaml similarity index 100% rename from .github/workflows/php-cs-fixer.yaml rename to .github/workflows/new-php-cs-fixer.yaml diff --git a/.github/workflows/poeditor-export.yaml b/.github/workflows/new-poeditor-export.yaml similarity index 100% rename from .github/workflows/poeditor-export.yaml rename to .github/workflows/new-poeditor-export.yaml diff --git a/.github/workflows/static-analysis.yaml b/.github/workflows/new-static-analysis.yaml similarity index 100% rename from .github/workflows/static-analysis.yaml rename to .github/workflows/new-static-analysis.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3aff524ac0..3538c02404 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,84 +1,10 @@ -# Contributing to Pimcore -As an open core project we love to work together with our community to improve and develop our products. -It's also important for us to make clear that **we're not working for you or your company**, -but we enjoy to work together to solve issues or improve the product. - -## Contributing Pull Requests -We gladly accept community pull requests. This is the preferred way to contribute to Pimcore. -There are a few necessary steps before we can accept a pull request: - -> **Note:** Before opening a PR, also see our [Pull Request Guidelines](https://github.com/orgs/pimcore/discussions/19239) for the automated checks your PR must pass. +## Contributing Studio Pull Requests +We gladly accept community pull requests. This is the preferred way to contribute to Pimcore. There are a few necessary steps before we can accept a pull request: * [Fork us!](https://help.github.com/articles/fork-a-repo/) -* Select the right branch. `main`(`2026.x`) for features and improvements or latest maintenance branch for bug fixes (`2026.2`) -* Code! Follow the coding standards defined [here](https://github.com/pimcore/pimcore/blob/2026.x/.php-cs-fixer.dist.php) and [here](https://github.com/pimcore/pimcore/blob/2026.x/doc/19_Development_Tools_and_Details/29_Testing/02_Core_Tests.md#perform-phpstan-analysis) +* Select the right branch. `main`(`2026.x`) for features and improvements or latest maintenance branch for bug fixes (`2025.4`) * [Send a pull request](https://help.github.com/articles/using-pull-requests/) from your fork’s branch to our repo branch. * [Sign the CLA](https://cla-assistant.io/pimcore/pimcore) - see also below. +* Ensure that Github pipelines pass (linter, frontend build...) - -## Bug Reports -**Please provide a fix for the bug as a pull request (PR) whenever possible!** -If you've created a pull request, it's not necessary anymore to create an issue for the bug. - -* Only file an issue if you're not able to fix the bug and provide the patch as a pull request. -* Please keep in mind that the Pimcore team will only work on system critical and security bugs. -* [Open an issue](https://github.com/pimcore/platform-version/issues) here on GitHub. -* Report security issues only by using [security advisories](https://github.com/pimcore/platform-version/security/advisories). -* Please be patient as not all items will be tested immediately - remember, pimcore is open core and free of charge. -* Occasionally we'll close issues if they appear stale or are too vague - please don't take this personally! -Please feel free to re-open issues we've closed if there's something we've missed and they still need to be addressed. - -### Package Types -Please note that we categorize our packages into two types, as indicated in the 'About' section of each GitHub repository. -This categorization helps us prioritize and focus our resources effectively: - -* **Core Packages**: These are packages under active development by the Pimcore team, and of course we also welcome and incorporate contributions from the community. -* **Community Packages**: These packages are not currently being actively developed by the Pimcore team. However, we remain committed to their basic maintenance, as well as to reviewing and accepting pull requests, especially for critical bug fixes, and will release new versions as needed. - -### Inactive Issue Closing Policy -Pimcore uses a bot that closes abandoned issues after a period of inactivity. -If an issue was not labeled as "Priority" or "Backlog" by us, -this means that we're not going to work on that anytime soon. -In case of a bug report, you can create a pull request fixing the issue instead, -which will be then reviewed as soon as possible. -If you're interested in contributing a feature, please contact us first, -before creating a pull request, we'll then decide whether we'd accept it or not. - -## Contributor License Agreement -The following terms are used throughout this agreement: - -* **You** - the person or legal entity including its affiliates asked to accept this agreement. An affiliate is any -entity that controls or is controlled by the legal entity, or is under common control with it. - -* **Project** - is an umbrella term that refers to any and all Pimcore projects. - -* **Contribution** - any type of work that is submitted to a Project, including any modifications or additions to -existing work. - -* **Submitted** - conveyed to a Project via a pull request, commit, issue, or any form of electronic, written, or -verbal communication with Pimcore, contributors or maintainers. - -#### 1. Grant of Copyright License. -Subject to the terms and conditions of this agreement, You grant to the Projects’ maintainers, contributors, users and -to Pimcore a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, -prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your contributions and such -derivative works. Except for this license, You reserve all rights, title, and interest in your contributions. - -#### 2. Grant of Patent License. -Subject to the terms and conditions of this agreement, You grant to the Projects’ maintainers, contributors, users and -to Pimcore a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer your contributions, where -such license applies only to those patent claims licensable by you that are necessarily infringed by your contribution -or by combination of your contribution with the project to which this contribution was submitted. - -If any entity institutes patent litigation - including cross-claim or counterclaim in a lawsuit - against You alleging -that your contribution or any project it was submitted to constitutes or is responsible for direct or contributory -patent infringement, then any patent licenses granted to that entity under this agreement shall terminate as of the -date such litigation is filed. - -#### 3. Source of Contribution. -Your contribution is either your original creation, based upon previous work that, to the best of your knowledge, is -covered under an appropriate open source license and you have the right under that license to submit that work with -modifications, whether created in whole or in part by you, or you have clearly identified the source of the contribution -and any license or other restriction (like related patents, trademarks, and license agreements) of which you are -personally aware. +For details please check also the contributing docs of [pimcore/pimcore](https://github.com/pimcore/pimcore/blob/2026.x/CONTRIBUTING.md). diff --git a/assets/js/src/core/components/many-to-many-relation/grid.tsx b/assets/js/src/core/components/many-to-many-relation/grid.tsx index 1bbe80b498..d503fb9b46 100644 --- a/assets/js/src/core/components/many-to-many-relation/grid.tsx +++ b/assets/js/src/core/components/many-to-many-relation/grid.tsx @@ -41,7 +41,6 @@ export interface ManyToManyRelationGridProps { handleOrderChange: (data: ManyToManyRelationValue) => void pathFormatterConfig?: { name: string | undefined, class: string | undefined } enableRowVirtualizer: boolean - hideOpenButton?: boolean } export const ManyToManyRelationGrid = forwardRef(function ManyToManyRelationGrid (props: ManyToManyRelationGridProps, ref: MutableRefObject): React.JSX.Element { diff --git a/assets/js/src/core/components/many-to-many-relation/hooks/use-columns.tsx b/assets/js/src/core/components/many-to-many-relation/hooks/use-columns.tsx index f66b126a59..01db176bc4 100644 --- a/assets/js/src/core/components/many-to-many-relation/hooks/use-columns.tsx +++ b/assets/js/src/core/components/many-to-many-relation/hooks/use-columns.tsx @@ -75,18 +75,15 @@ export const useColumns = (props: UseColumnsProps): UseColumnsReturn => { ? [...props.columnDefinition] : defaultColumns - const showActionsColumn = props.hideOpenButton !== true || props.assetInlineDownloadAllowed || props.disabled !== true - - const actionsColumn = columnHelper.accessor('actions', { - header: t('actions'), - size: 110, - cell: (info) => { - const rowIndex = info.row.index - const rowValue = info.row.original as DisplayManyToManyRelationValueItem - - const buttons: ReactElement[] = [] - - if (props.hideOpenButton !== true) { + columns.push( + columnHelper.accessor('actions', { + header: t('actions'), + size: 110, + cell: (info) => { + const rowIndex = info.row.index + const rowValue = info.row.original as DisplayManyToManyRelationValueItem + + const buttons: ReactElement[] = [] buttons.push( { /> ) - } - if (props.assetInlineDownloadAllowed && rowValue.type === 'asset') { - buttons.push( - - { - download( - rowValue.id.toString() - ) - } } - type="link" + if (props.assetInlineDownloadAllowed && rowValue.type === 'asset') { + buttons.push( + + { + download( + rowValue.id.toString() + ) + } } + type="link" + /> + + ) + } + + if (props.disabled !== true) { + buttons.push( + + { + confirm({ + title: t('remove'), + content: t('delete-confirmation-advanced', { + type: t('relation'), + value: rowValue.originalPath ?? rowValue.fullPath, + interpolation: { escapeValue: false } + }), + onOk: () => { + props.deleteItem(rowIndex) + } + }) + } } + type="link" + /> + + ) + } + + return ( + + - + ) } - - if (props.disabled !== true) { - buttons.push( - - { - confirm({ - title: t('remove'), - content: t('delete-confirmation-advanced', { - type: t('relation'), - value: rowValue.originalPath ?? rowValue.fullPath, - interpolation: { escapeValue: false } - }), - onOk: () => { - props.deleteItem(rowIndex) - } - }) - } } - type="link" - /> - - ) - } - - return ( - - - - ) - } - }) - - if (showActionsColumn) { - columns.push(actionsColumn) - } + }) + ) return { columns diff --git a/assets/js/src/core/components/many-to-many-relation/many-to-many-relation.tsx b/assets/js/src/core/components/many-to-many-relation/many-to-many-relation.tsx index 83fc0e7d63..c21dbbb7a3 100644 --- a/assets/js/src/core/components/many-to-many-relation/many-to-many-relation.tsx +++ b/assets/js/src/core/components/many-to-many-relation/many-to-many-relation.tsx @@ -31,7 +31,6 @@ export interface ManyToManyRelationClassDefinitionProps { height: number | string | null assetInlineDownloadAllowed?: boolean | null onUpdateCellData?: (event: OnUpdateCellDataEvent) => void - hideOpenButton?: boolean } export interface ManyToManyRelationProps extends IRelationAllowedTypesDataComponent, ManyToManyRelationClassDefinitionProps { @@ -115,7 +114,6 @@ export const ManyToManyRelation = ({ enableRowDrag = true, ...props }: ManyToMan enrichRowData={ props.enrichRowData } handleOrderChange={ onOrderChange } height={ props.height } - hideOpenButton={ props.hideOpenButton } hint={ props.hint } inherited={ props.inherited } onUpdateCellData={ handleUpdateCellData } diff --git a/assets/js/src/core/components/modal/modal.styles.tsx b/assets/js/src/core/components/modal/modal.styles.tsx index 2087e817f8..0c4aa1cc54 100644 --- a/assets/js/src/core/components/modal/modal.styles.tsx +++ b/assets/js/src/core/components/modal/modal.styles.tsx @@ -42,7 +42,7 @@ export const useStyle = createStyles(({ token, css }) => { display: inline-flex; flex-direction: column; align-items: start; - gap: ${token.marginXXS}px; + gap: ${token.marginSM}px; .ant-modal-header { margin-bottom: 0; diff --git a/assets/js/src/core/components/pipeline/item/dynamic-group/dynamic-group-content.tsx b/assets/js/src/core/components/pipeline/item/dynamic-group/dynamic-group-content.tsx index 477411d1cc..990b576fbc 100644 --- a/assets/js/src/core/components/pipeline/item/dynamic-group/dynamic-group-content.tsx +++ b/assets/js/src/core/components/pipeline/item/dynamic-group/dynamic-group-content.tsx @@ -122,7 +122,7 @@ export const DynamicGroupContent = ({ dynamicTypeRegistryId, id, showTitle = fal ), [memoizedValues, items, onDragEnd, sensors, dynamicTypeRegistryId]) return ( - + { dynamicGroupItem: css` background-color: ${token.colorFillAdditional}; border-radius: ${token.borderRadius}px; - - .ant-form-item { - margin-bottom: 0; - } - - .ant-form-item + .ant-form-item { - margin-top: ${token.marginXS}px; - } ` } }) diff --git a/assets/js/src/core/components/pipeline/pipeline.tsx b/assets/js/src/core/components/pipeline/pipeline.tsx index 994e94999e..a682f49515 100644 --- a/assets/js/src/core/components/pipeline/pipeline.tsx +++ b/assets/js/src/core/components/pipeline/pipeline.tsx @@ -20,7 +20,6 @@ import { isEqual } from 'lodash' export interface PipelineItem { id: string component: ReactNode - noDivider?: boolean } export interface PipelineProps { @@ -70,7 +69,7 @@ const Pipeline = ({ items, value: baseValue, onChange }: PipelineProps): React.J
{item.component} - {!isLastItem && item.noDivider !== true && ( + {!isLastItem && ( ({ dividerContainer: css` position: relative; - min-width: 16px; + min-width: 24px; outline: none; - padding-top: ${token.paddingXXS}px; - padding-bottom: ${token.paddingXXS}px; `, resizable: css` @@ -26,9 +24,8 @@ export const useStyles = createStyles(({ css, token }) => ({ divider: css` position: absolute; left: 50%; - top: ${token.paddingXXS}px; width: 1px; - height: calc(100% - ${token.paddingXXS * 2}px); + height: 100%; overflow: hidden; background-color: ${token.Divider.colorSplit}; `, diff --git a/assets/js/src/core/components/stack-list/stack-list-item.styles.tsx b/assets/js/src/core/components/stack-list/stack-list-item.styles.tsx index 9d095f24c5..783edb06df 100644 --- a/assets/js/src/core/components/stack-list/stack-list-item.styles.tsx +++ b/assets/js/src/core/components/stack-list/stack-list-item.styles.tsx @@ -14,17 +14,18 @@ export const useStyles = createStyles(({ token, css }) => { return { stackListItem: css` border-radius: 4px; - border: 1px solid ${token.colorBorderSecondary}; + border: 1px solid ${token.colorBorder}; background-color: ${token.colorBgContainer}; .stack-list-item__title { display: flex; align-items: center; - padding: 4px ${token.paddingXS}px 4px 0; + gap: 2px; + padding: 4px; } .stack-list-item__body { - padding: 0 ${token.paddingXS}px; + padding: 0 4px 4px 4px; .ant-picker { width: 100%; @@ -34,15 +35,11 @@ export const useStyles = createStyles(({ token, css }) => { .stack-list-item__content { flex: 1; min-width: 0; // allows the content to shrink and enables text ellipsis - - .ant-tag { - margin-inline-end: 0; - } } &.stack-list-item { .ant-collapse.ant-collapse-small>.ant-collapse-item>.ant-collapse-header { - padding: 0 ${token.paddingXS}px 0 0; + padding: 0; } .ant-collapse.collapse-item--theme-card-with-highlight.collapse-item--bordered, .ant-collapse.collapse-item--theme-default.collapse-item--bordered { diff --git a/assets/js/src/core/components/stack-list/stack-list-item.tsx b/assets/js/src/core/components/stack-list/stack-list-item.tsx index 14aec76e10..863eb571ab 100644 --- a/assets/js/src/core/components/stack-list/stack-list-item.tsx +++ b/assets/js/src/core/components/stack-list/stack-list-item.tsx @@ -107,11 +107,11 @@ export const StackListItem = (props: StackListItemProps): React.JSX.Element => { style={ style } > {leftSidebarContent} } size='small' > diff --git a/assets/js/src/core/components/tabs/tabs.styles.tsx b/assets/js/src/core/components/tabs/tabs.styles.tsx index 17a39987e1..bc8f535101 100644 --- a/assets/js/src/core/components/tabs/tabs.styles.tsx +++ b/assets/js/src/core/components/tabs/tabs.styles.tsx @@ -79,10 +79,6 @@ export const useStyles = createStyles(({ token, css }) => { padding-right: 0; } - &.tabs--no-padding .ant-tabs-nav .ant-tabs-tab + .ant-tabs-tab { - margin-left: ${token.marginSM}px; - } - &.tabs--no-tab-bar-margin.ant-tabs-top>.ant-tabs-nav+.ant-tabs-content-holder { padding-top: 0; } @@ -126,43 +122,10 @@ export const useStyles = createStyles(({ token, css }) => { } &.tabs--full-height { - display: flex; - flex-direction: column; height: 100%; - - .ant-tabs-content-holder { - flex: 1; - min-height: 0; - position: relative; - overflow: hidden; - } - + .ant-tabs-content { - position: absolute; - inset: 0; - } - - .ant-tabs-tabpane { - position: relative; height: 100%; - overflow: hidden; - } - } - - &.tabs--equal-width { - .ant-tabs-nav-list { - width: 100%; - padding-left: 0; - padding-right: 0; - - .ant-tabs-tab { - flex: 1; - justify-content: center; - - + .ant-tabs-tab { - margin-left: 0; - } - } } } `, diff --git a/assets/js/src/core/modules/asset/listing/decorator/column-configuration/view-layer/components/sidebar/tabs/grid-config/grid-config-list.tsx b/assets/js/src/core/modules/asset/listing/decorator/column-configuration/view-layer/components/sidebar/tabs/grid-config/grid-config-list.tsx index 2aa94f05b2..c05f960245 100644 --- a/assets/js/src/core/modules/asset/listing/decorator/column-configuration/view-layer/components/sidebar/tabs/grid-config/grid-config-list.tsx +++ b/assets/js/src/core/modules/asset/listing/decorator/column-configuration/view-layer/components/sidebar/tabs/grid-config/grid-config-list.tsx @@ -8,7 +8,7 @@ * @license Pimcore Open Core License (POCL) */ -import React, { useEffect, useRef, type ReactNode } from 'react' +import React, { type ReactNode } from 'react' import { StackList, type StackListProps } from '@Pimcore/components/stack-list/stack-list' import { Empty, Tag } from 'antd' import { IconButton } from '@Pimcore/components/icon-button/icon-button' @@ -23,16 +23,7 @@ import { type StackListItemProps } from '@Pimcore/components/stack-list/stack-li import { type AvailableColumn } from '@Pimcore/modules/element/listing/decorators/utils/column-configuration/context-layer/provider/available-columns/available-columns-provider' import { isEmptyValue } from '@Pimcore/utils/type-utils' import { hasFieldDefinition } from '@Pimcore/modules/element/listing/decorators/utils/column-configuration/has-field-definition' - -function findScrollableParent (element: HTMLElement | null): HTMLElement | null { - if (element === null || element === document.documentElement) return null - const { overflow, overflowY } = window.getComputedStyle(element) - if (/(auto|scroll)/.test(overflow + overflowY) && element.scrollHeight > element.clientHeight) { - return element - } - return findScrollableParent(element.parentElement) -} - +import { useScrollIntoViewOnAppend } from '@Pimcore/modules/element/listing/decorators/utils/column-configuration/view-layer/hooks/use-scroll-into-view-on-append' interface GridConfigListProps { columns: AvailableColumn[] @@ -50,37 +41,7 @@ export const GridConfigList = ({ columns }: GridConfigListProps): React.JSX.Elem const { setColumns } = useGridConfig() const settings = useSettings() const { t } = useTranslation() - const containerRef = useRef(null) - const prevColumnKeysRef = useRef([]) - const hasMountedRef = useRef(false) - - useEffect(() => { - const currentKeys = columns.map((col) => col.key) - - if (!hasMountedRef.current) { - hasMountedRef.current = true - prevColumnKeysRef.current = currentKeys - return - } - - const prevKeys = prevColumnKeysRef.current - const isAppend = currentKeys.length > prevKeys.length && - prevKeys.every((key, i) => key === currentKeys[i]) - - if (isAppend) { - requestAnimationFrame(() => { - requestAnimationFrame(() => { - const container = containerRef.current - if (container === null) return - const scrollParent = findScrollableParent(container.parentElement) - if (scrollParent === null) return - scrollParent.scrollTo({ top: scrollParent.scrollHeight - scrollParent.clientHeight, behavior: 'smooth' }) - }) - }) - } - - prevColumnKeysRef.current = currentKeys - }, [columns]) + const scrollSentinelRef = useScrollIntoViewOnAppend(columns, (column) => column.key) const stackListItems: ColumnStackListProps['items'] = columns.map((column) => { const uniqueId = uuid() @@ -105,7 +66,6 @@ export const GridConfigList = ({ columns }: GridConfigListProps): React.JSX.Elem { onRemoveColumn(uniqueId) } } - size='small' theme='secondary' /> @@ -117,14 +77,16 @@ export const GridConfigList = ({ columns }: GridConfigListProps): React.JSX.Elem <> { stackListItems.length === 0 && } { stackListItems.length > 0 && ( -
- -
+ ) } +
) diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/advanced-column-form.tsx b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/advanced-column-form.tsx index 2e2ea1fcb7..762bbe7ac3 100644 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/advanced-column-form.tsx +++ b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/advanced-column-form.tsx @@ -68,17 +68,13 @@ export const AdvancedColumnForm = ({ column, onChange, showPreview = true }: Adv > - + + + component: {pipelineLayout === 'default' && ( - - ) - }, + + ) + }, - { - key: 'transformers', - label: t('grid.advanced-column.transformers'), - forceRender: true, - children: ( - - ) - } - ] } + { + key: 'transformers', + label: t('grid.advanced-column.transformers'), + forceRender: true, + children: ( + + ) + } + ] } /> )} diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-item-selection.tsx b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-item-selection.tsx index 4a70fc350d..1587ed1f69 100644 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-item-selection.tsx +++ b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-item-selection.tsx @@ -14,28 +14,10 @@ import { SelectionType } from '@Pimcore/modules/element/element-selector/provide import { useClassDefinitionSelection } from '@Pimcore/modules/data-object/listing/decorator/class-definition-selection/context-layer/provider/use-class-definition-selection' import React from 'react' import { Button } from '@Pimcore/components/button/button' -import { Flex } from '@Pimcore/components/flex/flex' -import { Text } from '@Pimcore/components/text/text' -import { Tooltip } from '@Pimcore/components/tooltip/tooltip' -import { useTranslation } from 'react-i18next' - -interface PreviewItemData { - id?: string | number - fullpath?: string -} - -function truncatePath (fullpath: string): string { - const parts = fullpath.split('/').filter(Boolean) - if (parts.length <= 2) { - return parts.join('/ ') - } - return `.../ ${parts[parts.length - 2]}/ ${parts[parts.length - 1]}` -} export const PreviewItemSelection = (): React.JSX.Element => { - const { item, setItem } = usePreviewItem() + const { setItem } = usePreviewItem() const { selectedClassDefinition } = useClassDefinitionSelection() - const { t } = useTranslation() const { open: openElementSelector } = useElementSelector({ selectionType: SelectionType.Single, @@ -55,26 +37,9 @@ export const PreviewItemSelection = (): React.JSX.Element => { } }) - const data = item?.data as PreviewItemData | undefined - const fullpath = typeof data?.fullpath === 'string' ? data.fullpath : null - const id = data?.id - return ( - - - - {fullpath !== null && ( - - - ID: {id} {'│'} {truncatePath(fullpath)} - - - )} - + ) } diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-loader.styles.ts b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-loader.styles.ts deleted file mode 100644 index 0ad1cc7436..0000000000 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-loader.styles.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * 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 '@Pimcore/modules/ant-design/styles/create-styles' - -export const useStyles = createStyles(({ token, css }) => { - return { - descriptionText: css` - color: ${token.colorTextDescription}; - ` - } -}) diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-loader.tsx b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-loader.tsx index a0a52f823a..ece079c2db 100644 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-loader.tsx +++ b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview-loader.tsx @@ -10,7 +10,6 @@ import React from 'react' import { useTranslation } from 'react-i18next' -import { useStyles } from './preview-loader.styles' import { isUndefined } from 'lodash' import { type AdvancedColumnConfig } from '@Pimcore/modules/asset/asset-api-slice.gen' import { useDataObjectGetGridPreviewQuery } from '@Pimcore/modules/data-object/data-object-api-slice.gen' @@ -36,7 +35,6 @@ export const PreviewLoader = (props: PreviewProps): React.JSX.Element => { const advancedColumnConfig = (column?.__meta?.advancedColumnConfig ?? column.config) as unknown as AdvancedColumnConfig[] | undefined const { t } = useTranslation() - const { styles } = useStyles() const { data, error } = useDataObjectGetGridPreviewQuery({ body: { @@ -55,12 +53,9 @@ export const PreviewLoader = (props: PreviewProps): React.JSX.Element => { return ( <> {!isUndefined(error) && ( - <> - {t('grid.advanced-column.error-preview-data')} - {'error' in error && ( - {error.error} - )} - + + {t('grid.advanced-column.error-preview-data')}: {'error' in error ? error?.error : <>} + )} {isUndefined(error) @@ -71,7 +66,7 @@ export const PreviewLoader = (props: PreviewProps): React.JSX.Element => { ) : ( - {t('grid.advanced-column.no-preview-data')} +
{t('grid.advanced-column.no-preview-data')}
)} ) diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview.styles.ts b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview.styles.ts deleted file mode 100644 index 8ee1849382..0000000000 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview.styles.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * 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 '@Pimcore/modules/ant-design/styles/create-styles' - -export const useStyles = createStyles(({ token, css }) => { - return { - noPreviewText: css` - color: ${token.colorTextDescription}; - ` - } -}) diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview.tsx b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview.tsx index 0defe0f46c..26bfae7515 100644 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview.tsx +++ b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/forms/advanced-column-form/preview/preview.tsx @@ -17,7 +17,6 @@ import { useData } from '@Pimcore/modules/element/listing/abstract/data-layer/pr import { PreviewLoader } from './preview-loader' import { useDebounce } from '@Pimcore/utils/hooks/use-debounce' import { useTranslation } from 'react-i18next' -import { useStyles } from './preview.styles' export interface PreviewProps { column: AvailableColumn @@ -28,22 +27,21 @@ export const Preview = (props: PreviewProps): React.JSX.Element => { const hasFirstItem = gridData?.items.length > 0 && gridData?.items?.[0] !== undefined const bufferedColumn = useDebounce(props.column, 300) const { t } = useTranslation() - const { styles } = useStyles() return useMemo(() => ( - + - {t('grid.advanced-column.preview')} + {t('grid.advanced-column.preview')}: {hasFirstItem ? ( ) : ( - {t('grid.advanced-column.no-preview')} + {t('grid.advanced-column.no-preview')} )} diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-list.tsx b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-list.tsx index 79856b2020..ef297dc3a9 100644 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-list.tsx +++ b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-list.tsx @@ -8,7 +8,7 @@ * @license Pimcore Open Core License (POCL) */ -import React, { useEffect, useMemo, useRef, type ReactNode } from 'react' +import React, { useMemo, type ReactNode } from 'react' import { StackList, type StackListProps } from '@Pimcore/components/stack-list/stack-list' import { Empty, Tag } from 'antd' import { IconButton } from '@Pimcore/components/icon-button/icon-button' @@ -23,16 +23,7 @@ import { Tooltip } from '@Pimcore/components/tooltip/tooltip' import { PermissionBasedLanguageSelectionControl } from '@Pimcore/modules/element/components/language-selection/permission-based-language-selection-control' import { isEmptyValue } from '@Pimcore/utils/type-utils' import { hasFieldDefinition } from '@Pimcore/modules/element/listing/decorators/utils/column-configuration/has-field-definition' - -function findScrollableParent (element: HTMLElement | null): HTMLElement | null { - if (element === null || element === document.documentElement) return null - const { overflow, overflowY } = window.getComputedStyle(element) - if (/(auto|scroll)/.test(overflow + overflowY) && element.scrollHeight > element.clientHeight) { - return element - } - return findScrollableParent(element.parentElement) -} - +import { useScrollIntoViewOnAppend } from '@Pimcore/modules/element/listing/decorators/utils/column-configuration/view-layer/hooks/use-scroll-into-view-on-append' interface ColumnStackListItemProps extends StackListItemProps { meta: AvailableColumn @@ -45,49 +36,7 @@ interface ColumnStackListProps extends Omit { export const GridConfigList = (): React.JSX.Element => { const { setColumns, columns } = useGridConfig() const { t } = useTranslation() - const containerRef = useRef(null) - const prevColumnKeysRef = useRef([]) - const hasMountedRef = useRef(false) - - useEffect(() => { - const currentKeys = columns.map((col) => col.__meta?.uniqueId ?? col.key) - - if (!hasMountedRef.current) { - hasMountedRef.current = true - prevColumnKeysRef.current = currentKeys - return - } - - const prevKeys = prevColumnKeysRef.current - const isAppend = currentKeys.length > prevKeys.length && - prevKeys.every((key, i) => key === currentKeys[i]) - - if (isAppend) { - const isAdvanced = columns[columns.length - 1]?.key === 'advanced' - - requestAnimationFrame(() => { - requestAnimationFrame(() => { - const container = containerRef.current - if (container === null) return - - const scrollParent = findScrollableParent(container.parentElement) - if (scrollParent === null) return - - if (isAdvanced) { - const items = container.querySelectorAll('.stack-list__item') - const lastItem = items[items.length - 1] - if (lastItem === undefined) return - const itemTop = lastItem.getBoundingClientRect().top - scrollParent.getBoundingClientRect().top + scrollParent.scrollTop - scrollParent.scrollTo({ top: itemTop - 8, behavior: 'smooth' }) - } else { - scrollParent.scrollTo({ top: scrollParent.scrollHeight - scrollParent.clientHeight, behavior: 'smooth' }) - } - }) - }) - } - - prevColumnKeysRef.current = currentKeys - }, [columns]) + const scrollSentinelRef = useScrollIntoViewOnAppend(columns, (column) => column.key) const stackListItems: ColumnStackListProps['items'] = useMemo(() => columns.map((column) => { const uniqueId = column.__meta?.uniqueId ?? uuid() @@ -131,7 +80,6 @@ export const GridConfigList = (): React.JSX.Element => { { onRemoveColumn(uniqueId) } } - size='small' theme='secondary' /> @@ -143,14 +91,16 @@ export const GridConfigList = (): React.JSX.Element => { <> { stackListItems.length === 0 && } { stackListItems.length > 0 && ( -
- -
+ ) } +
) diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-modal.styles.ts b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-modal.styles.ts index 44f5ea3779..f58f258124 100644 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-modal.styles.ts +++ b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-modal.styles.ts @@ -23,7 +23,6 @@ export const useStyles = createStyles(({ css, token }) => { min-width: 0; height: 100%; overflow-y: auto; - padding-right: ${token.paddingXS}px; ` } }) diff --git a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-modal.tsx b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-modal.tsx index f7226cb397..f1fd615deb 100644 --- a/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-modal.tsx +++ b/assets/js/src/core/modules/data-object/listing/decorator/column-configuration/view-layer/components/grid/hooks/use-grid-options/tabs/grid-config/grid-config-modal.tsx @@ -16,7 +16,6 @@ import { Toolbar } from '@Pimcore/components/toolbar/toolbar' import { useTranslation } from 'react-i18next' import { Button } from '@Pimcore/components/button/button' import { Space } from '@Pimcore/components/space/space' -import { IconButton } from '@Pimcore/components/icon-button/icon-button' import { Content } from '@Pimcore/components/content/content' import { GridConfigList } from './grid-config-list' import { AddColumnControls } from '@Pimcore/modules/element/listing/decorators/utils/column-configuration/view-layer/components/add-column-controls/add-column-controls' @@ -66,7 +65,7 @@ export const GridConfigModal = (props: GridConfigModalProps): React.JSX.Element size="XL" title={ ( - { t('listing.grid-config.title') } + Grid Config ) } > @@ -98,7 +97,7 @@ export const GridConfigModal = (props: GridConfigModalProps): React.JSX.Element - -