Skip to content

N°9152 - Add extensibility API endpoints for UI elements - #1017

Draft
steffunky wants to merge 3 commits into
developfrom
feature/9152-UI-extensibility
Draft

N°9152 - Add extensibility API endpoints for UI elements#1017
steffunky wants to merge 3 commits into
developfrom
feature/9152-UI-extensibility

Conversation

@steffunky

@steffunky steffunky commented Aug 20, 2026

Copy link
Copy Markdown
Member

Base information

Question Answer
Related to a SourceForge thread / Another PR / A GitHub Issue / Combodo ticket? N°9152
Type of change? Enhancement

Symptom (bug) / Objective (enhancement)

With upcoming AI extensions and in order to remove a lot of UI hacks from iTop extensions, we need to add endpoints to iTop core in order to place buttons or actions in the main part of UI elements.

There's already a good number of endpoints in iPopupMenuExtension but we still need to do some JS hacks for more complex elements added in iTop 3.0

Proposed solution (bug and enhancement)

This PR adds new endpoints for iPopupMenuExtension and provides UIBlock factories a way to build elements with ApplicationPopupMenuItem objects.

MENU_TOPBAR_ACTIONS (red) allows to add actions in the top bar

MENU_OBJDETAILS_FIELD_ACTIONS (purple) allows to add actions next to attributes, in read/write and includes caselogs

MENU_OBJDETAILS_ACTIVITY_PANEL_ACTIONS (green) allows to add action to the activity panel on read and can be filtered on caselog attribute or activity tab itself.

image image image

Checklist before requesting a review

  • I have performed a self-review of my code
  • I have tested all changes I made on an iTop instance
  • I have added a unit test, otherwise I have explained why I couldn't
  • Is the PR clear and detailed enough so anyone can understand without digging in the code?
  • Make elements interact well in the UI (popovermenus)
  • Make buttons regroup in a kebab menu when a threshold is met (attributes)
  • Make buttons regroup in a kebab menu when there's no space left (caselog form)
  • Handle Separator Popupmenuitems
  • Add metadata interfaces to enrich ApplicationPopupMenuItem API

…. API endpoints are working and displaying in the UI
@steffunky steffunky added this to the 3.3.0 milestone Aug 20, 2026
@steffunky steffunky self-assigned this Aug 20, 2026
Copilot AI balanced review requested due to automatic review settings August 20, 2026 13:17
@steffunky steffunky added UI API internal Work made by Combodo labels Aug 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds extension API endpoints for top-bar, field, case-log, and activity-panel actions.

Changes:

  • Adds new popup-menu extension constants and UI action factories.
  • Renders extension actions across object-detail interfaces.
  • Adds supporting JavaScript, templates, styles, and autoload mappings.

Reviewed changes

Copilot reviewed 43 out of 44 changed files in this pull request and generated 18 comments.

Show a summary per file
File Description
templates/base/layouts/top-bar/top-bar-quick-action/top-bar-quick-action-url.js.twig Adds URL-action JS template.
templates/base/layouts/top-bar/top-bar-quick-action/top-bar-quick-action-url.html.twig Renders top-bar URL actions.
templates/base/layouts/top-bar/top-bar-quick-action/top-bar-quick-action-js.js.twig Handles top-bar JS actions.
templates/base/layouts/top-bar/top-bar-quick-action/top-bar-quick-action-js.html.twig Renders top-bar JS actions.
templates/base/layouts/top-bar/top-bar-quick-action/layout.html.twig Adds abstract action template.
templates/base/layouts/top-bar/layout.html.twig Renders top-bar extension actions.
templates/base/layouts/activity-panel/layout.html.twig Renders activity-panel actions.
templates/base/layouts/activity-panel/activity-action/activity-action-url.js.twig Adds URL-action JS placeholder.
templates/base/layouts/activity-panel/activity-action/activity-action-url.html.twig Renders activity URL actions.
templates/base/layouts/activity-panel/activity-action/activity-action-js.js.twig Adds JS-action JS placeholder.
templates/base/layouts/activity-panel/activity-action/activity-action-js.html.twig Renders activity JS actions.
templates/base/components/field/layout.html.twig Renders field actions and value.
sources/Application/UI/Base/Layout/TopBar/TopBarQuickAction/TopBarQuickActionURL.php Defines URL quick actions.
sources/Application/UI/Base/Layout/TopBar/TopBarQuickAction/TopBarQuickActionJS.php Defines JS quick actions.
sources/Application/UI/Base/Layout/TopBar/TopBarQuickAction/TopBarQuickActionFactory.php Converts popup items to quick actions.
sources/Application/UI/Base/Layout/TopBar/TopBarQuickAction/TopBarQuickAction.php Defines the quick-action base class.
sources/Application/UI/Base/Layout/TopBar/TopBarFactory.php Collects top-bar extension actions.
sources/Application/UI/Base/Layout/TopBar/TopBar.php Stores top-bar actions.
sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryFormFactory.php Adds case-log field actions.
sources/Application/UI/Base/Layout/ActivityPanel/ActivityPanelFactory.php Collects activity-panel actions.
sources/Application/UI/Base/Layout/ActivityPanel/ActivityPanelAction/ActivityPanelActionURL.php Defines activity URL actions.
sources/Application/UI/Base/Layout/ActivityPanel/ActivityPanelAction/ActivityPanelActionJS.php Defines activity JS actions.
sources/Application/UI/Base/Layout/ActivityPanel/ActivityPanelAction/ActivityPanelActionFactory.php Groups and converts activity actions.
sources/Application/UI/Base/Layout/ActivityPanel/ActivityPanelAction/ActivityPanelAction.php Defines the activity-action base.
sources/Application/UI/Base/Layout/ActivityPanel/ActivityPanel.php Stores activity actions.
sources/Application/UI/Base/Component/Field/FieldUIBlockFactory.php Builds field action buttons and menus.
sources/Application/UI/Base/Component/Field/Field.php Adds field values and actions.
sources/Application/UI/Base/Component/Button/ButtonUIBlockFactory.php Converts popup items into buttons.
sources/Application/UI/Base/Common/Action/tActionURL.php Adds shared URL-action behavior.
sources/Application/UI/Base/Common/Action/tActionJs.php Adds shared JS-action behavior.
sources/Application/UI/Base/Common/Action/tActionCommon.php Adds shared action metadata.
lib/composer/autoload_static.php Registers new classes and traits.
lib/composer/autoload_classmap.php Updates generated class mappings.
js/layouts/activity-panel/activity-panel.js Dispatches actions by active tab.
css/backoffice/layout/top-bar/_top-bar.scss Defines top-bar styling.
css/backoffice/layout/top-bar/_top-bar-action.scss Styles top-bar actions.
css/backoffice/layout/top-bar/_all.scss Aggregates top-bar styles.
css/backoffice/layout/activity-panel/_all.scss Imports activity-action styles.
css/backoffice/layout/activity-panel/_activity-action.scss Styles activity-panel actions.
css/backoffice/layout/_all.scss Updates layout imports.
css/backoffice/components/_field.scss Styles field action buttons.
application/cmdbabstract.class.inc.php Collects per-field extension actions.
application/applicationextension/backoffice/iPopupMenuExtension.php Declares new extension endpoints.
application/applicationextension/backoffice/ApplicationPopupMenuItem.php Adds popup-item label mutation.
Suppressed comments (2)

sources/Application/UI/Base/Component/Button/ButtonUIBlockFactory.php:429

  • This JS popup-item conversion copies the click code but drops GetLinkedScripts(). Case-log actions using the API's optional script dependencies will therefore execute without their required libraries. Register each linked script on the returned button, as the existing popup-menu rendering path does.
			$oButton->SetOnClickJsCode($oPopupItem->GetJsCode());

			return $oButton;

sources/Application/UI/Base/Component/Button/ButtonUIBlockFactory.php:400

  • The popup-item label is mandatory but its tooltip is optional and defaults to an empty string. This icon-only link passes only the optional tooltip, so the generated control has no accessible name when no tooltip was set. Fall back to GetLabel() when the tooltip is empty.
			$oButton = self::MakeIconLink(
				$oPopupItem->GetIconClass(),
				$oPopupItem->GetTooltip(),
				$oPopupItem->GetURL(),
				$oPopupItem->GetTarget(),
			);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread sources/Application/UI/Base/Component/Field/FieldUIBlockFactory.php

