Merge pull request #8103 from tchak/feat-graphql-improuve-groupe-instructeur
feat(graphql): expose groupe_instructeur state and update mutation
This commit is contained in:
commit
4f3e29873e
13 changed files with 183 additions and 18 deletions
|
@ -32,7 +32,7 @@ module Administrateurs
|
|||
.new({ instructeurs: [current_administrateur.instructeur] }.merge(groupe_instructeur_params))
|
||||
|
||||
if @groupe_instructeur.save
|
||||
routing_notice = " et le routage a été activé" if procedure.groupe_instructeurs.actif.size == 2
|
||||
routing_notice = " et le routage a été activé" if procedure.groupe_instructeurs.active.size == 2
|
||||
redirect_to admin_procedure_groupe_instructeur_path(procedure, @groupe_instructeur),
|
||||
notice: "Le groupe d’instructeurs « #{@groupe_instructeur.label} » a été créé#{routing_notice}."
|
||||
else
|
||||
|
@ -56,7 +56,7 @@ module Administrateurs
|
|||
@instructeurs = paginated_instructeurs
|
||||
@available_instructeur_emails = available_instructeur_emails
|
||||
|
||||
flash[:alert] = @groupe_instructeur.errors.values.join('<br>')
|
||||
flash[:alert] = @groupe_instructeur.errors.full_messages.to_sentence
|
||||
render :show
|
||||
end
|
||||
end
|
||||
|
@ -70,7 +70,7 @@ module Administrateurs
|
|||
flash[:alert] = "Suppression impossible : il doit y avoir au moins un groupe instructeur sur chaque procédure"
|
||||
else
|
||||
@groupe_instructeur.destroy!
|
||||
if procedure.groupe_instructeurs.actif.one?
|
||||
if procedure.groupe_instructeurs.active.one?
|
||||
procedure.update!(routing_enabled: false)
|
||||
routing_notice = " et le routage a été désactivé"
|
||||
end
|
||||
|
|
|
@ -711,5 +711,16 @@ class API::V2::StoredQuery
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation groupeInstructeurModifier($input: GroupeInstructeurModifierInput!) {
|
||||
groupeInstructeurModifier(input: $input) {
|
||||
groupeInstructeur {
|
||||
id
|
||||
}
|
||||
errors {
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
|
20
app/graphql/mutations/groupe_instructeur_modifier.rb
Normal file
20
app/graphql/mutations/groupe_instructeur_modifier.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
module Mutations
|
||||
class GroupeInstructeurModifier < Mutations::BaseMutation
|
||||
description "Modifier un groupe instructeur."
|
||||
|
||||
argument :groupe_instructeur_id, ID, "Groupe instructeur ID", required: true, loads: Types::GroupeInstructeurType
|
||||
argument :label, String, "Libellé du groupe instructeur.", required: false
|
||||
argument :closed, Boolean, "L’état du groupe instructeur.", required: false
|
||||
|
||||
field :groupe_instructeur, Types::GroupeInstructeurType, null: true
|
||||
field :errors, [Types::ValidationErrorType], null: true
|
||||
|
||||
def resolve(groupe_instructeur:, label: nil, closed: nil)
|
||||
if groupe_instructeur.update({ label: label, closed: closed }.compact)
|
||||
{ groupe_instructeur: groupe_instructeur }
|
||||
else
|
||||
{ errors: groupe_instructeur.errors.full_messages }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -572,7 +572,7 @@ type Demarche {
|
|||
updatedSince: ISO8601DateTime
|
||||
): DossierConnection!
|
||||
draftRevision: Revision!
|
||||
groupeInstructeurs: [GroupeInstructeur!]!
|
||||
groupeInstructeurs(closed: Boolean): [GroupeInstructeur!]!
|
||||
id: ID!
|
||||
|
||||
"""
|
||||
|
@ -1523,8 +1523,16 @@ type GeoJSON {
|
|||
Un groupe instructeur
|
||||
"""
|
||||
type GroupeInstructeur {
|
||||
"""
|
||||
L’état du groupe instructeur.
|
||||
"""
|
||||
closed: Boolean!
|
||||
id: ID!
|
||||
instructeurs: [Profile!]!
|
||||
|
||||
"""
|
||||
Libellé du groupe instructeur.
|
||||
"""
|
||||
label: String!
|
||||
|
||||
"""
|
||||
|
@ -1533,10 +1541,52 @@ type GroupeInstructeur {
|
|||
number: Int!
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated input type of GroupeInstructeurModifier
|
||||
"""
|
||||
input GroupeInstructeurModifierInput {
|
||||
"""
|
||||
A unique identifier for the client performing the mutation.
|
||||
"""
|
||||
clientMutationId: String
|
||||
|
||||
"""
|
||||
L’état du groupe instructeur.
|
||||
"""
|
||||
closed: Boolean
|
||||
|
||||
"""
|
||||
Groupe instructeur ID
|
||||
"""
|
||||
groupeInstructeurId: ID!
|
||||
|
||||
"""
|
||||
Libellé du groupe instructeur.
|
||||
"""
|
||||
label: String
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated return type of GroupeInstructeurModifier.
|
||||
"""
|
||||
type GroupeInstructeurModifierPayload {
|
||||
"""
|
||||
A unique identifier for the client performing the mutation.
|
||||
"""
|
||||
clientMutationId: String
|
||||
errors: [ValidationError!]
|
||||
groupeInstructeur: GroupeInstructeur
|
||||
}
|
||||
|
||||
"""
|
||||
Un groupe instructeur avec ses dossiers
|
||||
"""
|
||||
type GroupeInstructeurWithDossiers {
|
||||
"""
|
||||
L’état du groupe instructeur.
|
||||
"""
|
||||
closed: Boolean!
|
||||
|
||||
"""
|
||||
Liste de tous les dossiers supprimés d’un groupe instructeur.
|
||||
"""
|
||||
|
@ -1638,6 +1688,10 @@ type GroupeInstructeurWithDossiers {
|
|||
): DossierConnection!
|
||||
id: ID!
|
||||
instructeurs: [Profile!]!
|
||||
|
||||
"""
|
||||
Libellé du groupe instructeur.
|
||||
"""
|
||||
label: String!
|
||||
|
||||
"""
|
||||
|
@ -1866,6 +1920,16 @@ type Mutation {
|
|||
"""
|
||||
input: DossierRepasserEnInstructionInput!
|
||||
): DossierRepasserEnInstructionPayload
|
||||
|
||||
"""
|
||||
Modifier un groupe instructeur.
|
||||
"""
|
||||
groupeInstructeurModifier(
|
||||
"""
|
||||
Parameters for GroupeInstructeurModifier
|
||||
"""
|
||||
input: GroupeInstructeurModifierInput!
|
||||
): GroupeInstructeurModifierPayload
|
||||
}
|
||||
|
||||
enum Order {
|
||||
|
|
|
@ -29,7 +29,9 @@ module Types
|
|||
field :date_depublication, GraphQL::Types::ISO8601DateTime, "Date de la dépublication.", null: true, method: :unpublished_at
|
||||
field :date_fermeture, GraphQL::Types::ISO8601DateTime, "Date de la fermeture.", null: true, method: :closed_at
|
||||
|
||||
field :groupe_instructeurs, [Types::GroupeInstructeurType], null: false
|
||||
field :groupe_instructeurs, [Types::GroupeInstructeurType], null: false do
|
||||
argument :closed, Boolean, required: false
|
||||
end
|
||||
field :service, Types::ServiceType, null: true
|
||||
|
||||
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers d’une démarche.", null: false, extras: [:lookahead] do
|
||||
|
@ -60,8 +62,14 @@ module Types
|
|||
object.aasm.current_state
|
||||
end
|
||||
|
||||
def groupe_instructeurs
|
||||
Loaders::Association.for(object.class, groupe_instructeurs: { procedure: [:administrateurs] }).load(object)
|
||||
def groupe_instructeurs(closed: nil)
|
||||
if closed.nil?
|
||||
Loaders::Association.for(object.class, groupe_instructeurs: { procedure: [:administrateurs] }).load(object)
|
||||
elsif closed.true?
|
||||
Loaders::Association.for(object.class, active_groupe_instructeurs: { procedure: [:administrateurs] }).load(object)
|
||||
else
|
||||
Loaders::Association.for(object.class, closed_groupe_instructeurs: { procedure: [:administrateurs] }).load(object)
|
||||
end
|
||||
end
|
||||
|
||||
def service
|
||||
|
|
|
@ -4,8 +4,9 @@ module Types
|
|||
|
||||
global_id_field :id
|
||||
field :number, Int, "Le numero du groupe instructeur.", null: false, method: :id
|
||||
field :label, String, null: false
|
||||
field :label, String, "Libellé du groupe instructeur.", null: false
|
||||
field :instructeurs, [Types::ProfileType], null: false
|
||||
field :closed, Boolean, "L’état du groupe instructeur.", null: false
|
||||
|
||||
def instructeurs
|
||||
Loaders::Association.for(object.class, :instructeurs).load(object)
|
||||
|
|
|
@ -18,5 +18,7 @@ module Types
|
|||
field :dossier_modifier_annotation_datetime, mutation: Mutations::DossierModifierAnnotationDatetime
|
||||
field :dossier_modifier_annotation_integer_number, mutation: Mutations::DossierModifierAnnotationIntegerNumber
|
||||
field :dossier_modifier_annotation_ajouter_ligne, mutation: Mutations::DossierModifierAnnotationAjouterLigne
|
||||
|
||||
field :groupe_instructeur_modifier, mutation: Mutations::GroupeInstructeurModifier
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,16 +19,17 @@ class GroupeInstructeur < ApplicationRecord
|
|||
has_and_belongs_to_many :exports, dependent: :destroy
|
||||
has_and_belongs_to_many :bulk_messages, dependent: :destroy
|
||||
|
||||
validates :label, presence: { message: 'doit être renseigné' }, allow_nil: false
|
||||
validates :label, uniqueness: { scope: :procedure, message: 'existe déjà' }
|
||||
validates :closed, acceptance: { accept: [false], message: "Modification impossible : il doit y avoir au moins un groupe instructeur actif sur chaque procédure" }, if: -> { self.procedure.groupe_instructeurs.actif.one? }
|
||||
validates :label, presence: true, allow_nil: false
|
||||
validates :label, uniqueness: { scope: :procedure }
|
||||
validates :closed, acceptance: { accept: [false] }, if: -> { self.procedure.groupe_instructeurs.active.one? }
|
||||
|
||||
before_validation -> { label&.strip! }
|
||||
after_save :toggle_routing
|
||||
|
||||
scope :without_group, -> (group) { where.not(id: group) }
|
||||
scope :for_api_v2, -> { includes(procedure: [:administrateurs]) }
|
||||
scope :actif, -> { where(closed: false) }
|
||||
scope :active, -> { where(closed: false) }
|
||||
scope :closed, -> { where(closed: true) }
|
||||
|
||||
def add(instructeur)
|
||||
return if in?(instructeur.groupe_instructeurs)
|
||||
|
@ -48,12 +49,12 @@ class GroupeInstructeur < ApplicationRecord
|
|||
end
|
||||
|
||||
def can_delete?
|
||||
dossiers.empty? && (procedure.groupe_instructeurs.actif.many? || (procedure.groupe_instructeurs.actif.one? && closed))
|
||||
dossiers.empty? && (procedure.groupe_instructeurs.active.many? || (procedure.groupe_instructeurs.active.one? && closed))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def toggle_routing
|
||||
procedure.update!(routing_enabled: procedure.groupe_instructeurs.actif.many?)
|
||||
procedure.update!(routing_enabled: procedure.groupe_instructeurs.active.many?)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -185,6 +185,9 @@ class Procedure < ApplicationRecord
|
|||
has_many :groupe_instructeurs, -> { order(:label) }, inverse_of: :procedure, dependent: :destroy
|
||||
has_many :instructeurs, through: :groupe_instructeurs
|
||||
|
||||
has_many :active_groupe_instructeurs, -> { active }, class_name: 'GroupeInstructeur', inverse_of: false
|
||||
has_many :closed_groupe_instructeurs, -> { closed }, class_name: 'GroupeInstructeur', inverse_of: false
|
||||
|
||||
# This relationship is used in following dossiers through. We can not use revisions relationship
|
||||
# as order scope introduces invalid sql in some combinations.
|
||||
has_many :unordered_revisions, class_name: 'ProcedureRevision', inverse_of: :procedure, dependent: :destroy
|
||||
|
@ -196,7 +199,7 @@ class Procedure < ApplicationRecord
|
|||
has_one :refused_mail, class_name: "Mails::RefusedMail", dependent: :destroy
|
||||
has_one :without_continuation_mail, class_name: "Mails::WithoutContinuationMail", dependent: :destroy
|
||||
|
||||
has_one :defaut_groupe_instructeur, -> { actif.order(:label) }, class_name: 'GroupeInstructeur', inverse_of: false
|
||||
has_one :defaut_groupe_instructeur, -> { active.order(:label) }, class_name: 'GroupeInstructeur', inverse_of: false
|
||||
|
||||
has_one_attached :logo
|
||||
has_one_attached :notice
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
= dossier.procedure.routing_criteria_name
|
||||
%span.mandatory *
|
||||
= f.select :groupe_instructeur_id,
|
||||
dossier.procedure.groupe_instructeurs.actif.map { |gi| [gi.label, gi.id] },
|
||||
dossier.procedure.groupe_instructeurs.active.map { |gi| [gi.label, gi.id] },
|
||||
{ include_blank: dossier.brouillon? }
|
||||
|
||||
- dossier.champs_public.each do |champ|
|
||||
|
|
18
config/locales/models/groupe_instructeur/fr.yml
Normal file
18
config/locales/models/groupe_instructeur/fr.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
fr:
|
||||
activerecord:
|
||||
models:
|
||||
procedure:
|
||||
one: Groupe instructeur
|
||||
other: Groupes instructeur
|
||||
attributes:
|
||||
groupe_instructeur:
|
||||
label: Libellé
|
||||
errors:
|
||||
models:
|
||||
groupe_instructeur:
|
||||
attributes:
|
||||
label:
|
||||
format: "Le libellé %{message}"
|
||||
closed:
|
||||
format: "%{message}"
|
||||
accepted: Il doit y avoir au moins un groupe instructeur actif sur chaque démarche
|
|
@ -206,7 +206,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
|||
it { expect(response).to render_template(:show) }
|
||||
it { expect(gi_1_1.label).not_to eq(new_name) }
|
||||
it { expect(gi_1_1.closed).to eq(false) }
|
||||
it { expect(flash.alert).to be_present }
|
||||
it { expect(flash.alert).to eq('Il doit y avoir au moins un groupe instructeur actif sur chaque démarche') }
|
||||
end
|
||||
|
||||
context 'when the name is already taken' do
|
||||
|
@ -214,7 +214,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
|||
let(:new_name) { gi_1_2.label }
|
||||
|
||||
it { expect(gi_1_1.label).not_to eq(new_name) }
|
||||
it { expect(flash.alert).to be_present }
|
||||
it { expect(flash.alert).to eq('Le libellé est déjà utilisé(e)') }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1003,6 +1003,43 @@ describe API::V2::GraphqlController do
|
|||
expect(gql_data[:dossierClasserSansSuite][:dossier][:state]).to eq('sans_suite')
|
||||
}
|
||||
end
|
||||
|
||||
context 'groupeInstructeurModifier' do
|
||||
let(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure: procedure) }
|
||||
let(:variables) { { input: { groupeInstructeurId: dossier.groupe_instructeur.to_typed_id, label: 'nouveau groupe instructeur' } } }
|
||||
let(:operation_name) { 'groupeInstructeurModifier' }
|
||||
|
||||
it {
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:groupeInstructeurModifier][:errors]).to be_nil
|
||||
expect(gql_data[:groupeInstructeurModifier][:groupeInstructeur][:id]).to eq(dossier.groupe_instructeur.to_typed_id)
|
||||
expect(dossier.groupe_instructeur.reload.label).to eq('nouveau groupe instructeur')
|
||||
}
|
||||
|
||||
context 'close groupe instructeur' do
|
||||
let(:variables) { { input: { groupeInstructeurId: dossier.groupe_instructeur.to_typed_id, closed: true } } }
|
||||
|
||||
context 'with multiple groupes' do
|
||||
before do
|
||||
create(:groupe_instructeur, procedure: procedure)
|
||||
end
|
||||
|
||||
it {
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:groupeInstructeurModifier][:errors]).to be_nil
|
||||
expect(gql_data[:groupeInstructeurModifier][:groupeInstructeur][:id]).to eq(dossier.groupe_instructeur.to_typed_id)
|
||||
expect(dossier.groupe_instructeur.reload.closed).to be_truthy
|
||||
}
|
||||
end
|
||||
|
||||
context 'validation error' do
|
||||
it {
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:groupeInstructeurModifier][:errors].first[:message]).to eq('Il doit y avoir au moins un groupe instructeur actif sur chaque démarche')
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue