Skip to content

Commit 5d3d38c

Browse files
authored
IBX-9170: AI Assistant (#1385)
1 parent 4f18fbb commit 5d3d38c

File tree

16 files changed

+585
-25
lines changed

16 files changed

+585
-25
lines changed

src/bundle/Resources/config/bazinga_js_translation.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ active_domains:
1212
- 'ibexa_user_invitation'
1313
- 'ibexa_content_type'
1414
- 'ibexa_dropdown'
15+
- 'ibexa_popup_menu'
1516
- 'messages'

src/bundle/Resources/public/js/scripts/admin.input.text.js

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
(function (global, doc) {
2+
const INPUT_PADDING = 12;
23
const togglePasswordVisibility = (event) => {
34
const passwordTogglerBtn = event.currentTarget;
45
const passwordShowIcon = passwordTogglerBtn.querySelector('.ibexa-input-text-wrapper__password-show');
@@ -40,35 +41,27 @@
4041
passwordTogglerBtns.forEach((passwordTogglerBtn) => passwordTogglerBtn.addEventListener('click', togglePasswordVisibility, false));
4142
recalculateStyling();
4243
};
43-
const handleInputChange = ({ target: { value } }, btn) => {
44-
btn.disabled = value.trim() === '';
45-
};
46-
const recalculateStyling = () => {
47-
const extraBtns = doc.querySelectorAll('.ibexa-input-text-wrapper__action-btn--extra-btn');
48-
49-
extraBtns.forEach((btn) => {
50-
const input = btn.closest('.ibexa-input-text-wrapper').querySelector('input');
51-
const clearButton = btn.previousElementSibling?.classList.contains('ibexa-input-text-wrapper__action-btn--clear')
52-
? btn.previousElementSibling
53-
: null;
44+
const recalculateInputStyling = (inputActionsContainer) => {
45+
const input = inputActionsContainer.closest('.ibexa-input-text-wrapper').querySelector('input');
5446

55-
if (!input) {
56-
return;
57-
}
47+
if (!input) {
48+
return;
49+
}
5850

59-
btn.disabled = !input.value;
60-
input.addEventListener('input', (inputEvent) => handleInputChange(inputEvent, btn), false);
51+
const { width: actionsWidth } = inputActionsContainer.getBoundingClientRect();
6152

62-
if (!clearButton) {
63-
return;
64-
}
53+
input.style.paddingRight = `${actionsWidth + INPUT_PADDING}px`;
54+
};
55+
const recalculateStyling = () => {
56+
const inputActionsContainers = doc.querySelectorAll('.ibexa-input-text-wrapper__actions');
6557

66-
const clearButtonStyles = global.getComputedStyle(clearButton);
67-
const clearButtonMarginRight = parseInt(clearButtonStyles.getPropertyValue('margin-right'), 10);
68-
const clearButtonWidth = parseInt(clearButtonStyles.getPropertyValue('width'), 10);
69-
const paddingRight = `${btn.offsetWidth + clearButtonMarginRight + clearButtonWidth}px`;
58+
inputActionsContainers.forEach((inputActionsContainer) => {
59+
const inputActionsContainerObserver = new ResizeObserver(() => {
60+
recalculateInputStyling(inputActionsContainer);
61+
});
7062

71-
input.style.paddingRight = paddingRight;
63+
inputActionsContainerObserver.observe(inputActionsContainer);
64+
recalculateInputStyling(inputActionsContainer);
7265
});
7366
};
7467

src/bundle/Resources/public/js/scripts/helpers/config.loader.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import * as modal from './modal.helper';
1212
import * as notification from './notification.helper';
1313
import * as objectInstances from './object.instances';
1414
import * as pagination from './pagination.helper';
15+
import * as react from './react.helper';
1516
import * as request from './request.helper';
1617
import * as system from './system.helper';
1718
import * as table from './table.helper';
@@ -36,6 +37,7 @@ import * as user from './user.helper';
3637
ibexa.addConfig('helpers.notification', notification);
3738
ibexa.addConfig('helpers.objectInstances', objectInstances);
3839
ibexa.addConfig('helpers.pagination', pagination);
40+
ibexa.addConfig('helpers.react', react);
3941
ibexa.addConfig('helpers.request', request);
4042
ibexa.addConfig('helpers.system', system);
4143
ibexa.addConfig('helpers.table', table);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { getRootDOMElement } from './context.helper';
2+
3+
const createDynamicRoot = ({ contextDOMElement = getRootDOMElement(), id } = {}) => {
4+
if (id && window.document.getElementById(id) !== null) {
5+
console.warn(`You're creating second root element with ID "${id}". IDs should be unique inside a document.`);
6+
}
7+
8+
const rootDOMElement = document.createElement('div');
9+
10+
rootDOMElement.classList.add('ibexa-react-root');
11+
12+
if (id) {
13+
rootDOMElement.id = id;
14+
}
15+
16+
contextDOMElement.appendChild(rootDOMElement);
17+
18+
const reactRoot = window.ReactDOM.createRoot(rootDOMElement);
19+
20+
return reactRoot;
21+
};
22+
23+
const removeDynamicRoot = (reactRoot) => {
24+
const rootDOMElement = reactRoot._internalRoot?.containerInfo;
25+
26+
reactRoot.unmount();
27+
rootDOMElement?.remove();
28+
};
29+
30+
export { createDynamicRoot, removeDynamicRoot };

src/bundle/Resources/public/scss/ui/modules/_common.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
@import 'common/user.name';
66
@import 'common/taggify';
77
@import 'common/spinner';
8+
@import 'common/draggable.dialog';
9+
@import 'common/popup.menu';
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.c-draggable-dialog {
2+
position: fixed;
3+
z-index: 10000;
4+
5+
&--hidden {
6+
visibility: hidden;
7+
}
8+
9+
&__draggable {
10+
cursor: grab;
11+
user-select: none;
12+
}
13+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
.c-popup-menu {
2+
display: flex;
3+
flex-direction: column;
4+
gap: calculateRem(1px);
5+
padding: calculateRem(8px) 0;
6+
background: $ibexa-color-white;
7+
border: calculateRem(1px) solid $ibexa-color-light;
8+
border-radius: $ibexa-border-radius;
9+
box-shadow: calculateRem(4px) calculateRem(22px) calculateRem(67px) 0 rgba($ibexa-color-info, 0.2);
10+
position: fixed;
11+
z-index: 1060;
12+
13+
&--hidden {
14+
visibility: hidden;
15+
}
16+
17+
&__search {
18+
margin-bottom: calculateRem(4px);
19+
padding: 0 calculateRem(8px);
20+
21+
&--hidden {
22+
display: none;
23+
}
24+
}
25+
26+
&__search-input {
27+
border-radius: $ibexa-border-radius;
28+
}
29+
30+
&__groups {
31+
max-height: calculateRem(390px);
32+
overflow-y: auto;
33+
}
34+
35+
&__group:not(:last-child) {
36+
&::after {
37+
content: '';
38+
border-top: calculateRem(1px) solid $ibexa-color-light;
39+
display: flex;
40+
width: calc(100% - calculateRem(16px));
41+
margin: calculateRem(1px) calculateRem(8px) 0;
42+
}
43+
}
44+
45+
&__item {
46+
display: flex;
47+
align-items: center;
48+
min-width: calculateRem(150px);
49+
padding: 0 calculateRem(8px);
50+
transition: all $ibexa-admin-transition-duration $ibexa-admin-transition;
51+
}
52+
53+
&__item-content {
54+
position: relative;
55+
display: flex;
56+
align-items: baseline;
57+
width: 100%;
58+
cursor: pointer;
59+
padding: calculateRem(9px);
60+
color: $ibexa-color-dark;
61+
font-size: $ibexa-text-font-size-medium;
62+
text-align: left;
63+
text-decoration: none;
64+
border: none;
65+
border-radius: $ibexa-border-radius;
66+
transition: all $ibexa-admin-transition-duration $ibexa-admin-transition;
67+
68+
&:hover {
69+
background-color: $ibexa-color-light-300;
70+
color: $ibexa-color-black;
71+
text-decoration: none;
72+
}
73+
}
74+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
3+
<file source-language="en" target-language="en" datatype="plaintext" original="not.available">
4+
<header>
5+
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
6+
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
7+
</header>
8+
<body>
9+
<trans-unit id="e4f3034ecab5de30a4ea60991375e4c6ccb21ed1" resname="ibexa_popup_menu.search.placeholder">
10+
<source>Search...</source>
11+
<target state="new">Search...</target>
12+
<note>key: ibexa_popup_menu.search.placeholder</note>
13+
</trans-unit>
14+
</body>
15+
</file>
16+
</xliff>

src/bundle/Resources/views/themes/admin/content/form_fields.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
{{- block('form_label') }}
6969
</div>
7070
<div{% with { attr: widget_wrapper_attr } %}{{ block('attributes') }}{% endwith %}>
71-
{{- form_widget(form, {'attr': attr}) -}}
71+
{{- form_widget(form, { attr }) -}}
7272
</div>
7373
<div class="ibexa-form-error">
7474
{{- block('form_errors') -}}

src/bundle/Resources/views/themes/admin/ui/form_fields.html.twig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,9 @@
389389
{%- set type = type|default('text') -%}
390390
{%- set is_text_input = type == 'text' or type == 'number' or force_text|default(false) -%}
391391
{%- if is_text_input -%}
392+
{# @deprecated extra_actions_after in attr will be removed in 5.0, used for BC in 4.6 #}
393+
{%- set extra_actions_after_from_attr = attr.extra_actions_after|default(null) -%}
394+
{%- set attr = attr|filter((value, key) => key != 'extra_actions_after') -%}
392395
{%- set attr = attr|merge({class: (attr.class|default('') ~ ' ibexa-input ibexa-input--text')|trim}) -%}
393396
{%- set empty_placeholder_for_hiding_clear_btn_with_css = ' ' -%}
394397
{%- set attr = attr|merge({placeholder: (attr.placeholder is defined and attr.placeholder is not null) ? attr.placeholder : empty_placeholder_for_hiding_clear_btn_with_css}) -%}
@@ -399,6 +402,11 @@
399402
{% block content %}
400403
{{ input_html }}
401404
{% endblock %}
405+
406+
{% block actions %}
407+
{{ parent() }}
408+
{{ extra_actions_after|default(extra_actions_after_from_attr)}}
409+
{% endblock %}
402410
{%- endembed -%}
403411
{%- else -%}
404412
{{ parent() }}

0 commit comments

Comments
 (0)