Merge pull request #8385 from tchak/feat-batches-by-possible-operation
feat(batch_operation): enable only available operations
This commit is contained in:
commit
8adada9857
7 changed files with 77 additions and 24 deletions
|
@ -87,7 +87,7 @@
|
||||||
|
|
||||||
// display
|
// display
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.visible-on-previous-hover {
|
.visible-on-previous-hover {
|
||||||
|
|
|
@ -10,6 +10,21 @@ class Dossiers::BatchOperationComponent < ApplicationComponent
|
||||||
['a-suivre', 'traites', 'suivis'].include?(@statut)
|
['a-suivre', 'traites', 'suivis'].include?(@statut)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def operations_for_dossier(dossier)
|
||||||
|
case dossier.state
|
||||||
|
when Dossier.states.fetch(:en_construction)
|
||||||
|
[BatchOperation.operations.fetch(:passer_en_instruction)]
|
||||||
|
when Dossier.states.fetch(:en_instruction)
|
||||||
|
[BatchOperation.operations.fetch(:accepter)]
|
||||||
|
when Dossier.states.fetch(:accepte), Dossier.states.fetch(:refuse), Dossier.states.fetch(:sans_suite)
|
||||||
|
[BatchOperation.operations.fetch(:archiver)]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
def available_operations
|
def available_operations
|
||||||
case @statut
|
case @statut
|
||||||
when 'a-suivre' then
|
when 'a-suivre' then
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
.batch-operation.fr-ml-auto.flex
|
.batch-operation.fr-ml-auto.flex
|
||||||
- if available_operations[:options].count.between?(1,3)
|
- if available_operations[:options].count.between?(1,3)
|
||||||
= form_for(BatchOperation.new, url: instructeur_batch_operations_path(procedure_id: procedure.id), method: :post, html: { class: 'form', id: "#{dom_id(BatchOperation.new)}" }) do |form|
|
= form_for(BatchOperation.new, url: instructeur_batch_operations_path(procedure_id: procedure.id), method: :post, html: { class: 'form', id: dom_id(BatchOperation.new) }) do |form|
|
||||||
- available_operations[:options].each do |opt|
|
- available_operations[:options].each do |opt|
|
||||||
= render partial: "instructeurs/dossiers/batch_operation_inline_buttons", locals: { opt: opt, icons: icons, form: form }
|
= render Dossiers::BatchOperationInlineButtonsComponent.new(opt:, icons:, form:)
|
||||||
|
|
||||||
- else
|
- else
|
||||||
= form_for(BatchOperation.new, url: instructeur_batch_operations_path(procedure_id: procedure.id), method: :post, html: { class: 'form flex', id: "#{dom_id(BatchOperation.new)}" }) do |form|
|
= form_for(BatchOperation.new, url: instructeur_batch_operations_path(procedure_id: procedure.id), method: :post, html: { class: 'form flex', id: dom_id(BatchOperation.new) }) do |form|
|
||||||
- available_operations[:options][0,2].each do |opt|
|
- available_operations[:options][0,2].each do |opt|
|
||||||
= render partial: "instructeurs/dossiers/batch_operation_inline_buttons", locals: { opt: opt, icons: icons, form: form }
|
= render Dossiers::BatchOperationInlineButtonsComponent.new(opt:, icons:, form:)
|
||||||
|
|
||||||
.dropdown{ data: { controller: 'menu-button', popover: 'true' } }
|
.dropdown{ data: { controller: 'menu-button', popover: 'true' } }
|
||||||
-# Dropdown button title
|
-# Dropdown button title
|
||||||
%button.fr-btn.fr-btn--sm.fr-ml-1w.dropdown-button{ disabled: true, data: { menu_button_target: 'button'} }
|
%button.fr-btn.fr-btn--sm.fr-ml-1w.dropdown-button{ disabled: true, data: { menu_button_target: 'button', batch_operation_target: 'menu' } }
|
||||||
Autres actions multiples
|
Autres actions multiples
|
||||||
|
|
||||||
#state-menu.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
#state-menu.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||||
%ul.dropdown-items
|
%ul.dropdown-items
|
||||||
- available_operations[:options][2, available_operations[:options].count].each do |opt|
|
- available_operations[:options][2, available_operations[:options].count].each do |opt|
|
||||||
%li{ 'data-turbo': 'true' }
|
%li{ 'data-turbo': 'true' }
|
||||||
= form.button opt[:label], class: 'dropdown-items-link ', disabled: true, name: "#{form.object_name}[operation]", value: opt[:operation] do
|
= form.button opt[:label], class: 'dropdown-items-link ', disabled: true, name: "#{form.object_name}[operation]", value: opt[:operation], data: { operation: opt[:operation] } do
|
||||||
%span{ class: icons[opt[:operation].to_sym] }
|
%span{ class: icons[opt[:operation].to_sym] }
|
||||||
.dropdown-description
|
.dropdown-description
|
||||||
%h4= opt[:label]
|
%h4= opt[:label]
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
class Dossiers::BatchOperationInlineButtonsComponent < ApplicationComponent
|
||||||
|
attr_reader :opt, :icons, :form
|
||||||
|
|
||||||
|
def initialize(opt:, icons:, form:)
|
||||||
|
@opt = opt
|
||||||
|
@icons = icons
|
||||||
|
@form = form
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
- if opt[:operation] == 'accepter'
|
- if opt[:operation] == 'accepter'
|
||||||
.dropdown{ data: { controller: 'menu-button', popover: 'true' } }
|
.dropdown{ data: { controller: 'menu-button', popover: 'true', operation: opt[:operation] } }
|
||||||
-# Dropdown button title
|
-# Dropdown button title
|
||||||
%button{ disabled: true, class: ['fr-btn fr-btn--sm fr-btn--icon-left fr-ml-1w', icons[opt[:operation].to_sym]], disabled: true, name: "#{form.object_name}[operation]" , data: { menu_button_target: 'button' } }
|
%button{ disabled: true, class: ['fr-btn fr-btn--sm fr-btn--icon-left fr-ml-1w', icons[opt[:operation].to_sym]], disabled: true, name: "#{form.object_name}[operation]" , data: { menu_button_target: 'button' } }
|
||||||
= opt[:label]
|
= opt[:label]
|
||||||
|
@ -16,13 +16,13 @@
|
||||||
|
|
||||||
.motivation.accept
|
.motivation.accept
|
||||||
= form.text_area :motivation, class: 'motivation-text-area'
|
= form.text_area :motivation, class: 'motivation-text-area'
|
||||||
.optional-justificatif{ id: "justificatif_motivation_suggest_accept", onclick: "DS.showImportJustificatif('accept');" }
|
#justificatif_motivation_suggest_accept.optional-justificatif
|
||||||
.button Ajouter un justificatif (optionnel)
|
%button.button{ type: 'button', onclick: "DS.showImportJustificatif('accept');" } Ajouter un justificatif (optionnel)
|
||||||
.hidden{ id: "justificatif_motivation_import_accept" }
|
#justificatif_motivation_import_accept.hidden
|
||||||
= form.file_field :justificatif_motivation, direct_upload: true
|
= form.file_field :justificatif_motivation, direct_upload: true
|
||||||
|
|
||||||
|
|
||||||
= form.button "Valider la décision", class: ['fr-btn fr-mt-2w'], disabled: true, name: "#{form.object_name}[operation]", value: opt[:operation]
|
= form.button "Valider la décision", class: ['fr-btn fr-mt-2w'], disabled: true, name: "#{form.object_name}[operation]", value: opt[:operation]
|
||||||
|
|
||||||
- else
|
- else
|
||||||
= form.button opt[:label], class: ['fr-btn fr-btn--sm fr-btn--icon-left fr-ml-1w', icons[opt[:operation].to_sym]], disabled: true, name: "#{form.object_name}[operation]", value: opt[:operation]
|
= form.button opt[:label], class: ['fr-btn fr-btn--sm fr-btn--icon-left fr-ml-1w', icons[opt[:operation].to_sym]], disabled: true, name: "#{form.object_name}[operation]", value: opt[:operation], data: { operation: opt[:operation] }
|
|
@ -1,9 +1,12 @@
|
||||||
import { ApplicationController } from './application_controller';
|
import { ApplicationController } from './application_controller';
|
||||||
import { disable, enable } from '@utils';
|
import { disable, enable } from '@utils';
|
||||||
|
import invariant from 'tiny-invariant';
|
||||||
|
|
||||||
export class BatchOperationController extends ApplicationController {
|
export class BatchOperationController extends ApplicationController {
|
||||||
static targets = ['input'];
|
static targets = ['menu', 'input'];
|
||||||
|
|
||||||
|
declare readonly menuTarget: HTMLButtonElement;
|
||||||
|
declare readonly hasMenuTarget: boolean;
|
||||||
declare readonly inputTargets: HTMLInputElement[];
|
declare readonly inputTargets: HTMLInputElement[];
|
||||||
|
|
||||||
onCheckOne() {
|
onCheckOne() {
|
||||||
|
@ -18,16 +21,42 @@ export class BatchOperationController extends ApplicationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSubmitButtonWhenNeeded() {
|
toggleSubmitButtonWhenNeeded() {
|
||||||
const available = this.inputTargets.some((e) => e.checked);
|
const buttons = [
|
||||||
const buttons = this.element.querySelectorAll<HTMLButtonElement>(
|
...this.element.querySelectorAll<HTMLButtonElement>('[data-operation]')
|
||||||
'.batch-operation button'
|
];
|
||||||
);
|
const checked = this.inputTargets.filter((input) => input.checked);
|
||||||
for (const button of buttons) {
|
if (checked.length) {
|
||||||
if (available) {
|
const available = buttons.filter((button) => {
|
||||||
|
const operation = button.dataset.operation;
|
||||||
|
invariant(operation, 'data-operation is required');
|
||||||
|
const available = checked.every(isInputForOperation(operation));
|
||||||
|
switchButton(button, available);
|
||||||
|
return available;
|
||||||
|
});
|
||||||
|
if (this.hasMenuTarget) {
|
||||||
|
if (available.length) {
|
||||||
|
enable(this.menuTarget);
|
||||||
|
} else {
|
||||||
|
disable(this.menuTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (this.hasMenuTarget) {
|
||||||
|
disable(this.menuTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInputForOperation(operation: string) {
|
||||||
|
return (input: HTMLInputElement) =>
|
||||||
|
(input.dataset.operations?.split(',') ?? []).includes(operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchButton(button: HTMLButtonElement, flag: boolean) {
|
||||||
|
if (flag) {
|
||||||
enable(button);
|
enable(button);
|
||||||
|
button.querySelectorAll('button').forEach((button) => enable(button));
|
||||||
} else {
|
} else {
|
||||||
disable(button);
|
disable(button);
|
||||||
}
|
button.querySelectorAll('button').forEach((button) => disable(button));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
- if p.batch_operation_id.present?
|
- if p.batch_operation_id.present?
|
||||||
= check_box_tag :"batch_operation[dossier_ids][]", p.dossier_id, true, disabled: true, id: dom_id(BatchOperation.new, "checkbox_#{p.dossier_id}"), aria: { label: t('views.instructeurs.dossiers.batch_operation.disabled') }
|
= check_box_tag :"batch_operation[dossier_ids][]", p.dossier_id, true, disabled: true, id: dom_id(BatchOperation.new, "checkbox_#{p.dossier_id}"), aria: { label: t('views.instructeurs.dossiers.batch_operation.disabled') }
|
||||||
- else
|
- else
|
||||||
= check_box_tag :"batch_operation[dossier_ids][]", p.dossier_id, false, data: { batch_operation_target: "input", action: "batch-operation#onCheckOne" }, form: dom_id(BatchOperation.new), id: dom_id(BatchOperation.new, "checkbox_#{p.dossier_id}"), aria: { label: t('views.instructeurs.dossiers.batch_operation.enabled') }
|
= check_box_tag :"batch_operation[dossier_ids][]", p.dossier_id, false, data: { batch_operation_target: "input", action: "batch-operation#onCheckOne", operations: batch_operation_component.operations_for_dossier(p).join(',') }, form: dom_id(BatchOperation.new), id: dom_id(BatchOperation.new, "checkbox_#{p.dossier_id}"), aria: { label: t('views.instructeurs.dossiers.batch_operation.enabled') }
|
||||||
|
|
||||||
- if @not_archived_notifications_dossier_ids.include?(p.dossier_id)
|
- if @not_archived_notifications_dossier_ids.include?(p.dossier_id)
|
||||||
%span.notifications{ 'aria-label': 'notifications' }
|
%span.notifications{ 'aria-label': 'notifications' }
|
||||||
|
|
Loading…
Reference in a new issue