From 4702eb9f18d4ef8a06c2629b5605f41580324e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Tue, 22 Sep 2026 13:43:04 +0200 Subject: [PATCH 01/11] New config UI. Admin -> Administration --- .../administration/admin_panel/admin_panel.md | 5 +- .../admin_panel/corporate_admin_panel.md | 2 +- .../admin_panel/roles_admin_panel.md | 2 +- .../system_information_admin_panel.md | 3 +- .../admin_panel/url_management_admin_panel.md | 4 +- .../admin_panel/users_admin_panel.md | 2 +- .../configuration/configuration.md | 27 ++- .../img/siteaccess_configuration.png | Bin 0 -> 20408 bytes .../img/siteaccess_configuration_blocks.png | Bin 0 -> 28666 bytes .../content_organization/content_types.md | 4 +- .../content_organization/sections.md | 2 +- .../recent_activity/recent_activity.md | 2 +- docs/ai/ai_actions/ai_actions_guide.md | 6 +- docs/content_management/content_model.md | 2 +- docs/content_management/content_relations.md | 2 +- docs/content_management/locations.md | 2 +- .../url_management/url_management.md | 4 +- .../customer_portal_guide.md | 2 +- docs/getting_started/first_steps.md | 6 +- docs/ibexa_products/editions.md | 62 ------ docs/ibexa_products/ibexa_experience.md | 135 ------------- docs/ibexa_products/ibexa_headless.md | 184 ------------------ .../security/security_checklist.md | 2 +- docs/multisite/languages/languages.md | 4 +- docs/multisite/multisite.md | 2 +- docs/multisite/multisite_configuration.md | 37 ---- docs/on_premise.md | 7 - docs/permissions/limitation_reference.md | 6 +- docs/permissions/permission_use_cases.md | 2 +- docs/release_notes.md | 10 +- docs/users/user_management_guide.md | 2 +- main.py | 7 +- mkdocs.yml | 8 +- tests/yaml-validation-baseline.yaml | 5 - 34 files changed, 66 insertions(+), 484 deletions(-) create mode 100644 docs/administration/configuration/img/siteaccess_configuration.png create mode 100644 docs/administration/configuration/img/siteaccess_configuration_blocks.png delete mode 100644 docs/ibexa_products/editions.md delete mode 100644 docs/ibexa_products/ibexa_experience.md delete mode 100644 docs/ibexa_products/ibexa_headless.md delete mode 100644 docs/multisite/multisite_configuration.md delete mode 100644 docs/on_premise.md diff --git a/docs/administration/admin_panel/admin_panel.md b/docs/administration/admin_panel/admin_panel.md index 5b4f0abe15c..5e3da9599c7 100644 --- a/docs/administration/admin_panel/admin_panel.md +++ b/docs/administration/admin_panel/admin_panel.md @@ -6,9 +6,9 @@ page_type: landing_page # Admin panel Once you set up your environment you can start your work as an administrator. -You can find key tools in **Admin** panel. +You can find key tools in **Administration** panel. -To access **Admin** panel, click the icon: ![Admin panel Icon](admin_panel_icon.png){.inline-image}. +To access **Administration** panel, click the icon: ![Admin panel Icon](admin_panel_icon.png){.inline-image}. [[= cards([ "administration/admin_panel/users_admin_panel", @@ -19,4 +19,5 @@ To access **Admin** panel, click the icon: ![Admin panel Icon](admin_panel_icon. "administration/admin_panel/corporate_admin_panel", "administration/admin_panel/workflow_admin_panel", "administration/admin_panel/system_information_admin_panel", + "administration/configuration/configuration", ], columns=4) =]] diff --git a/docs/administration/admin_panel/corporate_admin_panel.md b/docs/administration/admin_panel/corporate_admin_panel.md index 43810c4808b..1e027ab6831 100644 --- a/docs/administration/admin_panel/corporate_admin_panel.md +++ b/docs/administration/admin_panel/corporate_admin_panel.md @@ -4,7 +4,7 @@ description: You can manage companies profiles in the Admin Panel. # Corporate -You can manage companies profiles in the **Admin** panel. +You can manage companies profiles in the **Administration** panel. There, in the **Corporate** section, you can find basic information about existing companies, for example, details, versions, locations, translations, a list of members, billing addresses, and technical details regarding the organization, such as visibility, IDs, or relations. diff --git a/docs/administration/admin_panel/roles_admin_panel.md b/docs/administration/admin_panel/roles_admin_panel.md index 59507440006..92a6897df8c 100644 --- a/docs/administration/admin_panel/roles_admin_panel.md +++ b/docs/administration/admin_panel/roles_admin_panel.md @@ -4,7 +4,7 @@ description: To give users an access to your website you need to assign them rol # Roles -To give users an access to your website you need to assign them roles in the **Admin** panel. +To give users an access to your website you need to assign them roles in the **Administration** panel. ![Roles](admin_panel_roles.png "Roles") diff --git a/docs/administration/admin_panel/system_information_admin_panel.md b/docs/administration/admin_panel/system_information_admin_panel.md index 37be8c2c220..b23c54b4410 100644 --- a/docs/administration/admin_panel/system_information_admin_panel.md +++ b/docs/administration/admin_panel/system_information_admin_panel.md @@ -4,7 +4,6 @@ description: System information provides basic system information such as versio # System Information -The System Information panel in the back office is sourced in the [`ibexa/system-info` repository](https://github.com/ibexa/system-info). -There you can also find basic system information such as versions of all installed packages. +The System Information panel in the back office displays information about your content repository, for example, the number of publish content objects or the number of users in the system. ![System Information](admin_panel_system_info.png "System Information") diff --git a/docs/administration/admin_panel/url_management_admin_panel.md b/docs/administration/admin_panel/url_management_admin_panel.md index 132d65d6e34..7e5d8ce7c0e 100644 --- a/docs/administration/admin_panel/url_management_admin_panel.md +++ b/docs/administration/admin_panel/url_management_admin_panel.md @@ -1,10 +1,10 @@ --- -description: URL Management lets you manage external URL addresses and URL wildcards. +description: URL Management lets you manage external URL addresses. --- # URL Management -You can manage external URL addresses and URL wildcards in the **Admin** panel. +You can manage external URL addresses in the **Administration** panel. Configure URL aliases to have human-readable URL addresses throughout your system. For more information, see [URL management](url_management.md). diff --git a/docs/administration/admin_panel/users_admin_panel.md b/docs/administration/admin_panel/users_admin_panel.md index 9190dc32a83..da15b8c379c 100644 --- a/docs/administration/admin_panel/users_admin_panel.md +++ b/docs/administration/admin_panel/users_admin_panel.md @@ -6,7 +6,7 @@ description: You can access all users and user groups in the Users tab. [Users](users.md) in [[= product_name =]] are treated the same way as content items. They're organized in groups such as *Guests*, *Editors*, *Anonymous*, which makes it easier to manage them and their permissions. -You can access all users and user groups in the **Admin** panel by selecting **Users**. +You can access all users and user groups in the **Administration** panel by selecting **Users**. ![Users and user groups](admin_panel_users.png "Users and user groups") diff --git a/docs/administration/configuration/configuration.md b/docs/administration/configuration/configuration.md index a0586b97e4e..e92ae5d7f3a 100644 --- a/docs/administration/configuration/configuration.md +++ b/docs/administration/configuration/configuration.md @@ -1,13 +1,30 @@ --- -description: In Cohesivo you store and manage configuration in project files, typically in YAML format. +description: Manage your Cohesivo configuration. --- # Configuration -TODO: Rework this to describe the SiteAccess UI, and siteacces-aware settings. +To manage the configuration of your [[= product_name =]] sites, go to the **SiteAccess Configuration** screen in the **Administration** tab. +It exposes settings that you can change directly in the back office, without deploying any code. -Merge the content from docs/multisite/siteaccess/siteaccess_aware_configuration.md +!!! note "On-premise configuration" -## `admin` SiteAccess + The Configuration UI replaces the [YAML configuration layer]([[= on_premise_doc =]]/administration/configuration/configuration/) you know from on-premise version of [[= product_name =]]. -The predefined `admin` SiteAccess in `admin_group` serves the back office. +## Configuration scopes + +Configuration is [SiteAccess](siteaccess.md)-aware, so the same setting can have a different value on each of your sites. + +![SiteAccess Configuration screen](siteaccess_configuration.png "SiteAccess Configuration screen") + +You can set the default configuration, or choose a SiteAccess to configure a specific one: + +- To edit the default values, don't select any SiteAccess from the list. Values you set apply for all SiteAccesses unless a SiteAccess overrides them. +- To edit the values for one SiteAccess, select its SiteAccess first. Values saved for a SiteAccess override the default values. + +## Editing configuration + +After you choose an available configuration, follow the displayed instructions to learn more about the given setting and how to configure it. +Once you're done, use the "Generated Parameters" section to verify your configuration is correct. + +![Page Builder block overrides](siteaccess_configuration_blocks.png "Page Builder block overrides") diff --git a/docs/administration/configuration/img/siteaccess_configuration.png b/docs/administration/configuration/img/siteaccess_configuration.png new file mode 100644 index 0000000000000000000000000000000000000000..c362d5d6af0c33750a6f6a757020106f00241e4a GIT binary patch literal 20408 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%0DsZbT&f&2CWLy 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 literal 0 HcmV?d00001 diff --git a/docs/administration/configuration/img/siteaccess_configuration_blocks.png b/docs/administration/configuration/img/siteaccess_configuration_blocks.png new file mode 100644 index 0000000000000000000000000000000000000000..ca775ab7736c2efd436c6b830b7de97635bf4018 GIT binary patch literal 28666 zcmd43byQUE`!>?;r13>x?ehZf5U!_TJBP-`9Oz*F8b+<)yG55k11dz`&AzE3Slrakm}= z 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 **Activity list**, the dashboard's **Recent activity** block, and the user profile's **Recent activity**. +The [`activity_log/read`](policies.md#activity-log) policy gives a role the access to the **Administration** -> **Activity list**, the dashboard's **Recent activity** block, and the user profile's **Recent activity**. It can be limited to "Only own logs" ([`ActivityLogOwner`](limitation_reference.md#activity-log-owner-limitation)). The policy should be given to every roles having access to the back office, at least with the `ActivityLogOwner` owner limitation, to allow them to use the "Recent activity" block in the dashboard. diff --git a/docs/ai/ai_actions/ai_actions_guide.md b/docs/ai/ai_actions/ai_actions_guide.md index e5afd50a628..a676867e8a3 100644 --- a/docs/ai/ai_actions/ai_actions_guide.md +++ b/docs/ai/ai_actions/ai_actions_guide.md @@ -65,7 +65,7 @@ By defining AI action types, developers can create a wide range of functionaliti #### AI action configuration AI action configurations store detailed parameters needed to generate AI actions based on AI action types. -Website administrators manage AI action configurations in the [**Admin** panel](admin_panel.md), where they customize and fine-tune the behavior of each AI action. +Website administrators manage AI action configurations in the [**Administration** panel](admin_panel.md), where they customize and fine-tune the behavior of each AI action. It might involve setting specific parameters used by the AI service, a response length, an expense limit, or configuring how the output should be handled. By making such adjustments, administrators can ensure that the actions are tailored to meet the needs of your organization. @@ -81,7 +81,7 @@ Handlers take parameters defined in the AI action type and configuration, combin Among other elements, AI Actions include UI components that are used in: -- AI action management in the **Admin** panel +- AI action management in the **Administration** panel - text modification in online editor - alt-text generation in the image management modal @@ -104,7 +104,7 @@ Additionally, AI action configurations can be enabled or disabled depending on t ![Configurations management screen](img/ai_actions_list.png) -An intuitive AI Actions interface within the **Admin** panel displays a list of all available AI actions. +An intuitive AI Actions interface within the **Administration** panel displays a list of all available AI actions. Here, you can search for specific actions and filter them by type or status. By accessing the detailed view of individual AI actions, you can quickly review all their parameters. diff --git a/docs/content_management/content_model.md b/docs/content_management/content_model.md index a20aef73daa..91865e2cdef 100644 --- a/docs/content_management/content_model.md +++ b/docs/content_management/content_model.md @@ -63,7 +63,7 @@ It's [set per content type](content_availability.md). **`remoteId`** - a global unique ID of the content item. Accepts up to 100 characters. Cannot contain non-printable characters and control sequences (anything in ASCII range `\x00` - `\x1F`). -It's recommended to either let this value be generated by the Public PHP API as an MD5 hash, or at least to generate it as a hash (for example, one from SHA family). +It's recommended to either let this value be generated by the API, or at least to generate it as a hash (for example, one from SHA family). **`mainLanguageCode`** - the main language code of the content item. If the `alwaysAvailable` flag is set to true, the content item is shown in this language when the requested language doesn't exist. diff --git a/docs/content_management/content_relations.md b/docs/content_management/content_relations.md index 3ec699cf893..92f56675d09 100644 --- a/docs/content_management/content_relations.md +++ b/docs/content_management/content_relations.md @@ -21,7 +21,7 @@ These fields allow you to select one or more other content items in the field va *Relations at content item level* can be of three different types: -- *Common Relations* are created between two content items using the public PHP API. +- *Common Relations* are created between two content items by using the back office or [API](/api/rest_api/rest_api_reference/rest_api_reference.html#tag/Objects/operation/ibexa.rest.create_relation). - *RichText linked Relations* are created using a field of the RichText type. When an internal link (a link to another location or content item) is placed in a RichText field, the system automatically creates a Relation. diff --git a/docs/content_management/locations.md b/docs/content_management/locations.md index 5a5ac9e89fd..b1433d7002d 100644 --- a/docs/content_management/locations.md +++ b/docs/content_management/locations.md @@ -65,7 +65,7 @@ A user is simply a content item of the user account content type. The users are organized within user group content items below this location. In other words, the **Users** location contains the actual users and user groups, -which can be viewed by selecting the **Users** tab in the **Admin** Panel. +which can be viewed by selecting the **Users** tab in the **Administration** Panel. ### Forms diff --git a/docs/content_management/url_management/url_management.md b/docs/content_management/url_management/url_management.md index 71c41879c56..f2f3e5d4e9e 100644 --- a/docs/content_management/url_management/url_management.md +++ b/docs/content_management/url_management/url_management.md @@ -1,11 +1,11 @@ --- -description: Manage URL aliases and wildcards, and validate external URLs. +description: Manage URL aliases and validate external URLs. month_change: false --- # URL management -You can manage external URL addresses and URL wildcards in the back office, **Admin** tab, the **URL Management** node. +You can manage external URL addresses in the back office, **Administration** tab, the **URL Management** node. Configure URL aliases to have human-readable URL addresses throughout your system. ## Link manager diff --git a/docs/customer_management/customer_portal_guide.md b/docs/customer_management/customer_portal_guide.md index b3dccd0ee7f..b0b0913390e 100644 --- a/docs/customer_management/customer_portal_guide.md +++ b/docs/customer_management/customer_portal_guide.md @@ -58,7 +58,7 @@ You can also set up policies for every user who has a business account by editin ### Members Company members aren't standard users. They belong to a separate category called Corporate Accounts. -This category is located in **Admin** -> **Corporate** -> **Corporate Accounts**. +This category is located in **Administration** -> **Corporate** -> **Corporate Accounts**. There, you can find a list of companies and their members. This feature comes with a set of new roles: diff --git a/docs/getting_started/first_steps.md b/docs/getting_started/first_steps.md index ad4fe636179..e41d29d6095 100644 --- a/docs/getting_started/first_steps.md +++ b/docs/getting_started/first_steps.md @@ -62,7 +62,7 @@ For more information, see [Multisite](multisite.md) and [SiteAccess](siteaccess. One of the most common use cases for SiteAccesses is having different language versions of a site. -1\. Go to the back office and select **Admin** > **Languages**. Add a new language called "German", with the language code `ger-DE`. +1\. Go to the back office and select **Administration** > **Languages**. Add a new language called "German", with the language code `ger-DE`. Make sure it's enabled. ![Creating a language](first-steps-create-language.png) @@ -87,7 +87,7 @@ Users and user groups are assigned roles. A role can contain a number of policies, which are rules that permit the user to perform a specific function. Policies can be additionally restricted by limitations. -1\. Go to **Admin** -> **Users**. +1\. Go to **Administration** -> **Users**. Create a new user group (the same way you create regular content). Call the group "Bloggers". @@ -97,7 +97,7 @@ Mark the user as "Enabled". ![Creating a User](first-steps-create-user.png) -3\. Go to **Admin** -> **Roles**. +3\. Go to **Administration** -> **Roles**. Create a new role called "Blogger". 4\. Add the following policies to ensure the user can log in and access content: diff --git a/docs/ibexa_products/editions.md b/docs/ibexa_products/editions.md deleted file mode 100644 index f31643e3c0e..00000000000 --- a/docs/ibexa_products/editions.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -description: Learn more about various Cohesivo editions' features to help yourself choose the right one for your project. -page_type: landing_page ---- - -# [[= product_name =]] editions - -Three [[= product_name =]] product editions are available to help you accelerate your digital transformation at the speed and cost that work best for you. - -[[= cards([ - "ibexa_products/ibexa_headless", - "ibexa_products/ibexa_experience", -], columns=3) =]] - -## Feature comparison - -Compare all features available in [[= product_name_headless =]], [[= product_name_exp =]], and [[= product_name_com =]] to help you choose the right products for your needs: - -| Feature | [[= product_name_headless =]] | [[= product_name_exp =]] | [[= product_name_com =]] | -|-----------------|-----------------|-----------------|-----------------| -| [Content model](content_model.md) | ✔ | ✔ | ✔ | -| [AI Actions](ai_actions_guide.md) | ✔ | ✔ | ✔ | -| [User management](user_management_guide.md) | ✔ | ✔ | ✔ | -| [Focus Mode]([[= user_doc =]]/getting_started/discover_ui/#focus-mode) | ✔ | ✔ | ✔ | -| [Image editor]([[= user_doc =]]/image_management/edit_images/) | ✔ | ✔ | ✔ | -| [Content scheduler]([[= user_doc =]]/content_management/schedule_publishing/) | ✔ | ✔ | ✔ | -| [SEO]([[= user_doc =]]/search_engine_optimization/seo/) | ✔ | ✔ | ✔ | -| [Content translation]([[= user_doc =]]/content_management/translate_content/) | ✔ | ✔ | ✔ | -| [Search]([[= user_doc =]]/search/search_for_content/) | ✔ | ✔ | ✔ | -| [Editorial workflow]([[= user_doc =]]/content_management/workflow_management/editorial_workflow/) | ✔ | ✔ | ✔ | -| [Digital Asset Management]([[= user_doc =]]/dam/ibexa_dam/) | ✔ | ✔ | ✔ | -| [Product catalog capabilities]([[= user_doc =]]/product_catalog/product_catalog/) | ✔ | ✔ | ✔ | -| [Date and time attribute type](date_and_time.md) | ✔ | ✔ | ✔ | -| [Symbol attribute type](symbol_attribute_type.md) | ✔ | ✔ | ✔ | -| [Recommendations](raptor_connector_guide.md) | ✔ | ✔ | ✔ | -| Migrations | ✔ | ✔ | ✔ | -| [[[= product_name_connect =]]]([[= connect_doc =]]/) | ✔ | ✔ | ✔ | -| OAuth client | ✔ | ✔ | ✔ | -| OAuth Server | ✔ | ✔ | ✔ | -| [Site Factory](site_factory.md) | | ✔ | ✔ | -| [Customizable Dashboard]([[= user_doc =]]/getting_started/dashboard/work_with_dashboard/#customize-dashboard) | | ✔ | ✔ | -| [Page Builder](page_builder_guide.md) | | ✔ | ✔ | -| [Form Builder](form_builder_guide.md) | | ✔ | ✔ | -| [Scheduler tab]([[= user_doc =]]/content_management/schedule_publishing/#scheduler-tab) | | ✔ | ✔ | -| [Content Scheduler block]([[= user_doc =]]/content_management/schedule_publishing/#content-scheduler-block) | | ✔ | ✔ | -| [Corporate account management]([[= user_doc =]]/customer_management/manage_customers/) | | ✔ | ✔ | -| [Customer Portal](customer_portal_guide.md) | | ✔ | ✔ | -| [Segments](segments_admin_panel.md) | | ✔ | ✔ | -| [Recent activity](recent_activity.md) | | ✔ | ✔ | -| [[[= product_name_engage =]] add-on]([[= user_doc =]]/qualifio/qualifio/) | | ✔ | ✔ | -| [[[= product_name_cdp =]] (Customer Data Platform) add-on](/raptor_cdp/raptor_cdp_guide.md) | | ✔ | ✔ | - -## LTS Updates - -LTS Updates are opt-in packages that bring additional features to the LTS releases that they enhance. -The features brought by LTS Updates become standard parts of the next LTS release. - -| Feature | [[= product_name_headless =]] | [[= product_name_exp =]] | [[= product_name_com =]] | -|-----------------|-----------------|-----------------|-----------------| -| [Integrated help](integrated_help.md) | ✔ | ✔ | ✔ | -| [MCP servers](mcp_guide.md) | ✔ | ✔ | ✔ | -| [Translations management](translations_management_guide.md) | ✔ | ✔ | ✔ | diff --git a/docs/ibexa_products/ibexa_experience.md b/docs/ibexa_products/ibexa_experience.md deleted file mode 100644 index 5d7983eea30..00000000000 --- a/docs/ibexa_products/ibexa_experience.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -description: Learn about all the main attributes, features, and benefits of the customer-focused Ibexa Experience edition. -month_change: false ---- - -# [[= product_name_exp =]] edition product guide - -## What is [[= product_name_exp =]] - -[[= product_name_exp =]] is a [[= product_name =]] edition that focuses on the customer. -It offers smooth consumer journey and great online experience. In everything you do, it places your clients first. -With Experience edition you can empower Editors to quickly create new pages or personalized content, and improve their daily work. -It also provides tools for using segmentation and targeting, and it can be widely used in B2B thanks its features and integrations. - -## Availability - -To start using [[= product_name_exp =]], you need to purchase a product license. - -For more information, see [[[= product_name_exp =]] license pricing](https://www.ibexa.co/products/pricing?tab=2). -You can also [contact us](https://www.ibexa.co/about-ibexa/contact-us) or [one of our partners](https://www.ibexa.co/partners). - -## How it works - -### Technical backstage - -[[= product_name_exp =]] is based on [Symfony]([[= symfony_doc =]]). -With a help of documentation and trainings, any developer familiar with Symfony or simply PHP may learn how to use available extension points and extend the platform. - -[[= product_name_exp =]] is built on top of [[[= product_name_headless =]]](ibexa_headless.md), therefore it includes all bundles, APIs, and [features that come with Headless edition](ibexa_headless.md#core-features), but also more advanced features for digital experience management. - -Version control systems and environment variables allow you to deploy your projects and settings on several environments, such as [[= product_name_cloud =]]. - -## Capabilities and benefits - -With [[= product_name_exp =]] you can focus on your customers and treat each one as a VIP. -It has everything that you may need to offer a transformative digital experience, from developing new websites or portals, through eye-catching landing pages and personalized product suggestions, to managing SEO strategies across several locations. - -### Core features - -[[= product_name_exp =]] comes with a variety of new features designed to help you create an exceptional customer experience. - -#### Page Builder - -[[= product_name_exp =]] brings the [Page Builder](page_builder_guide.md), a powerful visual tool that helps you design and modify pages, without requiring advanced technical skills. -With its intuitive and user-friendly interface, you can develop pages, tailor content, and create perfectly targeted landing pages. -You build pages from ready-to-use elements called blocks, which can be easily configured and customized to suit your needs. -Before you start building a page, you also need to select a layout. It has a significant impact on how the content pieces in the drop zones are arranged. - -#### Form Builder - -[Form Builder](form_builder_guide.md) is an intuitive tool that allows you to transform user engagement on your website. -With this tool, you can design, deploy, and manage online forms quickly. -You can create a variety of forms that consist of different fields, including sign-up forms, surveys, or questionnaires. -Additionally, you can monitor and manage the information obtained from website visitors and adjust your forms if needed. - -#### Site Factory - -[Site Factory](site_factory.md) is a site management interface, integrated with the back office. -It enables you to configure new sites without leaving the administration interface and editing SiteAccess configuration. -With this feature you can create and deploy multiple websites at lightning speed and at scale. -It allows you to manage expenses and resources while industrializing your web presence. -Additionally, together with localized information and tailored product catalogs and prices, it helps you to quickly enter new markets. - -#### Customizable dashboard - -Starting from Experience edition of [[= product_name =]] you can [customize the dashboard]([[= user_doc =]]/getting_started/dashboard/work_with_dashboard/#customize-dashboard), and you do it with the Dashboard Builder. -You can tailor dashboard to your specific needs by choosing from a set of widgets. -You can easily preview the sections that you use more often and omit the less significant ones. - -#### Publish Later - -You can take complete control of where and when your content blocks are visible to your predefined audiences and [schedule content publication]([[= user_doc =]]/content_management/schedule_publishing/). -[[= product_name_exp =]] comes with a Publish Later feature that allows you to schedule personalized content and reach different user groups at optimal dates and times to boost performance. -What's more, you can turn specific content pages and blocks on and off to meet the needs of your marketing campaigns and promotions. -Publish Later feature combined with Page Builder allows you to see all changes that you plan for the future. To do it, just use the slider to see all the upcoming changes. - -#### Customer Portal - -Use the [Customer Portal](customer_portal.md) and customer management capabilities that come with it, to establish new corporate accounts, manage existing ones, and communicate with your partners within a personalized space. -With the help of this feature, you can create customized areas that give users a smooth, integrated experience and provide them with access to a variety of resources, apps, and services from a single point of entry. -Using this tool, your customers can change their organization details, invite and see members, self-register, and more. - -#### Segments - -[Segmentation](segments_admin_panel.md) allows you to split up the user base. -By assigning users to segments, you can display specific content to selected visitors and tailor the content that they can see. -One of the tools that you can use right out of the box is the Targeting block that is available in the Page Builder. -Segmentation is also useful with the [Recommendations](raptor_connector_guide.md). -You can assign users to different recommendation groups and create advanced logic with operators to provide your audience with the best recommendations. - -#### [[= product_name_cdp =]] (Customer Data Platform) - -[[[= product_name_cdp =]]](/raptor_cdp/raptor_cdp_guide.md) is an add-on available for the Experience edition of [[= product_name =]]. -To use it, you must make arrangements with [[= product_name_base =]] to define the initial configuration. -Once you activate [[= product_name_cdp =]], you can create complete customer profiles, including their interactions, behavior, and preferences. -It helps you improve user engagement, conversion rates, and return on investment by segmenting your audience and delivering tailored campaigns and experiences. -Additionally, you can manage and analyze campaigns, evaluate customer data, and identify the best ways to improve performance. -By using [[= product_name_cdp =]] you can store and manage large volumes of customer data in a structured manner. -This central data storage supports business growth with a scalable infrastructure, helping to futureproof your business. - -![CDP](../raptor_cdp/img/cdp.png) - -#### [[= product_name_engage =]] - -Another add-on available for the Experience edition is [[[= product_name_engage =]]](/qualifio/qualifio.md). -To use it, you must make arrangements with [[= product_name_base =]] to define the initial configuration, and then get and set up a user account. -[[= product_name_engage =]] is a data collection tool. -It gives you the ability to use the [Qualifio](https://qualifio.com/en) tools to engage your audiences. You can use Qualifio's existing templates and interactive elements, such as quizzes, pools, and forms, to create visually appealing, customized campaigns and collect important data. -To promote your campaign, you can add a Campaign block to a page in Page Builder or embed a campaign within the Rich Text field by using a Campaign custom tag. - -### Use cases - -With [[= product_name_exp =]], your customers are the main focus of all that you do. -It makes it simpler than ever to create the different touchpoints that your customers have with your brand, giving you the ability to guide them through your significant business procedures. - -#### Build new pages and integrated forms - -User interface of [[= product_name_exp =]] is intuitive and plain. -With its new features - Page and Form Builder - you can build new pages or forms quickly efficiently. -Page Builder comes with predefined layouts, blocks, and templates to streamline your design process, while Form Builder provides ready-to-use elements for easy form creation. -You can integrate your custom forms and surveys into the website and reuse content from existing sites on new ones. -With Site Factory, you can publish as many sites as you like, there are no limits. - -#### Target customers in their preferred channels - -To make your products attractive, you must remember each of your customers is unique and special, and tailor your marketing strategy to their needs and preferences. -[[= product_name_exp =]] allows you to deliver personalized content and recommendations through different channels. -With segmentation, you can define audiences to distribute specific content through the right channels, at the right time. -Available add-ons give you even more possibilities. You can analyze customer behaviours, use interactive content, and collect important data. - -#### Build your future - -Planning and scheduling is a part of management. -With scheduling tools available in Experience edition, you can prepare content publishing timetables, schedule how your website can evolve, and test or preview it before publication. -Additionally, you can use editorial calendars for an easier collaboration. diff --git a/docs/ibexa_products/ibexa_headless.md b/docs/ibexa_products/ibexa_headless.md deleted file mode 100644 index 77fe3826ba7..00000000000 --- a/docs/ibexa_products/ibexa_headless.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -description: Get to know Ibexa Headless - an edition that focuses on content management. ---- - -# [[= product_name_headless =]] edition product guide - -## What is [[= product_name_headless =]] - -The Headless edition of [[= product_name =]] focuses on content management. -It provides tools to collaboratively create content, and interfaces (API) to distribute this content. - -Multilingual, multichannel, extensible, [[= product_name_headless =]] is an advanced Content Management Framework (CMF) with product catalog capabilities, and a Digital Asset Management (DAM) repository. -It's provided without a default front office, but with a complete back office and several APIs to manage and access content. - -## Availability - -To start using [[= product_name_headless =]] you must purchase a product license. - -For more information, see [[[= product_name_headless =]] license pricing](https://www.ibexa.co/products/pricing?tab=1). -You can [contact us](https://www.ibexa.co/about-ibexa/contact-us) or [contact one of our partners](https://www.ibexa.co/partners). - -## How it works - -### Editorial stage - -You access with any web browser from any platform to a rich back office, the main place to - -- define users and their rights (for example, customers, subscribers, or editors), -- organize content (content types, fields, tree, tags, languages, and more), -- edit content in a collaborative workplace with versions and workflows. - -Then, content is available to end users through REST, GraphQL, or every output you can imagine like websites or apps. - -### Technical backstage - -When you have a license, you install [[= product_name_headless =]] through Composer on an architecture including at least a web server with PHP and a relational database server. -For performance, several bricks can be added to your stack such as a reverse proxy or a search engine. - -[[= product_name_headless =]] is based on Symfony. Any Symfony developer, or even PHP developer, can quickly learn how to extend it with the help of an online documentation. - -By using a version control system and environment variables, you can deploy your configuration and extensions on several environments including [[= product_name_cloud =]]. - -Standard web APIs and [[[= product_name_connect =]]]([[= connect_doc =]]/general/ibexa_connect/) help establish interoperability, even if you aren't an advanced developer. - -APIs summary: - -- The REST and GraphQL APIs give access to the content in standardized ways. -- The OAuth 2 Client and Server allow to connect to an SSO or be the SSO. -- The design engine and its theme templates mechanism allows to serve the content in several shapes. -- The PHP API opens [[= product_name_headless =]] to extendability to fit your needs. - For example, content can be computed, edited, or served in specific ways such as scheduled/live imports/exports, automated edition tasks, or specific controllers to communicate with other applications. - -## Capabilities and benefits - -[[= product_name_headless =]] is a tool box with a back office. -It comes without a default front office. -You don't lose time to develop a theme for a provided front office before discovering it doesn't fit your needs. -No distraction. -[[= product_name_headless =]] helps you focus on the content, create and organize with its straightforward user interface (UI), imagine its inputs/outputs, and implement them with its various layers' APIs. - -### Core features - -The core of [[= product_name_headless =]] offers everything to structure your content repositories and access them. - -#### Content model - -Content modeling and management are the foundation of [[= product_name =]] with the following main layers: - -- Content items are organized as a tree in a repository. -- An item can have multiple locations in this tree. -- Content items are typed. -- Content types are sets of typed data fields, with optional conditions on the possible values. -- Rich Text field type comes with an [online editor](online_editor_guide.md). -- Multilingual, it can store a content in several languages, the content model defines which field must be translated, and which don't vary. - -For more information, see [Content management product guide](content_management_guide.md). - -#### User management - -User and user group rights are set by roles with thin granular limited permission policies in a safe deny-by-default security system. -Users are content items as well, so your knowledge about content management is reused. - -For more information, see [User management product guide](user_management_guide.md). - -#### Content access - -There are many paths to access the content in many shapes: - -- The REST API and GraphQL API support access to, and edition of the content. -- [[= product_name_headless =]] offers a complete PHP API to extend the ways to access content. -- A design engine and a view controller offer to create plain text content views (such as HTML, JSON, XML, CSS, JS, CSV, or Markdown), - and to factorize those views by using theme cascades. - This design engine is used in the back office which is equally extendable. -- Multichannel, content can be accessed through several channel configurations, - such as the domain name it replies to, the sub-part of the content tree it starts from, the users rights, or the design theme. - The back office itself is such a channel. -- Multi-repository, the same platform can use separate databases if data isolation is needed between channel groups. - -### Advanced features - -On top of this strong core, [[= product_name_headless =]] brings tools to increase user experience, from final front users to back office contributors. - -#### Complete platform - -[[= product_name_headless =]] is a complete platform, which comes with the following components to enhance user's journey: - -- [Recommendations](raptor_connector_guide.md) connector, which allows you to recommend content to end users according to their behavior, - or, when authenticated, by matching with their segment/group. -- Content scheduler, which allows you to establish the future of the content and use events to have a living front application, even when the editorial team is absent or reduced. -This way, visitors can discover new content at midnight, during weekends or vacations. -A calendar summarises those scheduled content events. -Like everything in the back office, the calendar is extendable: you can add an event source to coordinate content events with other company events. - -#### Many ways to structure and organize content - -[Product catalog](product_catalog_guide.md) helps organize complex products and their catalogs: - -- Products are organized by using product types, variants, catalogs, categories, and tags. -- Product attributes are grouped and factorized among product types. For example, fabric + color + size can be shared by many clothing product types. -- Product variants can rapidly be created by the automatic declination of attributes that have a defined set of values. -- With taxonomy, you can tag content items to organize them by topics in a much intuitive way for the editor than a content tree with multiple locations would. -Tags themselves are organized in a tree. -Tag organization can be handled by a supervisor who doesn't need to move content items around a corporate content tree. -At search time, tags can be keywords with a high value in relevance score to help the end user having results closer to the searched topic. - -#### Collaboration - -Several features help end users collaborate on the content, such as: - -- Version comparison helps track changes and solve concurrent editing conflicts. -- Workflows helps with collaborative editing chain. - A built-in “Quick review“ workflow allows an editor to send a content draft to a colleague for review, and comment or publishing. - But, as a framework, more complex workflows can be imagined, with several steps and paths, even some automated tasks. - -#### Accelerated content editing - -- [[= product_name_headless =]]'s content tree has several actions available directly on its items. For example, no need to open a content to hide it, you can do it directly from the content tree. -- An Image Editor offers to crop and flip images. When serving the image in various context, you can even set a focal point to indicate to automated cropping which part of the image should be kept. -- A Digital Asset Management (DAM) helps you crawl through your image resources to use and reuse them in your content. And a DAM connector allows you to search for images hosted on third party DAM servers. -- [AI Actions](ai_actions_guide.md) help you automate time-consuming editorial tasks. - -#### Network integration - -##### Intranets and extranets - -- [[= product_name_connect =]]'s role is to create application interconnections with low code and drag-and-drop, in a compelling visual interface. - Complex data flows can be easily implemented with a huge library of connectors and actions for famous to specific applications. - For more information, see [[[= product_name_connect =]] product guide]([[= connect_doc =]]/general/ibexa_connect/). -- An OAuth 2 server offers the possibility to use the platform as the authentication service for other applications. -- An OAuth 2 client supports authentication with a third-party OAuth 2 server. -- A DAM Connector, previously mentioned, helps to access any image repository when needing to illustrate a content. -- [[= product_name_headless =]] uses Solr as its search engine, which powers full-text search, - Search Criteria, Sort Clauses, and aggregations. -- [[= product_name_headless =]] offers to export and import from command line part of the content model or content items. - For example, it can be used to move new content types and items from a staging instance to the production one. - -##### Internet, delivery, web search engines, and social networks - -- [[= product_name_headless =]] comes with the support of Fastly content delivery network (CDN). - The HTTP cache varies on current user's role and is purged when content changes. - With its huge network of points of presence (POP) around the world, Fastly is quickly delivering cached content from nearest server for a better user experience. -- A Search Engine Optimization (SEO) field implements best practices about web search engine indexing and social network sharing. - It covers canonical URLs which are mandatory if multiple locations are used for a same content item to avoid duplicate content, - Open Graph protocol to better describe a content item to social networks and search engine, and Twitter Cards. - -## Use cases - -As a content repository with an omnipotent back office, many APIs to absorb, compute and distribute content, even a recommendation engine to deliver the right content to various readers, [[= product_name_headless =]] can be used in several cases. -Here are few examples. - -### Brick and mortar, but with an online showcase - -If you prefer the human warmth of a retail store, if your products' numerous complex options should be discussed, -or if you're not ready yet to sell online, [[= product_name_headless =]] helps to build an exposition of your product catalog and your philosophy, an online presence to keep earlier customers interested and gather new ones. -It can be a structuring first step to test customer's adoption of your website, before increasing user experience with [[= product_name_exp =]], and finally becoming an online store with [[= product_name_com =]]. - -### Large network with multiple inputs and outputs - -Departments, subsidiaries, and even partners now produce content in the same repository from the same collaborative workspace. -Thanks to migration feature and PHP API, existing content has been imported from previous repositories. -Fine-tuned user rights and workflows ensure that each collaborator can focus on their own tasks without the risk to disturb the content model or content organization. -Content is distributed on several websites and applications, some running on the [[= product_name_base =]] platform itself, some on third parties' servers, some as native mobile apps. -Part of the content has multiple locations or is translated, and reused from place to place. -While the back office offers to search into the whole repository, the front end apps have correctly circumscribed search capabilities. diff --git a/docs/infrastructure_and_maintenance/security/security_checklist.md b/docs/infrastructure_and_maintenance/security/security_checklist.md index b367a50b2fd..eb355871147 100644 --- a/docs/infrastructure_and_maintenance/security/security_checklist.md +++ b/docs/infrastructure_and_maintenance/security/security_checklist.md @@ -30,7 +30,7 @@ This is specially important for admin accounts and other privileged users. - Never go online with admin password set to `publish` or any other default value. - Introduce password quality checks. Make sure the checks are strict enough (length/complexity). - 16 characters is a quite secure minimum length. Don't go below 10. -- If using [[= product_name =]] v4.5 or newer, enable the password rule that rejects any password which has been exposed in a public breach. +- Enable the password rule that rejects any password which has been exposed in a public breach. !!! tip "Password rules" diff --git a/docs/multisite/languages/languages.md b/docs/multisite/languages/languages.md index 8f2477235c3..5f06bf3ab0a 100644 --- a/docs/multisite/languages/languages.md +++ b/docs/multisite/languages/languages.md @@ -22,7 +22,7 @@ However, even if work on a draft takes time and other translations are updated i ### Adding available languages The multilanguage system operates based on a global translation list that contains all languages available in the installation. -Languages can be [added to this list from the **Admin** panel]([[= user_doc =]]/content_management/translate_content/) in the back office. +Languages can be [added to this list from the **Administration** panel]([[= user_doc =]]/content_management/translate_content/) in the back office. **The new language must then be added to the [SiteAccess](multisite.md) configuration**. Once this is done, any user with proper permissions can create content item versions in these languages in the user interface. @@ -62,7 +62,7 @@ When this SiteAccess is used, the system goes through this list. If a content item is unavailable in the first (prioritized) language, it attempts to use the next language in the list, and more. Thanks to this you can have a fallback in case of a lacking translation. -You can also assign a Default content availability flag to content types (available in the **Admin** panel). +You can also assign a Default content availability flag to content types (available in the **Administration** panel). When this flag is assigned, content items of this type are available even when they don't have a language version in any of the languages configured for the current SiteAccess. If a language isn't provided in the list of prioritized languages and it's not the content item's first language, the URL alias for this content in this language isn't generated. diff --git a/docs/multisite/multisite.md b/docs/multisite/multisite.md index 506c68b3c09..a09b3261b00 100644 --- a/docs/multisite/multisite.md +++ b/docs/multisite/multisite.md @@ -13,7 +13,7 @@ To quickly set up new sites with predefined site templates, use [Site Factory](s [[= cards([ "multisite/siteaccess/siteaccess", - "multisite/multisite_configuration", + "administration/configuration/configuration", "multisite/site_factory/site_factory", "multisite/site_factory/site_factory_configuration", ], columns=3) =]] diff --git a/docs/multisite/multisite_configuration.md b/docs/multisite/multisite_configuration.md deleted file mode 100644 index 35e95c32f2e..00000000000 --- a/docs/multisite/multisite_configuration.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -description: Configure SiteAccesses to serve different content. ---- - -# Multisite configuration - -You can configure the available SiteAccesses by using the [configuration](configuration.md). - -## SiteAccess configuration - -``` yaml -ibexa: - siteaccess: - list: [site, event] - groups: - site_group: [site] - event_group: [event] - default_siteaccess: site - match: - URIElement: 1 -``` - -### SiteAccess groups - -`ibexa.siteaccess.groups` defines which groups SiteAccesses belong to. - -``` yaml -ibexa: - siteaccess: - groups: - site_group: [site] - event_group: [event] -``` - -You can use groups when you want to use common settings for several SiteAccesses and avoid duplicating configuration. -SiteAccess groups act like regular SiteAccesses as far as configuration is concerned. -A SiteAccess can be part of several groups. SiteAccess configuration has always precedence over group configuration. diff --git a/docs/on_premise.md b/docs/on_premise.md deleted file mode 100644 index 23d9fd7e2cc..00000000000 --- a/docs/on_premise.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -description: Cohesivo On-premise ---- - -# Cohesivo On-premise - -TODO: Combine Headless, Experience, Commerce into a product guide for On-Premise diff --git a/docs/permissions/limitation_reference.md b/docs/permissions/limitation_reference.md index c9f2c213cdf..8a19a99ee2d 100644 --- a/docs/permissions/limitation_reference.md +++ b/docs/permissions/limitation_reference.md @@ -161,7 +161,7 @@ The Owner (`Owner`) limitation specifies that only the owner of the content item |Value|UI value|Description| |------|------|------| |`1`|"self"|Only the user who is the owner gets access| -|`2`|"session"|Deprecated and works exactly like "self" in public PHP API since it has no knowledge of user Sessions| +|`2`|"session"|Deprecated and works exactly like "self" since it has no knowledge of user Sessions| ## Owner of Parent limitation @@ -172,7 +172,7 @@ The Owner of Parent (`ParentOwner`) limitation specifies that only the users who |Value|UI value|Description| |------|------|------| |`1`|"self"|Only the user who is the owner of all parent locations gets access| -|`2`|"session"|Deprecated and works exactly like "self" in public PHP API since it has no knowledge of user Sessions| +|`2`|"session"|Deprecated and works exactly like "self" since it has no knowledge of user Sessions| ## Parent Depth limitation @@ -234,7 +234,7 @@ The SiteAccess (`SiteAccess`) limitation specifies to which SiteAccesses a certa ### Legacy compatibility notes -`SiteAccess` limitation is deprecated and isn't used actively in public PHP API, but is allowed for being able to read / create limitations for legacy. +`SiteAccess` limitation is deprecated and isn't used actively, but is allowed for being able to read / create limitations for legacy. ## Subtree limitation diff --git a/docs/permissions/permission_use_cases.md b/docs/permissions/permission_use_cases.md index 6fba39073f8..ca2a7a8199b 100644 --- a/docs/permissions/permission_use_cases.md +++ b/docs/permissions/permission_use_cases.md @@ -85,7 +85,7 @@ You do it by creating two new roles for a user group: Follow the example below to learn how to do that. **Cookbook**, **Dinner recipes** and **Dessert recipes** containers aren't accessible in the frontend. -Edit access to them in the **Admin** panel. +Edit access to them in the **Administration** panel. ![Subtree file structure](subtree_usability_notes_1.png) diff --git a/docs/release_notes.md b/docs/release_notes.md index e9d6c8f4ce9..b5fc7177c28 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -11,19 +11,19 @@ month_change: false
[[% set version = 'v5.0.9' %]] -[[% set date = '2026-07-01' %]] +[[% set date = '2026-10-01' %]] [[= release_note_entry_begin( - 'TODO: Release notes for SaaS', date, - ['New feature'] + ['New feature', 'First release'] ) =]] ### Highlights -- ASD -- QWE +[[= product_name =]] SaaS is now available. + +To learn more about this product, see the [Cohesivo SaaS product guide](TODO: link) and the [official website](https://cohesivo.com/en). [[= release_note_entry_end() =]] diff --git a/docs/users/user_management_guide.md b/docs/users/user_management_guide.md index 222246fc1d8..c16f75900c0 100644 --- a/docs/users/user_management_guide.md +++ b/docs/users/user_management_guide.md @@ -19,7 +19,7 @@ User management is available in all [[= product_name =]] versions. ## How does user management work [[= product_name =]] simplifies user management with an intuitive and powerful system of accounts, roles, permissions, groups, and segments. -You can find all user groups and users in the **Admin** panel by selecting **Users**. +You can find all user groups and users in the **Administration** panel by selecting **Users**. Here, you can manage users, their relations, roles, and policies. ![User's section](users_section.png) diff --git a/main.py b/main.py index 5b6205f4809..99a0ac8be2a 100644 --- a/main.py +++ b/main.py @@ -190,7 +190,7 @@ def release_notes_filters(header : str, categories : List[str]) -> str: """.format(header=header, visible_filters=filters, categories_dropdown=categories_dropdown) @env.macro - def release_note_entry_begin(header : str, date: str, categories : List[str]) -> str: + def release_note_entry_begin(date: str, categories : List[str]) -> str: validate_categories(categories) category_badges = "".join( @@ -204,12 +204,11 @@ def release_note_entry_begin(header : str, date: str, categories : List[str]) -> return """
-## {header} +## {date}
{category_badges}
-
{date}
-""".format(header=header, date=date, category_badges=category_badges) +""".format(date=date, category_badges=category_badges) @env.macro def release_note_entry_end() -> str: diff --git a/mkdocs.yml b/mkdocs.yml index 69b034e1ddf..4863871a6ab 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -20,11 +20,7 @@ not_in_nav: | /snippets/* nav: - Cohesivo Developer Documentation: index.md - - Cohesivo editions: - - On-premise Cohesivo: on_premise.md - - Editions: ibexa_products/editions.md - - Cohesivo Headless: ibexa_products/ibexa_headless.md - - Cohesivo Experience: ibexa_products/ibexa_experience.md + - Cohesivo: - Cohesivo SaaS: ibexa_products/cohesivo_saas_guide.md - Getting started: - Getting started: getting_started/getting_started.md @@ -155,7 +151,6 @@ nav: - Integrate Qualifio with Ibexa Connect: qualifio/integrate_ibexa_connect.md - Multisite: - Multisite: multisite/multisite.md - - Multisite configuration: multisite/multisite_configuration.md - SiteAccess: - SiteAccess: multisite/siteaccess/siteaccess.md - Site Factory: @@ -392,6 +387,7 @@ extra: symfony_version: '7.4' symfony_doc: 'https://symfony.com/doc/7.4' user_doc: 'https://doc.ibexa.co/projects/userguide/en/saas' + on_premise_doc: 'https://doc.ibexa.co/en/latest' connect_doc: 'https://doc.ibexa.co/projects/connect/en/latest' extra_css: diff --git a/tests/yaml-validation-baseline.yaml b/tests/yaml-validation-baseline.yaml index a764ff1cf5c..28c931c01db 100644 --- a/tests/yaml-validation-baseline.yaml +++ b/tests/yaml-validation-baseline.yaml @@ -2,8 +2,3 @@ # To suppress a failure: regenerate this file after confirming it is expected. # To fix a suppressed failure: fix the doc error and regenerate. ignoreErrors: - - - path: docs/multisite/multisite_configuration.md - line: 28 - hash: 306a74d1cc587b13c8d3378a9b05815d16cfe0a0e10f9766685e8f39e81f98fd - message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' From 161f8a9bae166592083d104daa432011549c9351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Wed, 23 Sep 2026 22:43:40 +0200 Subject: [PATCH 02/11] Manual changes --- .../content_organization/content_types.md | 2 +- .../recent_activity/recent_activity.md | 13 +----- docs/ai/ai_actions/ai_actions_guide.md | 2 +- .../rest_api/rest_api_usage/rest_requests.md | 5 -- .../rest_api_usage/testing_rest_api.md | 4 +- .../content_management_guide.md | 4 +- docs/content_management/content_model.md | 7 +-- .../images/configure_image_editor.md | 13 ------ .../pages/page_builder_guide.md | 4 -- .../url_management/url_management.md | 2 +- .../security/security_checklist.md | 46 +------------------ docs/multisite/languages/languages.md | 1 - docs/multisite/multisite.md | 3 +- .../site_factory_configuration.md | 37 --------------- docs/multisite/siteaccess/siteaccess.md | 5 +- .../translations_management_guide.md | 4 -- docs/product_catalog/product_catalog_guide.md | 6 +-- .../raptor_cdp_add_tracking.md | 2 +- .../floatstats_aggregation.md | 7 --- .../integerstats_aggregation.md | 8 +--- .../rawstats_aggregation.md | 7 --- .../contentname_criterion.md | 2 +- .../criteria_reference/createdat_criterion.md | 14 +++++- .../objectstateidentifier_criterion.md | 2 +- .../productcode_criterion.md | 16 +++---- .../updated_at_criterion.md | 18 ++++---- .../updated_at_range_criterion.md | 4 +- docs/users/user_management_guide.md | 9 ---- mkdocs.yml | 3 -- 29 files changed, 50 insertions(+), 200 deletions(-) delete mode 100644 docs/content_management/images/configure_image_editor.md delete mode 100644 docs/multisite/site_factory/site_factory_configuration.md diff --git a/docs/administration/content_organization/content_types.md b/docs/administration/content_organization/content_types.md index 4aee5f4ebd9..030126ed257 100644 --- a/docs/administration/content_organization/content_types.md +++ b/docs/administration/content_organization/content_types.md @@ -32,7 +32,7 @@ It can consist of letters, digits, spaces, and special characters (it's mandator Even if your content type defines a field intended as a name for the content item (for example, a title of an article or product name), don't confuse it with this Name, which is a piece of metadata, not a field. -**Identifier** – an identifier for internal use in configuration, for example, files, templates, or PHP code. +**Identifier** – an identifier for internal use in configuration, for example, website templates. It must be unique, can only contain lowercase letters, digits, and underscores (it's mandatory and the maximum length is 50 characters). **Description** – a detailed description of the content type (optional). diff --git a/docs/administration/recent_activity/recent_activity.md b/docs/administration/recent_activity/recent_activity.md index a6f7782819c..637aa099742 100644 --- a/docs/administration/recent_activity/recent_activity.md +++ b/docs/administration/recent_activity/recent_activity.md @@ -1,5 +1,5 @@ --- -description: Log and monitor activity through UI, PHP API and REST API. +description: Log and monitor activity through UI and REST API. month_change: false --- @@ -23,17 +23,6 @@ This policy is required to view [activity log in user profile]([[= user_doc =]]/ Don't assign `activity_log/read` permission to the Anonymous role, even with the owner limitation, because this role is shared among all unauthenticated users. -## User privacy - -!!! caution - - A username of the User who performs the action is logged. - When acting through the web server, the User's IP address is also logged. - Other access, such as console commands, doesn't log an IP. - Your Data Protection Officer or GDPR representative should be aware of this, so they can ensure users are informed if needed, depending on your use case, jurisdiction, and company policy. - - For example, if a content edition feature, such as reader's comments, is available in the front office, the recent activity log records the front users' IPs. - ## REST API You can browse activity logs with REST API. diff --git a/docs/ai/ai_actions/ai_actions_guide.md b/docs/ai/ai_actions/ai_actions_guide.md index a676867e8a3..832aead6e0e 100644 --- a/docs/ai/ai_actions/ai_actions_guide.md +++ b/docs/ai/ai_actions/ai_actions_guide.md @@ -73,7 +73,7 @@ By making such adjustments, administrators can ensure that the actions are tailo Once an AI action is defined and configured, it must be executed, and this is where models come into play. Each model is designed to work with a specific AI service and AI action type pair. -Pieces of PHP code that are responsible for resolving a model are called handlers. +Pieces of code that are responsible for resolving a model are called handlers. They may include hardcoded prompts for conversational AI services like ChatGPT, or operate without prompts in the case of other types of AI. Handlers take parameters defined in the AI action type and configuration, combine it with user input and any predefined settings or prompts, and pass this information to the AI service for processing. diff --git a/docs/api/rest_api/rest_api_usage/rest_requests.md b/docs/api/rest_api/rest_api_usage/rest_requests.md index 70a5422affc..24266c25717 100644 --- a/docs/api/rest_api/rest_api_usage/rest_requests.md +++ b/docs/api/rest_api/rest_api_usage/rest_requests.md @@ -101,11 +101,6 @@ Accept: application/vnd.ibexa.api.Root+json X-Siteaccess: restapi ``` -One of the principles of REST is that the same resource (such as content item, location, content type) should be unique. -It allows caching your REST API with a reverse proxy such as Varnish. -If the same resource is available in multiple locations, cache purging is noticeably more complex. -This is why SiteAccess matching with REST isn't enabled at URL level (or domain). - ### Media types On top of methods, HTTP request headers allow you to personalize the request's behavior. diff --git a/docs/api/rest_api/rest_api_usage/testing_rest_api.md b/docs/api/rest_api/rest_api_usage/testing_rest_api.md index 9475577395b..4a4fa6ebe32 100644 --- a/docs/api/rest_api/rest_api_usage/testing_rest_api.md +++ b/docs/api/rest_api/rest_api_usage/testing_rest_api.md @@ -1,5 +1,5 @@ --- -description: You can test operations in the REST API by using command line, PHP or JS code. +description: You can test operations in the REST API by using command line, JS code, or other programming languages. --- # Testing REST API @@ -8,7 +8,7 @@ A standard web browser isn't sufficient to fully test the API. You can, however, try opening the root resource located at `/api/ibexa/v2/`. Depending on how your browser understands XML, it either downloads the XML file, or opens it in the browser. -The following examples show how to interrogate the REST API with cURL, PHP or JS. +The following examples show how to interrogate the REST API with cURL or JS. ## CLI diff --git a/docs/content_management/content_management_guide.md b/docs/content_management/content_management_guide.md index 1bc52c67f35..b8ccfc79606 100644 --- a/docs/content_management/content_management_guide.md +++ b/docs/content_management/content_management_guide.md @@ -24,7 +24,7 @@ A system that relies on roles and permissions controls access to content items a - media (for example, images or videos) - user accounts -You can set up content structure, define the templates to be filled with content, and assign different areas of the structure to your editors. +You can set up content structure and assign different areas of the structure to your editors. Next steps would be to create the actual content, and then classify content items, and organize them as necessary. You can then build an external systems that uses [[= product_name =]] as a headless CMS, a single source of truth for anything related to content. @@ -47,7 +47,7 @@ You can customize and adapt the content model to your organization's needs and t Content managers or even editors can then apply such field types when they modify existing or create new content types. The editing interface lets all users, including those with no coding experience, create or modify certain areas of the content model. -For technical details, see [a Content model](content_model.md#content-model). +For technical details, see [Content model](content_model.md#content-model). ### Field types diff --git a/docs/content_management/content_model.md b/docs/content_management/content_model.md index 91865e2cdef..22c4e1080dc 100644 --- a/docs/content_management/content_model.md +++ b/docs/content_management/content_model.md @@ -95,15 +95,13 @@ Aside from the field type, the field definition in a content type provides the f **Name** – a user-friendly name that describes the field. This name is used in the interface, but not internally by the system. It can consist of letters, digits, spaces, and special characters (the maximum length is 255 characters). If no name is provided, a unique one is automatically generated. -**Identifier** – an identifier for internal use, for example, in configuration files, templates, or PHP code. It can only contain lowercase letters, digits and underscores (the maximum length is 50 characters). This identifier is also used in name patterns for the content type. +**Identifier** – an identifier for specific field. It can only contain lowercase letters, digits and underscores (the maximum length is 50 characters). Use it to detect a specific field when you consume content from [[= product_name =]]. This identifier is also used in name patterns for the content type. **Description** – a detailed description of the field. **Required** – a flag which indicates if the field is required for the system to accept the content item. By default, if a field is flagged as Required, a user isn't able to publish a content item without filling in this field. !!! note - You can use the `ContentService::validate()` method to decide whether the required fields or whole content items are checked for completeness at other stages of the editing process. - The Required flag is in no way related to field validation. A field's value is validated whether the field is set as required or not. **[Searchable](search.md)** – a flag which indicates if the value of the field is indexed for searching. @@ -126,8 +124,7 @@ A new version is created every time a content item is edited. The previous publi Only one version can be published at the same time. When you publish a new version, the previous published version changes its status to Archived. -The number of preserved archived versions is set in `ibexa.repositories.default.options.default_version_archive_limit`. -By default it's set to 5. +The number of preserved archived versions is 5. A new version is also created when a new [language](languages.md) is added to the content item. diff --git a/docs/content_management/images/configure_image_editor.md b/docs/content_management/images/configure_image_editor.md deleted file mode 100644 index 7e54da7c0f0..00000000000 --- a/docs/content_management/images/configure_image_editor.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -description: Configure image editor to crop, flip, and modify images. ---- - -# Configure Image Editor - -When a content item contains fields of the [`ibexa_image`](imageassetfield.md) type, users can perform basic image editing functions with the Image Editor. - -For more information, see [User Documentation]([[= user_doc =]]/image_management/edit_images/). - -!!! note - - The Image Editor doesn't support images that come from a Digital Asset Management (DAM) system. diff --git a/docs/content_management/pages/page_builder_guide.md b/docs/content_management/pages/page_builder_guide.md index 75e967ace42..7d4d1347caf 100644 --- a/docs/content_management/pages/page_builder_guide.md +++ b/docs/content_management/pages/page_builder_guide.md @@ -45,10 +45,6 @@ It's also important to choose a layout - it determines the arrangement of drop z ![Page Builder - diagram](page_builder_diagram.png) -### Availability - -Page Builder is available in [[= product_name =]]. - ### How does Page Builder work #### Page Builder interface diff --git a/docs/content_management/url_management/url_management.md b/docs/content_management/url_management/url_management.md index f2f3e5d4e9e..e32bb68e02e 100644 --- a/docs/content_management/url_management/url_management.md +++ b/docs/content_management/url_management/url_management.md @@ -31,5 +31,5 @@ For each URL alias definition the history of changes is preserved, so that users URL aliases that initially had the same name in multiple languages aren't archived. URL aliases aren't SiteAccess-aware. When creating an alias, you can select a SiteAccess to base it on. -If the SiteAccess root path (configured in `content.tree_root.location_id`) is different than the default, +If the SiteAccess root path (configured as [Content Tree Root](configuration.md)) is different than the default, the prefix path that results from the configured content root is prepended to the final alias path. diff --git a/docs/infrastructure_and_maintenance/security/security_checklist.md b/docs/infrastructure_and_maintenance/security/security_checklist.md index eb355871147..fc9419f28ce 100644 --- a/docs/infrastructure_and_maintenance/security/security_checklist.md +++ b/docs/infrastructure_and_maintenance/security/security_checklist.md @@ -8,7 +8,7 @@ When getting ready to go live with your project for the first time, or when re-l !!! caution - Security is an ongoing process. After going live, you should pay attention to Ibexa security advisories released via [your Service portal](https://support.ibexa.co/), or via [Security advisories](https://developers.ibexa.co/security-advisories) if you're not a subscriber. + Security is an ongoing process. After going live, you should pay attention to Ibexa security advisories released via [your Service portal](https://support.ibexa.co/). ## [[= product_name =]] @@ -71,47 +71,3 @@ The [Code block]([[= user_doc =]]/content_management/block_reference/#code-block This means that editors who have access to Code blocks could add malicious JS including [cross site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting). As site administrator, be aware of this when giving editors access to the Page Builder features, and limit that access only to trusted editors. You can [limit access to specific blocks per content type]([[= user_doc =]]/content_management/configure_ct_field_settings/#default-configuration-of-pages) by defining which page blocks are available to editors. - -## Security headers - -There are a number of security related HTTP response headers that you can use to improve your security. -Headers must be adapted to the site in question, and in most cases it's site owner's responsibility. - -You most likely need to vary the security headers based on the SiteAccess in question and site implementation details, such as frontend code and libraries used. - -- `Strict-Transport-Security` - ensures that all requests are sent over HTTPS, with no fallback to HTTP. -All production sites should use HTTPS and this header unless they have particular needs. -This header is less important during development provided that the site is on an internal, protected network. -- `X-Frame-Options` - ensures that the site isn't embedded in a frame by a compliant browser. -Set the header to `SAMEORIGIN` to allow embedding by your own site, or `DENY` to block framing completely. -- `X-Content-Type-Options` - prevents the browser from second-guessing the mime-type of delivered content. -This header is less important if users cannot upload content and/or you trust your editors. However, it's safer to use it at all times. -Make sure that the `Content-Type` header is also correctly set, including for the top-level document, to avoid issues with HTML documents being downloaded while they should be rendered. -- `Content-Security-Policy` - blocks cross site scripting (XSS) attacks by setting an allowlist (whitelist) of resources to be loaded for a given page. -You can set separate lists for scripts, images, fonts, and more. -For experimentation and testing, you can use `Content-Security-Policy-Report-Only` before activating the actual policy. -- `Referrer-Policy` - limits what information is sent from the previous page or site when navigating to a new page or site. -This header has several directives for fine-tuning the referrer information. -- `Permissions-Policy` - limits what features the browser can use, such as fullscreen, notifications, location, camera, or microphone. -For example, if someone succeeds in injecting their JavaScript into your site, this header prevents them from using those features to attack your users. - -## Domain - -### Enable Domain Name System Security Extensions (DNSSEC) - -DNSSEC is a DNS feature that authenticates responses to DNS requests. -It protects against DNS poisoning attacks, which is when an attacker manipulates the responses to DNS requests with the goal of directing users to an IP address the attacker controls. -Enabling DNSSEC involves creating the DNSSEC records in your domain, activating DNSSEC with your domain registrar, and enabling DNSSEC signature validation on all DNS servers. -[Read more on DNSSEC on ICANN's website](https://www.icann.org/resources/pages/dnssec-what-is-it-why-important-2019-03-05-en). - -### Enable domain update/delete protection - -Domain update/delete protection is a DNS setting that makes it harder for an attacker to take over a domain from the real owner, or hinder availability for users. -You can enable this protection at your domain registrar's site. -Log in to their site to enable these protection settings and save the new configuration. - -### Enable Certificate Authority Authorization (CAA) - -CAA allows domain owners to specify which Certificate Authorities (CAs) are permitted to issue SSL/TLS certificates for their domain. -This prevents attackers from having certificates issued for domains they don't own, hindering some types of attack. -CAA is configured in your DNS zone file. diff --git a/docs/multisite/languages/languages.md b/docs/multisite/languages/languages.md index 5f06bf3ab0a..abb6e7df6ce 100644 --- a/docs/multisite/languages/languages.md +++ b/docs/multisite/languages/languages.md @@ -23,7 +23,6 @@ However, even if work on a draft takes time and other translations are updated i The multilanguage system operates based on a global translation list that contains all languages available in the installation. Languages can be [added to this list from the **Administration** panel]([[= user_doc =]]/content_management/translate_content/) in the back office. -**The new language must then be added to the [SiteAccess](multisite.md) configuration**. Once this is done, any user with proper permissions can create content item versions in these languages in the user interface. ### Translatable and untranslatable fields diff --git a/docs/multisite/multisite.md b/docs/multisite/multisite.md index a09b3261b00..67fb53bc02a 100644 --- a/docs/multisite/multisite.md +++ b/docs/multisite/multisite.md @@ -1,5 +1,5 @@ --- -description: Multisite enables hosting multiple websites with different content, templates and configuration by using one repository. +description: Multisite enables hosting multiple websites with different content configuration by using one repository. page_type: landing_page --- @@ -15,5 +15,4 @@ To quickly set up new sites with predefined site templates, use [Site Factory](s "multisite/siteaccess/siteaccess", "administration/configuration/configuration", "multisite/site_factory/site_factory", - "multisite/site_factory/site_factory_configuration", ], columns=3) =]] diff --git a/docs/multisite/site_factory/site_factory_configuration.md b/docs/multisite/site_factory/site_factory_configuration.md deleted file mode 100644 index 58f7f592c67..00000000000 --- a/docs/multisite/site_factory/site_factory_configuration.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -description: Configure Site Factory, including site skeletons. ---- - -# Site Factory configuration - -## Site skeletons - -The Site skeleton enables you to copy an entire content structure of the site design to the defined location. - -Site skeleton copying is a one-off operation, it only happens during the site creation process. -After that, you cannot copy the Site skeleton again, for example in the edit view. - -You can create as many skeletons as you need and assign them to templates. -Remember that one template can only have one Site skeleton. - -If the design doesn't have a defined Site skeleton, a directory of the new site is created in a standard Site Factory process. - -To define a Site skeleton, add the `site_skeleton_id` or `site_skeleton_remote_id` key to the site template definition. -This can be either a location ID (for example, `5966`), or a remote location ID (for example, `3bed95afb1f8126f06a3c464e461e1ae66`). - -``` yaml hl_lines="7 12" -ibexa_site_factory: - templates: - site1: - siteaccess_group: example_site_factory_group_1 - name: example_site_1 - thumbnail: /path/to/image/example-thumbnail_1.png - site_skeleton_id: 5966 - site2: - siteaccess_group: example_site_factory_group_2 - name: example_site_2 - thumbnail: /path/to/image/example-thumbnail_2.png - site_skeleton_remote_id: 3bed95afb1f8126f06a3c464e461e1ae66 -``` - -Now, you can choose a design with a defined Site skeleton, and decide if you want to use its skeleton by toggling **Generate site using site skeleton**. diff --git a/docs/multisite/siteaccess/siteaccess.md b/docs/multisite/siteaccess/siteaccess.md index 1290cec4d97..7908db81468 100644 --- a/docs/multisite/siteaccess/siteaccess.md +++ b/docs/multisite/siteaccess/siteaccess.md @@ -5,8 +5,7 @@ page_type: landing_page # SiteAccess -A SiteAccess is a set of configuration settings that the application uses when you access the site through a specific address. -When the user visits the site, the system analyzes the URI and compares it to rules specified in the configuration. -If it finds a set of fitting rules, this SiteAccess is used. +A SiteAccess is a set of configuration settings that can vary between sites, for example, the primary language of the site. +When the user visits the site, the delivered content can vary based on [selected SiteAccess](rest_requests.md#siteaccess), changing the response. Each SiteAccess can have different [configuration](configuration.md). diff --git a/docs/multisite/translations_management/translations_management_guide.md b/docs/multisite/translations_management/translations_management_guide.md index 0919205db1d..5b01c123a86 100644 --- a/docs/multisite/translations_management/translations_management_guide.md +++ b/docs/multisite/translations_management/translations_management_guide.md @@ -99,7 +99,3 @@ Seeing the translation in context makes it easier to identify omissions, inconsi Regardless of technical and conceptual differences, the experience of working with various translation providers is the same. Administrators can assign providers to specific language pairs and editors can override the assignment when needed. - -### Readiness for automated processing - -The CLI command enables integration with automated processes, which can help you reduce manual effort for large content volumes. diff --git a/docs/product_catalog/product_catalog_guide.md b/docs/product_catalog/product_catalog_guide.md index 97b7cae7854..fae5407bcf6 100644 --- a/docs/product_catalog/product_catalog_guide.md +++ b/docs/product_catalog/product_catalog_guide.md @@ -10,10 +10,6 @@ month_change: false The product catalog is a comprehensive set of capabilities for managing products in [[= product_name =]] that can be used standalone. It lets you create, configure, and manage products, their specifications, assets, variants, and prices, and group products into categories and catalogs. -## Availability - -Product catalog capabilities are available in [[= product_name =]]. - ## How does product catalog work Products in [[= product_name =]]’s product catalog have underlying content items enriched with product-specific information such as attributes, assets, prices, and others. @@ -150,7 +146,7 @@ Catalog filters let you narrow down the products from the product catalog that a ### Quable PIM integration -You can store product information inside [[= product_name =]], or you can store it inside ([[= pim_product_name =]]). +You can store product information inside [[= product_name =]], or you can store it inside [[= pim_product_name =]]. For more information, see [Quable integration](quable.md). ## How to get started diff --git a/docs/raptor_cdp/raptor_cdp_activation/raptor_cdp_add_tracking.md b/docs/raptor_cdp/raptor_cdp_activation/raptor_cdp_add_tracking.md index 0d67838f8a5..ba234228217 100644 --- a/docs/raptor_cdp/raptor_cdp_activation/raptor_cdp_add_tracking.md +++ b/docs/raptor_cdp/raptor_cdp_activation/raptor_cdp_add_tracking.md @@ -4,7 +4,7 @@ description: Adding tracking in Raptor CDP. # Track with [[= product_name_cdp =]] -The final step is setting up a tracking script that identifies visitors and records their interactions. +To set up Raptor CDP, set up a tracking script that identifies visitors and records their interactions. ## Set up tracking with tracking scripts diff --git a/docs/search/aggregation_reference/floatstats_aggregation.md b/docs/search/aggregation_reference/floatstats_aggregation.md index c67e144dd8f..da7f049f3ea 100644 --- a/docs/search/aggregation_reference/floatstats_aggregation.md +++ b/docs/search/aggregation_reference/floatstats_aggregation.md @@ -5,13 +5,6 @@ description: FloatStatsAggregation # FloatStatsAggregation The field-based FloatStatsAggregation aggregates search results by the value of the Float field and provides statistical information for the values. -You can use the provided getters to access the values: - -- sum (`getSum()`) -- count of values (`getCount()`) -- minimum value (`getMin()`) -- maximum value (`getMax()`) -- average (`getAvg()`) ## Arguments diff --git a/docs/search/aggregation_reference/integerstats_aggregation.md b/docs/search/aggregation_reference/integerstats_aggregation.md index 4fdc0f264c5..70f295bda92 100644 --- a/docs/search/aggregation_reference/integerstats_aggregation.md +++ b/docs/search/aggregation_reference/integerstats_aggregation.md @@ -4,13 +4,7 @@ description: IntegerStatsAggregation # IntegerStatsAggregation -The field-based IntegerStatsAggregation aggregates search results by the value of the Integer field and provides statistical information for the values. You can use the provided getters to access the values: - -- sum (`getSum()`) -- count of values (`getCount()`) -- minimum value (`getMin()`) -- maximum value (`getMax()`) -- average (`getAvg()`) +The field-based IntegerStatsAggregation aggregates search results by the value of the Integer field and provides statistical information for the values. ## Arguments diff --git a/docs/search/aggregation_reference/rawstats_aggregation.md b/docs/search/aggregation_reference/rawstats_aggregation.md index cc57dafb9b4..f1224bfe086 100644 --- a/docs/search/aggregation_reference/rawstats_aggregation.md +++ b/docs/search/aggregation_reference/rawstats_aggregation.md @@ -5,13 +5,6 @@ description: RawStatsAggregation # RawStatsAggregation The RawStatsAggregation aggregates search results by the value of the selected search index field and provides statistical information for the values. -You can use the provided getters to access the values: - -- sum (`getSum()`) -- count of values (`getCount()`) -- minimum value (`getMin()`) -- maximum value (`getMax()`) -- average (`getAvg()`) ## Arguments diff --git a/docs/search/criteria_reference/contentname_criterion.md b/docs/search/criteria_reference/contentname_criterion.md index 1d29cd52ae4..7564889cc04 100644 --- a/docs/search/criteria_reference/contentname_criterion.md +++ b/docs/search/criteria_reference/contentname_criterion.md @@ -4,7 +4,7 @@ description: ContentName Search Criterion # ContentName Criterion -The [`ContentName` Search Criterion](https://github.com/ibexa/core/blob/6.0/src/contracts/Repository/Values/Content/Query/Criterion/ContentName.php) searches for content by its name. +The `ContentName` Search Criterion searches for content by its name. ## Arguments diff --git a/docs/search/criteria_reference/createdat_criterion.md b/docs/search/criteria_reference/createdat_criterion.md index e819ebc0bbf..a5b4f033100 100644 --- a/docs/search/criteria_reference/createdat_criterion.md +++ b/docs/search/criteria_reference/createdat_criterion.md @@ -8,8 +8,18 @@ The `CreatedAt` Search Criterion searches for products based on the date when th ## Arguments -- `createdAt` (PHP), `created_at` (REST) - indicating the date that should be matched, provided as a `DateTimeInterface` object in PHP, or as a string acceptable by `DateTime` constructor in REST -- `operator` - Operator constant (EQ, GT, GTE, LT, LTE) in PHP or its value in REST +- `created_at` - indicating the date that should be matched, provided as a string acceptable by[`DateTimeInterface`](https://www.php.net/manual/en/class.datetimeinterface.php) constructor +- `operator` - Operator value + +## Operators + +| Value | Description | +|-------|-------------| +| `=` | Matches products updated exactly on the given date (default) | +| `>` | Matches products updated after the given date | +| `>=` | Matches products updated on or after the given date | +| `<` | Matches products updated before the given date | +| `<=` | Matches products updated on or before the given date | ## Example diff --git a/docs/search/criteria_reference/objectstateidentifier_criterion.md b/docs/search/criteria_reference/objectstateidentifier_criterion.md index f40c61ae139..cc96f8fc29b 100644 --- a/docs/search/criteria_reference/objectstateidentifier_criterion.md +++ b/docs/search/criteria_reference/objectstateidentifier_criterion.md @@ -9,7 +9,7 @@ The `ObjectStateIdentifier` Search Criterion searches for content based on its o ## Arguments - `value` - string(s) representing the object state identifier(s) -- `target` (optional for PHP) - string representing the object state group +- `target` - string representing the object state group ## Example diff --git a/docs/search/criteria_reference/productcode_criterion.md b/docs/search/criteria_reference/productcode_criterion.md index 3a19fdb5ec6..1bb5a1a7fab 100644 --- a/docs/search/criteria_reference/productcode_criterion.md +++ b/docs/search/criteria_reference/productcode_criterion.md @@ -16,14 +16,14 @@ You can use this Search Criterion over the REST API, in the payload of the [`POS === "XML" -```xml - - - ski - snowboard - - -``` + ```xml + + + ski + snowboard + + + ``` === "JSON" diff --git a/docs/search/criteria_reference/updated_at_criterion.md b/docs/search/criteria_reference/updated_at_criterion.md index c4b0546bb8b..93c420982d7 100644 --- a/docs/search/criteria_reference/updated_at_criterion.md +++ b/docs/search/criteria_reference/updated_at_criterion.md @@ -9,18 +9,18 @@ The `UpdatedAt` Search Criterion searches for products based on the date when th ## Arguments -- `date` - indicating the date that should be matched, provided as a [`DateTimeInterface`](https://www.php.net/manual/en/class.datetimeinterface.php) object in PHP, or as a string acceptable by `DateTimeInterface` constructor in REST -- `operator` - Operator constant (EQ, GT, GTE, LT, LTE) in PHP or its value in REST +- `date` - indicating the date that should be matched, provided as a string acceptable by [`DateTimeInterface`](https://www.php.net/manual/en/class.datetimeinterface.php) +- `operator` - Operator value ## Operators -| Operator | Value | Description | -|----------|-------|-------------| -| `Operator::EQ` | `=` | Matches products updated exactly on the given date (default) | -| `Operator::GT` | `>` | Matches products updated after the given date | -| `Operator::GTE` | `>=` | Matches products updated on or after the given date | -| `Operator::LT` | `<` | Matches products updated before the given date | -| `Operator::LTE` | `<=` | Matches products updated on or before the given date | +| Value | Description | +|-------|-------------| +| `=` | Matches products updated exactly on the given date (default) | +| `>` | Matches products updated after the given date | +| `>=` | Matches products updated on or after the given date | +| `<` | Matches products updated before the given date | +| `<=` | Matches products updated on or before the given date | ## Example diff --git a/docs/search/criteria_reference/updated_at_range_criterion.md b/docs/search/criteria_reference/updated_at_range_criterion.md index e273521844d..332efed3c1b 100644 --- a/docs/search/criteria_reference/updated_at_range_criterion.md +++ b/docs/search/criteria_reference/updated_at_range_criterion.md @@ -9,8 +9,8 @@ The `UpdatedAtRange` Search Criterion searches for products based on the date ra ## Arguments -- `min` - the start of the date range (inclusive), provided as a [`DateTimeInterface`](https://www.php.net/manual/en/class.datetimeinterface.php) object in PHP, or as a string acceptable by `DateTimeInterface` constructor in REST -- `max` - the end of the date range (inclusive), provided as a [`DateTimeInterface`](https://www.php.net/manual/en/class.datetimeinterface.php) object in PHP, or as a string acceptable by `DateTimeInterface` constructor in REST +- `min` - the start of the date range (inclusive), provided as a string acceptable by [`DateTimeInterface`](https://www.php.net/manual/en/class.datetimeinterface.php) +- `max` - the end of the date range (inclusive), provided as a string acceptable by [`DateTimeInterface`](https://www.php.net/manual/en/class.datetimeinterface.php) At least one of `min` or `max` must be provided. diff --git a/docs/users/user_management_guide.md b/docs/users/user_management_guide.md index c16f75900c0..1a4501d33da 100644 --- a/docs/users/user_management_guide.md +++ b/docs/users/user_management_guide.md @@ -12,10 +12,6 @@ User management is a fundamental aspect of any system. User management refers to the process of granting, configuring, and controlling access for users by administrators. This encompasses the creation of user accounts, assigning roles and permissions, setting authentication methods, and managing user-related data. -## Availability - -User management is available in all [[= product_name =]] versions. - ## How does user management work [[= product_name =]] simplifies user management with an intuitive and powerful system of accounts, roles, permissions, groups, and segments. @@ -119,8 +115,3 @@ This ensures quality and consistency in their digital properties. ### Content relevance By delivering content that resonates with different user segments, clients can increase user engagement and retention. - -### Customizability - -Clients can adapt the user management system to their unique needs. -Custom policies and limitations enable tailored solutions that align with their specific use cases. diff --git a/mkdocs.yml b/mkdocs.yml index 4863871a6ab..ea959e0d6c7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -68,7 +68,6 @@ nav: - Taxonomy: content_management/taxonomy/taxonomy.md - Images: - Images: content_management/images/images.md - - Configure Image Editor: content_management/images/configure_image_editor.md - RichText: - RichText: content_management/rich_text/rich_text.md - Online Editor guide: content_management/rich_text/online_editor_guide.md @@ -155,7 +154,6 @@ nav: - SiteAccess: multisite/siteaccess/siteaccess.md - Site Factory: - Site Factory: multisite/site_factory/site_factory.md - - Site Factory configuration: multisite/site_factory/site_factory_configuration.md - Languages: - Languages: multisite/languages/languages.md - Translations management: @@ -316,7 +314,6 @@ nav: - Product attribute aggregations: search/aggregation_reference/product_attribute_aggregations.md - ProductAvailabilityTermAggregation: search/aggregation_reference/productavailabilityterm_aggregation.md - ProductStockRangeAggregation: search/aggregation_reference/productstockrange_aggregation.md - - ProductStockRangeAggregation: search/aggregation_reference/productstockrange_aggregation.md - ProductPriceRangeAggregation: search/aggregation_reference/productpricerange_aggregation.md - ProductTypeTermAggregation: search/aggregation_reference/producttypeterm_aggregation.md - Security: From 112e3c1d80c1da08ad563f0e92c75b304e32bf90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Wed, 23 Sep 2026 23:20:04 +0200 Subject: [PATCH 03/11] REST --- .../admin_panel/users_admin_panel.md | 21 +++ docs/api/rest_api/rest_api_authentication.md | 125 ++++++++++++++++-- 2 files changed, 138 insertions(+), 8 deletions(-) diff --git a/docs/administration/admin_panel/users_admin_panel.md b/docs/administration/admin_panel/users_admin_panel.md index da15b8c379c..6a6b0ff9517 100644 --- a/docs/administration/admin_panel/users_admin_panel.md +++ b/docs/administration/admin_panel/users_admin_panel.md @@ -14,3 +14,24 @@ You can access all users and user groups in the **Administration** panel by sele Be careful not to delete an existing user account. If you do this, content created by this user can be broken and the application can face malfunction. + +## Built-in users + +Built-in roles and users control the behavior of the system: + +### Anonymous user + +The Anonymous user, in the **Anonymous users** group, is a special user that controls what data can be seen by unauthenticated users and visitors. +It applies both to the UI and [API](rest_api_authentication.md#anonymous-access). + +### Service Account user + +The `REST Service Account` user, in the **SSO users** user group, is used when authenticating to the REST API or MCP Server with [client credentials](rest_api_authentication.md#client-credentials). + +You can: + +- change the permissions assigned to this user +- assign new roles to it +- move it between user groups + +**If you modify or delete this user, authentication with client credentials won't be possible.** diff --git a/docs/api/rest_api/rest_api_authentication.md b/docs/api/rest_api/rest_api_authentication.md index d71934f6c0b..b94545fb7d8 100644 --- a/docs/api/rest_api/rest_api_authentication.md +++ b/docs/api/rest_api/rest_api_authentication.md @@ -1,20 +1,129 @@ --- -description: To authenticate REST API communication you can use session (default), JWT, basic, OAuth and client certificate (SSL) authentication. +description: To authenticate REST API communication, use OAuth 2.0 access tokens issued by the authorization server. month_change: false --- # REST API authentication -This page refers to [REST API reference](rest_api_reference/rest_api_reference.html), where you can find detailed information about -REST API resources and endpoints. +This page refers to [REST API reference](rest_api_reference/rest_api_reference.html), where you can find detailed information about REST API resources and endpoints. -!!! caution "SiteAccess login" +[[= product_name =]] authenticates REST API requests with [OAuth 2.0](https://oauth.net/2/) access tokens. +You get an access token from the authorization server, and send it with every request in the `Authorization` header: - The anonymous user is used to perform authentification requests. - Therefore, the "Anonymous" role must have `user/login` permission on the SiteAccess that matches the REST domain or is passed through the [`X-Siteaccess` header](rest_requests.md#siteaccess). +``` http +Authorization: Bearer +``` + +The same tokens also give access to the [MCP server](mcp_usage.md). + +## Anonymous access + +Requests without the `Authorization` header are performed as the anonymous user, and can only access what the `Anonymous` role allows. + +For example, the REST root and publicly readable content are available without a token: + +``` bash +curl https://example.cohesivo.app/api/ibexa/v2/ \ + --header 'Accept: application/vnd.ibexa.api.Root+json' +``` ## OAuth -TODO: Oauth is the only authentication method. Add an example showing the whole flow. +To get an access token, use the values received during [[= product_name =]] onboarding: + +| Value | Description | +|---|---| +| `TOKEN_ENDPOINT` | Token endpoint of the authorization server. | +| `AUTHORIZATION_ENDPOINT` | Authorization endpoint of the authorization server, used by the [authorization code flow](#authorization-code-with-pkce). | +| `CLIENT_ID` | Identifier of the machine-to-machine client. | +| `CLIENT_SECRET` | Secret of the machine-to-machine client. | + +Two flows are available: + +- With [Client credentials](#client-credentials), the API runs as a [service account](users_admin_panel.md#service-account). Use it for server-to-server integrations. +- With [Authorization code with PKCE](#authorization-code-with-pkce), the API runs as the person who logged in, with their permissions. +Use it for applications that act on behalf of a user. + +### Client credentials + +Request a token from the token endpoint with the client identifier and secret: + +``` bash +curl --request POST "$TOKEN_ENDPOINT" \ + --user "$CLIENT_ID:$CLIENT_SECRET" \ + --data 'grant_type=client_credentials' +``` + +The response contains the access token: + +``` json +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6...", + "token_type": "Bearer" +} +``` + +Requests made with this token run as the [service account](users_admin_panel.md#service-account). + +### Authorization code with PKCE + +The authorization code flow with [PKCE](https://oauth.net/2/pkce/) requires a browser, because the user logs in on the authorization server. + +Use a client that can perform the redirect. +You can follow the example below in Postman: + +1. Fill in the request details: + + | Field | Value | + |---|---| + | Type | OAuth 2.0 | + | Add auth data to | Request Headers | + | Grant type | Authorization Code (With PKCE) | + | Callback URL | Redirect URI registered for your client, with **Authorize using browser** selected | + | Auth URL | `AUTHORIZATION_ENDPOINT` | + | Access Token URL | `TOKEN_ENDPOINT` | + | Client ID | Identifier of the client that's configured for the authorization code flow | + | Client Secret | (empty) | + | Code Challenge Method | SHA-256 | + | Scope | `openid` | + +2. Select **Get New Access Token**, log in with your user account +3. Select **Use Token**. + +Requests made with this token run as the user who logged in, and are subject to that user's permissions. + +## Use authentication token + +Send the access token in the `Authorization` header: + +``` bash +curl https://example.cohesivo.app/api/ibexa/v2/user/current \ + --location \ + --header 'Accept: application/vnd.ibexa.api.User+json' \ + --header "Authorization: Bearer $ACCESS_TOKEN" +``` + +The response describes the user that the request runs as, which is the quickest way to confirm +which identity a token carries. + +Access tokens are valid for 15 minutes. + +## Rate limits + +To prevent abuse, REST API calls are rate limited as described below: + +| Request type | Limit | +|---|---| +| Authenticated | 300 per minute | +| Unauthenticated | 30 per minute | + +Every response carries the current state of the quota: + +| Header | Description | +|---|---| +| `X-RateLimit-Limit` | Number of requests permitted in the window. | +| `X-RateLimit-Remaining` | Number of requests still available. | +| `X-RateLimit-Reset` | Unix timestamp at which the window resets. | -For more information, see [OAuth 2.0 protocol for authorization](https://oauth.net/2/). +When you exceed the quota, the request responds with `429 Too Many Requests` and a `Retry-After` header +that tells you how many seconds to wait. From f7119fa5fb9f9ff5bc4e283e2a4410cf4fd66bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Wed, 23 Sep 2026 21:51:02 +0200 Subject: [PATCH 04/11] Mcp doc --- docs/ai/mcp/mcp_usage.md | 166 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 162 insertions(+), 4 deletions(-) diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index b9e8d3cebb7..4a3c4d51c7b 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -1,11 +1,169 @@ --- -description: Use MCP server. +description: Connect an AI agent to the built-in MCP server, authenticate it with an OAuth access token, and use the built-in tools. +month_change: false --- # Work with MCP servers -The MCP Servers feature includes several built-in tools. +[[= product_name =]] comes with a built-in MCP server called `management`, +which exposes a set of [built-in tools](mcp_guide.md#built-in-tools) to AI agents. -## Use built-in tools +The server is available under the `/mcp/management` path, for example: -TODO: Explain how to use the built-in tools. +``` text +https://example.cohesivo.app/mcp/management +``` + +The server uses the [Streamable HTTP transport](https://modelcontextprotocol.io/docs/2025-11-25/learn/architecture#transport-layer). + +## Connect to the MCP server + +The MCP server accepts the same OAuth 2.0 access tokens as the REST API. +Send the token in the `Authorization` header of every request: + +``` http +Authorization: Bearer +``` + +For information about how to get a token, see [REST API authentication](rest_api_authentication.md#oauth). + +Unlike the REST API, the MCP server has no anonymous access. +Requests without a valid token respond with `401 Unauthorized`: + +``` json +{ + "error": "MCP endpoints require authentication." +} +``` + +## Use the built-in tools + +Once an agent connects, it discovers the available tools. +Based on the prompt you provide to the agent, the agent decides which tools to call. + +The [built-in tools](mcp_guide.md#built-in-tools) let an agent work with content types, +field definitions, content type groups, translations, and SEO metadata. +For example, you can ask the agent to create a content type with a set of fields, +to list the content items that have no translation into a given language, +or to point out the content items that are missing a meta title. + +Because the tools act through the API, everything the agent can do is limited by the permissions +of the user associated with the authorization + +## Perform Copilot or Claude Code test + +You can test your MCP server with [Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli) or [Claude Code CLI](https://code.claude.com/docs/en/overview), as illustrated here, or with any other agent or interface. + +### Add MCP server to agent CLI + +You can handle the JWT token for this test in the following ways: + +- [Hard-code the JWT token](#hard-coded-variant) into the configuration and update it at every expiration. +- [Wrap a JWT token request and an MCP server call into a script](#fully-scripted-variant). + +#### Hard-coded variant + +The hard-coded JWT token configuration in `.mcp.json` looks as follows: + +```json +{ + "mcpServers": { + "cohesivo-example": { + "type": "http", + "url": "https://example.cohesivo.app/mcp/management", + "headers": { + "Authorization": "Bearer " + }, + "tools": ["*"] + } + } +} +``` + +In this approach, you must edit the `.mcp.json` file every time the JWT token expires. + +When Copilot or Claude Code complains that it can't communicate with the MCP server: + +=== Copilot CLI + + - Update the JWT token in the `.mcp.json` file. + - Reload the MCP servers in Copilot CLI with one of these methods: + - Run `/mcp reload` command to reload all MCP servers. + - Run `/mcp disable cohesivo-example` and `/mcp enable cohesivo-example` to only reload the `cohesivo-example` server. + + > **Note: Reloading multiple MCP servers** + > + > If you have several MCP servers enabled globally, reloading all of them at the same time can be time-consuming. Consider reloading them one by one. + +=== Claude Code CLI + + - Update the JWT token in the `.mcp.json` file. + - Run `/mcp reconnect cohesivo-example` command to reconnect the `cohesivo-example` MCP server. + +##### Fully scripted variant + +The wrapping script configuration in `.mcp.json` looks as follows: + +```json +{ + "mcpServers": { + "cohesivo-example": { + "type": "stdio", + "command": "bash", + "args": ["mcp-cohesivo-example-wrapper.sh"], + "tools": ["*"] + } + } +} +``` + +`mcp-cohesivo-example-wrapper.sh` is a script that [requests an authorization token through REST](rest_api_authentication.md) and establishes a connection with the MCP server. + +For example, thanks to [`npx`](https://www.npmjs.com/package/npx), you can do it with [Supergateway](https://www.npmjs.com/package/supergateway): + +```bash +#!/bin/bash +set -e + +mcpServer="https://example.cohesivo.app/mcp/management" +token=$(curl --request POST "$TOKEN_ENDPOINT" \ + --user "$CLIENT_ID:$CLIENT_SECRET" \ + --data 'grant_type=client_credentials' | jq -r .access_token) + +exec npx -y supergateway \ + --streamableHttp "$mcpServer" \ + --oauth2Bearer "$token" \ + --logLevel none +``` + +When the agent complains that it can't communicate with the MCP server, reload it: + +=== Copilot CLI + + Reload the MCP servers in Copilot CLI with one of these methods: + + - Run `/mcp reload` command to reload all MCP servers. + - Run `/mcp disable cohesivo-example` and `/mcp enable cohesivo-example` to only reload the `cohesivo-example` server. + + > **Note: Reloading multiple MCP servers** + > + > If you have several MCP servers enabled globally, reloading all of them at the same time can be time-consuming. Consider reloading them one by one. + +=== Claude Code CLI + + Run `/mcp reconnect cohesivo-example` command to reconnect the `cohesivo-example` MCP server. + +## Rate limits + +To prevent abuse, MCP server calls are rate limited to 300 requests per minute. + +Every response carries the current state: + +| Header | Description | +|---|---| +| `X-RateLimit-Limit` | Number of requests permitted in the window. | +| `X-RateLimit-Remaining` | Number of requests still available. | +| `X-RateLimit-Reset` | Unix timestamp at which the window resets. | + +When you exceed the quota, the request responds with `429 Too Many Requests` and a `Retry-After` header +that tells you how many seconds to wait. From 590d6518da58d34395426718da7c0caf14646f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Wed, 23 Sep 2026 22:01:38 +0200 Subject: [PATCH 05/11] MCP and REST --- docs/ai/mcp/mcp_usage.md | 80 ++++++++++---------- docs/api/rest_api/rest_api_authentication.md | 4 +- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index 4a3c4d51c7b..4e898e9afb1 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -48,22 +48,23 @@ to list the content items that have no translation into a given language, or to point out the content items that are missing a meta title. Because the tools act through the API, everything the agent can do is limited by the permissions -of the user associated with the authorization +of the user that the access token represents. +With the [client credentials](rest_api_authentication.md#client-credentials) flow, this is the service account. -## Perform Copilot or Claude Code test +## Test the MCP server with Copilot CLI or Claude Code -You can test your MCP server with [Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli) or [Claude Code CLI](https://code.claude.com/docs/en/overview), as illustrated here, or with any other agent or interface. +You can test your MCP server with [Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli) or [Claude Code](https://code.claude.com/docs/en/overview), as illustrated here, or with any other agent or interface. ### Add MCP server to agent CLI -You can handle the JWT token for this test in the following ways: +You can handle the access token for this test in the following ways: -- [Hard-code the JWT token](#hard-coded-variant) into the configuration and update it at every expiration. -- [Wrap a JWT token request and an MCP server call into a script](#fully-scripted-variant). +- [Hard-code the access token](#hard-coded-variant) into the configuration and update it every time it expires, which happens after 15 minutes. +- [Wrap the token request and the MCP server connection into a script](#fully-scripted-variant). #### Hard-coded variant -The hard-coded JWT token configuration in `.mcp.json` looks as follows: +The configuration with a hard-coded access token in `.mcp.json` looks as follows: ```json { @@ -72,7 +73,7 @@ The hard-coded JWT token configuration in `.mcp.json` looks as follows: "type": "http", "url": "https://example.cohesivo.app/mcp/management", "headers": { - "Authorization": "Bearer " + "Authorization": "Bearer " }, "tools": ["*"] } @@ -80,29 +81,30 @@ The hard-coded JWT token configuration in `.mcp.json` looks as follows: } ``` -In this approach, you must edit the `.mcp.json` file every time the JWT token expires. +In this approach, you must edit the `.mcp.json` file every time the access token expires. -When Copilot or Claude Code complains that it can't communicate with the MCP server: +When the agent can't connect to the MCP server: -=== Copilot CLI +=== "Copilot CLI" - - Update the JWT token in the `.mcp.json` file. - - Reload the MCP servers in Copilot CLI with one of these methods: - - Run `/mcp reload` command to reload all MCP servers. - - Run `/mcp disable cohesivo-example` and `/mcp enable cohesivo-example` to only reload the `cohesivo-example` server. + 1. Update the access token in the `.mcp.json` file. + 2. Reload the MCP servers in Copilot CLI with one of these methods: + - Run the `/mcp reload` command to reload all MCP servers. + - Run the `/mcp disable cohesivo-example` and `/mcp enable cohesivo-example` commands to reload only the `cohesivo-example` server. - > **Note: Reloading multiple MCP servers** - > - > If you have several MCP servers enabled globally, reloading all of them at the same time can be time-consuming. Consider reloading them one by one. + !!! note "Reloading multiple MCP servers" -=== Claude Code CLI + If you have several MCP servers enabled globally, reloading all of them at the same time can be time-consuming. + Consider reloading them one by one. - - Update the JWT token in the `.mcp.json` file. - - Run `/mcp reconnect cohesivo-example` command to reconnect the `cohesivo-example` MCP server. +=== "Claude Code" -##### Fully scripted variant + 1. Update the access token in the `.mcp.json` file. + 2. Run the `/mcp reconnect cohesivo-example` command to reconnect the `cohesivo-example` MCP server. -The wrapping script configuration in `.mcp.json` looks as follows: +#### Fully scripted variant + +The configuration with a wrapper script in `.mcp.json` looks as follows: ```json { @@ -117,47 +119,49 @@ The wrapping script configuration in `.mcp.json` looks as follows: } ``` -`mcp-cohesivo-example-wrapper.sh` is a script that [requests an authorization token through REST](rest_api_authentication.md) and establishes a connection with the MCP server. +`mcp-cohesivo-example-wrapper.sh` is a script that [requests an access token](rest_api_authentication.md#client-credentials) and connects to the MCP server. -For example, thanks to [`npx`](https://www.npmjs.com/package/npx), you can do it with [Supergateway](https://www.npmjs.com/package/supergateway): +For example, you can use [Supergateway](https://www.npmjs.com/package/supergateway), run through [`npx`](https://www.npmjs.com/package/npx). +The script below requires Node.js, `jq`, and the `TOKEN_ENDPOINT`, `CLIENT_ID`, and `CLIENT_SECRET` environment variables: ```bash #!/bin/bash set -e mcpServer="https://example.cohesivo.app/mcp/management" -token=$(curl --request POST "$TOKEN_ENDPOINT" \ +token=$(curl --silent --fail --request POST "$TOKEN_ENDPOINT" \ --user "$CLIENT_ID:$CLIENT_SECRET" \ --data 'grant_type=client_credentials' | jq -r .access_token) +if [ -z "$token" ] || [ "$token" = "null" ]; then + echo "Token request failed" >&2 + exit 1 +fi + exec npx -y supergateway \ --streamableHttp "$mcpServer" \ --oauth2Bearer "$token" \ --logLevel none ``` -When the agent complains that it can't communicate with the MCP server, reload it: +When the agent can't connect to the MCP server, reload it: -=== Copilot CLI +=== "Copilot CLI" Reload the MCP servers in Copilot CLI with one of these methods: - - Run `/mcp reload` command to reload all MCP servers. - - Run `/mcp disable cohesivo-example` and `/mcp enable cohesivo-example` to only reload the `cohesivo-example` server. - - > **Note: Reloading multiple MCP servers** - > - > If you have several MCP servers enabled globally, reloading all of them at the same time can be time-consuming. Consider reloading them one by one. + - Run the `/mcp reload` command to reload all MCP servers. + - Run the `/mcp disable cohesivo-example` and `/mcp enable cohesivo-example` commands to reload only the `cohesivo-example` server. -=== Claude Code CLI +=== "Claude Code" - Run `/mcp reconnect cohesivo-example` command to reconnect the `cohesivo-example` MCP server. + Run the `/mcp reconnect cohesivo-example` command to reconnect the `cohesivo-example` MCP server. ## Rate limits -To prevent abuse, MCP server calls are rate limited to 300 requests per minute. +To prevent abuse, MCP server calls are rate limited. -Every response carries the current state: +Responses carry the current state of the quota: | Header | Description | |---|---| diff --git a/docs/api/rest_api/rest_api_authentication.md b/docs/api/rest_api/rest_api_authentication.md index b94545fb7d8..c8de0bc3eb6 100644 --- a/docs/api/rest_api/rest_api_authentication.md +++ b/docs/api/rest_api/rest_api_authentication.md @@ -40,7 +40,7 @@ To get an access token, use the values received during [[= product_name =]] onbo Two flows are available: -- With [Client credentials](#client-credentials), the API runs as a [service account](users_admin_panel.md#service-account). Use it for server-to-server integrations. +- With [Client credentials](#client-credentials), the API runs as a [service account](users_admin_panel.md#service-account-user). Use it for server-to-server integrations. - With [Authorization code with PKCE](#authorization-code-with-pkce), the API runs as the person who logged in, with their permissions. Use it for applications that act on behalf of a user. @@ -63,7 +63,7 @@ The response contains the access token: } ``` -Requests made with this token run as the [service account](users_admin_panel.md#service-account). +Requests made with this token run as the [service account](users_admin_panel.md#service-account-user). ### Authorization code with PKCE From 323bb27c5d40dcf048877ff3eef76aaad78aa273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Wed, 23 Sep 2026 22:12:30 +0200 Subject: [PATCH 06/11] Field type names --- .../field_type_reference/addressfield.md | 6 +-- .../field_type_reference/authorfield.md | 8 ++-- .../field_type_reference/binaryfilefield.md | 8 ++-- .../field_type_reference/checkboxfield.md | 6 +-- .../field_type_reference/countryfield.md | 6 +-- .../customergroupfield.md | 8 ++-- .../field_type_reference/dateandtimefield.md | 8 ++-- .../field_type_reference/datefield.md | 6 +-- .../field_type_reference/emailaddressfield.md | 10 ++--- .../field_type_reference.md | 40 +++++++++---------- .../field_type_reference/floatfield.md | 6 +-- .../field_type_reference/formfield.md | 6 +-- .../field_type_reference/imageassetfield.md | 8 ++-- .../field_type_reference/imagefield.md | 6 +-- .../field_type_reference/integerfield.md | 6 +-- .../field_type_reference/isbnfield.md | 6 +-- .../field_type_reference/keywordfield.md | 8 ++-- .../field_type_reference/maplocationfield.md | 8 ++-- .../field_type_reference/matrixfield.md | 6 +-- .../field_type_reference/measurementfield.md | 6 +-- .../field_type_reference/mediafield.md | 6 +-- .../field_type_reference/pagefield.md | 10 ++--- .../productspecificationfield.md | 6 +-- .../field_type_reference/relationfield.md | 8 ++-- .../field_type_reference/relationlistfield.md | 8 ++-- .../field_type_reference/richtextfield.md | 14 +++---- .../field_type_reference/selectionfield.md | 6 +-- .../taxonomyentryassignmentfield.md | 10 ++--- .../taxonomyentryfield.md | 10 ++--- .../field_type_reference/textblockfield.md | 8 ++-- .../field_type_reference/textlinefield.md | 8 ++-- .../field_type_reference/timefield.md | 6 +-- .../field_type_reference/urlfield.md | 6 +-- .../field_type_reference/userfield.md | 8 ++-- mkdocs.yml | 36 ++++++++--------- 35 files changed, 161 insertions(+), 161 deletions(-) diff --git a/docs/content_management/field_types/field_type_reference/addressfield.md b/docs/content_management/field_types/field_type_reference/addressfield.md index 19b0c85cb98..efdcf922f6a 100644 --- a/docs/content_management/field_types/field_type_reference/addressfield.md +++ b/docs/content_management/field_types/field_type_reference/addressfield.md @@ -3,9 +3,9 @@ This field represents and handles address fields. It allows you to customize address fields per country. -| Name | Internal name | -|-----------|-----------------| -| `Address` | `ibexa_address` | +| Name | Field type identifier | +|---------|-----------------------| +| Address | `ibexa_address` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/authorfield.md b/docs/content_management/field_types/field_type_reference/authorfield.md index e2988078bc3..8b76a154cb8 100644 --- a/docs/content_management/field_types/field_type_reference/authorfield.md +++ b/docs/content_management/field_types/field_type_reference/authorfield.md @@ -1,10 +1,10 @@ -# Author field type +# Authors field type This field type allows the storage and retrieval of one or more authors. For each author, it can handle a name and an email address. It's typically used to store information about additional authors who have written/created different parts of a content item. -| Name | Internal name | -|----------|----------------| -| `Author` | `ibexa_author` | +| Name | Field type identifier | +|---------|-----------------------| +| Authors | `ibexa_author` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/binaryfilefield.md b/docs/content_management/field_types/field_type_reference/binaryfilefield.md index ab56a5c0db7..9c0cf069870 100644 --- a/docs/content_management/field_types/field_type_reference/binaryfilefield.md +++ b/docs/content_management/field_types/field_type_reference/binaryfilefield.md @@ -1,13 +1,13 @@ -# BinaryFile field type +# File field type This field type represents and handles a single binary file. It also counts the number of times the file has been downloaded. It's capable of handling virtually any file type and is typically used for storing document types, for example, PDF files, Word documents, or spreadsheets. The maximum allowed file size is determined by the `FileSizeValidator` configuration of the field definition. -| Name | Internal name | -|--------------|--------------------| -| `BinaryFile` | `ibexa_binaryfile` | +| Name | Field type identifier | +|------|-----------------------| +| File | `ibexa_binaryfile` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/checkboxfield.md b/docs/content_management/field_types/field_type_reference/checkboxfield.md index 9275fe7fccc..55ef2f251aa 100644 --- a/docs/content_management/field_types/field_type_reference/checkboxfield.md +++ b/docs/content_management/field_types/field_type_reference/checkboxfield.md @@ -2,9 +2,9 @@ The Checkbox field type stores the current status for a checkbox input, checked or unchecked. -| Name | Internal name | -|------------|-----------------| -| `Checkbox` | `ibexa_boolean` | +| Name | Field type identifier | +|----------|-----------------------| +| Checkbox | `ibexa_boolean` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/countryfield.md b/docs/content_management/field_types/field_type_reference/countryfield.md index af5e054c8e8..12b7694c06b 100644 --- a/docs/content_management/field_types/field_type_reference/countryfield.md +++ b/docs/content_management/field_types/field_type_reference/countryfield.md @@ -2,9 +2,9 @@ This field type represents one or multiple countries. -| Name | Internal name | -|-----------|-----------------| -| `Country` | `ibexa_country` | +| Name | Field type identifier | +|---------|-----------------------| +| Country | `ibexa_country` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/customergroupfield.md b/docs/content_management/field_types/field_type_reference/customergroupfield.md index 5be96a66c71..e83c8e5cbea 100644 --- a/docs/content_management/field_types/field_type_reference/customergroupfield.md +++ b/docs/content_management/field_types/field_type_reference/customergroupfield.md @@ -1,10 +1,10 @@ -# Customer group field +# Customer group field type This field type represents a customer group that a user belongs to. -| Name | Internal name | -|------------------|------------------------| -| `Customer group` | `ibexa_customer_group` | +| Name | Field type identifier | +|----------------|------------------------| +| Customer group | `ibexa_customer_group` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/dateandtimefield.md b/docs/content_management/field_types/field_type_reference/dateandtimefield.md index e4cef202694..5188b15bcda 100644 --- a/docs/content_management/field_types/field_type_reference/dateandtimefield.md +++ b/docs/content_management/field_types/field_type_reference/dateandtimefield.md @@ -1,10 +1,10 @@ -# DateAndTime field type +# Date and time field type This field type represents a full date and time information. -| Name | Internal name | -|---------------|------------------| -| `DateAndTime` | `ibexa_datetime` | +| Name | Field type identifier | +|---------------|-----------------------| +| Date and time | `ibexa_datetime` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/datefield.md b/docs/content_management/field_types/field_type_reference/datefield.md index 460f2b8c571..eedc8c75483 100644 --- a/docs/content_management/field_types/field_type_reference/datefield.md +++ b/docs/content_management/field_types/field_type_reference/datefield.md @@ -5,9 +5,9 @@ This field type represents a date without time information. Time information is **not stored**. Before storing, the provided input value is set to the beginning of the day in the given or the environment timezone. -| Name | Internal name | -|--------|---------------| -| `Date` | `ibexa_date` | +| Name | Field type identifier | +|------|-----------------------| +| Date | `ibexa_date` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/emailaddressfield.md b/docs/content_management/field_types/field_type_reference/emailaddressfield.md index 6ed50030f64..e58a3d0d112 100644 --- a/docs/content_management/field_types/field_type_reference/emailaddressfield.md +++ b/docs/content_management/field_types/field_type_reference/emailaddressfield.md @@ -1,10 +1,10 @@ -# EmailAddress field type +# Email address field type -The EmailAddress field type represents an email address, in the form of a string. +The Email address field type represents an email address, in the form of a string. -| Name | Internal name | -|----------------|---------------| -| `EmailAddress` | `ibexa_email` | +| Name | Field type identifier | +|---------------|-----------------------| +| Email address | `ibexa_email` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/field_type_reference.md b/docs/content_management/field_types/field_type_reference/field_type_reference.md index 711713ab839..00fe26c5731 100644 --- a/docs/content_management/field_types/field_type_reference/field_type_reference.md +++ b/docs/content_management/field_types/field_type_reference/field_type_reference.md @@ -20,42 +20,42 @@ Field definition is provided by the content type, and holds any user defined rul The following table gives an overview of the supported field types that come with [[= product_name =]]. Each field type reference page describes the JSON structure that the REST API returns for a field of that type, and that you send when you create or update it. -The **Internal name** column holds the value that the REST API uses as `fieldTypeIdentifier` in field payloads and as `fieldType` in field definitions. +The **Field type identifier** column holds the value that the REST API uses as `fieldTypeIdentifier` in field payloads and as `fieldType` in field definitions. ## Available field types -| Field type | Internal name | Description | Searchable | +| Field type | Field type identifier | Description | Searchable | |---|---|---|---| | [Address](addressfield.md) | `ibexa_address` | Stores an address. | No | -| [Author](authorfield.md) | `ibexa_author` | Stores a list of authors, each consisting of author name and author email. | Yes | -| [BinaryFile](binaryfilefield.md) | `ibexa_binaryfile` | Stores a file. | Yes | +| [Authors](authorfield.md) | `ibexa_author` | Stores a list of authors, each consisting of author name and author email. | Yes | +| [File](binaryfilefield.md) | `ibexa_binaryfile` | Stores a file. | Yes | | [Checkbox](checkboxfield.md) | `ibexa_boolean` | Stores a boolean value. | Yes | | [Country](countryfield.md) | `ibexa_country` | Stores country names as a string. | Yes | | [Customer group](customergroupfield.md) | `ibexa_customer_group` | Stores customer group to which a user belongs. | Yes | -| [DateAndTime](dateandtimefield.md) | `ibexa_datetime` | Stores a full date including time information. | Yes | +| [Date and time](dateandtimefield.md) | `ibexa_datetime` | Stores a full date including time information. | Yes | | [Date](datefield.md) | `ibexa_date` | Stores date information. | Yes | -| [EmailAddress](emailaddressfield.md) | `ibexa_email` | Validates and stores an email address. | Yes | +| [Email address](emailaddressfield.md) | `ibexa_email` | Validates and stores an email address. | Yes | | [Float](floatfield.md) | `ibexa_float` | Validates and stores a floating-point number. | Yes | | [Form](formfield.md) | `ibexa_form` | Stores a form. | Yes | | [Image](imagefield.md) | `ibexa_image` | Validates and stores an image. | Yes | -| [ImageAsset](imageassetfield.md) | `ibexa_image_asset` | Stores images in independent content items of a generic Image content type. | Yes | +| [Image Asset](imageassetfield.md) | `ibexa_image_asset` | Stores images in independent content items of a generic Image content type. | Yes | | [Integer](integerfield.md) | `ibexa_integer` | Validates and stores an integer value. | Yes | | [ISBN](isbnfield.md) | `ibexa_isbn` | Handles International Standard Book Number (ISBN) in 10-digit or 13-digit format. | Yes | -| [Keyword](keywordfield.md) | `ibexa_keyword` | Stores keywords. | Yes | -| [MapLocation](maplocationfield.md) | `ibexa_gmap_location` | Stores map coordinates. | Yes | +| [Keywords](keywordfield.md) | `ibexa_keyword` | Stores keywords. | Yes | +| [Map location](maplocationfield.md) | `ibexa_gmap_location` | Stores map coordinates. | Yes | | [Matrix](matrixfield.md) | `ibexa_matrix` | Represents and handles a table of rows and columns of data. | No | | [Measurement](measurementfield.md) | `ibexa_measurement` | Validates and stores a unit of measure, and either a single measurement value, or a pair of range values. | Yes | | [Media](mediafield.md) | `ibexa_media` | Validates and stores a media file. | Yes | -| [Page](pagefield.md) | `ibexa_landing_page` | Stores a Page with a layout consisting of multiple zones. | N/A | -| [ProductSpecification](productspecificationfield.md) | `ibexa_product_specification` | Stores product attributes and VAT | Yes | -| [Relation](relationfield.md) | `ibexa_object_relation` | Validates and stores a relation to a content item. | Yes | -| [RelationList](relationlistfield.md) | `ibexa_object_relation_list` | Validates and stores a list of relations to content items. | Yes | -| [RichText](richtextfield.md) | `ibexa_richtext` | Validates and stores structured rich text in XML. | Yes | +| [Landing Page](pagefield.md) | `ibexa_landing_page` | Stores a Page with a layout consisting of multiple zones. | N/A | +| [Product specification](productspecificationfield.md) | `ibexa_product_specification` | Stores product attributes and VAT | Yes | +| [Content relation (single)](relationfield.md) | `ibexa_object_relation` | Validates and stores a relation to a content item. | Yes | +| [Content relations (multiple)](relationlistfield.md) | `ibexa_object_relation_list` | Validates and stores a list of relations to content items. | Yes | +| [Rich text](richtextfield.md) | `ibexa_richtext` | Validates and stores structured rich text in XML. | Yes | | [Selection](selectionfield.md) | `ibexa_selection` | Validates and stores a single selection or multiple choices from a list of options. | Yes | -| [TaxonomyEntry](taxonomyentryfield.md) | `ibexa_taxonomy_entry` | Stores information about the Taxonomy tree. | Yes | -| [TaxonomyEntryAssignment](taxonomyentryassignmentfield.md) | `ibexa_taxonomy_entry_assignment` | Makes content taggable by Taxonomy. | Yes | -| [TextBlock](textblockfield.md) | `ibexa_text` | Validates and stores a larger block of text. | Yes | -| [TextLine](textlinefield.md) | `ibexa_string` | Validates and stores a single line of text. | Yes | +| [Taxonomy Entry](taxonomyentryfield.md) | `ibexa_taxonomy_entry` | Stores information about the Taxonomy tree. | Yes | +| [Taxonomy Entry Assignment](taxonomyentryassignmentfield.md) | `ibexa_taxonomy_entry_assignment` | Makes content taggable by Taxonomy. | Yes | +| [Text block](textblockfield.md) | `ibexa_text` | Validates and stores a larger block of text. | Yes | +| [Text line](textlinefield.md) | `ibexa_string` | Validates and stores a single line of text. | Yes | | [Time](timefield.md) | `ibexa_time` | Stores time information. | Yes | -| [Url](urlfield.md) | `ibexa_url` | Stores a URL / address. | Yes | -| [User](userfield.md) | `ibexa_user` | Validates and stores information about a user. | No | +| [URL](urlfield.md) | `ibexa_url` | Stores a URL / address. | Yes | +| [User account](userfield.md) | `ibexa_user` | Validates and stores information about a user. | No | diff --git a/docs/content_management/field_types/field_type_reference/floatfield.md b/docs/content_management/field_types/field_type_reference/floatfield.md index eb0710cedba..84303ba7d55 100644 --- a/docs/content_management/field_types/field_type_reference/floatfield.md +++ b/docs/content_management/field_types/field_type_reference/floatfield.md @@ -2,9 +2,9 @@ This field type stores numeric values which are provided as floats. -| Name | Internal name | -|---------|---------------| -| `Float` | `ibexa_float` | +| Name | Field type identifier | +|-------|-----------------------| +| Float | `ibexa_float` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/formfield.md b/docs/content_management/field_types/field_type_reference/formfield.md index ca145f05ef1..2c13ad13299 100644 --- a/docs/content_management/field_types/field_type_reference/formfield.md +++ b/docs/content_management/field_types/field_type_reference/formfield.md @@ -2,8 +2,8 @@ The Form field type stores a Form consisting of one or more form fields. -| Name | Internal name | -|--------|---------------| -| `Form` | `ibexa_form` | +| Name | Field type identifier | +|------|-----------------------| +| Form | `ibexa_form` | For more information about working with Forms, see the [Form Builder guide](form_builder_guide.md). diff --git a/docs/content_management/field_types/field_type_reference/imageassetfield.md b/docs/content_management/field_types/field_type_reference/imageassetfield.md index b4c4948e43e..50073fe833f 100644 --- a/docs/content_management/field_types/field_type_reference/imageassetfield.md +++ b/docs/content_management/field_types/field_type_reference/imageassetfield.md @@ -1,11 +1,11 @@ -# ImageAsset field type +# Image Asset field type Image Asset field type enables storing images in independent content items of a generic Image content type, in the media library. It makes them reusable across system. -| Name | Internal name | -|--------------|---------------------| -| `ImageAsset` | `ibexa_image_asset` | +| Name | Field type identifier | +|-------------|-----------------------| +| Image Asset | `ibexa_image_asset` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/imagefield.md b/docs/content_management/field_types/field_type_reference/imagefield.md index 6c4417bc9d1..88036455f21 100644 --- a/docs/content_management/field_types/field_type_reference/imagefield.md +++ b/docs/content_management/field_types/field_type_reference/imagefield.md @@ -2,9 +2,9 @@ The Image field type allows you to store an image file. -| Name | Internal name | -|---------|---------------| -| `Image` | `ibexa_image` | +| Name | Field type identifier | +|-------|-----------------------| +| Image | `ibexa_image` | A **variation service** handles the conversion of the original image into different formats and sizes through a set of preconfigured named variations, for example, large, small, medium, or black and white thumbnail. diff --git a/docs/content_management/field_types/field_type_reference/integerfield.md b/docs/content_management/field_types/field_type_reference/integerfield.md index f78f80bd93c..5ef5373fce9 100644 --- a/docs/content_management/field_types/field_type_reference/integerfield.md +++ b/docs/content_management/field_types/field_type_reference/integerfield.md @@ -2,9 +2,9 @@ This field type represents an integer value. -| Name | Internal name | -|-----------|-----------------| -| `Integer` | `ibexa_integer` | +| Name | Field type identifier | +|---------|-----------------------| +| Integer | `ibexa_integer` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/isbnfield.md b/docs/content_management/field_types/field_type_reference/isbnfield.md index 0a24fd41043..6594cb80720 100644 --- a/docs/content_management/field_types/field_type_reference/isbnfield.md +++ b/docs/content_management/field_types/field_type_reference/isbnfield.md @@ -2,9 +2,9 @@ This field type represents an ISBN string either an ISBN-10 or ISBN-13 format. -| Name | Internal name | -|--------|---------------| -| `ISBN` | `ibexa_isbn` | +| Name | Field type identifier | +|------|-----------------------| +| ISBN | `ibexa_isbn` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/keywordfield.md b/docs/content_management/field_types/field_type_reference/keywordfield.md index 454f13ff687..4b78a41a8fe 100644 --- a/docs/content_management/field_types/field_type_reference/keywordfield.md +++ b/docs/content_management/field_types/field_type_reference/keywordfield.md @@ -1,10 +1,10 @@ -# Keyword field type +# Keywords field type This field type stores one or several keywords. -| Name | Internal name | -|-----------|-----------------| -| `Keyword` | `ibexa_keyword` | +| Name | Field type identifier | +|----------|-----------------------| +| Keywords | `ibexa_keyword` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/maplocationfield.md b/docs/content_management/field_types/field_type_reference/maplocationfield.md index 33dd73c92f2..2c642b2de25 100644 --- a/docs/content_management/field_types/field_type_reference/maplocationfield.md +++ b/docs/content_management/field_types/field_type_reference/maplocationfield.md @@ -1,10 +1,10 @@ -# MapLocation field type +# Map location field type This field type represents a geographical location. -| Name | Internal name | -|---------------|-----------------------| -| `MapLocation` | `ibexa_gmap_location` | +| Name | Field type identifier | +|--------------|-----------------------| +| Map location | `ibexa_gmap_location` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/matrixfield.md b/docs/content_management/field_types/field_type_reference/matrixfield.md index 213e4ad5260..20e9d58c044 100644 --- a/docs/content_management/field_types/field_type_reference/matrixfield.md +++ b/docs/content_management/field_types/field_type_reference/matrixfield.md @@ -2,9 +2,9 @@ This field represents and handles a table of rows and columns of data. -| Name | Internal name | -|----------|----------------| -| `Matrix` | `ibexa_matrix` | +| Name | Field type identifier | +|--------|-----------------------| +| Matrix | `ibexa_matrix` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/measurementfield.md b/docs/content_management/field_types/field_type_reference/measurementfield.md index 47c688ae7ef..0a6d310b50b 100644 --- a/docs/content_management/field_types/field_type_reference/measurementfield.md +++ b/docs/content_management/field_types/field_type_reference/measurementfield.md @@ -3,9 +3,9 @@ The Measurement field type represents measurement information. It stores the unit of measure, and either a single measurement value, or a pair of top and bottom values that defines a range. -| Name | Internal name | -|---------------|---------------------| -| `Measurement` | `ibexa_measurement` | +| Name | Field type identifier | +|-------------|-----------------------| +| Measurement | `ibexa_measurement` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/mediafield.md b/docs/content_management/field_types/field_type_reference/mediafield.md index 689bbcfbd30..8154b4690f5 100644 --- a/docs/content_management/field_types/field_type_reference/mediafield.md +++ b/docs/content_management/field_types/field_type_reference/mediafield.md @@ -12,9 +12,9 @@ It's capable of handling the following types of files: - HTML5 Video - HTML5 Audio -| Name | Internal name | -|---------|---------------| -| `Media` | `ibexa_media` | +| Name | Field type identifier | +|-------|-----------------------| +| Media | `ibexa_media` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/pagefield.md b/docs/content_management/field_types/field_type_reference/pagefield.md index e3061f3b6b5..d7495927e79 100644 --- a/docs/content_management/field_types/field_type_reference/pagefield.md +++ b/docs/content_management/field_types/field_type_reference/pagefield.md @@ -1,11 +1,11 @@ -# Page field type +# Landing Page field type -Page field type represents a page with a layout consisting of multiple zones. +The Landing Page field type represents a page with a layout consisting of multiple zones. Each zone can in turn contain blocks. -| Name | Internal name | -|---------------|----------------------| -| `LandingPage` | `ibexa_landing_page` | +| Name | Field type identifier | +|--------------|-----------------------| +| Landing Page | `ibexa_landing_page` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/productspecificationfield.md b/docs/content_management/field_types/field_type_reference/productspecificationfield.md index dd12f4ede98..7bcf6905d03 100644 --- a/docs/content_management/field_types/field_type_reference/productspecificationfield.md +++ b/docs/content_management/field_types/field_type_reference/productspecificationfield.md @@ -7,9 +7,9 @@ month_change: false This field represents and handles [product attributes](products.md#product-attributes) and VAT. Consider it as internal to the [product catalog](product_catalog.md). -| Name | Internal name | -|------------------------|-------------------------------| -| `ProductSpecification` | `ibexa_product_specification` | +| Name | Field type identifier | +|-----------------------|-------------------------------| +| Product specification | `ibexa_product_specification` | !!! caution diff --git a/docs/content_management/field_types/field_type_reference/relationfield.md b/docs/content_management/field_types/field_type_reference/relationfield.md index 9024a98c632..ae47f6b9dde 100644 --- a/docs/content_management/field_types/field_type_reference/relationfield.md +++ b/docs/content_management/field_types/field_type_reference/relationfield.md @@ -1,10 +1,10 @@ -# Relation field type +# Content relation (single) field type This field type makes it possible to store and retrieve the value of a relation to another content item. -| Name | Internal name | -|------------|-------------------------| -| `Relation` | `ibexa_object_relation` | +| Name | Field type identifier | +|---------------------------|-------------------------| +| Content relation (single) | `ibexa_object_relation` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/relationlistfield.md b/docs/content_management/field_types/field_type_reference/relationlistfield.md index 2207e03b064..8ec34f4a5fa 100644 --- a/docs/content_management/field_types/field_type_reference/relationlistfield.md +++ b/docs/content_management/field_types/field_type_reference/relationlistfield.md @@ -1,10 +1,10 @@ -# RelationList field type +# Content relations (multiple) field type This field type makes it possible to store and retrieve values of a relation to other content items. -| Name | Internal name | -|----------------|------------------------------| -| `RelationList` | `ibexa_object_relation_list` | +| Name | Field type identifier | +|------------------------------|------------------------------| +| Content relations (multiple) | `ibexa_object_relation_list` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/richtextfield.md b/docs/content_management/field_types/field_type_reference/richtextfield.md index b3cf2be003d..387a1acb8bd 100644 --- a/docs/content_management/field_types/field_type_reference/richtextfield.md +++ b/docs/content_management/field_types/field_type_reference/richtextfield.md @@ -1,10 +1,10 @@ -# RichText field type +# Rich text field type This field type validates and stores structured rich text in [DocBook](https://docbook.org/) XML format, and exposes it in several formats. -| Name | Internal name | -|------------|------------------| -| `RichText` | `ibexa_richtext` | +| Name | Field type identifier | +|-----------|-----------------------| +| Rich text | `ibexa_richtext` | ## Field value @@ -31,7 +31,7 @@ If the input doesn't conform to the internal format, it's converted into it. ### Internal format -As its internal format, the RichText field type uses a [custom flavor of the DocBook format](#custom-docbook-format). +As its internal format, the Rich text field type uses a [custom flavor of the DocBook format](#custom-docbook-format). ``` xml @@ -70,7 +70,7 @@ The examples below show the DocBook markup that goes into that string. The RichText format enriches [DocBook](https://docbook.org/) with the following custom elements: -- `section` - main element of a RichText field +- `section` - main element of a Rich text field - `ezembed` - holds embedded images - `ezembedinline` - holds embedded content items - `eztemplate` - holds custom tags, including built-in custom tags for embedded Facebook, Twitter, and YouTube content @@ -81,7 +81,7 @@ The RichText format enriches [DocBook](https://docbook.org/) with the following !!! note "Unsupported DocBook elements" - Some DocBook elements aren't supported by RichText. + Some DocBook elements aren't supported by the Rich text field type. Refer to [`ezpublish.rng`](https://github.com/ibexa/fieldtype-richtext/blob/6.0/src/bundle/Resources/richtext/schemas/docbook/ezpublish.rng#L137) for a full list. ### Online Editor elements diff --git a/docs/content_management/field_types/field_type_reference/selectionfield.md b/docs/content_management/field_types/field_type_reference/selectionfield.md index 3c654bedfde..1179039fd92 100644 --- a/docs/content_management/field_types/field_type_reference/selectionfield.md +++ b/docs/content_management/field_types/field_type_reference/selectionfield.md @@ -2,9 +2,9 @@ The Selection field type stores single selections or multiple choices from a list of options defined in the field definition. -| Name | Internal name | -|-------------|-------------------| -| `Selection` | `ibexa_selection` | +| Name | Field type identifier | +|-----------|-----------------------| +| Selection | `ibexa_selection` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md b/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md index bf772c929d7..5401d0a7a5f 100644 --- a/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md +++ b/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md @@ -1,17 +1,17 @@ -# TaxonomyEntryAssignment field type +# Taxonomy Entry Assignment field type -`TaxonomyEntryAssignment` field is used to integrate content with the Taxonomy module. +The Taxonomy Entry Assignment field type is used to integrate content with the Taxonomy module. It allows you to select tags or categories and assign them to content. !!! caution "Duplicate taxonomy fields" Because tags are assigned per content item, not per field, you cannot use two **Taxonomy Entry Assignment** fields with the same taxonomy type in one content type. -To be able to assign tags to the content, first, you need to add a `TaxonomyEntryAssignment` field to the content type definition. +To be able to assign tags to the content, first, you need to add a Taxonomy Entry Assignment field to the content type definition. -| Name | Internal name | +| Name | Field type identifier | |---------------------------|-----------------------------------| -| `TaxonomyEntryAssignment` | `ibexa_taxonomy_entry_assignment` | +| Taxonomy Entry Assignment | `ibexa_taxonomy_entry_assignment` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/taxonomyentryfield.md b/docs/content_management/field_types/field_type_reference/taxonomyentryfield.md index 44c88eb183c..8fcf24c00e9 100644 --- a/docs/content_management/field_types/field_type_reference/taxonomyentryfield.md +++ b/docs/content_management/field_types/field_type_reference/taxonomyentryfield.md @@ -1,10 +1,10 @@ -# TaxonomyEntry field type +# Taxonomy Entry field type -TaxonomyEntry is a field type that stores information about the parent entry in the taxonomy tree, placing the taxonomy entry (tag or product category) in the taxonomy structure. +Taxonomy Entry is a field type that stores information about the parent entry in the taxonomy tree, placing the taxonomy entry (tag or product category) in the taxonomy structure. -| Name | Internal name | -|-----------------|------------------------| -| `TaxonomyEntry` | `ibexa_taxonomy_entry` | +| Name | Field type identifier | +|----------------|------------------------| +| Taxonomy Entry | `ibexa_taxonomy_entry` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/textblockfield.md b/docs/content_management/field_types/field_type_reference/textblockfield.md index 729ebab8620..8cc628ea2a2 100644 --- a/docs/content_management/field_types/field_type_reference/textblockfield.md +++ b/docs/content_management/field_types/field_type_reference/textblockfield.md @@ -1,10 +1,10 @@ -# TextBlock field type +# Text block field type The field type handles a block of multiple lines of unformatted text. It's capable of handling up to 16,777,216 characters. -| Name | Internal name | -|-------------|---------------| -| `TextBlock` | `ibexa_text` | +| Name | Field type identifier | +|------------|-----------------------| +| Text block | `ibexa_text` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/textlinefield.md b/docs/content_management/field_types/field_type_reference/textlinefield.md index a40b5929959..fd3a7608cfd 100644 --- a/docs/content_management/field_types/field_type_reference/textlinefield.md +++ b/docs/content_management/field_types/field_type_reference/textlinefield.md @@ -1,11 +1,11 @@ -# TextLine field type +# Text line field type This field type makes possible to store and retrieve a single line of unformatted text. It's capable of handling up to 255 characters. -| Name | Internal name | -|------------|----------------| -| `TextLine` | `ibexa_string` | +| Name | Field type identifier | +|-----------|-----------------------| +| Text line | `ibexa_string` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/timefield.md b/docs/content_management/field_types/field_type_reference/timefield.md index 4bba38017a1..05e447da152 100644 --- a/docs/content_management/field_types/field_type_reference/timefield.md +++ b/docs/content_management/field_types/field_type_reference/timefield.md @@ -5,9 +5,9 @@ This field type represents time information. Date information is **not stored**. What is stored is the number of seconds, calculated from the beginning of the day in the given or the environment timezone. -| Name | Internal name | -|--------|---------------| -| `Time` | `ibexa_time` | +| Name | Field type identifier | +|------|-----------------------| +| Time | `ibexa_time` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/urlfield.md b/docs/content_management/field_types/field_type_reference/urlfield.md index bc6abd10401..e30e173b3a8 100644 --- a/docs/content_management/field_types/field_type_reference/urlfield.md +++ b/docs/content_management/field_types/field_type_reference/urlfield.md @@ -3,9 +3,9 @@ This field type represents and handles a URL. It's formed by the combination of a link and the respective text. -| Name | Internal name | -|-------|---------------| -| `Url` | `ibexa_url` | +| Name | Field type identifier | +|------|-----------------------| +| URL | `ibexa_url` | ## Field value diff --git a/docs/content_management/field_types/field_type_reference/userfield.md b/docs/content_management/field_types/field_type_reference/userfield.md index df4e03dd218..bdbb5f933d1 100644 --- a/docs/content_management/field_types/field_type_reference/userfield.md +++ b/docs/content_management/field_types/field_type_reference/userfield.md @@ -1,10 +1,10 @@ -# User field type +# User account field type This field type validates and stores information about a user. -| Name | Internal name | -|--------|---------------| -| `User` | `ibexa_user` | +| Name | Field type identifier | +|--------------|-----------------------| +| User account | `ibexa_user` | ## Field value diff --git a/mkdocs.yml b/mkdocs.yml index ea959e0d6c7..92818ade7a5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -87,38 +87,38 @@ nav: - Field type reference: - Field type reference: content_management/field_types/field_type_reference/field_type_reference.md - Address field type: content_management/field_types/field_type_reference/addressfield.md - - Author field type: content_management/field_types/field_type_reference/authorfield.md - - BinaryFile field type: content_management/field_types/field_type_reference/binaryfilefield.md + - Authors field type: content_management/field_types/field_type_reference/authorfield.md + - File field type: content_management/field_types/field_type_reference/binaryfilefield.md - Checkbox field type: content_management/field_types/field_type_reference/checkboxfield.md - Country field type: content_management/field_types/field_type_reference/countryfield.md - - CustomerGroup field type: content_management/field_types/field_type_reference/customergroupfield.md - - DateAndTime field type: content_management/field_types/field_type_reference/dateandtimefield.md + - Customer group field type: content_management/field_types/field_type_reference/customergroupfield.md + - Date and time field type: content_management/field_types/field_type_reference/dateandtimefield.md - Date field type: content_management/field_types/field_type_reference/datefield.md - - EmailAddress field type: content_management/field_types/field_type_reference/emailaddressfield.md + - Email address field type: content_management/field_types/field_type_reference/emailaddressfield.md - Float field type: content_management/field_types/field_type_reference/floatfield.md - Form field type: content_management/field_types/field_type_reference/formfield.md - Image field type: content_management/field_types/field_type_reference/imagefield.md - - ImageAsset field type: content_management/field_types/field_type_reference/imageassetfield.md + - Image Asset field type: content_management/field_types/field_type_reference/imageassetfield.md - Integer field type: content_management/field_types/field_type_reference/integerfield.md - ISBN field type: content_management/field_types/field_type_reference/isbnfield.md - - Keyword field type: content_management/field_types/field_type_reference/keywordfield.md - - MapLocation field type: content_management/field_types/field_type_reference/maplocationfield.md + - Keywords field type: content_management/field_types/field_type_reference/keywordfield.md + - Map location field type: content_management/field_types/field_type_reference/maplocationfield.md - Matrix field type: content_management/field_types/field_type_reference/matrixfield.md - Measurement field type: content_management/field_types/field_type_reference/measurementfield.md - Media field type: content_management/field_types/field_type_reference/mediafield.md - - Page field type: content_management/field_types/field_type_reference/pagefield.md - - ProductSpecification field type: content_management/field_types/field_type_reference/productspecificationfield.md - - Relation field type: content_management/field_types/field_type_reference/relationfield.md - - RelationList field type: content_management/field_types/field_type_reference/relationlistfield.md - - RichText field type: content_management/field_types/field_type_reference/richtextfield.md + - Landing Page field type: content_management/field_types/field_type_reference/pagefield.md + - Product specification field type: content_management/field_types/field_type_reference/productspecificationfield.md + - Content relation (single) field type: content_management/field_types/field_type_reference/relationfield.md + - Content relations (multiple) field type: content_management/field_types/field_type_reference/relationlistfield.md + - Rich text field type: content_management/field_types/field_type_reference/richtextfield.md - Selection field type: content_management/field_types/field_type_reference/selectionfield.md - - TaxonomyEntry field type: content_management/field_types/field_type_reference/taxonomyentryfield.md - - TaxonomyEntryAssignment field type: content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md - - TextBlock field type: content_management/field_types/field_type_reference/textblockfield.md - - TextLine field type: content_management/field_types/field_type_reference/textlinefield.md + - Taxonomy Entry field type: content_management/field_types/field_type_reference/taxonomyentryfield.md + - Taxonomy Entry Assignment field type: content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md + - Text block field type: content_management/field_types/field_type_reference/textblockfield.md + - Text line field type: content_management/field_types/field_type_reference/textlinefield.md - Time field type: content_management/field_types/field_type_reference/timefield.md - URL field type: content_management/field_types/field_type_reference/urlfield.md - - User field type: content_management/field_types/field_type_reference/userfield.md + - User account field type: content_management/field_types/field_type_reference/userfield.md - AI: - AI: ai/ai.md - AI Actions: From 4e56de76ef4672629c299fca8f7b5c49ba000f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Thu, 24 Sep 2026 10:58:15 +0200 Subject: [PATCH 07/11] Fieldtypes improvments --- .../field_type_reference/imagefield.md | 20 ++++++++++++++++++- .../field_type_reference/relationlistfield.md | 6 +----- .../taxonomyentryassignmentfield.md | 1 - 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/content_management/field_types/field_type_reference/imagefield.md b/docs/content_management/field_types/field_type_reference/imagefield.md index 88036455f21..f1de986694d 100644 --- a/docs/content_management/field_types/field_type_reference/imagefield.md +++ b/docs/content_management/field_types/field_type_reference/imagefield.md @@ -25,7 +25,7 @@ The field value is an object with the following keys, or `null` when the field i | `path` | `string` | Same value as `inputUri`, with a leading slash. | `/var/site/storage/images/0/8/4/1/1480-1-eng-GB/image.png` | | `width` | `string` | Original image width in pixels. Returned as a string when you read a content item, and as an integer in the response to creating one. | `960` | | `height` | `string` | Original image height in pixels. Returned as a string when you read a content item, and as an integer in the response to creating one. | `540` | -| `additionalData` | `object` | Extra information about the image, if available. | `{}` | +| `additionalData` | `object` | Extra information about the image, if available, for example, its [focal point](#focal-point). | `{}` | | `variations` | `object` | Available image variations, keyed by variation identifier. Read-only, added by the API on output only. | See below. | ``` json @@ -55,6 +55,24 @@ The field value is an object with the following keys, or `null` when the field i } ``` +### Focal point + +When an editor [sets a focal point]([[= user_doc =]]/image_management/edit_images/#focal-point) for the image in the image editor, its coordinates are stored in `additionalData` under the `focalPointX` and `focalPointY` keys. +The coordinates are in pixels, relative to the original image, and are returned as strings. +If no focal point is set, the keys are absent. + +``` json +"additionalData": { + "focalPointX": "480", + "focalPointY": "270" +} +``` + +The focal point has no effect on how the image is rendered by itself. +You can use it in your front end, for example, to decide which part of the image stays visible when it's cropped. + +To keep the focal point when you update the field, include `additionalData` in the value that you send. + ## Image variations For each variation, the field value provides a URI. diff --git a/docs/content_management/field_types/field_type_reference/relationlistfield.md b/docs/content_management/field_types/field_type_reference/relationlistfield.md index 8ec34f4a5fa..85bc0f1846f 100644 --- a/docs/content_management/field_types/field_type_reference/relationlistfield.md +++ b/docs/content_management/field_types/field_type_reference/relationlistfield.md @@ -35,15 +35,11 @@ When you create or update a field, provide `destinationContentIds` only. This field type validates if: -- the `selectionMethod` specified is `"SELECTION_BROWSE"` or `"SELECTION_DROPDOWN"`. A validation error is returned if the value doesn't match. +- the `selectionMethod` specified is `"SELECTION_BROWSE"`. A validation error is returned if the value doesn't match. - the `selectionDefaultLocation` specified is `null`, a string, or an integer. If the type validation fails, a validation error is returned. - the value specified in `selectionContentTypes` is an array. If not, a validation error is returned. - the number of content items selected in the field isn't greater than the `selectionLimit`. -!!! note - - The dropdown selection method isn't implemented yet. - ## Settings The field definition of this field type can be configured with the following options: diff --git a/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md b/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md index 5401d0a7a5f..6ad3da03f6a 100644 --- a/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md +++ b/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md @@ -23,7 +23,6 @@ The field value is an object with the following keys: | `taxonomy` | `string` | Identifier of the taxonomy that all the entries must be assigned to. | `product_categories` | Set the `taxonomy` value to the same identifier as the `taxonomy` setting of the field definition. -The REST API doesn't check that the two match. ``` json { From beb3479966859d622d9635ed3cd8f2ec6522302b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Thu, 24 Sep 2026 11:00:06 +0200 Subject: [PATCH 08/11] Fixed link --- docs/ibexa_products/cohesivo_saas_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ibexa_products/cohesivo_saas_guide.md b/docs/ibexa_products/cohesivo_saas_guide.md index e8142560438..e4420f6f89b 100644 --- a/docs/ibexa_products/cohesivo_saas_guide.md +++ b/docs/ibexa_products/cohesivo_saas_guide.md @@ -64,7 +64,7 @@ Sites can share content and assets, while granular [user permissions]([[= user_d ### Agentic AI -With [AI Assistant]([[= user_doc =]]/content_management/create_edit_content_items/#ai-assistant) as the entry point, you can use an [MCP tool set](mcp_usage.md#use-built-in-tools) identical across the [[= product_name_base =]] ecosystem. +With [AI Assistant]([[= user_doc =]]/content_management/create_edit_content_items/#ai-assistant) as the entry point, you can use an [MCP tool set](mcp_guide.md#built-in-tools) identical across the [[= product_name_base =]] ecosystem. The MCP server allows AI tools and agents to interact with [[= product_name =]] capabilities through a standardized interface rather than requiring a separate integration for each agent or tool. ### Secured remote MCP endpoint From 731b7f4a18988f065b8129315ad757aaef818e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Thu, 24 Sep 2026 11:03:24 +0200 Subject: [PATCH 09/11] Fixed link --- docs/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release_notes.md b/docs/release_notes.md index b5fc7177c28..9ab58c98203 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -23,7 +23,7 @@ month_change: false [[= product_name =]] SaaS is now available. -To learn more about this product, see the [Cohesivo SaaS product guide](TODO: link) and the [official website](https://cohesivo.com/en). +To learn more about this product, see the [Cohesivo SaaS product guide](cohesivo_saas_guide.md) and the [official website](https://cohesivo.com/en). [[= release_note_entry_end() =]] From ed3c527e8ef916c8b3d38b3e52854c0f1be8e11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Tue, 29 Sep 2026 10:12:47 +0200 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> --- docs/api/rest_api/rest_api_authentication.md | 2 +- .../field_types/field_type_reference/imagefield.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/rest_api/rest_api_authentication.md b/docs/api/rest_api/rest_api_authentication.md index c8de0bc3eb6..ee219d0bd4d 100644 --- a/docs/api/rest_api/rest_api_authentication.md +++ b/docs/api/rest_api/rest_api_authentication.md @@ -106,7 +106,7 @@ curl https://example.cohesivo.app/api/ibexa/v2/user/current \ The response describes the user that the request runs as, which is the quickest way to confirm which identity a token carries. -Access tokens are valid for 15 minutes. +Access tokens are valid for 15 minutes after their creation. ## Rate limits diff --git a/docs/content_management/field_types/field_type_reference/imagefield.md b/docs/content_management/field_types/field_type_reference/imagefield.md index f1de986694d..85418931e35 100644 --- a/docs/content_management/field_types/field_type_reference/imagefield.md +++ b/docs/content_management/field_types/field_type_reference/imagefield.md @@ -71,7 +71,7 @@ If no focal point is set, the keys are absent. The focal point has no effect on how the image is rendered by itself. You can use it in your front end, for example, to decide which part of the image stays visible when it's cropped. -To keep the focal point when you update the field, include `additionalData` in the value that you send. +To keep the focal point when you update the field through an API, include `additionalData` in the value that you send. ## Image variations From acbc48b8e1fef041249370ac7142b9335ffd0ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Tue, 29 Sep 2026 10:52:50 +0200 Subject: [PATCH 11/11] Removed YAML testing --- .github/workflows/yaml_samples.yaml | 51 ----- .gitignore | 1 - README.md | 13 -- composer.json | 26 +-- phpunit.xml.dist | 14 -- tests/ConfigurationProvider.php | 184 --------------- tests/Markdown/MarkdownYamlExtractor.php | 78 ------- tests/Markdown/MarkdownYamlExtractorTest.php | 224 ------------------- tests/ValidationBaseline.php | 75 ------- tests/Yaml/CodeSample.php | 16 -- tests/Yaml/YamlSamplesProvider.php | 66 ------ tests/Yaml/YamlTest.php | 169 -------------- tests/generate-yaml-baseline.php | 156 ------------- tests/yaml-validation-baseline.yaml | 4 - 14 files changed, 3 insertions(+), 1074 deletions(-) delete mode 100644 .github/workflows/yaml_samples.yaml delete mode 100644 phpunit.xml.dist delete mode 100644 tests/ConfigurationProvider.php delete mode 100644 tests/Markdown/MarkdownYamlExtractor.php delete mode 100644 tests/Markdown/MarkdownYamlExtractorTest.php delete mode 100644 tests/ValidationBaseline.php delete mode 100644 tests/Yaml/CodeSample.php delete mode 100644 tests/Yaml/YamlSamplesProvider.php delete mode 100644 tests/Yaml/YamlTest.php delete mode 100644 tests/generate-yaml-baseline.php delete mode 100644 tests/yaml-validation-baseline.yaml diff --git a/.github/workflows/yaml_samples.yaml b/.github/workflows/yaml_samples.yaml deleted file mode 100644 index 5bfafa96bbe..00000000000 --- a/.github/workflows/yaml_samples.yaml +++ /dev/null @@ -1,51 +0,0 @@ -name: "Validate YAML samples" - -on: - pull_request: ~ - -jobs: - yaml-samples-validation: - name: Validate YAML samples - runs-on: "ubuntu-26.04" - strategy: - fail-fast: false - matrix: - php: - - "8.4" # Upper supported version - - "8.3" # Lower supported version - steps: - - uses: actions/checkout@v7 - - - name: Setup PHP Action - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: "pdo_sqlite, gd" - tools: cs2pr - - - name: Generate token - id: generate_token - uses: actions/create-github-app-token@v3 - with: - app-id: ${{ secrets.AUTOMATION_CLIENT_ID }} - private-key: ${{ secrets.AUTOMATION_CLIENT_SECRET }} - owner: ${{ github.repository_owner }} - - - name: Add composer keys for private packagist - run: | - composer config --global http-basic.updates.ibexa.co $SATIS_NETWORK_KEY $SATIS_NETWORK_TOKEN - composer config --global github-oauth.github.com $GITHUB_TOKEN - env: - SATIS_NETWORK_KEY: ${{ secrets.SATIS_NETWORK_KEY }} - SATIS_NETWORK_TOKEN: ${{ secrets.SATIS_NETWORK_TOKEN }} - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} - - # The installed ibexa/* bundles are what makes it possible to build the - # full Symfony configuration tree the YAML samples are validated against. - - uses: ramsey/composer-install@v4 - with: - dependency-versions: highest - - - name: Validate YAML configuration samples - run: composer check-yaml --ansi diff --git a/.gitignore b/.gitignore index 682c3921e04..afb74c2ae2f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ docs/css/*.map lychee.toml /repositories/ lychee-report.md -.phpunit.result.cache /build/ *.egg-info/ /doc/ diff --git a/README.md b/README.md index a66ba392b49..a7f20cd35d6 100644 --- a/README.md +++ b/README.md @@ -44,19 +44,6 @@ of the command. ## Testing the documentation -### YAML configuration - -The YAML snippets in the Markdown pages are validated against the -Symfony configuration trees of the installed Ibexa bundles. To run the validation, use: - -``` bash -composer update -composer check-yaml -``` - -To add an error into a baseline, run `composer yaml-update-baseline` and commit the result. -Error added to the baseline are not reported again. - ### markdownlint This repository uses [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2) to check Markdown formatting, including table syntax. diff --git a/composer.json b/composer.json index 84242b333f8..b75592baddc 100644 --- a/composer.json +++ b/composer.json @@ -4,11 +4,6 @@ "type": "library", "keywords": ["ibexa", "cohesivo", "documentation", "markdown", "llm", "ai", "agents"], "license": "GNU General Public License v2.0", - "autoload-dev": { - "psr-4": { - "Ibexa\\Tests\\Documentation\\": "tests/" - } - }, "repositories": [ { "type": "composer", @@ -19,8 +14,6 @@ "php": "^8.3" }, "require-dev": { - "phpunit/phpunit": "^11.0", - "symfony/yaml": "^7.0", "ibexa/connector-gemini": "6.0.x-dev", "ibexa/doctrine-schema": "6.0.x-dev", "ibexa/search": "6.0.x-dev", @@ -89,10 +82,6 @@ "ibexa/design-system-twig": "~6.0.x-dev" }, "scripts": { - "check-yaml": "phpunit --group yaml", - "phpunit": "phpunit --exclude-group=yaml", - "yaml-update-baseline": "php tests/generate-yaml-baseline.php", - "composer-update": "[ -d vendor ] || composer update", "yarn-install": "[ -d node_modules ] || yarn install", "markdownlint": [ "@yarn-install", @@ -103,27 +92,18 @@ "yarn markdownlint --fix" ], "test": [ - "@composer-update", - "EXIT=0; FAILED=''; { composer markdownlint; } || { EXIT=1; FAILED=\"$FAILED markdownlint\"; }; { composer check-yaml; } || { EXIT=1; FAILED=\"$FAILED check-yaml\"; }; if [ 1 -eq $EXIT ]; then echo \"Failed:$FAILED\"; fi; exit $EXIT;" + "@markdownlint" ], "fix": [ "@composer fix-markdownlint" - ], - "baseline": [ - "@composer-update", - "@composer yaml-update-baseline" ] }, "scripts-descriptions": { - "check-yaml": "Run PHPUnit tests (YAML validation)", - "yaml-update-baseline": "Regenerate tests/yaml-validation-baseline.yaml from current failures", - "composer-update": "Install composer dependencies if not already installed", "yarn-install": "Install yarn dependencies if not already installed", "markdownlint": "Run Markdownlint on all documentation files", "fix-markdownlint": "Automatically fixes Markdownlint issues in all documentation files", - "test": "Run all checks (Markdownlint, YAML checks), continuing past failures and reporting failure overall if any check failed", - "fix": "Run all automatic fixes (Markdownlint)", - "baseline": "Regenerate the YAML validation baseline from current failures" + "test": "Run all checks (Markdownlint)", + "fix": "Run all automatic fixes (Markdownlint)" }, "config": { "allow-plugins": false diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index fe275b22dd7..00000000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - tests/ - - - diff --git a/tests/ConfigurationProvider.php b/tests/ConfigurationProvider.php deleted file mode 100644 index 99a509b25f7..00000000000 --- a/tests/ConfigurationProvider.php +++ /dev/null @@ -1,184 +0,0 @@ -container = $this->buildContainer(); - } - - public function hasExtension(string $alias): bool - { - return $this->container->hasExtension($alias); - } - - public function createConfiguration(string $alias): ConfigurationInterface - { - $configuration = $this->container->getExtension($alias)->getConfiguration([], $this->container); - - if ($configuration === null) { - throw new \Exception('Cannot create configuration for extension "' . $alias . '"'); - } - - return $configuration; - } - - /** - * Recursively resolves %parameter% placeholders using the container's - * parameter bag, mirroring what the real Symfony kernel does before - * passing config to the Config component. Unknown parameters (custom app - * params not present in the test container) are left as-is. - * - * @param array $config - * - * @return array - */ - public function resolveParameters(array $config): array - { - /** @var array $result */ - $result = $this->resolveValue($this->container->getParameterBag(), $config); - - return $result; - } - - private function resolveValue(ParameterBagInterface $bag, mixed $value): mixed - { - if (is_array($value)) { - return array_map(fn (mixed $v): mixed => $this->resolveValue($bag, $v), $value); - } - - if (!is_string($value)) { - return $value; - } - - try { - return $bag->resolveValue($value); - } catch (ParameterNotFoundException) { - return $value; - } - } - - private function buildContainer(): ContainerBuilder - { - $container = new ContainerBuilder(); - $container->setParameter('kernel.debug', false); - $container->setParameter('kernel.bundles', []); - $container->setParameter('kernel.bundles_metadata', []); - $container->setParameter('kernel.project_dir', sys_get_temp_dir()); - $container->setParameter('kernel.environment', 'test'); - - $bundles = self::discoverBundles(); - - // Register all extensions before calling build() on any bundle, - // because some bundles call $container->getExtension('ibexa') during build(). - foreach ($bundles as $bundle) { - try { - $extension = $bundle->getContainerExtension(); - if ($extension !== null) { - $container->registerExtension($extension); - } - } catch (\Throwable) { - // Skip bundles whose extension cannot be instantiated. - } - } - - // build() registers parsers/factories into the extensions. - foreach ($bundles as $bundle) { - try { - $bundle->build($container); - } catch (\Throwable) { - // Skip bundles whose build() fails (e.g. missing sibling extensions). - } - } - - return $container; - } - - /** - * Returns all installed bundles with SecurityBundle and IbexaCoreBundle - * guaranteed first (other bundles may call getExtension('ibexa') or - * getExtension('security') during their build()). - * - * @return list - */ - private static function discoverBundles(): array - { - // These must be registered before any bundle that calls - // $container->getExtension('ibexa'/'security') inside build(). - $bundles = [ - new SecurityBundle(), - new IbexaCoreBundle(), - ]; - - $seen = [SecurityBundle::class, IbexaCoreBundle::class]; - - $vendorBase = __DIR__ . '/../vendor'; - $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($vendorBase)); - - foreach ($iterator as $file) { - if (!$file->isFile() || !preg_match('/\w+Bundle\.php$/', $file->getFilename())) { - continue; - } - - $content = file_get_contents($file->getPathname()); - preg_match('/^namespace (.+);/m', $content, $nsMatch); - preg_match('/^(?:(?:final|abstract)\s+)?class (\w+Bundle)\b/m', $content, $clsMatch); - - if (empty($nsMatch[1]) || empty($clsMatch[1])) { - continue; - } - - $fqcn = $nsMatch[1] . '\\' . $clsMatch[1]; - - if (!class_exists($fqcn) || in_array($fqcn, $seen, true)) { - continue; - } - - $reflection = new \ReflectionClass($fqcn); - if ($reflection->isAbstract() || !$reflection->implementsInterface(BundleInterface::class)) { - continue; - } - - $seen[] = $fqcn; - - try { - $bundles[] = new $fqcn(); - } catch (\Throwable) { - // Skip bundles that cannot be instantiated without arguments. - } - } - - return $bundles; - } -} diff --git a/tests/Markdown/MarkdownYamlExtractor.php b/tests/Markdown/MarkdownYamlExtractor.php deleted file mode 100644 index bed5e59ffc6..00000000000 --- a/tests/Markdown/MarkdownYamlExtractor.php +++ /dev/null @@ -1,78 +0,0 @@ - *)```\s*yaml[^\n]*\n(?P.*?)\n(?P=indent)```/ms'; - - private const string SKIP_PATTERN = '/include_(?:file|code)\s*\(|--8<--/'; - - /** - * @return iterable - */ - public function extract(string $content): iterable - { - if (!preg_match_all(self::FENCE_PATTERN, $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { - return; - } - - foreach ($matches as $match) { - $body = $match['body'][0]; - $offset = $match['body'][1]; - - if (preg_match(self::SKIP_PATTERN, $body)) { - continue; - } - - $indent = $match['indent'][0]; - if ($indent !== '') { - $body = $this->stripIndentation($body, strlen($indent)); - } - - $line = substr_count(substr($content, 0, $offset), "\n") + 1; - - yield ['body' => $body, 'line' => $line]; - } - } - - private function stripIndentation(string $body, int $spaces): string - { - $prefix = str_repeat(' ', $spaces); - $lines = explode("\n", $body); - $stripped = array_map( - static fn (string $line): string => str_starts_with($line, $prefix) - ? substr($line, $spaces) - : $line, - $lines - ); - - return implode("\n", $stripped); - } -} diff --git a/tests/Markdown/MarkdownYamlExtractorTest.php b/tests/Markdown/MarkdownYamlExtractorTest.php deleted file mode 100644 index 0575ae51df7..00000000000 --- a/tests/Markdown/MarkdownYamlExtractorTest.php +++ /dev/null @@ -1,224 +0,0 @@ -extractor = new MarkdownYamlExtractor(); - } - - public function testExtractsNothing(): void - { - self::assertEmpty(iterator_to_array($this->extractor->extract('No code blocks here.'))); - self::assertEmpty(iterator_to_array($this->extractor->extract(''))); - } - - public function testIgnoresNonYamlFences(): void - { - $content = <<<'MD' - ```php - $x = 1; - ``` - - ```json - {"key": "value"} - ``` - MD; - - self::assertEmpty(iterator_to_array($this->extractor->extract($content))); - } - - public function testExtractsSingleBlock(): void - { - $content = <<<'MD' - Some text. - - ```yaml - foo: bar - ``` - - More text. - MD; - - $blocks = iterator_to_array($this->extractor->extract($content)); - - self::assertCount(1, $blocks); - self::assertSame('foo: bar', $blocks[0]['body']); - } - - public function testExtractsMultipleBlocks(): void - { - $content = <<<'MD' - ```yaml - first: 1 - ``` - - ```yaml - second: 2 - ``` - MD; - - $blocks = iterator_to_array($this->extractor->extract($content)); - - self::assertCount(2, $blocks); - self::assertSame('first: 1', $blocks[0]['body']); - self::assertSame('second: 2', $blocks[1]['body']); - } - - public function testReportsCorrectLineNumber(): void - { - $content = "line1\nline2\nline3\n```yaml\nfoo: bar\n```\n"; - - $blocks = iterator_to_array($this->extractor->extract($content)); - - self::assertCount(1, $blocks); - // The body starts on line 5 (after 4 preceding newlines inside the fence open) - self::assertSame(5, $blocks[0]['line']); - } - - public function testAcceptsSpaceBeforeLanguageTag(): void - { - $content = "``` yaml\nfoo: bar\n```\n"; - - $blocks = iterator_to_array($this->extractor->extract($content)); - - self::assertCount(1, $blocks); - self::assertSame('foo: bar', $blocks[0]['body']); - } - - public function testAcceptsTrailingAnnotations(): void - { - $content = "```yaml hl_lines=\"1 2\"\nfoo: bar\n```\n"; - - $blocks = iterator_to_array($this->extractor->extract($content)); - - self::assertCount(1, $blocks); - self::assertSame('foo: bar', $blocks[0]['body']); - } - - public function testStripsAdmonitionIndentation(): void - { - $content = <<<'MD' - !!! note - - ```yaml - foo: bar - baz: qux - ``` - MD; - - $blocks = iterator_to_array($this->extractor->extract($content)); - - self::assertCount(1, $blocks); - self::assertSame("foo: bar\nbaz: qux", $blocks[0]['body']); - } - - public function testSkipsBlocksWithIncludeFile(): void - { - $content = <<<'MD' - ```yaml - [[= include_file('some/file.yaml') =]] - ``` - MD; - - self::assertEmpty(iterator_to_array($this->extractor->extract($content))); - } - - public function testSkipsBlocksWithIncludeCode(): void - { - $content = <<<'MD' - ```yaml - [[= include_code('some/file.yaml', 1, 10) =]] - ``` - MD; - - self::assertEmpty(iterator_to_array($this->extractor->extract($content))); - } - - public function testSkipsBlocksWithSnippetMarker(): void - { - $content = <<<'MD' - ```yaml - --8<-- - some/file.yaml - --8<-- - ``` - MD; - - self::assertEmpty(iterator_to_array($this->extractor->extract($content))); - } - - public function testSkipsOnlyMatchingBlocksWhenMixed(): void - { - $content = <<<'MD' - ```yaml - [[= include_file('foo.yaml') =]] - ``` - - ```yaml - [[= include_code('bar.yaml', 1, 5) =]] - ``` - - ```yaml - real: config - ``` - MD; - - $blocks = iterator_to_array($this->extractor->extract($content)); - - self::assertCount(1, $blocks); - self::assertSame('real: config', $blocks[0]['body']); - } - - /** - * @param array $expected - */ - #[DataProvider('provideMultilineBlocks')] - public function testExtractsMultilineBody(string $content, array $expected): void - { - $blocks = iterator_to_array($this->extractor->extract($content)); - - self::assertCount(count($expected), $blocks); - foreach ($expected as $i => $exp) { - self::assertSame($exp['body'], $blocks[$i]['body'], "body at index $i"); - self::assertSame($exp['line'], $blocks[$i]['line'], "line at index $i"); - } - } - - /** - * @return iterable}> - */ - public static function provideMultilineBlocks(): iterable - { - yield 'nested mapping' => [ - "```yaml\nparent:\n child: value\n```\n", - [['body' => "parent:\n child: value", 'line' => 2]], - ]; - - yield 'sequence' => [ - "```yaml\nlist:\n - a\n - b\n```\n", - [['body' => "list:\n - a\n - b", 'line' => 2]], - ]; - - yield 'two blocks with correct lines' => [ - "```yaml\nfoo: 1\n```\n\nsome text\n\n```yaml\nbar: 2\n```\n", - [ - ['body' => 'foo: 1', 'line' => 2], - ['body' => 'bar: 2', 'line' => 8], - ], - ]; - } -} diff --git a/tests/ValidationBaseline.php b/tests/ValidationBaseline.php deleted file mode 100644 index 223669e8a1e..00000000000 --- a/tests/ValidationBaseline.php +++ /dev/null @@ -1,75 +0,0 @@ -|null */ - private ?array $entries = null; - - public function __construct( - private readonly string $baselineFile, - private readonly string $repoRoot, - ) { - } - - public function isInBaseline(string $relativePath, ?string $bodyHash, string $errorMessage): bool - { - foreach ($this->getEntries() as $entry) { - $entryPath = $entry['path'] ?? ''; - - // Path: exact match or trailing-suffix match (allows glob-like partial paths) - if ($relativePath !== $entryPath && !str_ends_with($relativePath, ltrim($entryPath, '/'))) { - continue; - } - - // Hash (optional): must match exactly when provided; line is ignored for matching - if (isset($entry['hash']) && $bodyHash !== null && $entry['hash'] !== $bodyHash) { - continue; - } - - // Message (optional): treated as a regex pattern - if (isset($entry['message']) && !preg_match($entry['message'], $errorMessage)) { - continue; - } - - return true; - } - - return false; - } - - /** - * @return list - */ - private function getEntries(): array - { - if ($this->entries !== null) { - return $this->entries; - } - - if (!file_exists($this->baselineFile)) { - return $this->entries = []; - } - - $parsed = \Symfony\Component\Yaml\Yaml::parseFile($this->baselineFile); - - return $this->entries = $parsed['ignoreErrors'] ?? []; - } -} diff --git a/tests/Yaml/CodeSample.php b/tests/Yaml/CodeSample.php deleted file mode 100644 index 3d582da9b75..00000000000 --- a/tests/Yaml/CodeSample.php +++ /dev/null @@ -1,16 +0,0 @@ -bodyHash = hash('sha256', $body); - } -} diff --git a/tests/Yaml/YamlSamplesProvider.php b/tests/Yaml/YamlSamplesProvider.php deleted file mode 100644 index 8af96c9af31..00000000000 --- a/tests/Yaml/YamlSamplesProvider.php +++ /dev/null @@ -1,66 +0,0 @@ - - */ - public function getCodeSampleYaml(): iterable - { - yield from $this->iterateMarkdownYamlBlocks(); - } - - /** - * Yields every fenced YAML block found in .md files under docs/. - * - * @return iterable - */ - private function iterateMarkdownYamlBlocks(): iterable - { - $extractor = new MarkdownYamlExtractor(); - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator(self::DOCS_DIR, RecursiveDirectoryIterator::SKIP_DOTS) - ); - - /** @var \SplFileInfo $file */ - foreach ($iterator as $file) { - if (!$file->isFile() || $file->getExtension() !== 'md') { - continue; - } - - $path = $file->getRealPath(); - $content = file_get_contents($path); - - if ($content === false) { - continue; - } - - foreach ($extractor->extract($content) as $block) { - yield new CodeSample($path, $block['line'], $block['body']); - } - } - } -} diff --git a/tests/Yaml/YamlTest.php b/tests/Yaml/YamlTest.php deleted file mode 100644 index e6dc396127e..00000000000 --- a/tests/Yaml/YamlTest.php +++ /dev/null @@ -1,169 +0,0 @@ -isInBaseline($filePath, $bodyHash, $e->getMessage())) { - self::markTestSkipped(sprintf( - 'Known baseline issue in %s at line %d: %s', - $filePath, - $line, - $e->getMessage(), - )); - } - - self::fail(sprintf( - 'YAML parse error at %s:%d [hash:%s]: %s', - $filePath, - $line, - $bodyHash, - $e->getMessage(), - )); - } - - $this->addToAssertionCount(1); - } - - /** - * @param int $line Starting line of the config block (0 for standalone YAML files). - */ - #[DataProvider('provideBundleConfigs')] - public function testBundleConfigurationIsValid( - string $extensionName, - mixed $config, - string $filePath, - int $line, - string $bodyHash - ): void { - try { - $configuration = self::configurationProvider()->createConfiguration($extensionName); - $processor = new Processor(); - - $config = self::configurationProvider()->resolveParameters(is_array($config) ? $config : []); - $processor->processConfiguration($configuration, [$config]); - } catch (\Exception $e) { - if (self::baseline()->isInBaseline($filePath, $bodyHash, $e->getMessage())) { - self::markTestSkipped(sprintf( - 'Known baseline issue for "%s" in %s:%d: %s', - $extensionName, - $filePath, - $line, - $e->getMessage(), - )); - } - - self::fail(sprintf( - 'Invalid configuration for "%s" in %s:%d [hash:%s] — %s', - $extensionName, - $filePath, - $line, - $bodyHash, - $e->getMessage(), - )); - } - - $this->addToAssertionCount(1); - } - - /** - * Yields all standalone YAML files from code_samples/ plus every fenced - * YAML block extracted from docs Markdown files. - * - * @return iterable - */ - public static function provideYamlSources(): iterable - { - foreach (self::samplesProvider()->getCodeSampleYaml() as $item) { - yield self::makeLabel($item->path, $item->line) => [$item->path, $item->line, $item->body, $item->bodyHash]; - } - } - - /** - * Yields one entry per (extension, config) pair found in YAML files and - * in fenced YAML blocks from docs Markdown files. - * - * @return iterable - */ - public static function provideBundleConfigs(): iterable - { - foreach (self::provideYamlSources() as [$filePath, $line, $body, $bodyHash]) { - $path = self::relativePath($filePath); - try { - $parsed = Yaml::parse($body, Yaml::PARSE_CUSTOM_TAGS); - } catch (\Throwable) { - continue; - } - - if (!is_array($parsed)) { - continue; - } - - foreach ($parsed as $extensionName => $config) { - if (!is_string($extensionName) || !self::configurationProvider()->hasExtension($extensionName)) { - continue; - } - - yield sprintf('%s (%s)', $extensionName, self::makeLabel($path, $line)) => [$extensionName, $config, $path, $line, $bodyHash]; - } - } - } - - private static function configurationProvider(): ConfigurationProvider - { - static $provider = null; - - return $provider ??= new ConfigurationProvider(); - } - - private static function samplesProvider(): YamlSamplesProvider - { - static $provider = null; - - return $provider ??= new YamlSamplesProvider(); - } - - private static function baseline(): ValidationBaseline - { - static $baseline = null; - - return $baseline ??= new ValidationBaseline(self::BASELINE_FILE, realpath(self::REPO_ROOT)); - } - - private static function makeLabel(string $absolutePath, int $lineNumber): string - { - return ltrim(str_replace(realpath(self::REPO_ROOT), '', $absolutePath), '/') . ':' . $lineNumber; - } - - private static function relativePath(string $absolutePath): string - { - return ltrim(str_replace(realpath(self::REPO_ROOT), '', $absolutePath), '/'); - } -} diff --git a/tests/generate-yaml-baseline.php b/tests/generate-yaml-baseline.php deleted file mode 100644 index 51c816dee48..00000000000 --- a/tests/generate-yaml-baseline.php +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env php -/dev/null', - escapeshellarg($phpunitBin), - escapeshellarg($tmpLog), -); - -passthru($cmd); - -if (!file_exists($tmpLog)) { - if ($previousBaseline !== null) { - file_put_contents($outFile, $previousBaseline); - } - fwrite(STDERR, "ERROR: PHPUnit did not produce a JUnit log file.\n"); - exit(1); -} - -$xml = simplexml_load_file($tmpLog); -unlink($tmpLog); - -if ($xml === false) { - fwrite(STDERR, "ERROR: Could not parse JUnit XML.\n"); - exit(1); -} - -$repoRoot = dirname(__DIR__); -$entries = []; - -// Collect all failures/errors at any nesting depth using XPath -/** @var \SimpleXMLElement[] $testcases */ -$testcases = $xml->xpath('//testcase[failure or error]') ?: []; - -foreach ($testcases as $testcase) { - $failure = $testcase->failure ?? $testcase->error ?? null; - if ($failure === null) { - continue; - } - - $message = (string) $failure; - // Extract file path and line from failure message - // Patterns: - // "Invalid configuration for "X" in path/to/file.yaml: error" - // "Invalid configuration for "X" in path/to/file.md:123 [hash:abc] — error" - // "YAML parse error at path/to/file.md:123 [hash:abc]: error" - $path = null; - $line = null; - $bodyHash = null; - $errorMessage = null; - - if (preg_match('/Invalid configuration for "[^"]*" in ([^\n:]+?):(\d+) \[hash:([a-f0-9]+)\] — (.+)/s', $message, $m)) { - $path = trim($m[1]); - $line = (int) $m[2]; - $bodyHash = $m[3]; - $errorMessage = trim(explode("\n", $m[4])[0]); - } elseif (preg_match('/Invalid configuration for "[^"]*" in ([^\n:]+?): (.+)/s', $message, $m)) { - $path = trim($m[1]); - $errorMessage = trim(explode("\n", $m[2])[0]); - } elseif (preg_match('/YAML parse error at ([^\n:]+?):(\d+) \[hash:([a-f0-9]+)\]: (.+)/s', $message, $m)) { - $path = trim($m[1]); - $line = (int) $m[2]; - $bodyHash = $m[3]; - $errorMessage = trim(explode("\n", $m[4])[0]); - } - - if ($path === null) { - fwrite(STDERR, sprintf( - "WARNING: could not parse failure message of %s, it will NOT be baselined:\n%s\n", - (string) $testcase['name'], - $message, - )); - continue; - } - - // Convert absolute path to relative - if (str_starts_with($path, $repoRoot)) { - $path = ltrim(substr($path, strlen($repoRoot)), '/'); - } - - $entry = ['path' => $path]; - if ($line !== null) { - $entry['line'] = $line; - } - if ($bodyHash !== null) { - $entry['hash'] = $bodyHash; - } - if ($errorMessage !== null) { - // Store as a regex: escape special chars, keep it readable - $entry['message'] = '~' . preg_quote($errorMessage, '~') . '~'; - } - - $key = $path . ':' . ($bodyHash ?? $line ?? ''); - $entries[$key] = $entry; -} - -ksort($entries); - -// Render as YAML manually (keep it readable without needing a YAML library) -$lines = []; -$lines[] = '# Auto-generated by `composer yaml-update-baseline`. Do not edit manually.'; -$lines[] = '# To suppress a failure: regenerate this file after confirming it is expected.'; -$lines[] = '# To fix a suppressed failure: fix the doc error and regenerate.'; -$lines[] = 'ignoreErrors:'; - -foreach ($entries as $entry) { - $lines[] = ' -'; - $lines[] = sprintf(' path: %s', $entry['path']); - if (isset($entry['line'])) { - $lines[] = sprintf(' line: %d', $entry['line']); - } - if (isset($entry['hash'])) { - $lines[] = sprintf(' hash: %s', $entry['hash']); - } - if (isset($entry['message'])) { - // Wrap message in single quotes, escaping internal single quotes - $msg = str_replace("'", "''", $entry['message']); - $lines[] = sprintf(" message: '%s'", $msg); - } -} - -$content = implode("\n", $lines) . "\n"; -$outFile = __DIR__ . '/yaml-validation-baseline.yaml'; -file_put_contents($outFile, $content); - -$count = count($entries); -echo "Baseline written to tests/yaml-validation-baseline.yaml ({$count} entries)\n"; -if ($count === 0) { - echo "No failures found — baseline is empty. All tests pass!\n"; -} diff --git a/tests/yaml-validation-baseline.yaml b/tests/yaml-validation-baseline.yaml deleted file mode 100644 index 28c931c01db..00000000000 --- a/tests/yaml-validation-baseline.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# Auto-generated by `composer yaml-update-baseline`. Do not edit manually. -# To suppress a failure: regenerate this file after confirming it is expected. -# To fix a suppressed failure: fix the doc error and regenerate. -ignoreErrors: