From e8396993eab07c6213393377aee37cd5d63c6ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Wed, 20 May 2026 13:46:35 +0200 Subject: [PATCH 01/14] Redesign authorization requests index as DSFR card grid Replace the 4-column table (habilitation, token, actions, detail) with a responsive grid of DSFR cards showing title, status badge, DataPass reference and user role label. - Switch eager loading from :active_token to :user_authorization_request_roles (fixes N+1 for role display) - Filter roles in Ruby on the preloaded collection instead of hitting the DB per row - Load @tokens (all tokens) in show action instead of @main_token + @other_tokens (preparation for show redesign) - Rewrite index feature spec to match the new card-based UI --- .../authorization_requests_management.rb | 5 +- .../authorization_requests/index.html.erb | 86 ++++------ .../authorization_request_index_spec.rb | 150 ++---------------- 3 files changed, 47 insertions(+), 194 deletions(-) diff --git a/site/app/controllers/concerns/authorization_requests_management.rb b/site/app/controllers/concerns/authorization_requests_management.rb index 1a8ce42969..3d60e2d33a 100644 --- a/site/app/controllers/concerns/authorization_requests_management.rb +++ b/site/app/controllers/concerns/authorization_requests_management.rb @@ -3,8 +3,7 @@ module AuthorizationRequestsManagement def show @authorization_request = extract_authorization_request - @main_token = @authorization_request.token.decorate - @other_tokens = @authorization_request.tokens.where.not(id: @main_token.id).decorate + @tokens = @authorization_request.tokens.order(created_at: :desc).decorate load_delegations_data render 'shared/authorization_requests/show' @@ -22,7 +21,7 @@ def index .viewable_by_users .order( first_submitted_at: :desc - ).includes(:active_token) + ).includes(:user_authorization_request_roles) render 'shared/authorization_requests/index' end diff --git a/site/app/views/shared/authorization_requests/index.html.erb b/site/app/views/shared/authorization_requests/index.html.erb index 06e4603fc4..cc6f2b492f 100644 --- a/site/app/views/shared/authorization_requests/index.html.erb +++ b/site/app/views/shared/authorization_requests/index.html.erb @@ -1,7 +1,7 @@
- <%= link_to t('.links.profile'), user_profile_path, class: %w(fr-link fr-icon-account-fill fr-link--icon-left fr-text--lg pull-right fr-mb-2w ) %> + <%= link_to t('.links.profile'), user_profile_path, class: %w(fr-link fr-icon-account-fill fr-link--icon-left fr-text--lg pull-right fr-mb-2w) %>

@@ -13,64 +13,36 @@

-
-
-
-
-
- <%= t('.table.head.authorization_request') %> -
-
- <%= t('.table.head.token') %> -
-
- <%= t('.table.head.actions') %> -
-
- <%= t('.table.head.detail') %> -
-
- <% @authorization_requests.each do |authorization_request| %> -
-
-

<%= authorization_request.intitule %>

- <%= authorization_request_status_badge(authorization_request) %> - - <%= link_to t('.links.to_datapass_html', external_id: authorization_request.external_id), - datapass_authorization_request_url(authorization_request), - id: dom_id(authorization_request, :authorization_request_link), - class: %w(fr-link fr-text--sm fr-mt-2v), - target: '_blank', - rel: 'noopener noreferrer' - %> - - Vous êtes - <%= authorization_request.user_authorization_request_roles.for_user(@current_user).map { |uarr| - I18n.t("user_authorization_request_roles.role.#{uarr.role}") - }.join(', ') - %> - -
-
- <% displayed_tokens = authorization_request.tokens.active.to_a %> - <% displayed_tokens = [authorization_request.token].compact if displayed_tokens.empty? %> - <% displayed_tokens.each_with_index do |token, index| %> -
- <%= render partial: 'shared/tokens/detail_short', locals: { token: token.decorate } %> -
- <% end %> -
-
- <% authorization_request_expected_actions(authorization_request, current_user).each do |action| %> - <%= render partial: "shared/authorization_requests/actions/#{action[:action]}", locals: { label: action[:label], authorization_request:, to_datapass_reopen: action[:to_datapass_reopen] } %> - <% end %> -
-
- <%= link_to "Plus d'informations", authorization_request_path(authorization_request), class: %w[fr-btn fr-btn--tertiary center] %> +
+ <% @authorization_requests.each do |authorization_request| %> +
+
-
+ <% end %>
diff --git a/site/spec/features/api_particulier/authorization_request_index_spec.rb b/site/spec/features/api_particulier/authorization_request_index_spec.rb index d064680b10..30e395634a 100644 --- a/site/spec/features/api_particulier/authorization_request_index_spec.rb +++ b/site/spec/features/api_particulier/authorization_request_index_spec.rb @@ -4,33 +4,6 @@ end let!(:authenticated_user) { create(:user) } - let!(:non_authenticated_user) { create(:user, :demandeur) } - - let!(:authorization_request) do - create( - :authorization_request, - :with_demandeur, - demandeur: non_authenticated_user, - api: 'entreprise' - ) - end - - let!(:authorization_request_active) { nil } - let!(:authorization_request_expired) { nil } - let!(:authorization_request_blacklisted) { nil } - let!(:authorization_request_archived) { nil } - let!(:authorization_requests) do - [ - authorization_request_active, - authorization_request_expired, - authorization_request_blacklisted, - authorization_request_archived - ] - end - - let!(:token) do - create(:token, authorization_request:) - end describe 'when user is not authenticated' do it 'redirects to the login' do @@ -45,153 +18,62 @@ end describe 'when the user does not have authorization requests' do - it 'displays the page' do + it 'displays the empty state' do go_to_authorization_requests_index - expect(page).to have_current_path(api_particulier_authorization_requests_path, ignore_query: true) expect(page).to have_text("Vous n'avez aucune habilitation") end end describe 'when the user has authorization requests' do - let!(:tokens) do - [ - token_active, - token_blacklisted_later, - token_expired, - token_blacklisted - ] - end - - let!(:token_blacklisted_later) { create(:token, :blacklisted, blacklisted_at: 1.day.from_now, authorization_request:) } - let!(:token_active) { create(:token, authorization_request:, exp: 70.days.from_now) } let!(:authorization_request_active) do create( :authorization_request, :with_demandeur, :validated, - intitule: 'active', - tokens: [token_active, token_blacklisted_later], - demandeur: authenticated_user, - api: 'particulier' - ) - end - - let!(:token_expired) { create(:token, :expired, authorization_request:) } - let!(:authorization_request_expired) do - create( - :authorization_request, - :with_demandeur, - :validated, - tokens: [token_expired], - demandeur: authenticated_user, - api: 'particulier' - ) - end - - let!(:token_blacklisted) { create(:token, :blacklisted, authorization_request:) } - let!(:authorization_request_blacklisted) do - create( - :authorization_request, - :with_demandeur, - :validated, - tokens: [token_blacklisted], + intitule: 'Mon habilitation active', demandeur: authenticated_user, api: 'particulier' ) end - let!(:token_archived) { create(:token, authorization_request:) } let!(:authorization_request_archived) do create( :authorization_request, :with_demandeur, :submitted, status: 'archived', - tokens: [token_archived], + intitule: 'Mon habilitation archivée', demandeur: authenticated_user, api: 'particulier' ) end - let!(:prolong_wizard) { create(:prolong_token_wizard, :requires_update, token: authorization_request_active.token, status:) } - let!(:status) { 'owner' } - - let!(:approved_authorization_request_without_token) do - user_authorization_request_role = create(:user_authorization_request_role, authorization_request: create(:authorization_request, :validated, api: :particulier), user: authenticated_user, role: 'contact_technique') - user_authorization_request_role.authorization_request.tokens.delete_all - user_authorization_request_role.authorization_request - end - - it 'displays the page' do + it 'displays all authorization requests as cards' do go_to_authorization_requests_index - expect(page).to have_current_path(api_particulier_authorization_requests_path, ignore_query: true) - - expect(page).to have_text('Habilitations API Particulier (5)') - - authorization_requests.each do |ar| - expect(page).to have_css('#' << dom_id(ar)) - end + expect(page).to have_text('Habilitations API Particulier (2)') - tokens.each do |token| - expect(page).to have_css('#' << dom_id(token)) - end + expect(page).to have_css('#' << dom_id(authorization_request_active)) + expect(page).to have_css('#' << dom_id(authorization_request_archived)) - within('#' << dom_id(token_archived)) do - expect(page).to have_text('Aucun jeton actif') - end + expect(page).to have_text('Mon habilitation active') + expect(page).to have_text('Mon habilitation archivée') - expect(page).to have_text('☠️ Expiré') - expect(page).to have_text('🚫 Banni') - expect(page).to have_text('🔑 Nouveau jeton à utiliser') - - expect(page).to have_text('Cette demande ayant été archivée, aucun jeton ne peut être demandé') + expect(page).to have_text('Habilitation active') + expect(page).to have_text('Habilitation archivée') end - it 'displays the button to view the token details' do + it 'displays the user role on each card' do go_to_authorization_requests_index - expect(page).to have_css('#' << dom_id(authorization_request_active, :show_token_modal_link)) - expect(page).to have_no_css('#' << dom_id(authorization_request_blacklisted, :show_token_modal_link)) - expect(page).to have_no_css('#' << dom_id(authorization_request_archived, :show_token_modal_link)) + expect(page).to have_text('demandeur') end - describe 'displays the button to prolong the token' do - it 'displays the button to prolong the token' do - go_to_authorization_requests_index - - expect(page).to have_css('#' << dom_id(authorization_request_active, :prolong_token_modal_link)) - expect(page).to have_no_css('#' << dom_id(authorization_request_archived, :prolong_token_modal_link)) - end - - describe 'when there is no prolong wizard' do - it 'displays the default label' do - go_to_authorization_requests_index - - expect(page).to have_text('Prolonger le jeton') - end - end - - describe 'when there is a requires update prolong wizard' do - let!(:status) { 'requires_update' } - - it 'displays the correct label' do - go_to_authorization_requests_index - - expect(page).to have_text('Terminer la mise à jour') - end - end - - describe 'when there is a changes requested prolong wizard' do - let!(:status) { 'updates_requested' } - - it 'displays the correct label' do - go_to_authorization_requests_index + it 'links to the authorization request detail page' do + go_to_authorization_requests_index - expect(page).to have_text('Demande de mise à jour') - end - end + expect(page).to have_link('Mon habilitation active', href: api_particulier_authorization_request_path(authorization_request_active)) end end end From fa57a7ee1a4bd48bc14c86e5d61655dcceb2e829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Wed, 20 May 2026 13:46:46 +0200 Subject: [PATCH 02/14] Simplify authorization request show page Remove mono-token-centric UI and redundant sections: - Remove summary sidebar (sticky navigation) - Remove scopes/access rights section (available on DataPass) - Remove "main token" reveal/prolong/prolongation workflow - Remove attestations download section - Add prominent DataPass link button (fr-btn--lg) - Replace token sections with a single table listing all tokens with actions: reveal, transfer and stats links - Simplify contacts as an inline list with a DataPass edit link - Keep delegations section unchanged Adapt show spec and shared magic link spec to match new UI. --- .../authorization_requests/show.html.erb | 437 ++++++------------ site/config/locales/fr.yml | 35 +- .../authorization_request_show_spec.rb | 277 ++--------- .../features/create_token_magic_link.rb | 6 +- 4 files changed, 175 insertions(+), 580 deletions(-) diff --git a/site/app/views/shared/authorization_requests/show.html.erb b/site/app/views/shared/authorization_requests/show.html.erb index 9080a9b130..c7ae5439bc 100644 --- a/site/app/views/shared/authorization_requests/show.html.erb +++ b/site/app/views/shared/authorization_requests/show.html.erb @@ -1,327 +1,152 @@ <% content_for :page_title, @authorization_request.intitule %> -
-
-
- <%= render partial: 'shared/authorization_requests/summary', locals: { token: @main_token } %> -
-
-
-
- <%= render partial: 'shared/authorization_requests/header', locals: { authorization_request: @authorization_request, to_datapass: true } %> -
+
+ <%= render partial: 'shared/authorization_requests/breadcrumb', locals: { authorization_request: @authorization_request } %> -
-

- <%= t('.access').html_safe %> -

-
-
-
- <% build_scopes(@authorization_request.scopes, namespace == 'api_entreprise' ? 'entreprise' : 'particulier').each_pair do |key, values| %> -
-
-
-
-

- <%= key %> -

-
- <%= render partial: 'shared/tokens/scopes', - locals: { - scopes: values, - scope_type: key, - } - %> -
-
-
-
-
- <% end %> -
- -
-
-
+
+
+
+ <%= render partial: 'shared/authorization_requests/header', locals: { authorization_request: @authorization_request, to_datapass: false } %> -
-

- <%= t('.main_token.title').html_safe %> -

-
- <%= render partial: 'shared/tokens/detail', - locals: { - token: @main_token, - } - %> - -
-
+
+ <%= link_to datapass_authorization_request_url(@authorization_request), + class: %w(fr-btn fr-btn--lg fr-icon-external-link-line fr-btn--icon-right), + target: '_blank', + rel: 'noopener' do %> + <%= t('.datapass_cta', external_id: @authorization_request.external_id) %> + <% end %> +
+
-
-

- -

-
-
- - - - - - - - - - - - - <% @other_tokens.each do |token| %> - - - - - - +
<%= t('.other_tokens.title') %>
<%= t('.other_tokens.table.identifier')%><%= t('.other_tokens.table.status')%><%= t('.other_tokens.table.created_at')%><%= t('.other_tokens.table.exp')%><%= t('.other_tokens.table.see_more')%>
<%= token.id %><%= t("shared.tokens.show.status.label.#{token.status}") %><%= friendly_date_from_timestamp(token.created_at) %><%= friendly_date_from_timestamp(token.exp) %> - <% if token.active? %> - <%= render partial: "shared/tokens/reveal_token_button", locals: { token: token } %> + <% if @tokens.any? %> +
+

<%= t('.tokens.title') %>

+
+
+
+
+ + + + + + + + + + + + + <% @tokens.each do |token| %> + + + + + + + <% end %> - - - <% end %> - -
<%= t('.tokens.title') %>
<%= t('.tokens.table.identifier') %><%= t('.tokens.table.status') %><%= t('.tokens.table.created_at') %><%= t('.tokens.table.exp') %><%= t('.tokens.table.actions') %>
<%= token.id %><%= t("shared.tokens.show.status.label.#{token.status}") %><%= friendly_date_from_timestamp(token.created_at) %><%= friendly_date_from_timestamp(token.exp) %> + <% if token.active? %> +
    +
  • + <%= render partial: 'shared/tokens/reveal_token_button', locals: { token: token } %> +
  • +
  • + <%= link_to t('.tokens.table.transfer'), + token_transfer_path(id: token.id), + class: 'fr-btn fr-btn--sm fr-btn--tertiary fr-icon-share-line fr-btn--icon-left' %> +
  • +
  • + <%= link_to t('.tokens.table.stats'), + token_stats_path(id: token.id), + class: 'fr-btn fr-btn--sm fr-btn--tertiary fr-icon-line-chart-line fr-btn--icon-left' %> +
  • +
+ <% end %> +
-
-
- - <% if policy(@main_token).download_attestations? %> -
-
-

- <%= t('.attestations.title') %> -

-

- <%= t('.attestations.description').html_safe %> -

- <%= link_to t('.attestations.cta'), attestations_path(selected_token: @main_token.id),class: %w[fr-btn fr-btn--secondary fr-mt-2w] %> -
-
- <% end %> - -
-

- <%= t('.contacts.title').html_safe %> -

-
-
-
-

- - <%= t('.contacts.demandeur.title').html_safe %> -

-
- <% if @authorization_request.demandeur == current_user %> -
-
    -
  • -

    - <%= t('.contacts.its_me') %> -

    -
  • -
-
- <% end %> -
-
-

- <%= @authorization_request.demandeur.full_name %> -

-

- <%= @authorization_request.demandeur.email %> -

-
-
+
- <% if @authorization_request.contact_metier.present? %> -
-

- - <%= t('.contacts.contact_metier.title').html_safe %> -

-
- <% if @authorization_request.contact_metier == current_user %> -
-
    -
  • -

    - <%= t('.contacts.its_me') %> -

    -
  • -
-
- <% end %> -
-
-

- <%= @authorization_request.contact_metier.full_name %> -

-

- <%= @authorization_request.contact_metier.email %> -

-
-
-
-
- <% end %> - <% if @authorization_request.contact_technique.present? %> -
-

- - <%= t('.contacts.contact_technique.title').html_safe %> -

-
- <% if @authorization_request.contact_technique == current_user %> -
-
    -
  • -

    - <%= t('.contacts.its_me') %> -

    -
  • -
-
- <% end %> -
-
-

- <%= @authorization_request.contact_technique.full_name %> -

-

- <%= @authorization_request.contact_technique.email %> -

-
-
-
-
- <% end %>
+ <% end %> + +
+

<%= t('.contacts.title').html_safe %>

+

+ <%= t('.contacts.description') %> + <%= link_to t('.contacts.datapass_link'), + datapass_authorization_request_url(@authorization_request), + class: 'fr-link', + target: '_blank', + rel: 'noopener' %> +

+
    + <% [ + [:demandeur, @authorization_request.demandeur], + [:contact_metier, @authorization_request.contact_metier], + [:contact_technique, @authorization_request.contact_technique], + ].each do |role, contact| %> + <% next if contact.blank? %> +
  • + <%= t(".contacts.#{role}.title").html_safe %> + <%= contact.full_name %> (<%= contact.email %>)<%= " — #{t('.contacts.its_me')}" if contact == current_user %> +
  • + <% end %> +
+
- <% if @active_delegations.any? || @available_editors.any? %> -
-

- <%= t('.delegations.title').html_safe %> -

-

- <%= t('.delegations.description') %> -

+ <% if @active_delegations.any? || @available_editors.any? %> +
+

<%= t('.delegations.title').html_safe %>

+

<%= t('.delegations.description') %>

- <% if @active_delegations.any? %> -
-
-
-
- - - - - - - + <% if @active_delegations.any? %> +
+
+
+
+
<%= t('.delegations.title').html_safe %>
<%= t('.delegations.editor') %><%= t('.delegations.status') %><%= t('.delegations.actions') %>
+ + + + + + + + + + <% @active_delegations.each do |delegation| %> + + + + - - - <% @active_delegations.each do |delegation| %> - - - - - - <% end %> - -
<%= t('.delegations.title').html_safe %>
<%= t('.delegations.editor') %><%= t('.delegations.status') %><%= t('.delegations.actions') %>
<%= delegation.editor.name %> +

<%= t('.delegations.status_active') %>

+
+ <%= button_to t('.delegations.revoke'), authorization_request_delegation_path(@authorization_request, delegation), method: :delete, class: 'fr-btn fr-btn--secondary' %> +
<%= delegation.editor.name %> -

<%= t('.delegations.status_active') %>

-
- <%= button_to t('.delegations.revoke'), authorization_request_delegation_path(@authorization_request, delegation), method: :delete, class: 'fr-btn fr-btn--secondary' %> -
-
+ <% end %> + +
- <% end %> +
+ <% end %> - <% if @available_editors.any? %> - <%= form_with url: authorization_request_delegations_path(@authorization_request), method: :post, class: 'fr-mt-2w' do |f| %> -
- <%= f.label :editor_id, t('.delegations.add_label'), class: 'fr-label' %> - <%= f.select :editor_id, @available_editors.map { |e| [e.name, e.id] }, { prompt: t('.delegations.select_prompt') }, class: 'fr-select' %> -
- <%= f.submit t('.delegations.add_submit'), class: 'fr-btn fr-mt-1w' %> - <% end %> + <% if @available_editors.any? %> + <%= form_with url: authorization_request_delegations_path(@authorization_request), method: :post, class: 'fr-mt-2w' do |f| %> +
+ <%= f.label :editor_id, t('.delegations.add_label'), class: 'fr-label' %> + <%= f.select :editor_id, @available_editors.map { |e| [e.name, e.id] }, { prompt: t('.delegations.select_prompt') }, class: 'fr-select' %> +
+ <%= f.submit t('.delegations.add_submit'), class: 'fr-btn fr-mt-1w' %> <% end %> - - <% end %> - -
+ <% end %> + + <% end %>
diff --git a/site/config/locales/fr.yml b/site/config/locales/fr.yml index c0cde42e32..99c5e1289c 100644 --- a/site/config/locales/fr.yml +++ b/site/config/locales/fr.yml @@ -437,37 +437,28 @@ fr: header: delivered_at: "Délivré le : %{humanized_date}" show: - access: "Vos droits d'accès :" - modal: - renew: - display_cta: Demander l'accès à d'autres API - show: - display_cta: "Voir le jeton" - ask_for_prolongation: - display_cta: Relancer le demandeur pour prolonger le jeton - main_token: - title: "Jeton principal :" - attestations: - title: "Télécharger manuellement les attestations sociales et fiscales" - description: "Saisissez manuellement le SIREN de l'unité légale recherchée et vous aurez directement accès aux PDF des attestations :" - cta: "Utiliser l'interface de téléchargement" - other_tokens: - title: Voir les autres jetons + datapass_cta: "Voir sur DataPass n°%{external_id}" + tokens: + title: "Jetons" table: - identifier: "Identifiant du jeton" + identifier: "Identifiant" status: "Statut" created_at: "Date de délivrance" exp: "Date d'expiration" - see_more: "Voir plus" + actions: "Actions" + stats: "Statistiques" + transfer: "Transmettre" contacts: title: "Contacts associés :" + description: "Vous pouvez modifier ces contacts en amendant votre habilitation sur DataPass :" + datapass_link: "modifier sur DataPass" demandeur: - title: "Demandeur :" + title: "Demandeur :" contact_technique: - title: "Contact technique :" + title: "Contact technique :" contact_metier: - title: "Contact metier :" - its_me: "✋ C'est moi !" + title: "Contact métier :" + its_me: "c'est moi" delegations: title: "Délégations :" description: "Vous pouvez déléguer votre habilitation à un éditeur de logiciel. Celui-ci pourra alors interagir avec l'API au travers de votre demande en utilisant ses propres accès." diff --git a/site/spec/features/api_particulier/authorization_request_show_spec.rb b/site/spec/features/api_particulier/authorization_request_show_spec.rb index 808136e006..f9248a83bd 100644 --- a/site/spec/features/api_particulier/authorization_request_show_spec.rb +++ b/site/spec/features/api_particulier/authorization_request_show_spec.rb @@ -13,36 +13,10 @@ ) end - let!(:access_logs) do - [ - create(:access_log, token:, timestamp: 1.day.ago), - create(:access_log, token:, timestamp: 2.days.ago), - create(:access_log, token:, timestamp: 3.days.ago), - create(:access_log, token:, timestamp: 4.days.ago), - create(:access_log, token:, timestamp: 8.days.ago) - ] - end - let!(:token) do - create(:token, authorization_request:, exp:, blacklisted_at:, scopes:) - end - - let!(:other_tokens) do - [ - create(:token, authorization_request:, exp: 1.day.ago, blacklisted_at: 1.day.from_now, scopes:), - create(:token, authorization_request:, exp: 1.day.from_now, blacklisted_at: 1.day.ago, scopes:), - create(:token, authorization_request:, exp: 1.day.ago, blacklisted_at: 1.day.ago, scopes:), - create(:token, authorization_request:, exp: 2.days.from_now, blacklisted_at: 1.day.ago, scopes:) - ] + create(:token, authorization_request:, exp: 1.day.from_now.to_i) end - let!(:scopes) { [] } - - let!(:banned_token) { create(:token, authorization_request:, exp:, blacklisted_at: 1.day.ago) } - - let(:exp) { 1.day.from_now.to_i } - let(:blacklisted_at) { nil } - describe 'when user is not authenticated' do it 'redirects to the login' do go_to_authorization_request @@ -57,13 +31,13 @@ end describe 'when authorization_request does not belong to current_user' do - it 'redirects to the profile' do + it 'redirects to the index' do expect(page).to have_current_path(api_particulier_authorization_requests_path, ignore_query: true) end end describe 'when authorization_request belongs to current_user' do - describe 'when it not viewable by users' do + describe 'when it is not viewable by users' do let!(:authorization_request) do create( :authorization_request, @@ -74,126 +48,52 @@ ) end - it 'redirects to the profile' do + it 'redirects to the index' do expect(page).to have_current_path(api_particulier_authorization_requests_path, ignore_query: true) end end - describe 'when authorization_request is from api_entreprise' do + describe 'when authorization_request is from api_particulier' do let!(:authorization_request) do create( :authorization_request, :with_demandeur, demandeur: authenticated_user, - api: 'entreprise', + api: 'particulier', status: 'validated' ) end - it 'redirects to the profile' do - expect(page).to have_current_path(api_particulier_authorization_requests_path, ignore_query: true) + it 'displays basic information' do + expect(page).to have_current_path(api_particulier_authorization_request_path(id: authorization_request.id), ignore_query: true) + expect(page).to have_text('Habilitation active') + expect(page).to have_text(friendly_format_from_timestamp(authorization_request.created_at)) end - end - describe 'when authorization_request is from api_particulier' do - let!(:authorization_request) do - create( - :authorization_request, - :with_demandeur, - demandeur: authenticated_user, - api: 'particulier', - status:, - scopes: - ) + it 'displays a link to DataPass' do + expect(page).to have_link(href: datapass_authorization_request_url(authorization_request)) end - describe 'when the authorization request is not viewable by user' do - let(:status) { 'draft' } + describe 'tokens table' do + let!(:other_token) { create(:token, authorization_request:, exp: 2.days.from_now.to_i, intitule: authorization_request.intitule) } + + it 'displays all tokens' do + visit api_particulier_authorization_request_path(id: authorization_request.id) - it 'redirects to the profile' do - expect(page).to have_current_path(api_particulier_authorization_requests_path, ignore_query: true) + expect(page).to have_css('#' << dom_id(token)) + expect(page).to have_css('#' << dom_id(other_token)) end end - describe 'when the authorization request is validated' do - let(:status) { 'validated' } - - it 'diplays basic information on the page' do - expect(page).to have_current_path(api_particulier_authorization_request_path(id: authorization_request.id), ignore_query: true) - expect(page).to have_text('Habilitation active') - expect(page).to have_link(href: datapass_authorization_request_url(authorization_request)) - expect(page).to have_text(friendly_format_from_timestamp(authorization_request.created_at)) - - expect(page).to have_text('Jeton principal :') - expect(page).to have_text('Actif') - expect(page).to have_text('4 appels les 7 derniers jours') - expect(page).to have_text(distance_of_time_in_words(Time.zone.now, token.exp)) - - expect(page).to have_css('#' << dom_id(token, :stats_link)) - - expect(page).to have_text('Banni') - expect(page).to have_text(distance_of_time_in_words(Time.zone.now, banned_token.blacklisted_at)) + describe 'contacts section' do + it 'displays the demandeur' do + expect(page).to have_text(authorization_request.demandeur.full_name) + expect(page).to have_text(authorization_request.demandeur.email) end - describe 'when the user is demandeur' do - describe 'when the token has less than 90 days left' do - it 'displays the button to prolong the token' do - expect(page).to have_css('#prolong-token-modal-link') - - click_link 'prolong-token-modal-link' - - expect(page).to have_text('Prolonger le jeton') - end - end - - describe 'when the token has more than 90 days left' do - let(:exp) { 93.days.from_now.to_i } - - it 'does not display the button to prolong the token' do - expect(page).to have_no_css('#prolong-token-modal-link') - end - end - - it 'displays the show token modal button' do - expect(page).to have_css('#' << dom_id(token, :show)) - - click_link dom_id(token, :show) - - expect(page).to have_text('Utiliser le jeton') - expect(page).to have_text("Jeton d'accès") - end - - it 'does not displays the ask for prolongation modal button' do - expect(page).to have_no_css('#ask-for-prolongation-token-modal-link') - end - - describe 'when the token has no attestations scopes' do - it 'does not display the attestations block' do - expect(page).to have_no_css('#attestations_sociales_et_fiscales') - end - end - - describe 'when the token has attestations scopes' do - let!(:scopes) { %w[attestations_sociales attestations_fiscales] } - - it 'displays the attestations block' do - expect(page).to have_css('#attestations_sociales_et_fiscales') - expect(page).to have_css('#attestations_sociales_et_fiscales_link') - end - end - - it 'displays the contact informations' do - expect(page).to have_css('#contact_demandeur') - expect(page).to have_css('#contact_demandeur_its_me') - expect(page).to have_no_css('#contact_metier') - expect(page).to have_no_css('#contact_technique') - end - - it 'displays the summary' do - expect(page).to have_css('#summary') - expect(page).to have_css('#habilitation_main_token_infos_link') - expect(page).to have_css('#habilitation_contacts_infos_link') - expect(page).to have_no_css('#attestations_sociales_et_fiscales_link') + describe 'when the user is the demandeur' do + it 'shows the "its me" indicator' do + expect(page).to have_text('c\'est moi') end end @@ -206,131 +106,12 @@ demandeur: non_authenticated_user, contact_technique: authenticated_user, api: 'particulier', - status:, - scopes: - ) - end - - it 'displays the page' do - expect(page).to have_current_path(api_particulier_authorization_request_path(id: authorization_request.id), ignore_query: true) - end - - it 'does not display the button to prolong the token' do - expect(page).to have_no_css('#prolong-token-modal-link') - end - - it 'displays the show modal button' do - expect(page).to have_css('#' << dom_id(token, :show)) - - click_link dom_id(token, :show) - - expect(page).to have_text('Utiliser le jeton') - expect(page).to have_text("Jeton d'accès") - end - - it 'displays the ask for prolongation modal button' do - expect(page).to have_css('#ask-for-prolongation-token-modal-link') - - click_link 'ask-for-prolongation-token-modal-link' - - expect(page).to have_text('Relancer le demandeur') - end - - describe 'when the token has no attestations scopes' do - it 'does not display the attestations block' do - expect(page).to have_no_css('#attestations_sociales_et_fiscales') - end - end - - describe 'when the token has attestations scopes' do - let!(:scopes) { %w[attestations_sociales attestations_fiscales] } - - it 'does not display the attestations block' do - expect(page).to have_no_css('#attestations_sociales_et_fiscales') - end - end - - it 'displays the contact informations' do - expect(page).to have_css('#contact_demandeur') - expect(page).to have_no_css('#contact_demandeur_its_me') - expect(page).to have_no_css('#contact_metier') - expect(page).to have_css('#contact_technique') - expect(page).to have_css('#contact_technique_its_me') - end - - it 'displays others tokens accordion' do - expect(page).to have_css('#other_tokens_accordion_button') - - other_tokens.each do |other_token| - expect(page).to have_css('#' << dom_id(other_token)) - end - - expect(page).to have_no_css('#' << dom_id(token)) - end - end - - describe 'when the user is contact metier' do - let!(:authorization_request) do - create( - :authorization_request, - :with_demandeur, - :with_contact_technique, - :with_contact_metier, - demandeur: non_authenticated_user, - contact_metier: authenticated_user, - contact_technique: non_authenticated_user, - api: 'particulier', - status:, - scopes: + status: 'validated' ) end - it 'displays the page' do - expect(page).to have_current_path(api_particulier_authorization_request_path(id: authorization_request.id), ignore_query: true) - end - - it 'does not display the button to prolong the token' do - expect(page).to have_no_css('#prolong-token-modal-link') - end - - it 'displays the show modal button' do - expect(page).to have_css('#' << dom_id(token, :show)) - - click_link dom_id(token, :show) - - expect(page).to have_text('Utiliser le jeton') - expect(page).to have_text('demandeur') - end - - it 'displays the ask for prolongation modal button' do - expect(page).to have_css('#ask-for-prolongation-token-modal-link') - - click_link 'ask-for-prolongation-token-modal-link' - - expect(page).to have_text('Relancer le demandeur') - end - - describe 'when the token has no attestations scopes' do - it 'does not display the attestations block' do - expect(page).to have_no_css('#attestations_sociales_et_fiscales') - end - end - - describe 'when the token has attestations scopes' do - let!(:scopes) { %w[attestations_sociales attestations_fiscales] } - - it 'displays the attestations block' do - expect(page).to have_css('#attestations_sociales_et_fiscales') - end - end - - it 'displays the contact informations' do - expect(page).to have_css('#contact_demandeur') - expect(page).to have_no_css('#contact_demandeur_its_me') - expect(page).to have_css('#contact_metier') - expect(page).to have_css('#contact_metier_its_me') - expect(page).to have_css('#contact_technique') - expect(page).to have_no_css('#contact_technique_its_me') + it 'displays contact technique info' do + expect(page).to have_text(authenticated_user.full_name) end end end diff --git a/site/spec/support/shared_examples/features/create_token_magic_link.rb b/site/spec/support/shared_examples/features/create_token_magic_link.rb index a2b36149e6..93464b6541 100644 --- a/site/spec/support/shared_examples/features/create_token_magic_link.rb +++ b/site/spec/support/shared_examples/features/create_token_magic_link.rb @@ -45,10 +45,8 @@ let(:email) { 'valid@email.com' } describe 'with javascript actived', :js do - it 'from authorization_request page, displays modal on click' do - visit send(authorization_request_path_helper, authorization_request) - click_link dom_id(token, :show) - click_link dom_id(token, :transfer_modal_button) + it 'from transfer page, displays transfer form' do + visit send(token_transfer_path_helper, token) expect(page).to have_button(I18n.t('shared.transfer_tokens.new.modal.transfer.cta')) end end From dcb17a014daab24006762df58a4983ee1618f7f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Wed, 20 May 2026 13:46:54 +0200 Subject: [PATCH 03/14] Exclude refused authorization requests from user-facing views The viewable_by_users scope now filters out refused requests. These are not actionable by users and add noise to the list. Users can still see refused requests on DataPass directly. --- site/app/models/authorization_request.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/app/models/authorization_request.rb b/site/app/models/authorization_request.rb index 85feb543f2..2e10f3aaac 100644 --- a/site/app/models/authorization_request.rb +++ b/site/app/models/authorization_request.rb @@ -65,7 +65,7 @@ def self.ransackable_associations(_) scope :archived, -> { where(status: 'archived') } scope :eligible_for_token_creation, -> { where.not(validated_at: nil).where.not(status: %w[archived revoked]) } scope :for_api, ->(api) { where(api:) } - scope :viewable_by_users, -> { where('status in (?) or validated_at is not null', %w[archived revoked validated]) } + scope :viewable_by_users, -> { where('(status in (?) or validated_at is not null) and status != ?', %w[archived revoked validated], 'refused') } def token active_token || most_recent_token From 18d1e0d81a820fb568ebc7179d666ab5a65fdd1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Wed, 20 May 2026 13:47:10 +0200 Subject: [PATCH 04/14] Add seed habilitation where user@yopmail.com is only contact_technique Create a "Mairie de Nantes" authorization request (external_id 107) where contact_technique@yopmail.com is the demandeur and user@yopmail.com is only contact_technique. This allows testing the UI from a non-demandeur perspective. Also extract user creation into a dedicated create_users method to keep perform under the method length limit. --- site/app/lib/seeds.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/site/app/lib/seeds.rb b/site/app/lib/seeds.rb index b6f945a83a..3c42582544 100644 --- a/site/app/lib/seeds.rb +++ b/site/app/lib/seeds.rb @@ -52,6 +52,7 @@ def create_data_for_api_entreprise create_api_entreprise_token_blacklisted create_api_entreprise_token_expired create_api_entreprise_authorization_refused + create_api_entreprise_contact_technique_only end def create_data_for_api_particulier @@ -265,6 +266,22 @@ def create_api_entreprise_authorization_refused ) end + def create_api_entreprise_contact_technique_only + create_token( + @scopes_entreprise.sample(3), + 'entreprise', + demandeur: @contact, + contact_technique: @user, + authorization_request_params: { + intitule: 'Mairie de Nantes', + external_id: 107, + status: :validated, + validated_at: 1.month.ago, + first_submitted_at: 1.month.ago + } + ) + end + def create_api_particulier_token_valid create_token( @scopes_particulier, From 6735e9d005fe283222c7e1d393ae5c4ddd85fe61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 14:09:35 +0200 Subject: [PATCH 05/14] Add fr-table--stretch DSFR modifier for full-width tables DSFR renders the inner as display:block, so it only spans the width of its content instead of filling its container. This modifier forces display:table at 100% width, keeps horizontal scroll on the wrapper for small screens, and restores cell overflow so content such as button labels is not clipped. --- site/app/assets/stylesheets/dsfr-extensions.scss | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/site/app/assets/stylesheets/dsfr-extensions.scss b/site/app/assets/stylesheets/dsfr-extensions.scss index 87bbea4388..decb575752 100644 --- a/site/app/assets/stylesheets/dsfr-extensions.scss +++ b/site/app/assets/stylesheets/dsfr-extensions.scss @@ -97,6 +97,21 @@ } } +.fr-table--stretch { + .fr-table__content { + overflow-x: auto; + } + + table { + display: table; + width: 100%; + } + + td, th { + overflow: visible; + } +} + .fr-table--large { width: 1200px !important; } From 7263c9282454bc75e97014da1739bcccfd8148a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 14:09:46 +0200 Subject: [PATCH 06/14] Make habilitation tables full-width with clear token actions Apply fr-table--stretch to the tokens and delegations tables on the authorization request show page so they span 100% as expected. Fix the unclear token actions: - the reveal button pointed at a missing i18n key (shared.authorization_requests.show.modal.show.display_cta), dropped during the show page redesign, so it rendered the humanized "Display cta"; add shared.tokens.reveal_token_button.cta and use it from the shared partial. - the transfer button used fr-icon-share-line, which does not exist in this DSFR version and rendered as a solid blue square; switch to fr-icon-send-plane-line. - DSFR collapses icon buttons to 2rem (icon-only) inside a fr-btns-group--sm unless the group declares fr-btns-group--icon-*; add fr-btns-group--icon-left so the labels stay visible. Move the partial's fr-mt-2w spacing to the _detail_short caller so it no longer misaligns the button when reused inside a table row. --- .../views/shared/authorization_requests/show.html.erb | 10 +++++----- site/app/views/shared/tokens/_detail_short.html.erb | 2 +- .../views/shared/tokens/_reveal_token_button.html.erb | 4 ++-- site/config/locales/fr.yml | 2 ++ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/site/app/views/shared/authorization_requests/show.html.erb b/site/app/views/shared/authorization_requests/show.html.erb index c7ae5439bc..2c58598b13 100644 --- a/site/app/views/shared/authorization_requests/show.html.erb +++ b/site/app/views/shared/authorization_requests/show.html.erb @@ -20,7 +20,7 @@ <% if @tokens.any? %>

<%= t('.tokens.title') %>

-
+
@@ -44,14 +44,14 @@
<%= friendly_date_from_timestamp(token.exp) %> <% if token.active? %> -
    +
    • - <%= render partial: 'shared/tokens/reveal_token_button', locals: { token: token } %> + <%= render partial: 'shared/tokens/reveal_token_button', locals: { token: token, extra_classes: 'fr-btn--sm' } %>
    • <%= link_to t('.tokens.table.transfer'), token_transfer_path(id: token.id), - class: 'fr-btn fr-btn--sm fr-btn--tertiary fr-icon-share-line fr-btn--icon-left' %> + class: 'fr-btn fr-btn--sm fr-btn--tertiary fr-icon-send-plane-line fr-btn--icon-left' %>
    • <%= link_to t('.tokens.table.stats'), @@ -103,7 +103,7 @@

      <%= t('.delegations.description') %>

      <% if @active_delegations.any? %> -
      +
      diff --git a/site/app/views/shared/tokens/_detail_short.html.erb b/site/app/views/shared/tokens/_detail_short.html.erb index 5de08d9ca8..a34cfbcd85 100644 --- a/site/app/views/shared/tokens/_detail_short.html.erb +++ b/site/app/views/shared/tokens/_detail_short.html.erb @@ -14,6 +14,6 @@ ).html_safe %> <% unless local_assigns[:hide_reveal_token] %> - <%= render partial: "shared/tokens/reveal_token_button", locals: { token: token } %> + <%= render partial: "shared/tokens/reveal_token_button", locals: { token: token, extra_classes: 'fr-mt-2w' } %> <% end %> <% end %> diff --git a/site/app/views/shared/tokens/_reveal_token_button.html.erb b/site/app/views/shared/tokens/_reveal_token_button.html.erb index bc02dd833a..f37497c5bc 100644 --- a/site/app/views/shared/tokens/_reveal_token_button.html.erb +++ b/site/app/views/shared/tokens/_reveal_token_button.html.erb @@ -1,10 +1,10 @@ - <%= t('shared.authorization_requests.show.modal.show.display_cta') %> + <%= t('shared.tokens.reveal_token_button.cta') %> diff --git a/site/config/locales/fr.yml b/site/config/locales/fr.yml index 99c5e1289c..ebdb6d9745 100644 --- a/site/config/locales/fr.yml +++ b/site/config/locales/fr.yml @@ -267,6 +267,8 @@ fr: title: Jeton(s) non trouvés description: Le jeton ou les jetons demandé(s) n'ont pas été trouvés. Veuillez contacter le support. tokens: + reveal_token_button: + cta: Afficher le jeton renew: title: Demander l'accès à d'autres API description: |+ From 78e1ce8554918cc36612bf274d4e1f3c10838fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 14:31:58 +0200 Subject: [PATCH 07/14] Rework authorization request header: show form used below the title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display the DataPass form (démarche) as a "Formulaire utilisé : " line below the title instead of a badge above it, where it read as a disconnected tag. Drop the attachment icon and the redundant wrapper divs, and simplify the "delivered at" line so the header markup is flatter and easier to follow. --- .../authorization_requests/_header.html.erb | 41 ++++++++----------- site/config/locales/fr.yml | 1 + 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/site/app/views/shared/authorization_requests/_header.html.erb b/site/app/views/shared/authorization_requests/_header.html.erb index ced492714b..69ee0209a1 100644 --- a/site/app/views/shared/authorization_requests/_header.html.erb +++ b/site/app/views/shared/authorization_requests/_header.html.erb @@ -1,27 +1,20 @@ -
      - <%= authorization_request_status_badge(authorization_request) %> - <% if authorization_request.demarche.present? %> - - - <%= authorization_request.demarche %> - - <% end %> -

      <%= authorization_request.intitule %>

      -
      -
      - - <%= t('.delivered_at', humanized_date: friendly_format_from_timestamp(authorization_request.created_at)) %> - - - <% if to_datapass %> - <%= link_to safe_join([t('shared.links.to_datapass_html', external_id: authorization_request.external_id), content_tag(:span, '(nouvelle fenêtre)', class: 'fr-sr-only')]), +<%= authorization_request_status_badge(authorization_request) %> +

      <%= authorization_request.intitule %>

      + +<% if authorization_request.demarche.present? %> +

      <%= t('.form_used', name: authorization_request.demarche) %>

      +<% end %> + +

      + <%= t('.delivered_at', humanized_date: friendly_format_from_timestamp(authorization_request.created_at)) %> + - + <% if to_datapass %> + <%= link_to t('shared.links.to_datapass', external_id: authorization_request.external_id).html_safe, datapass_authorization_request_url(authorization_request), id: :authorization_request_link, class: %w(fr-link fr-text--xs), - target: '_blank', - rel: 'noopener noreferrer' - %> - <% else %> - <%= t('shared.links.to_datapass_html', external_id: authorization_request.external_id) %> - <% end %> - -

      + target: '_blank' %> + <% else %> + <%= t('shared.links.to_datapass', external_id: authorization_request.external_id).html_safe %> + <% end %> +

      diff --git a/site/config/locales/fr.yml b/site/config/locales/fr.yml index ebdb6d9745..78c68ecc42 100644 --- a/site/config/locales/fr.yml +++ b/site/config/locales/fr.yml @@ -438,6 +438,7 @@ fr: submitted: 🕐 Habilitation en cours d'instruction header: delivered_at: "Délivré le : %{humanized_date}" + form_used: "Formulaire utilisé : %{name}" show: datapass_cta: "Voir sur DataPass n°%{external_id}" tokens: From f0ba1b2edef66d615dd5d32ad034baaed5e5d18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 14:31:59 +0200 Subject: [PATCH 08/14] Rename "habilitation" to "demande" in the user account section In the account area the listed items are authorization requests (demandes), not granted habilitations; labelling them "Habilitation" was confusing. Rename the user-facing wording to "demande" across the index title, breadcrumb, status badges, table head and the contacts, delegations, token prolongation and account transfer texts. Left untouched on purpose: the public catalog "demande d'habilitation" wording (the act of requesting an habilitation), the provider dashboard which deliberately distinguishes "demandes et habilitations", and the editor section where delegated habilitations are correctly named. --- site/config/locales/fr.yml | 68 +++++++++---------- .../authorization_request_index_spec.rb | 8 +-- .../authorization_request_show_spec.rb | 2 +- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/site/config/locales/fr.yml b/site/config/locales/fr.yml index 78c68ecc42..94d8f8cbb0 100644 --- a/site/config/locales/fr.yml +++ b/site/config/locales/fr.yml @@ -162,10 +162,10 @@ fr: prolong_token_wizard: display_cta: Prolonger le jeton requires_update_cta: Terminer la mise à jour pour prolonger votre jeton - updates_requested_cta: Demande de mise à jour de l'habilitation en attente d'instruction + updates_requested_cta: Demande de mise à jour en attente d'instruction header: title: Prolonger le jeton - description: Votre jeton expire le %{humanize_date}. Avant de prolonger votre jeton, nous avons besoin de savoir si les conditions indiquées dans votre habilitation %{link_to_datapass} ont évolué. + description: Votre jeton expire le %{humanize_date}. Avant de prolonger votre jeton, nous avons besoin de savoir si les conditions indiquées dans votre demande %{link_to_datapass} ont évolué. Veuillez répondre aux questions suivantes, ce formulaire vous engage en regard des CGU d'%{api_name} steps: owner: Responsable de la demande @@ -174,15 +174,15 @@ fr: summary: Bilan et confirmation prolonged: title: Votre jeton a été prolongé jusqu'au %{humanized_date} - description: Merci ! Suite à vos réponses, les conditions de votre habilitation à l'%{api_name} n'ayant pas évolué, votre jeton a été prolongé de 18 mois. + description: Merci ! Suite à vos réponses, les conditions de votre demande à l'%{api_name} n'ayant pas évolué, votre jeton a été prolongé de 18 mois. link: - authorization_request: Revenir à votre demande d'habilitation + authorization_request: Revenir à votre demande summary: prolonged: owner_not_in_charge: "Suite aux réponses indiquées, vous déclarez que le contact principal a changé. Bien que cela ne soit pas bloquant pour - poursuivre la prolongation de votre jeton, l'équipe support vous contactera rapidement afin de procéder au transfert de vos habilitations. Vous pouvez démarrer cette démarche en autonomie + poursuivre la prolongation de votre jeton, l'équipe support vous contactera rapidement afin de procéder au transfert de vos demandes. Vous pouvez démarrer cette démarche en autonomie via votre espace personnel." - description: Suite aux réponses indiquées, vous déclarez qu'aucune des informations indiquées dans votre habilitation no%{external_id} n'a évolué. + description: Suite aux réponses indiquées, vous déclarez qu'aucune des informations indiquées dans votre demande no%{external_id} n'a évolué. cgu: ⚠️ Vos réponses vous engagent en regard des CGU finished: Confirmer requires_update: @@ -213,19 +213,19 @@ fr: change_contact_technique: A changé change_contact_metier: A changé project_purpose: - label: "Cette habilitation a été attribuée pour la finalité suivante :" - no_description: Vous n'avez pas renseigné de description pour cette habilitation. + label: "Cette demande a été attribuée pour la finalité suivante :" + no_description: Vous n'avez pas renseigné de description pour cette demande. radio: - project_purpose: Oui, le projet bénéficiant de cette habilitation a toujours la même finalité. + project_purpose: Oui, le projet bénéficiant de cette demande a toujours la même finalité. change_project_purpose: Non, le projet a changé. owner: label: Êtes-vous toujours en charge de la demande %{link_to_datapass} ? radio: still_in_charge: Oui, je suis toujours en charge will_change_soon: Oui, je suis toujours en charge mais pourrais passer la main d'ici quelques mois - not_in_charge: Non, je ne suis plus en charge de cette habilitation %{api} + not_in_charge: Non, je ne suis plus en charge de cette demande %{api} not_in_charge_alert: - text: Si vous n'êtes plus en charge de cette habilitation, vous devez la transférer à une autre personne de votre organisation depuis le site de DataPass.

      Cette démarche prend 2 minutes. La nouvelle personne en charge devra alors effectuer la prolongation du jeton. + text: Si vous n'êtes plus en charge de cette demande, vous devez la transférer à une autre personne de votre organisation depuis le site de DataPass.

      Cette démarche prend 2 minutes. La nouvelle personne en charge devra alors effectuer la prolongation du jeton. build: wizard_buttons: previous: Précédent @@ -233,15 +233,15 @@ fr: users: user: links: - authorization_requests: Vos habilitations + authorization_requests: Vos demandes title: "Vos informations" internal_id: "Identifiant interne : %{id}" transfer_account: - title: "Votre équipe évolue ? Vous quittez votre service ? Transmettez vos habilitations à une autre personne :" - subtitle_if_demandeur: "Habilitations où je suis demandeur :" - description_if_demandeur: Pour transmettre votre rôle de demandeur à une autre personne de votre organisation, veuillez vous rendre sur DataPass et transférer chacune de vos habilitations. - subtitle_if_other_roles: "Habilitations où je ne suis pas demandeur :" - description_if_other_roles: "Vous êtes contact métier et/ou technique d'une habilitation et souhaitez léguer ce rôle à une autre personne de votre organisation ? C'est au demandeur de l'habilitation d'effectuer une demande de modification des contacts. En savoir plus." + title: "Votre équipe évolue ? Vous quittez votre service ? Transmettez vos demandes à une autre personne :" + subtitle_if_demandeur: "Demandes où je suis demandeur :" + description_if_demandeur: Pour transmettre votre rôle de demandeur à une autre personne de votre organisation, veuillez vous rendre sur DataPass et transférer chacune de vos demandes. + subtitle_if_other_roles: "Demandes où je ne suis pas demandeur :" + description_if_other_roles: "Vous êtes contact métier et/ou technique d'une demande et souhaitez léguer ce rôle à une autre personne de votre organisation ? C'est au demandeur de la demande d'effectuer une demande de modification des contacts. En savoir plus." demandeur: "Demandeur" contact_metier: "Contact métier" contact_technique: "Contact technique" @@ -272,7 +272,7 @@ fr: renew: title: Demander l'accès à d'autres API description: |+ - Vous souhaitez demander de nouvelles API pour le même cas d'usage ? Cette fonctionnalité vous permet de demander une mise à jour de votre habilitation, dans laquelle vous pourrez cocher de nouvelles API. + Vous souhaitez demander de nouvelles API pour le même cas d'usage ? Cette fonctionnalité vous permet de demander une mise à jour de votre demande, dans laquelle vous pourrez cocher de nouvelles API.
      En cliquant sur "Continuer" vous serez transféré sur le site DataPass.
      @@ -285,7 +285,7 @@ fr: last_30_hours: 30 dernières heures last_8_days: 8 derniers jours links: - user_tokens: Retour à l'habilitation No%{external_id} + user_tokens: Retour à la demande No%{external_id} details: internal_id: "Identifiant technique du jeton : %{id}" requests_details: @@ -293,10 +293,10 @@ fr: cannot_show: title: Utiliser le jeton description: "En tant que contact métier, vous n'avez pas l'autorisation d'utiliser la clé d'accès. - Si le jeton arrive à expiration ou nécessite une action, veuillez contacter le demandeur et le contact technique de cette habilitation :" + Si le jeton arrive à expiration ou nécessite une action, veuillez contacter le demandeur et le contact technique de cette demande :" demandeur: "demandeur : %{demandeur}" contact_technique: "Contact technique : %{contact_technique}" - authorization_request_link: "Lien de l'habilitation à transmettre :" + authorization_request_link: "Lien de la demande à transmettre :" ask_for_prolongation: title: Relancer le demandeur description: "Malgré nos nombreuses relances, %{demandeur} n'a pas prolongé le jeton ID : %{token_id}, @@ -333,11 +333,11 @@ fr: description: future: "Votre jeton expire dans %{remaining_time}. Avant de prolonger votre jeton, nous avons besoin de savoir si les conditions - indiquées dans votre habilitation %{link_to_datapass} + indiquées dans votre demande %{link_to_datapass} ont évolué." past: "Votre jeton a expiré il y a %{remaining_time}. Avant de prolonger votre jeton, nous avons besoin de savoir si les conditions - indiquées dans votre habilitation %{link_to_datapass} + indiquées dans votre demande %{link_to_datapass} ont évolué." warning_description: "Pour prolonger votre jeton, veuillez compléter le formulaire suivant :" warning: ⚠️ Vos réponses au formulaire vous engagent en regard des CGU d'%{api_name}. @@ -400,8 +400,8 @@ fr: display_cta_replace_legacy: "Remplacer votre ancien jeton avec le nouveau jeton" display_cta_new_token: "Utiliser le nouveau jeton" display_cta_replace: "Remplacer le jeton banni par le nouveau jeton" - no_authorization_requests: "Vous n'avez aucune habilitation" - title: "Habilitations %{api_label} (%{count})" + no_authorization_requests: "Vous n'avez aucune demande" + title: "Demandes %{api_label} (%{count})" entreprise: API Entreprise particulier: API Particulier no_action: Aucune action attendue @@ -410,13 +410,13 @@ fr: profile: Vos informations table: head: - authorization_request: "Habilitation" + authorization_request: "Demande" token: Jeton principal actions: Actions attendues detail: Page détaillée breadcrumb: - index: Habilitations - current_page: Habilitation n°%{datapass_id} + index: Demandes + current_page: Demande n°%{datapass_id} summary: access: Droits d'accès active_tokens: Jetons @@ -432,10 +432,10 @@ fr: submitted: yellow-canari label: refused: 📃 Demande refusée - revoked: 📃 Habilitation révoquée - archived: 📃 Habilitation archivée - validated: 📃 Habilitation active - submitted: 🕐 Habilitation en cours d'instruction + revoked: 📃 Demande révoquée + archived: 📃 Demande archivée + validated: 📃 Demande active + submitted: 🕐 Demande en cours d'instruction header: delivered_at: "Délivré le : %{humanized_date}" form_used: "Formulaire utilisé : %{name}" @@ -453,7 +453,7 @@ fr: transfer: "Transmettre" contacts: title: "Contacts associés :" - description: "Vous pouvez modifier ces contacts en amendant votre habilitation sur DataPass :" + description: "Vous pouvez modifier ces contacts en amendant votre demande sur DataPass :" datapass_link: "modifier sur DataPass" demandeur: title: "Demandeur :" @@ -464,7 +464,7 @@ fr: its_me: "c'est moi" delegations: title: "Délégations :" - description: "Vous pouvez déléguer votre habilitation à un éditeur de logiciel. Celui-ci pourra alors interagir avec l'API au travers de votre demande en utilisant ses propres accès." + description: "Vous pouvez déléguer votre demande à un éditeur de logiciel. Celui-ci pourra alors interagir avec l'API au travers de votre demande en utilisant ses propres accès." editor: Éditeur status: Statut actions: Actions diff --git a/site/spec/features/api_particulier/authorization_request_index_spec.rb b/site/spec/features/api_particulier/authorization_request_index_spec.rb index 30e395634a..6a83d6e783 100644 --- a/site/spec/features/api_particulier/authorization_request_index_spec.rb +++ b/site/spec/features/api_particulier/authorization_request_index_spec.rb @@ -21,7 +21,7 @@ it 'displays the empty state' do go_to_authorization_requests_index - expect(page).to have_text("Vous n'avez aucune habilitation") + expect(page).to have_text("Vous n'avez aucune demande") end end @@ -52,7 +52,7 @@ it 'displays all authorization requests as cards' do go_to_authorization_requests_index - expect(page).to have_text('Habilitations API Particulier (2)') + expect(page).to have_text('Demandes API Particulier (2)') expect(page).to have_css('#' << dom_id(authorization_request_active)) expect(page).to have_css('#' << dom_id(authorization_request_archived)) @@ -60,8 +60,8 @@ expect(page).to have_text('Mon habilitation active') expect(page).to have_text('Mon habilitation archivée') - expect(page).to have_text('Habilitation active') - expect(page).to have_text('Habilitation archivée') + expect(page).to have_text('Demande active') + expect(page).to have_text('Demande archivée') end it 'displays the user role on each card' do diff --git a/site/spec/features/api_particulier/authorization_request_show_spec.rb b/site/spec/features/api_particulier/authorization_request_show_spec.rb index f9248a83bd..aee5a47e0f 100644 --- a/site/spec/features/api_particulier/authorization_request_show_spec.rb +++ b/site/spec/features/api_particulier/authorization_request_show_spec.rb @@ -66,7 +66,7 @@ it 'displays basic information' do expect(page).to have_current_path(api_particulier_authorization_request_path(id: authorization_request.id), ignore_query: true) - expect(page).to have_text('Habilitation active') + expect(page).to have_text('Demande active') expect(page).to have_text(friendly_format_from_timestamp(authorization_request.created_at)) end From 77bea22cf09d61bbba4b93be1ee5b9215bd35e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 15:08:41 +0200 Subject: [PATCH 09/14] Restructure authorization request header meta as uniform lines Show each piece of metadata on its own line at the same size: the request number (previously inline after the delivery date), the form used, the delivery date, and the description (when present). Bold the labels via _html i18n keys so interpolated values stay HTML-escaped. Drop the dead to_datapass branch (never passed as true; the dedicated "Voir sur DataPass" CTA already links out) and its now-unused local. --- .../authorization_requests/_header.html.erb | 22 +++++++------------ .../authorization_requests/show.html.erb | 2 +- site/app/views/shared/tokens/_show.html.erb | 2 +- site/config/locales/fr.yml | 6 +++-- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/site/app/views/shared/authorization_requests/_header.html.erb b/site/app/views/shared/authorization_requests/_header.html.erb index 69ee0209a1..d91a15729a 100644 --- a/site/app/views/shared/authorization_requests/_header.html.erb +++ b/site/app/views/shared/authorization_requests/_header.html.erb @@ -1,20 +1,14 @@ <%= authorization_request_status_badge(authorization_request) %>

      <%= authorization_request.intitule %>

      +

      <%= t('.request_number_html', external_id: authorization_request.external_id) %>

      + <% if authorization_request.demarche.present? %> -

      <%= t('.form_used', name: authorization_request.demarche) %>

      +

      <%= t('.form_used_html', name: authorization_request.demarche) %>

      <% end %> -

      - <%= t('.delivered_at', humanized_date: friendly_format_from_timestamp(authorization_request.created_at)) %> - - - <% if to_datapass %> - <%= link_to t('shared.links.to_datapass', external_id: authorization_request.external_id).html_safe, - datapass_authorization_request_url(authorization_request), - id: :authorization_request_link, - class: %w(fr-link fr-text--xs), - target: '_blank' %> - <% else %> - <%= t('shared.links.to_datapass', external_id: authorization_request.external_id).html_safe %> - <% end %> -

      +

      <%= t('.delivered_at_html', humanized_date: friendly_format_from_timestamp(authorization_request.created_at)) %>

      + +<% if authorization_request.description.present? %> +

      <%= t('.description_html', description: authorization_request.description) %>

      +<% end %> diff --git a/site/app/views/shared/authorization_requests/show.html.erb b/site/app/views/shared/authorization_requests/show.html.erb index 2c58598b13..b5c12b1464 100644 --- a/site/app/views/shared/authorization_requests/show.html.erb +++ b/site/app/views/shared/authorization_requests/show.html.erb @@ -5,7 +5,7 @@
      - <%= render partial: 'shared/authorization_requests/header', locals: { authorization_request: @authorization_request, to_datapass: false } %> + <%= render partial: 'shared/authorization_requests/header', locals: { authorization_request: @authorization_request } %>
      <%= link_to datapass_authorization_request_url(@authorization_request), diff --git a/site/app/views/shared/tokens/_show.html.erb b/site/app/views/shared/tokens/_show.html.erb index f9370db029..282e0dd3c5 100644 --- a/site/app/views/shared/tokens/_show.html.erb +++ b/site/app/views/shared/tokens/_show.html.erb @@ -1,5 +1,5 @@
      - <%= render partial: 'shared/authorization_requests/header', locals: { authorization_request: token.authorization_request, to_datapass: false} %> + <%= render partial: 'shared/authorization_requests/header', locals: { authorization_request: token.authorization_request } %>

      "> diff --git a/site/config/locales/fr.yml b/site/config/locales/fr.yml index 94d8f8cbb0..60d43116a6 100644 --- a/site/config/locales/fr.yml +++ b/site/config/locales/fr.yml @@ -437,8 +437,10 @@ fr: validated: 📃 Demande active submitted: 🕐 Demande en cours d'instruction header: - delivered_at: "Délivré le : %{humanized_date}" - form_used: "Formulaire utilisé : %{name}" + request_number_html: "Demande n° : %{external_id}" + form_used_html: "Formulaire utilisé : %{name}" + delivered_at_html: "Délivré le : %{humanized_date}" + description_html: "Description : %{description}" show: datapass_cta: "Voir sur DataPass n°%{external_id}" tokens: From cd21708c5fa749211eef375c2cb6d24bdcf79e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 15:09:32 +0200 Subject: [PATCH 10/14] Seed realistic descriptions on authorization requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Populate the description (finalité) of the seeded demandes with realistic, varied wording inspired by production data, so the header's new description line is exercised in development. --- site/app/lib/seeds.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/site/app/lib/seeds.rb b/site/app/lib/seeds.rb index 3c42582544..8842acabf1 100644 --- a/site/app/lib/seeds.rb +++ b/site/app/lib/seeds.rb @@ -187,6 +187,7 @@ def create_api_entreprise_token_valid contact_technique: @contact, authorization_request_params: { intitule: 'Mairie de Lyon 2', + description: 'Récupération automatique des informations légales et financières des entreprises pour l\'instruction des demandes de subventions par les agents habilités.', external_id: 102, status: :validated, validated_at: 2.weeks.ago, @@ -223,6 +224,7 @@ def create_api_entreprise_token_blacklisted demandeur: @user, authorization_request_params: { intitule: 'Mairie de Paris', + description: 'Récupération automatique des pièces justificatives des entreprises candidates dans le cadre de la passation des marchés publics.', external_id: 104, status: :validated, validated_at: 1.week.ago, @@ -240,6 +242,7 @@ def create_api_entreprise_token_expired demandeur: @user, authorization_request_params: { intitule: 'Mairie de Montpellier', + description: 'Préremplissage des informations des entreprises et associations pour les démarches en ligne des usagers de la collectivité.', external_id: 105, status: :validated, api: 'entreprise', @@ -256,6 +259,7 @@ def create_api_entreprise_authorization_refused authorization_request: create_authorization_request( api: 'entreprise', intitule: 'Mairie de Bruges', + description: 'Accès aux données ouvertes permettant aux usagers de pré-remplir les informations liées à leur entreprise.', status: :refused, external_id: 106, first_submitted_at: 2.years.ago, @@ -274,6 +278,7 @@ def create_api_entreprise_contact_technique_only contact_technique: @user, authorization_request_params: { intitule: 'Mairie de Nantes', + description: 'Contrôle de la validité du SIRET et récupération des informations des entreprises candidates aux marchés publics.', external_id: 107, status: :validated, validated_at: 1.month.ago, @@ -291,6 +296,7 @@ def create_api_particulier_token_valid contact_technique: @contact, authorization_request_params: { intitule: 'Mairie de Bordeaux', + description: 'Gestion de la tarification des services périscolaires et de restauration scolaire sur la base du quotient familial par des agents habilités.', external_id: 201, status: :validated, validated_at: 2.weeks.ago, From 6ea76d0cd2ce333faa9c006442fb3a77e3228a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 15:09:32 +0200 Subject: [PATCH 11/14] =?UTF-8?q?Seed=20a=20contact=20m=C3=A9tier=20on=20t?= =?UTF-8?q?he=20main=20API=20Entreprise=20demande?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a dedicated contact_metier user (Camille Bernard) and attach it to "Mairie de Lyon 2", which previously had only a demandeur and a contact technique, so the contacts section shows the three roles. Document the new dev-login test email. --- site/CLAUDE.md | 2 +- site/app/lib/seeds.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/site/CLAUDE.md b/site/CLAUDE.md index b035a5745c..eaf6a183ea 100644 --- a/site/CLAUDE.md +++ b/site/CLAUDE.md @@ -79,7 +79,7 @@ organizer qui se termine par l'interactor `Admin::TrackActivity`. ## Local Login (dev only) Bypass ProConnect via: `/compte/dev-login?email=user@yopmail.com` -Available test emails: `user@yopmail.com`, `contact_technique@yopmail.com`, `editeur@yopmail.com`, `user10@yopmail.com` +Available test emails: `user@yopmail.com`, `contact_technique@yopmail.com`, `contact_metier@yopmail.com`, `editeur@yopmail.com`, `user10@yopmail.com` ## Sentry / Production Errors diff --git a/site/app/lib/seeds.rb b/site/app/lib/seeds.rb index 8842acabf1..a983eb4f9a 100644 --- a/site/app/lib/seeds.rb +++ b/site/app/lib/seeds.rb @@ -2,6 +2,7 @@ class Seeds def perform @user = create_main_user @contact = create_contact + @contact_metier = create_contact_metier create_editor create_provider_user @@ -81,6 +82,14 @@ def create_contact ) end + def create_contact_metier + create_user( + email: 'contact_metier@yopmail.com', + first_name: 'Camille', + last_name: 'Bernard' + ) + end + def create_editor @editor = Editor.create!( name: 'MGDIS', @@ -185,6 +194,7 @@ def create_api_entreprise_token_valid token_params: { id: '00000000-0000-0000-0000-000000000000' }, demandeur: @user, contact_technique: @contact, + contact_metier: @contact_metier, authorization_request_params: { intitule: 'Mairie de Lyon 2', description: 'Récupération automatique des informations légales et financières des entreprises pour l\'instruction des demandes de subventions par les agents habilités.', From 433f8260458ce9729528723243f37291f21ee230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 15:39:22 +0200 Subject: [PATCH 12/14] Display the demande description as a prominent lead above the meta Move the description right under the title, render it larger (fr-text--lead) and drop the "Description :" label, so the purpose of the demande reads at a glance. The remaining metadata lines stay small below it. Remove the now-unused description_html i18n key. --- .../shared/authorization_requests/_header.html.erb | 10 +++++----- site/config/locales/fr.yml | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/site/app/views/shared/authorization_requests/_header.html.erb b/site/app/views/shared/authorization_requests/_header.html.erb index d91a15729a..96fcc68a81 100644 --- a/site/app/views/shared/authorization_requests/_header.html.erb +++ b/site/app/views/shared/authorization_requests/_header.html.erb @@ -1,14 +1,14 @@ <%= authorization_request_status_badge(authorization_request) %>

      <%= authorization_request.intitule %>

      +<% if authorization_request.description.present? %> +

      <%= authorization_request.description %>

      +<% end %> +

      <%= t('.request_number_html', external_id: authorization_request.external_id) %>

      <% if authorization_request.demarche.present? %>

      <%= t('.form_used_html', name: authorization_request.demarche) %>

      <% end %> -

      <%= t('.delivered_at_html', humanized_date: friendly_format_from_timestamp(authorization_request.created_at)) %>

      - -<% if authorization_request.description.present? %> -

      <%= t('.description_html', description: authorization_request.description) %>

      -<% end %> +

      <%= t('.delivered_at_html', humanized_date: friendly_format_from_timestamp(authorization_request.created_at)) %>

      diff --git a/site/config/locales/fr.yml b/site/config/locales/fr.yml index 60d43116a6..ec5c81b458 100644 --- a/site/config/locales/fr.yml +++ b/site/config/locales/fr.yml @@ -440,7 +440,6 @@ fr: request_number_html: "Demande n° : %{external_id}" form_used_html: "Formulaire utilisé : %{name}" delivered_at_html: "Délivré le : %{humanized_date}" - description_html: "Description : %{description}" show: datapass_cta: "Voir sur DataPass n°%{external_id}" tokens: From 4d7084f0131c511613017bd673481fe73a4542d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 15:39:22 +0200 Subject: [PATCH 13/14] Open token transfer in a modal instead of a new page The transfer view is already a main-modal turbo-frame, but the "Transmettre" link navigated to it as a full page. Add the modal trigger attributes (aria-controls, data-turbo-frame, data-fr-opened) so it opens in place, consistent with the reveal token button. --- site/app/views/shared/authorization_requests/show.html.erb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/site/app/views/shared/authorization_requests/show.html.erb b/site/app/views/shared/authorization_requests/show.html.erb index b5c12b1464..85ff24427b 100644 --- a/site/app/views/shared/authorization_requests/show.html.erb +++ b/site/app/views/shared/authorization_requests/show.html.erb @@ -51,7 +51,9 @@
    • <%= link_to t('.tokens.table.transfer'), token_transfer_path(id: token.id), - class: 'fr-btn fr-btn--sm fr-btn--tertiary fr-icon-send-plane-line fr-btn--icon-left' %> + class: 'fr-btn fr-btn--sm fr-btn--tertiary fr-icon-send-plane-line fr-btn--icon-left', + aria: { controls: 'main-modal' }, + data: { fr_opened: false, turbo_frame: 'main-modal-content' } %>
    • <%= link_to t('.tokens.table.stats'), From f511c7c7a2cc82e482b8773e64539215a652f1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Delmaire=20Lo=C3=AFc?= Date: Thu, 18 Jun 2026 15:41:05 +0200 Subject: [PATCH 14/14] Drop the count from the demandes index title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Demandes API Entreprise (4)" — the count adds nothing next to the visible card grid. Remove it from the title and the now-unused count interpolation. --- site/app/views/shared/authorization_requests/index.html.erb | 2 +- site/config/locales/fr.yml | 2 +- .../api_particulier/authorization_request_index_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/site/app/views/shared/authorization_requests/index.html.erb b/site/app/views/shared/authorization_requests/index.html.erb index cc6f2b492f..bc747d48ba 100644 --- a/site/app/views/shared/authorization_requests/index.html.erb +++ b/site/app/views/shared/authorization_requests/index.html.erb @@ -8,7 +8,7 @@ <% if @authorization_requests.empty? %> <%= t('.no_authorization_requests') %> <% else %> - <%= t('.title', api_label: t(".#{@authorization_requests.first.api}"), count: @authorization_requests.count).html_safe %> + <%= t('.title', api_label: t(".#{@authorization_requests.first.api}")).html_safe %> <% end %>
    • diff --git a/site/config/locales/fr.yml b/site/config/locales/fr.yml index ec5c81b458..a181b73fa0 100644 --- a/site/config/locales/fr.yml +++ b/site/config/locales/fr.yml @@ -401,7 +401,7 @@ fr: display_cta_new_token: "Utiliser le nouveau jeton" display_cta_replace: "Remplacer le jeton banni par le nouveau jeton" no_authorization_requests: "Vous n'avez aucune demande" - title: "Demandes %{api_label} (%{count})" + title: "Demandes %{api_label}" entreprise: API Entreprise particulier: API Particulier no_action: Aucune action attendue diff --git a/site/spec/features/api_particulier/authorization_request_index_spec.rb b/site/spec/features/api_particulier/authorization_request_index_spec.rb index 6a83d6e783..bc8e025fd9 100644 --- a/site/spec/features/api_particulier/authorization_request_index_spec.rb +++ b/site/spec/features/api_particulier/authorization_request_index_spec.rb @@ -52,7 +52,7 @@ it 'displays all authorization requests as cards' do go_to_authorization_requests_index - expect(page).to have_text('Demandes API Particulier (2)') + expect(page).to have_text('Demandes API Particulier') expect(page).to have_css('#' << dom_id(authorization_request_active)) expect(page).to have_css('#' << dom_id(authorization_request_archived))