mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 01:25:55 +02:00
Implement attachment CollectionType using stimulus
This commit is contained in:
parent
bf3dba0fb2
commit
8323f374a4
10 changed files with 141 additions and 231 deletions
|
@ -0,0 +1,29 @@
|
||||||
|
import {Controller} from "@hotwired/stimulus";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This controller synchronizes the filetype filters of the file input type with our selected attachment type
|
||||||
|
*/
|
||||||
|
export default class extends Controller
|
||||||
|
{
|
||||||
|
_selectInput;
|
||||||
|
_fileInput;
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
//Find the select input for our attachment form
|
||||||
|
this._selectInput = this.element.querySelector('select');
|
||||||
|
//Find the file input for our attachment form
|
||||||
|
this._fileInput = this.element.querySelector('input[type="file"]');
|
||||||
|
|
||||||
|
this._selectInput.addEventListener('change', this.updateAllowedFiletypes.bind(this));
|
||||||
|
|
||||||
|
//Update file file on load
|
||||||
|
this.updateAllowedFiletypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAllowedFiletypes() {
|
||||||
|
let selected_option = this._selectInput.options[this._selectInput.selectedIndex];
|
||||||
|
let filetype_filter = selected_option.dataset.filetype_filter;
|
||||||
|
//Apply filetype filter to file input
|
||||||
|
this._fileInput.setAttribute('accept', filetype_filter);
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,9 +95,6 @@ class AttachmentFormType extends AbstractType
|
||||||
'label' => 'attachment.edit.attachment_type',
|
'label' => 'attachment.edit.attachment_type',
|
||||||
'class' => AttachmentType::class,
|
'class' => AttachmentType::class,
|
||||||
'disable_not_selectable' => true,
|
'disable_not_selectable' => true,
|
||||||
'attr' => [
|
|
||||||
'class' => 'attachment_type_selector',
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('showInTable', CheckboxType::class, [
|
$builder->add('showInTable', CheckboxType::class, [
|
||||||
|
@ -139,9 +136,9 @@ class AttachmentFormType extends AbstractType
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => [
|
'attr' => [
|
||||||
'class' => 'file',
|
/*'class' => 'file',
|
||||||
'data-show-preview' => 'false',
|
'data-show-preview' => 'false',
|
||||||
'data-show-upload' => 'false',
|
'data-show-upload' => 'false',*/
|
||||||
],
|
],
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
//new AllowedFileExtension(),
|
//new AllowedFileExtension(),
|
||||||
|
@ -186,4 +183,9 @@ class AttachmentFormType extends AbstractType
|
||||||
'allow_builtins' => true,
|
'allow_builtins' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'attachment';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,9 +114,11 @@ class StructuralEntityType extends AbstractType
|
||||||
|
|
||||||
$resolver->setDefault('empty_message', null);
|
$resolver->setDefault('empty_message', null);
|
||||||
|
|
||||||
|
$resolver->setDefault('controller', 'elements--selectpicker');
|
||||||
|
|
||||||
$resolver->setDefault('attr', static function (Options $options) {
|
$resolver->setDefault('attr', static function (Options $options) {
|
||||||
$tmp = [
|
$tmp = [
|
||||||
'data-controller' => 'elements--selectpicker',
|
'data-controller' => $options['controller'],
|
||||||
'data-live-search' => true,
|
'data-live-search' => true,
|
||||||
'title' => 'selectpicker.nothing_selected',
|
'title' => 'selectpicker.nothing_selected',
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,115 +1,3 @@
|
||||||
{% set delete_btn %}
|
{% import "components/attachments.macro.html.twig" as attachments %}
|
||||||
<button type="button" class="btn btn-danger lot_btn_delete" onclick="delete_attachment_entry(this);">
|
|
||||||
<i class="fas fa-trash-alt fa-fw"></i>
|
|
||||||
{% trans %}attachment.delete{% endtrans %}
|
|
||||||
</button>
|
|
||||||
{% endset %}
|
|
||||||
|
|
||||||
{#{{ form_row(form.master_picture_attachment) }} #}
|
{{ attachments.attachment_edit_list(form.attachments) }}
|
||||||
|
|
||||||
<table class="table table-striped table-sm" id="attachments_table" data-prototype="{% if form.attachments.vars.prototype is defined %}{{ form_widget(form.attachments.vars.prototype)|e('html_attr') }}{% endif %}">
|
|
||||||
<tbody>
|
|
||||||
{% for attachment in form.attachments %}
|
|
||||||
<tr>
|
|
||||||
<td class="row">
|
|
||||||
<div class="col-9">
|
|
||||||
{{ form_widget(attachment) }}
|
|
||||||
</div>
|
|
||||||
<div class="ps-0 col-3">
|
|
||||||
{{ delete_btn }}
|
|
||||||
|
|
||||||
{% set attach = attachment.vars.value %}
|
|
||||||
{# @var attach \App\Entity\Attachments\Attachment #}
|
|
||||||
|
|
||||||
|
|
||||||
{% if attachment_manager.fileExisting(attach) %}
|
|
||||||
{% if not attach.external %}
|
|
||||||
<br><br>
|
|
||||||
<h6>
|
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fas fa-fw {{ ext_to_fa_icon(attach.extension) }}"></i> {{ attach.filename }}
|
|
||||||
</span>
|
|
||||||
<br>
|
|
||||||
<span class="badge bg-secondary">
|
|
||||||
<i class="fas fa-hdd fa-fw"></i> {{ attachment_manager.humanFileSize(attach) }}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
{% else %}
|
|
||||||
<br><br>
|
|
||||||
<h6>
|
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fas fa-fw fa-globe"></i> {% trans %}attachment.external{% endtrans %}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
{% endif %}
|
|
||||||
{% if attach.secure and not is_granted('show_private', attach) %}
|
|
||||||
{# Leave blank #}
|
|
||||||
{% elseif attach.picture %}
|
|
||||||
<a href="{{ attach | entityURL('file_view') }}" target="_blank" rel="noopener" data-turbo="false">
|
|
||||||
<img class="img-fluid img-thumbnail thumbnail-sm" src="{{ attachment_thumbnail(attach, 'thumbnail_md') }}" alt="{% trans %}attachment.preview.alt{% endtrans %}" />
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{{ attach | entityURL('file_view') }}" rel="noopener" target="_blank" data-turbo="false" class="link-external">{% trans %}attachment.view{% endtrans %}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
<br><br>
|
|
||||||
<h6>
|
|
||||||
<span class="badge bg-warning">
|
|
||||||
<i class="fas fa-exclamation-circle fa-fw"></i> {% trans %}attachment.file_not_found{% endtrans %}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if attach.secure %}
|
|
||||||
<h6>
|
|
||||||
<span class="badge bg-success">
|
|
||||||
<i class="fas fa-fw fa-shield-alt"></i> {% trans %}attachment.secure{% endtrans %}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-success" onclick="create_attachment_entry(this)">
|
|
||||||
<i class="fas fa-plus-square fa-fw"></i>
|
|
||||||
{% trans %}attachment.create{% endtrans %}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function delete_attachment_entry(btn) {
|
|
||||||
window.bootbox.confirm('{% trans %}part_lot.edit.delete.confirm{% endtrans %}', function (result) {
|
|
||||||
if(result) {
|
|
||||||
$(btn).parents("tr").remove();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_attachment_entry(btn) {
|
|
||||||
//Determine the table, so we can determine, how many entries there are already.
|
|
||||||
$holder = $("#attachments_table");
|
|
||||||
|
|
||||||
var index = $holder.children("tbody").children("tr").length;
|
|
||||||
var newForm = $holder.data("prototype");
|
|
||||||
|
|
||||||
//Increase the index
|
|
||||||
newForm = newForm.replace(/__name__/g, index);
|
|
||||||
newForm = '<div class="col-9">' + newForm + '</div>';
|
|
||||||
$newFormRow = $('<tr></tr>').html("<td class='row'>" + newForm + "</td>");
|
|
||||||
|
|
||||||
//Add delete button
|
|
||||||
$btn = '<div class="col-3">' + '{{ delete_btn|e('js') }}' + '</div>';
|
|
||||||
$('td' ,$newFormRow).append($btn);
|
|
||||||
|
|
||||||
$holder.append($newFormRow);
|
|
||||||
|
|
||||||
//Reinit the selectpickers
|
|
||||||
$(".file").fileinput();
|
|
||||||
|
|
||||||
//Reinit typeahead:
|
|
||||||
$(document).trigger('attachment:create');
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -115,7 +115,7 @@
|
||||||
|
|
||||||
{%- block choice_widget_collapsed -%}
|
{%- block choice_widget_collapsed -%}
|
||||||
{# Only add the BS5 form-select class if we dont use bootstrap-selectpicker #}
|
{# Only add the BS5 form-select class if we dont use bootstrap-selectpicker #}
|
||||||
{% if attr["data-controller"] is defined and attr["data-controller"] != "elements--selectpicker" %}
|
{% if attr["data-controller"] is defined and attr["data-controller"] not in ["elements--selectpicker"] %}
|
||||||
{%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-select')|trim}) -%}
|
{%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-select')|trim}) -%}
|
||||||
{% else %}
|
{% else %}
|
||||||
{# If it is an selectpicker add form-control class to fill whole width #}
|
{# If it is an selectpicker add form-control class to fill whole width #}
|
||||||
|
|
|
@ -1,112 +1,5 @@
|
||||||
{% set delete_btn %}
|
{% import "components/attachments.macro.html.twig" as attachments %}
|
||||||
<button type="button" class="btn btn-danger lot_btn_delete" onclick="delete_attachment_entry(this);" {% if not is_granted('attachments.delete', part) %}disabled{% endif %}>
|
|
||||||
<i class="fas fa-trash-alt fa-fw"></i>
|
|
||||||
{% trans %}attachment.delete{% endtrans %}
|
|
||||||
</button>
|
|
||||||
{% endset %}
|
|
||||||
|
|
||||||
{{ form_row(form.master_picture_attachment) }}
|
{{ form_row(form.master_picture_attachment) }}
|
||||||
|
|
||||||
<table class="table table-striped table-sm" id="attachments_table" data-prototype="{% if form.attachments.vars.prototype is defined %}{{ form_widget(form.attachments.vars.prototype)|e('html_attr') }}{% endif %}">
|
{{ attachments.attachment_edit_list(form.attachments) }}
|
||||||
<tbody>
|
|
||||||
{% for attachment in form.attachments %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
{{ form_widget(attachment) }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ delete_btn }}
|
|
||||||
|
|
||||||
{% set attach = attachment.vars.value %}
|
|
||||||
|
|
||||||
{% if attachment_manager.fileExisting(attach) %}
|
|
||||||
{% if not attach.external %}
|
|
||||||
<br><br>
|
|
||||||
<h6>
|
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fas fa-fw {{ ext_to_fa_icon(attach.extension) }}"></i> {{ attach.filename }}
|
|
||||||
</span>
|
|
||||||
<br>
|
|
||||||
<span class="badge bg-secondary">
|
|
||||||
<i class="fas fa-hdd fa-fw"></i> {{ attachment_manager.humanFileSize(attach) }}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
{% else %}
|
|
||||||
<br><br>
|
|
||||||
<h6>
|
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fas fa-fw fa-globe"></i> {% trans %}attachment.external{% endtrans %}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if attach.secure and not is_granted('show_private', attach) %}
|
|
||||||
{# Leave blank #}
|
|
||||||
{% elseif attach.picture %}
|
|
||||||
<a href="{{ attach | entityURL('file_view') }}" rel="noopener" target="_blank" data-turbo="false">
|
|
||||||
<img class="img-fluid img-thumbnail thumbnail-sm" src="{{ attachment_thumbnail(attach, 'thumbnail_md') }}" alt="{% trans %}attachment.preview.alt{% endtrans %}" />
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{{ attach | entityURL('file_view') }}" rel="noopener" target="_blank" data-turbo="false" class="link-external">{% trans %}attachment.view{% endtrans %}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
<br><br>
|
|
||||||
<h6>
|
|
||||||
<span class="badge bg-warning">
|
|
||||||
<i class="fas fa-exclamation-circle fa-fw"></i> {% trans %}attachment.file_not_found{% endtrans %}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if attach.secure %}
|
|
||||||
<h6>
|
|
||||||
<span class="badge bg-success">
|
|
||||||
<i class="fas fa-fw fa-shield-alt"></i> {% trans %}attachment.secure{% endtrans %}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-success" onclick="create_attachment_entry(this)" {% if not is_granted('attachments.create', part) %}disabled{% endif %}>
|
|
||||||
<i class="fas fa-plus-square fa-fw"></i>
|
|
||||||
{% trans %}attachment.create{% endtrans %}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function delete_attachment_entry(btn) {
|
|
||||||
window.bootbox.confirm('{% trans %}part_lot.edit.delete.confirm{% endtrans %}', function (result) {
|
|
||||||
if(result) {
|
|
||||||
$(btn).parents("tr").remove();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_attachment_entry(btn) {
|
|
||||||
//Determine the table, so we can determine, how many entries there are already.
|
|
||||||
$holder = $("#attachments_table");
|
|
||||||
|
|
||||||
var index = $holder.children("tbody").children("tr").length;
|
|
||||||
var newForm = $holder.data("prototype");
|
|
||||||
|
|
||||||
//Increase the index
|
|
||||||
newForm = newForm.replace(/__name__/g, index);
|
|
||||||
newForm = '<td>' + newForm + '</td>';
|
|
||||||
$newFormRow = $('<tr></tr>').html(newForm);
|
|
||||||
|
|
||||||
//Add delete button
|
|
||||||
$btn = '<td>' + '{{ delete_btn|e('js') }}' + '</td>';
|
|
||||||
$newFormRow.append($btn);
|
|
||||||
|
|
||||||
$holder.append($newFormRow);
|
|
||||||
|
|
||||||
$(".file").fileinput();
|
|
||||||
|
|
||||||
//Reinit typeahead:
|
|
||||||
$(document).trigger('attachment:create');
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -101,4 +101,74 @@
|
||||||
{{ form_errors(form) }}
|
{{ form_errors(form) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block attachment_widget %}
|
||||||
|
{% import 'components/collection_type.macro.html.twig' as collection %}
|
||||||
|
|
||||||
|
{% dump(form) %}
|
||||||
|
|
||||||
|
<tr {{ stimulus_controller('elements/attachmenttype_change') }}>
|
||||||
|
<td>
|
||||||
|
{{ form_widget(form) }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-danger lot_btn_delete" {{ collection.delete_btn() }} {# {% if not is_granted('attachments.delete', part) %}disabled{% endif %}#}>
|
||||||
|
<i class="fas fa-trash-alt fa-fw"></i>
|
||||||
|
{% trans %}attachment.delete{% endtrans %}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{% set attach = form.vars.value %}
|
||||||
|
|
||||||
|
{% if attach is not null %}
|
||||||
|
{% if attachment_manager.fileExisting(attach) %}
|
||||||
|
{% if not attach.external %}
|
||||||
|
<br><br>
|
||||||
|
<h6>
|
||||||
|
<span class="badge bg-primary">
|
||||||
|
<i class="fas fa-fw {{ ext_to_fa_icon(attach.extension) }}"></i> {{ attach.filename }}
|
||||||
|
</span>
|
||||||
|
<br>
|
||||||
|
<span class="badge bg-secondary">
|
||||||
|
<i class="fas fa-hdd fa-fw"></i> {{ attachment_manager.humanFileSize(attach) }}
|
||||||
|
</span>
|
||||||
|
</h6>
|
||||||
|
{% else %}
|
||||||
|
<br><br>
|
||||||
|
<h6>
|
||||||
|
<span class="badge bg-primary">
|
||||||
|
<i class="fas fa-fw fa-globe"></i> {% trans %}attachment.external{% endtrans %}
|
||||||
|
</span>
|
||||||
|
</h6>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if attach.secure and not is_granted('show_private', attach) %}
|
||||||
|
{# Leave blank #}
|
||||||
|
{% elseif attach.picture %}
|
||||||
|
<a href="{{ attach | entityURL('file_view') }}" rel="noopener" target="_blank" data-turbo="false">
|
||||||
|
<img class="img-fluid img-thumbnail thumbnail-sm" src="{{ attachment_thumbnail(attach, 'thumbnail_md') }}" alt="{% trans %}attachment.preview.alt{% endtrans %}" />
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ attach | entityURL('file_view') }}" rel="noopener" target="_blank" data-turbo="false" class="link-external">{% trans %}attachment.view{% endtrans %}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<br><br>
|
||||||
|
<h6>
|
||||||
|
<span class="badge bg-warning">
|
||||||
|
<i class="fas fa-exclamation-circle fa-fw"></i> {% trans %}attachment.file_not_found{% endtrans %}
|
||||||
|
</span>
|
||||||
|
</h6>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if attach.secure %}
|
||||||
|
<h6>
|
||||||
|
<span class="badge bg-success">
|
||||||
|
<i class="fas fa-fw fa-shield-alt"></i> {% trans %}attachment.secure{% endtrans %}
|
||||||
|
</span>
|
||||||
|
</h6>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endblock %}
|
{% endblock %}
|
20
templates/components/attachments.macro.html.twig
Normal file
20
templates/components/attachments.macro.html.twig
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{# Renders a editable list of all attachments. form is the Attachment CollectionType #}
|
||||||
|
{% macro attachment_edit_list(form, part_mode = false) %}
|
||||||
|
{% form_theme form with ['Parts/edit/edit_form_styles.html.twig'] %}
|
||||||
|
|
||||||
|
{% import 'components/collection_type.macro.html.twig' as collection %}
|
||||||
|
<div {{ collection.controller(form, 'attachment.edit.delete.confirm') }}>
|
||||||
|
<table class="table table-striped table-sm" {{ collection.target() }}>
|
||||||
|
<tbody>
|
||||||
|
{% for attachment in form %}
|
||||||
|
{{ form_widget(attachment) }}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-success" {{ collection.create_btn() }} {% if part_mode and not is_granted('attachments.create', part) %}disabled{% endif %}>
|
||||||
|
<i class="fas fa-plus-square fa-fw"></i>
|
||||||
|
{% trans %}attachment.create{% endtrans %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
|
@ -1,6 +1,6 @@
|
||||||
{% macro controller(form, deleteMessage) %}
|
{% macro controller(form, deleteMessage) %}
|
||||||
{{ stimulus_controller('elements/collection_type', {
|
{{ stimulus_controller('elements/collection_type', {
|
||||||
'deleteMessage': 'parameter.delete.confirm'|trans,
|
'deleteMessage': deleteMessage|trans,
|
||||||
'prototype': form_widget(form.vars.prototype)|e('html_attr')
|
'prototype': form_widget(form.vars.prototype)|e('html_attr')
|
||||||
}) }}
|
}) }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
|
@ -9351,5 +9351,11 @@ Element 3</target>
|
||||||
<target>Actions finished successfully.</target>
|
<target>Actions finished successfully.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="_3l6FO_" name="attachment.edit.delete.confirm">
|
||||||
|
<segment>
|
||||||
|
<source>attachment.edit.delete.confirm</source>
|
||||||
|
<target>Do you really want to delete this attachment?</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue