Skip to content

Commit

Permalink
more ui work
Browse files Browse the repository at this point in the history
  • Loading branch information
cconard96 committed Sep 30, 2024
1 parent 9e8a2a5 commit 9b8edd1
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 141 deletions.
66 changes: 66 additions & 0 deletions ajax/asset/assetdefinition.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

use Glpi\Asset\AssetDefinition;

/** @var \Glpi\Controller\LegacyFileLoadController $this */
$this->setAjax();

Session::checkRight(AssetDefinition::$rightname, READ);

header("Content-Type: application/json; charset=UTF-8");

if ($_GET['action'] === 'get_all_fields') {
$definition = new AssetDefinition();
if (!$definition->getFromDB($_GET['assetdefinitions_id'])) {
http_response_code(404);
exit();
}
$all_fields = $definition->getAllFields();
$field_results = [];
foreach ($all_fields as $k => $v) {
$field_info = is_array($v) ? $v : ['text' => $v];
if (!empty($_POST['searchText']) && stripos($field_info['text'], $_POST['searchText']) === false) {
continue;
}
$field_info['id'] = $k;
$field_results[] = $field_info;
}
echo json_encode([
'results' => $field_results,
'count' => count($all_fields)
], JSON_THROW_ON_ERROR);
exit();
}
http_response_code(400);
114 changes: 16 additions & 98 deletions src/Glpi/Asset/AssetDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $
$item->showCapacitiesForm();
break;
case 2:
$item->showCustomFieldsForm();
$item->showFieldsForm();
break;
case 3:
Expand Down Expand Up @@ -186,101 +185,6 @@ private function showCapacitiesForm(): void
);
}

/**
* Show the custom fields tab including the list of custom fields and a form to add/edit them.
* @return void
*/
private function showCustomFieldsForm(): void
{
/** @var \DBmysql $DB */
global $DB;

if (!$this->canViewItem()) {
return;
}

$canedit = $this->canUpdateItem();
$rand = mt_rand();
if ($canedit) {
TemplateRenderer::getInstance()->display('components/form/viewsubitem.html.twig', [
'cancreate' => CustomFieldDefinition::canCreate(),
'id' => $this->fields['id'],
'rand' => $rand,
'type' => CustomFieldDefinition::class,
'parenttype' => CustomFieldDefinition::$itemtype,
'items_id' => CustomFieldDefinition::$items_id,
'add_new_label' => __('Create new field'),
'datatable_id' => 'datatable_customfields' . $rand,
'subitem_container_id' => 'customfield_form_container'
]);
}

$iterator = $DB->request([
'SELECT' => ['id', 'name', 'label', 'type', 'field_options', 'itemtype'],
'FROM' => CustomFieldDefinition::getTable(),
'WHERE' => [
self::getForeignKeyField() => $this->fields['id'],
],
]);

$entries = [];
$adm = AssetDefinitionManager::getInstance();
$field_types = $adm->getCustomFieldTypes();
$allowed_dropdown_itemtypes = $adm->getAllowedDropdownItemtypes(true);
foreach ($iterator as $data) {
$entry = [
'id' => $data['id'],
'itemtype' => CustomFieldDefinition::class,
'name' => $data['name'],
'label' => $data['label'],
'type' => in_array($data['type'], $field_types, true) ? $data['type']::getName() : NOT_AVAILABLE,
'dropdown_itemtype' => $data['itemtype'] !== '' ? ($allowed_dropdown_itemtypes[$data['itemtype']] ?? NOT_AVAILABLE) : NOT_AVAILABLE,
'row_class' => 'cursor-pointer'
];

$field_options = json_decode($data['field_options'] ?? '[]', true) ?? [];
$flags = '';
if ($field_options['readonly'] ?? false) {
$flags .= '<span class="badge badge-outline text-secondary">' . __s('Read-only') . '</span>';
}
if ($field_options['required'] ?? false) {
$flags .= '<span class="badge badge-outline text-secondary">' . __s('Mandatory') . '</span>';
}
if ($field_options['multiple'] ?? false) {
$flags .= '<span class="badge badge-outline text-secondary">' . __s('Multiple values') . '</span>';
}
$entry['flags'] = $flags;
$entries[] = $entry;
}

TemplateRenderer::getInstance()->display('components/datatable.html.twig', [
'datatable_id' => 'datatable_customfields' . $rand,
'is_tab' => true,
'nopager' => true,
'nosort' => true,
'nofilter' => true,
'columns' => [
'name' => __('Name'),
'label' => __('Label'),
'type' => _n('Type', 'Types', 1),
'flags' => __('Flags'),
'dropdown_itemtype' => __('Item type'),
],
'formatters' => [
'flags' => 'raw_html'
],
'entries' => $entries,
'total_number' => count($entries),
'filtered_number' => count($entries),
'showmassiveactions' => $canedit,
'massiveactionparams' => [
'num_displayed' => count($entries),
'container' => 'mass' . str_replace('\\', '_', self::class) . $rand,
'specific_actions' => ['purge' => _x('button', 'Delete permanently')]
],
]);
}

/*
* Display fields form.
*
Expand All @@ -300,6 +204,17 @@ private function showFieldsForm(): void
'all_fields' => $this->getAllFields(),
'fields_display' => $fields_display,
'used' => $used,
'custom_field_form_params' => [
'cancreate' => CustomFieldDefinition::canCreate(),
'id' => $this->fields['id'],
'type' => CustomFieldDefinition::class,
'parenttype' => CustomFieldDefinition::$itemtype,
'items_id' => CustomFieldDefinition::$items_id,
'add_new_label' => __('Create new field'),
'subitem_container_id' => 'customfield_form_container',
'as_modal' => true,
'on_form_submit' => 'return false;', // Block redirect
]
]
);
}
Expand Down Expand Up @@ -616,7 +531,7 @@ private function getDecodedCapacitiesField(): array
}


private function getAllFields(): array
public function getAllFields(): array
{
$type_class = $this->getAssetTypeClassName();
$model_class = $this->getAssetModelClassName();
Expand All @@ -639,7 +554,10 @@ private function getAllFields(): array
];

foreach ($this->getCustomFieldDefinitions() as $custom_field_def) {
$fields['custom_' . $custom_field_def->fields['name']] = $custom_field_def->computeFriendlyName();
$fields['custom_' . $custom_field_def->fields['name']] = [
'customfields_id' => $custom_field_def->getID(),
'text' => $custom_field_def->computeFriendlyName()
];
}

return $fields;
Expand Down
43 changes: 40 additions & 3 deletions templates/components/form/fields_macros.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,44 @@
{% endif %}
{% endmacro %}

{% macro dropdownAjaxField(url, name, value, label = '', options = {}) %}
{% if options.multiple %}
{# Needed for empty value as the input wont be sent in this case... we need something to know the input was displayed AND empty #}
{% set defined_input_name = "_#{name}_defined" %}
<input type="hidden" name="{{ defined_input_name }}" value="1"></input>

{# Multiple values will be set, input need to be an array #}
{% set name = "#{name}[]" %}
{% endif %}
{% set options = {
'rand': random(),
'width': '100%',
}|merge(options) %}
{% if options.fields_template.isMandatoryField(name) %}
{% set options = {'specific_tags': {'required': true}}|merge(options) %}
{% endif %}

{% if options.fields_template.isReadonlyField(name) %}
{% set options = options|merge({'readonly': true}) %}
{% endif %}

{% if options.disabled %}
{% set options = options|merge({'specific_tags': {'disabled': 'disabled'}}) %}
{% endif %}

{% set options = options|merge({
'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand
}) %}
{% set field %}
{% set ajax_opts = options|filter((v, k) => k in ['templateResult', 'templateSelection', 'rand']) %}
{{ call('Html::jsAjaxDropdown', [name, options.id, url, ajax_opts])|raw }}
{% endset %}

{% if field|trim is not empty %}
{{ _self.field(name, field, label, options) }}
{% endif %}
{% endmacro %}

{% macro htmlField(name, value, label = '', options = {}) %}
{% if value|length == 0 %}
{% set value = '&nbsp;' %}
Expand Down Expand Up @@ -821,6 +859,7 @@
'add_field_attribs': {},
'center': false,
'label_align': 'end',
'inline_add_field_html': false,
}|merge(options) %}

{% if options.icon_label %}
Expand Down Expand Up @@ -870,9 +909,7 @@
<div class="form-field row align-items-center {{ options.field_class }} {{ options.add_field_class }} {{ options.mb }}" {{ extra_attribs|raw }}>
{% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
{{ _inputs.label(label, id, options, 'col-form-label ' ~ options.label_class ~ ' ' ~ options.add_label_class) }}
{% if options.center %}
{% set flex_class = "d-flex align-items-center" %}
{% endif %}
{% set flex_class = options.center ? 'd-flex align-items-center' : (options.inline_add_field_html ? 'd-flex' : '') %}
<div {{ container_id }} class="{{ options.input_class }} {{ flex_class }} field-container">
{{ field|raw }}
{{ add_field_html|raw }}
Expand Down
72 changes: 51 additions & 21 deletions templates/components/form/viewsubitem.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,41 @@
#}

{% set subitem_container_id = subitem_container_id|default('viewsubitem' ~ rand) %}
{% set as_modal = as_modal|default(false) %}
{% set add_new_label = add_new_label|default(__('Add')) %}

{% if as_modal %}
<div class="modal fade" id="{{ subitem_container_id ~ '_modal' }}" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{ _x('button', 'Close') }}"></button>
</div>
<div class="modal-body overflow-auto">
{% endif %}
<div id='{{ subitem_container_id }}'></div>
{% if as_modal %}
</div>
</div>
</div>
</div>
{% endif %}

<script>
$(() => {
function viewAddSubItem{{ rand }} (btn) {
{% do call('Ajax::updateItemJsCode', [
subitem_container_id,
config('root_doc') ~ '/ajax/viewsubitem.php',
{
'type': type,
'parenttype': parenttype,
(items_id): id,
'id': -1
const modal_el = $('#{{ subitem_container_id ~ '_modal' }}');
function viewAddEditSubItem{{ rand }}(id) {
$('#{{ subitem_container_id }}').load('/ajax/viewsubitem.php',{
type: "{{ type|e('js') }}",
parenttype: "{{ parenttype|e('js') }}",
{{ items_id }}: {{ id }},
id: id
}, () => {
if (modal_el.length) {
modal_el.modal('show');
}
]) %}
});
}
{% if datatable_id is defined %}
Expand All @@ -54,25 +75,34 @@
}
const subitem_id = $(e.currentTarget).data('id');
if (subitem_id) {
$('#{{ subitem_container_id }}').load('/ajax/viewsubitem.php',{
type: "{{ type|e('js') }}",
parenttype: "{{ parenttype|e('js') }}",
{{ items_id }}: {{ id }},
id: subitem_id
});
viewAddEditSubItem{{ rand }}(subitem_id);
}
});
{% endif %}
$('#addsubitem{{ rand }}').on('click', (e) => {
viewAddSubItem{{ rand }}(e.target);
viewAddEditSubItem{{ rand }}(-1);
});
$('#{{ subitem_container_id }}').on('submit', 'form', (e) => {
// Close the modal if it exists
if (modal_el.length) {
modal_el.modal('hide');
}
{% if on_form_submit is defined %}
{# Allow blocking redirect, or performing an action after form submit #}
{{ on_form_submit|raw }}
{% endif %}
});
});
</script>
{% if cancreate %}
<div class="text-center mt-1 mb-3">
<button id="addsubitem{{ rand }}" type="button" class="btn btn-primary">
{{ add_new_label|default(__('Add')) }}
{% if not add_new_inline %}
<div class="text-center mt-1 mb-3">
{% endif %}
<button id="addsubitem{{ rand }}" type="button" class="btn {{ add_new_btn_class|default('btn-primary') }}">
{{ add_new_label }}
</button>
</div>
{% if not add_new_inline %}
</div>
{% endif %}
{% endif %}
Loading

0 comments on commit 9b8edd1

Please sign in to comment.