Skip to content

Commit

Permalink
IBX-9170: AI Assistant (#1385)
Browse files Browse the repository at this point in the history
  • Loading branch information
GrabowskiM authored Dec 17, 2024
1 parent 4f18fbb commit 5d3d38c
Show file tree
Hide file tree
Showing 16 changed files with 585 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/bundle/Resources/config/bazinga_js_translation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ active_domains:
- 'ibexa_user_invitation'
- 'ibexa_content_type'
- 'ibexa_dropdown'
- 'ibexa_popup_menu'
- 'messages'
41 changes: 17 additions & 24 deletions src/bundle/Resources/public/js/scripts/admin.input.text.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
(function (global, doc) {
const INPUT_PADDING = 12;
const togglePasswordVisibility = (event) => {
const passwordTogglerBtn = event.currentTarget;
const passwordShowIcon = passwordTogglerBtn.querySelector('.ibexa-input-text-wrapper__password-show');
Expand Down Expand Up @@ -40,35 +41,27 @@
passwordTogglerBtns.forEach((passwordTogglerBtn) => passwordTogglerBtn.addEventListener('click', togglePasswordVisibility, false));
recalculateStyling();
};
const handleInputChange = ({ target: { value } }, btn) => {
btn.disabled = value.trim() === '';
};
const recalculateStyling = () => {
const extraBtns = doc.querySelectorAll('.ibexa-input-text-wrapper__action-btn--extra-btn');

extraBtns.forEach((btn) => {
const input = btn.closest('.ibexa-input-text-wrapper').querySelector('input');
const clearButton = btn.previousElementSibling?.classList.contains('ibexa-input-text-wrapper__action-btn--clear')
? btn.previousElementSibling
: null;
const recalculateInputStyling = (inputActionsContainer) => {
const input = inputActionsContainer.closest('.ibexa-input-text-wrapper').querySelector('input');

if (!input) {
return;
}
if (!input) {
return;
}

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

if (!clearButton) {
return;
}
input.style.paddingRight = `${actionsWidth + INPUT_PADDING}px`;
};
const recalculateStyling = () => {
const inputActionsContainers = doc.querySelectorAll('.ibexa-input-text-wrapper__actions');

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

input.style.paddingRight = paddingRight;
inputActionsContainerObserver.observe(inputActionsContainer);
recalculateInputStyling(inputActionsContainer);
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as modal from './modal.helper';
import * as notification from './notification.helper';
import * as objectInstances from './object.instances';
import * as pagination from './pagination.helper';
import * as react from './react.helper';
import * as request from './request.helper';
import * as system from './system.helper';
import * as table from './table.helper';
Expand All @@ -36,6 +37,7 @@ import * as user from './user.helper';
ibexa.addConfig('helpers.notification', notification);
ibexa.addConfig('helpers.objectInstances', objectInstances);
ibexa.addConfig('helpers.pagination', pagination);
ibexa.addConfig('helpers.react', react);
ibexa.addConfig('helpers.request', request);
ibexa.addConfig('helpers.system', system);
ibexa.addConfig('helpers.table', table);
Expand Down
30 changes: 30 additions & 0 deletions src/bundle/Resources/public/js/scripts/helpers/react.helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { getRootDOMElement } from './context.helper';

const createDynamicRoot = ({ contextDOMElement = getRootDOMElement(), id } = {}) => {
if (id && window.document.getElementById(id) !== null) {
console.warn(`You're creating second root element with ID "${id}". IDs should be unique inside a document.`);
}

const rootDOMElement = document.createElement('div');

rootDOMElement.classList.add('ibexa-react-root');

if (id) {
rootDOMElement.id = id;
}

contextDOMElement.appendChild(rootDOMElement);

const reactRoot = window.ReactDOM.createRoot(rootDOMElement);

return reactRoot;
};

const removeDynamicRoot = (reactRoot) => {
const rootDOMElement = reactRoot._internalRoot?.containerInfo;

reactRoot.unmount();
rootDOMElement?.remove();
};

export { createDynamicRoot, removeDynamicRoot };
2 changes: 2 additions & 0 deletions src/bundle/Resources/public/scss/ui/modules/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
@import 'common/user.name';
@import 'common/taggify';
@import 'common/spinner';
@import 'common/draggable.dialog';
@import 'common/popup.menu';
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.c-draggable-dialog {
position: fixed;
z-index: 10000;

&--hidden {
visibility: hidden;
}

&__draggable {
cursor: grab;
user-select: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
.c-popup-menu {
display: flex;
flex-direction: column;
gap: calculateRem(1px);
padding: calculateRem(8px) 0;
background: $ibexa-color-white;
border: calculateRem(1px) solid $ibexa-color-light;
border-radius: $ibexa-border-radius;
box-shadow: calculateRem(4px) calculateRem(22px) calculateRem(67px) 0 rgba($ibexa-color-info, 0.2);
position: fixed;
z-index: 1060;

&--hidden {
visibility: hidden;
}

&__search {
margin-bottom: calculateRem(4px);
padding: 0 calculateRem(8px);

&--hidden {
display: none;
}
}

&__search-input {
border-radius: $ibexa-border-radius;
}

&__groups {
max-height: calculateRem(390px);
overflow-y: auto;
}

&__group:not(:last-child) {
&::after {
content: '';
border-top: calculateRem(1px) solid $ibexa-color-light;
display: flex;
width: calc(100% - calculateRem(16px));
margin: calculateRem(1px) calculateRem(8px) 0;
}
}

&__item {
display: flex;
align-items: center;
min-width: calculateRem(150px);
padding: 0 calculateRem(8px);
transition: all $ibexa-admin-transition-duration $ibexa-admin-transition;
}

&__item-content {
position: relative;
display: flex;
align-items: baseline;
width: 100%;
cursor: pointer;
padding: calculateRem(9px);
color: $ibexa-color-dark;
font-size: $ibexa-text-font-size-medium;
text-align: left;
text-decoration: none;
border: none;
border-radius: $ibexa-border-radius;
transition: all $ibexa-admin-transition-duration $ibexa-admin-transition;

&:hover {
background-color: $ibexa-color-light-300;
color: $ibexa-color-black;
text-decoration: none;
}
}
}
16 changes: 16 additions & 0 deletions src/bundle/Resources/translations/ibexa_popup_menu.en.xliff
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file source-language="en" target-language="en" datatype="plaintext" original="not.available">
<header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
<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>
</header>
<body>
<trans-unit id="e4f3034ecab5de30a4ea60991375e4c6ccb21ed1" resname="ibexa_popup_menu.search.placeholder">
<source>Search...</source>
<target state="new">Search...</target>
<note>key: ibexa_popup_menu.search.placeholder</note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
{{- block('form_label') }}
</div>
<div{% with { attr: widget_wrapper_attr } %}{{ block('attributes') }}{% endwith %}>
{{- form_widget(form, {'attr': attr}) -}}
{{- form_widget(form, { attr }) -}}
</div>
<div class="ibexa-form-error">
{{- block('form_errors') -}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,9 @@
{%- set type = type|default('text') -%}
{%- set is_text_input = type == 'text' or type == 'number' or force_text|default(false) -%}
{%- if is_text_input -%}
{# @deprecated extra_actions_after in attr will be removed in 5.0, used for BC in 4.6 #}
{%- set extra_actions_after_from_attr = attr.extra_actions_after|default(null) -%}
{%- set attr = attr|filter((value, key) => key != 'extra_actions_after') -%}
{%- set attr = attr|merge({class: (attr.class|default('') ~ ' ibexa-input ibexa-input--text')|trim}) -%}
{%- set empty_placeholder_for_hiding_clear_btn_with_css = ' ' -%}
{%- 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}) -%}
Expand All @@ -399,6 +402,11 @@
{% block content %}
{{ input_html }}
{% endblock %}

{% block actions %}
{{ parent() }}
{{ extra_actions_after|default(extra_actions_after_from_attr)}}
{% endblock %}
{%- endembed -%}
{%- else -%}
{{ parent() }}
Expand Down
Loading

0 comments on commit 5d3d38c

Please sign in to comment.