/** @var \iPopupMenuExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance) {
foreach ($oExtensionInstance::EnumItems(iPopupMenuExtension::MENU_TOPBAR_ACTIONS, []) as $oMenuItem) {
Comment on lines +88 to +89
$oActionButton = ButtonUIBlockFactory::MakeIconButtonFromApplicationPopupMenuItem($oAction);
$oActionButton->AddCSSClass('ibo-field--action');
Comment on lines +384 to +387
$oButton = self::MakeIconAction(
$oPopupItem->GetIconClass(),
$oPopupItem->GetTooltip()
);
Comment on lines +5 to +6
aria-label="{{ oUIBlock.GetTooltip() }}"
data-tooltip-content="{{ oUIBlock.GetTooltip() }}"
Comment on lines +5 to +8
{% if oUIBlock.GetTooltip() is not empty %}
data-tooltip-content="{{ oUIBlock.GetTooltip() }}"
aria-label="{{ oUIBlock.GetTooltip() }}"
{% endif %}
Comment on lines +5 to +8
{% if oUIBlock.GetTooltip() is not empty %}
data-tooltip-content="{{ oUIBlock.GetTooltip() }}"
aria-label="{{ oUIBlock.GetTooltip() }}"
{% endif %}
$aActions = [];
// Create a button for a few action or a kebab button for multiple actions that a more than what's configured
if (count($aParams['actions']) > $iMaxActions) {
$oKebabButton = ButtonUIBlockFactory::MakeIconAction('fa-ellipsis-v', 'More actions', 'kebab');

@bdalsass bdalsass left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Great 🚀

Missing some parameters and return type, maybe you can add static return type when returning $this on traits.

Comment thread css/backoffice/components/_field.scss Outdated
}

.ibo-field--action {
padding: 3px 6px;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could be replaced with scss vars 🫣

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Could be pair-programmed with you 😉

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

gloups 😳

@Molkobain Molkobain left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some things to discuss, but very good job overall 🙌

}

.ibo-caselog-entry-form--action-buttons--extra-actions .ibo-button-separator{
vertical-align: center ;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can't you use flex align-items instead?

* @api
* @since 3.3.0
*/
public function SetLabel($sLabel)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
public function SetLabel($sLabel)
public function SetLabel(string $sLabel) : void

The rest of the API isn't typed because it has to be backward compatible, but it would hurt to type new methods IMO.


/**
* Get the list of items to be added to the backoffice top-bar items
* $param is null for now, in a distant future we want to give a complete context

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* $param is null for now, in a distant future we want to give a complete context
* $param is null for now, in a distant future we want to give a complete context
* @since 3.3.0

public const MENU_TOPBAR_ACTIONS = 11;
/**
* Get the list of items to be added to the actions on a given form field (i.e. the attribute of an object)
* $param is an array: ['object' => DBObject, att_code => attribute code , mode => edit/read]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* $param is an array: ['object' => DBObject, att_code => attribute code , mode => edit/read]
* $param is an array: ['object' => DBObject, att_code => attribute code , mode => edit/read]
* @since 3.3.0

public const MENU_OBJDETAILS_FIELD_ACTIONS = 12;
/**
* Get the list of items to be added to the actions in the activity panel (read-only mode)
* $param = ['object' => DBObject, caselog_att_code => caselog attribute code or 'activity']

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* $param = ['object' => DBObject, caselog_att_code => caselog attribute code or 'activity']
* $param = ['object' => DBObject, caselog_att_code => caselog attribute code or 'activity']
* @since 3.3.0

}

// Add object arrays
$aSubBlocksNames = ['Actions'];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't we rename all the following from "actions" to "quick actions" to match UIBlocks / SCSS?

}

/** @var \iPopupMenuExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same comment as above about InterfaceDiscovery.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When is that supposed to be called? I thought there should be no separator between (round) buttons on the activity panel.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If no needed, can't we just delete it and remove the reference in the PHP class?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IMO you should factorize most of the markup here instead of in the JS / URL children templates as there is a lot in common. And set TWIG blocks in it so you just have to overload these in the children templates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API internal Work made by Combodo UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants