Merge branch 'main' into bug-input-pj-apres-suppression
This commit is contained in:
commit
ceedbe9c45
37 changed files with 221 additions and 368 deletions
|
@ -10,7 +10,7 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
|
|
||||||
EXTENSIONS_ORDER = ['jpeg', 'png', 'pdf', 'zip'].freeze
|
EXTENSIONS_ORDER = ['jpeg', 'png', 'pdf', 'zip'].freeze
|
||||||
|
|
||||||
def initialize(champ: nil, auto_attach_url: nil, attached_file:, direct_upload: true, index: 0, as_multiple: false, view_as: :link, user_can_destroy: true, user_can_replace: false, attachments: [], **kwargs)
|
def initialize(champ: nil, auto_attach_url: nil, attached_file:, direct_upload: true, index: 0, as_multiple: false, view_as: :link, user_can_destroy: true, user_can_replace: false, attachments: [], max: nil, **kwargs)
|
||||||
@champ = champ
|
@champ = champ
|
||||||
@attached_file = attached_file
|
@attached_file = attached_file
|
||||||
@direct_upload = direct_upload
|
@direct_upload = direct_upload
|
||||||
|
@ -24,6 +24,7 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
@attachments = attachments.presence || (kwargs.key?(:attachment) ? [kwargs.delete(:attachment)] : [])
|
@attachments = attachments.presence || (kwargs.key?(:attachment) ? [kwargs.delete(:attachment)] : [])
|
||||||
@attachments << attached_file.attachment if attached_file.respond_to?(:attachment) && @attachments.empty?
|
@attachments << attached_file.attachment if attached_file.respond_to?(:attachment) && @attachments.empty?
|
||||||
@attachments.compact!
|
@attachments.compact!
|
||||||
|
@max = max
|
||||||
|
|
||||||
# Utilisation du premier attachement comme référence pour la rétrocompatibilité
|
# Utilisation du premier attachement comme référence pour la rétrocompatibilité
|
||||||
@attachment = @attachments.first
|
@attachment = @attachments.first
|
||||||
|
@ -54,7 +55,7 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy_attachment_path
|
def destroy_attachment_path
|
||||||
attachment_path(champ_id: champ&.public_id)
|
attachment_path(dossier_id: champ&.dossier_id, stable_id: champ&.stable_id, row_id: champ&.row_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def attachment_input_class
|
def attachment_input_class
|
||||||
|
@ -63,6 +64,7 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
|
|
||||||
def file_field_options
|
def file_field_options
|
||||||
track_issue_with_missing_validators if missing_validators?
|
track_issue_with_missing_validators if missing_validators?
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
class: class_names("fr-upload attachment-input": true, "#{attachment_input_class}": true, "hidden": persisted?),
|
class: class_names("fr-upload attachment-input": true, "#{attachment_input_class}": true, "hidden": persisted?),
|
||||||
direct_upload: @direct_upload,
|
direct_upload: @direct_upload,
|
||||||
|
@ -76,6 +78,7 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
|
|
||||||
options.merge!(has_content_type_validator? ? { accept: accept_content_type } : {})
|
options.merge!(has_content_type_validator? ? { accept: accept_content_type } : {})
|
||||||
options[:multiple] = true if as_multiple?
|
options[:multiple] = true if as_multiple?
|
||||||
|
options[:disabled] = true if @max && @index >= @max
|
||||||
|
|
||||||
options
|
options
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,10 +30,6 @@ class Attachment::MultipleComponent < ApplicationComponent
|
||||||
@attachments.each_with_index(&block)
|
@attachments.each_with_index(&block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_attach_next?
|
|
||||||
@attachments.count < @max
|
|
||||||
end
|
|
||||||
|
|
||||||
def empty_component_id
|
def empty_component_id
|
||||||
champ.present? ? "attachment-multiple-empty-#{champ.public_id}" : "attachment-multiple-empty-generic"
|
champ.present? ? "attachment-multiple-empty-#{champ.public_id}" : "attachment-multiple-empty-generic"
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
%li{ id: dom_id(attachment) }
|
%li{ id: dom_id(attachment) }
|
||||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment:, index:, view_as:, user_can_destroy:, form_object_name:)
|
= render Attachment::EditComponent.new(champ:, attached_file:, attachment:, index:, view_as:, user_can_destroy:, form_object_name:)
|
||||||
|
|
||||||
%div{ id: empty_component_id, class: class_names("hidden": !can_attach_next?), data: { turbo_force: :server } }
|
%div{ id: empty_component_id, data: { turbo_force: :server } }
|
||||||
= render Attachment::EditComponent.new(champ:, as_multiple: champ.nil?, attached_file:, attachment: nil, index: attachments_count, user_can_destroy:, form_object_name:)
|
= render Attachment::EditComponent.new(champ:, as_multiple: champ.nil?, attached_file:, attachment: nil, index: attachments_count, user_can_destroy:, form_object_name:, max: @max)
|
||||||
|
|
||||||
// single poll and refresh message for all attachments
|
// single poll and refresh message for all attachments
|
||||||
= render Attachment::PendingPollComponent.new(attachments: attachments, poll_url:, context: poll_context)
|
= render Attachment::PendingPollComponent.new(attachments: attachments, poll_url:, context: poll_context)
|
||||||
|
|
|
@ -2,6 +2,17 @@
|
||||||
class Dsfr::AlertComponent < ApplicationComponent
|
class Dsfr::AlertComponent < ApplicationComponent
|
||||||
renders_one :body
|
renders_one :body
|
||||||
|
|
||||||
|
attr_reader :state, :title, :size, :block, :extra_class_names, :heading_level
|
||||||
|
|
||||||
|
def initialize(state:, title: '', size: '', extra_class_names: nil, heading_level: 'h3')
|
||||||
|
@state = state
|
||||||
|
@title = title
|
||||||
|
@size = size
|
||||||
|
@block = block
|
||||||
|
@extra_class_names = extra_class_names
|
||||||
|
@heading_level = heading_level
|
||||||
|
end
|
||||||
|
|
||||||
def prefix_for_state
|
def prefix_for_state
|
||||||
case state
|
case state
|
||||||
when :error then "Erreur : "
|
when :error then "Erreur : "
|
||||||
|
@ -19,19 +30,4 @@ class Dsfr::AlertComponent < ApplicationComponent
|
||||||
extra_class_names => true
|
extra_class_names => true
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def initialize(state:, title: '', size: '', extra_class_names: nil, heading_level: 'h3')
|
|
||||||
@state = state
|
|
||||||
@title = title
|
|
||||||
@size = size
|
|
||||||
@block = block
|
|
||||||
@extra_class_names = extra_class_names
|
|
||||||
@heading_level = heading_level
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :state, :title, :size, :block, :extra_class_names, :heading_level
|
|
||||||
|
|
||||||
private
|
|
||||||
end
|
end
|
||||||
|
|
21
app/components/procedure_draft_warning_component.rb
Normal file
21
app/components/procedure_draft_warning_component.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ProcedureDraftWarningComponent < ApplicationComponent
|
||||||
|
attr_reader :revision
|
||||||
|
attr_reader :current_administrateur
|
||||||
|
attr_reader :extra_class_names
|
||||||
|
|
||||||
|
def initialize(revision:, current_administrateur:, extra_class_names: nil)
|
||||||
|
@revision = revision
|
||||||
|
@current_administrateur = current_administrateur
|
||||||
|
@extra_class_names = extra_class_names
|
||||||
|
end
|
||||||
|
|
||||||
|
def render?
|
||||||
|
revision.draft?
|
||||||
|
end
|
||||||
|
|
||||||
|
def admin?
|
||||||
|
current_administrateur.present? && revision.procedure.administrateurs.include?(current_administrateur)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
title: Procedure in testing
|
||||||
|
intro_procedure_brouillon_html: This procedure is currently in <b>testing</b>
|
||||||
|
intro_revision_draft_html: This page allows you to <b>test</b> a new version of the procedure
|
||||||
|
body_general_html: |
|
||||||
|
and this page is reserved for the administration in charge of its deployment.
|
||||||
|
If you start or submit a file, it may be <b>deleted at any time</b> without notice, even if it is accepted later.
|
||||||
|
body_user: |
|
||||||
|
If this link was shared with you, please contact the service in charge of this procedure
|
||||||
|
to obtain the public link for the procedure in order to submit your application.
|
||||||
|
body_admin_procedure_brouillon: Do not share this link with your users. When you publish the procedure, you will access the public link for the procedure to be shared.
|
||||||
|
body_admin_revision_draft: Do not share this link with your users, but rather the public link for the procedure displayed in your administrator dashboard.
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
title: Démarche en test
|
||||||
|
intro_procedure_brouillon_html: Cette démarche est actuellement en <b>test</b>
|
||||||
|
intro_revision_draft_html: Cette page permet de <b>tester</b> une nouvelle version de la démarche
|
||||||
|
body_general_html: |
|
||||||
|
et cette page est réservée à l’administration en charge de son déploiement.
|
||||||
|
Si vous commencez ou déposez un dossier, il pourra être <b>supprimé à tout moment</b> et sans préavis, même après avoir été accepté.
|
||||||
|
body_user: |
|
||||||
|
Si ce lien vous a été communiqué, contactez le service en charge de cette démarche
|
||||||
|
pour obtenir le lien public de la démarche afin de déposer votre dossier.
|
||||||
|
body_admin_procedure_brouillon: Ne communiquez pas ce lien à vos usagers. Lorsque vous publierez la démarche, vous accéderez au lien public de la démarche à communiquer.
|
||||||
|
body_admin_revision_draft: Ne communiquez pas ce lien à vos usagers, mais le lien public de la démarche affiché dans votre tableau de bord administrateur.
|
|
@ -0,0 +1,10 @@
|
||||||
|
= render Dsfr::AlertComponent.new(state: :warning, extra_class_names:, title: t(".title")) do |c|
|
||||||
|
- c.with_body do
|
||||||
|
%p
|
||||||
|
= revision.procedure.brouillon? ? t(".intro_procedure_brouillon_html") : t(".intro_revision_draft_html")
|
||||||
|
= t(".body_general_html")
|
||||||
|
|
||||||
|
- if admin?
|
||||||
|
%p= revision.procedure.brouillon? ? t(".body_admin_procedure_brouillon") : t(".body_admin_revision_draft")
|
||||||
|
- else
|
||||||
|
%p= t(".body_user")
|
|
@ -12,8 +12,8 @@ class AgentConnect::AgentController < ApplicationController
|
||||||
def login
|
def login
|
||||||
uri, state, nonce = AgentConnectService.authorization_uri
|
uri, state, nonce = AgentConnectService.authorization_uri
|
||||||
|
|
||||||
cookies.encrypted[STATE_COOKIE_NAME] = state
|
cookies.encrypted[STATE_COOKIE_NAME] = { value: state, secure: Rails.env.production?, httponly: true }
|
||||||
cookies.encrypted[NONCE_COOKIE_NAME] = nonce
|
cookies.encrypted[NONCE_COOKIE_NAME] = { value: nonce, secure: Rails.env.production?, httponly: true }
|
||||||
|
|
||||||
redirect_to uri, allow_other_host: true
|
redirect_to uri, allow_other_host: true
|
||||||
end
|
end
|
||||||
|
|
|
@ -117,7 +117,7 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
def set_locale(locale)
|
def set_locale(locale)
|
||||||
if locale && locale.to_sym.in?(I18n.available_locales)
|
if locale && locale.to_sym.in?(I18n.available_locales)
|
||||||
cookies[:locale] = locale
|
cookies[:locale] = { value: locale, secure: Rails.env.production?, httponly: true }
|
||||||
if user_signed_in?
|
if user_signed_in?
|
||||||
current_user.update(locale: locale)
|
current_user.update(locale: locale)
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,7 +24,8 @@ module ApplicationController::LongLivedAuthenticityToken
|
||||||
cookies.signed[COOKIE_NAME] = {
|
cookies.signed[COOKIE_NAME] = {
|
||||||
value: csrf_token,
|
value: csrf_token,
|
||||||
expires: 1.year.from_now,
|
expires: 1.year.from_now,
|
||||||
httponly: true
|
httponly: true,
|
||||||
|
secure: Rails.env.production?
|
||||||
}
|
}
|
||||||
session[:_csrf_token] = csrf_token
|
session[:_csrf_token] = csrf_token
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,18 @@ class AttachmentsController < ApplicationController
|
||||||
@attachment.purge_later
|
@attachment.purge_later
|
||||||
flash.notice = 'La pièce jointe a bien été supprimée.'
|
flash.notice = 'La pièce jointe a bien été supprimée.'
|
||||||
|
|
||||||
@champ_id = params[:champ_id]
|
@champ = find_champ if params[:dossier_id]
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.turbo_stream
|
format.turbo_stream
|
||||||
format.html { redirect_back(fallback_location: root_url) }
|
format.html { redirect_back(fallback_location: root_url) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_champ
|
||||||
|
dossier = policy_scope(Dossier).includes(:champs).find(params[:dossier_id])
|
||||||
|
dossier.champs.find_by(stable_id: params[:stable_id], row_id: params[:row_id])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -247,7 +247,9 @@ module Instructeurs
|
||||||
@export_templates = current_instructeur.export_templates_for(@procedure).includes(:groupe_instructeur)
|
@export_templates = current_instructeur.export_templates_for(@procedure).includes(:groupe_instructeur)
|
||||||
cookies.encrypted[cookies_export_key] = {
|
cookies.encrypted[cookies_export_key] = {
|
||||||
value: DateTime.current,
|
value: DateTime.current,
|
||||||
expires: Export::MAX_DUREE_GENERATION + Export::MAX_DUREE_CONSERVATION_EXPORT
|
expires: Export::MAX_DUREE_GENERATION + Export::MAX_DUREE_CONSERVATION_EXPORT,
|
||||||
|
httponly: true,
|
||||||
|
secure: Rails.env.production?
|
||||||
}
|
}
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
|
|
@ -52,11 +52,14 @@ export function useSingleList({
|
||||||
}: {
|
}: {
|
||||||
defaultItems?: Item[];
|
defaultItems?: Item[];
|
||||||
defaultSelectedKey?: string | null;
|
defaultSelectedKey?: string | null;
|
||||||
emptyFilterKey?: string;
|
emptyFilterKey?: string | null;
|
||||||
onChange?: (item: Item | null) => void;
|
onChange?: (item: Item | null) => void;
|
||||||
}) {
|
}) {
|
||||||
const [selectedKey, setSelectedKey] = useState(defaultSelectedKey);
|
const [selectedKey, setSelectedKey] = useState(defaultSelectedKey);
|
||||||
const items = useMemo(() => defaultItems || [], [defaultItems]);
|
const items = useMemo(
|
||||||
|
() => (defaultItems ? distinctBy(defaultItems, 'value') : []),
|
||||||
|
[defaultItems]
|
||||||
|
);
|
||||||
const selectedItem = useMemo(
|
const selectedItem = useMemo(
|
||||||
() => items.find((item) => item.value == selectedKey) ?? null,
|
() => items.find((item) => item.value == selectedKey) ?? null,
|
||||||
[items, selectedKey]
|
[items, selectedKey]
|
||||||
|
@ -82,8 +85,8 @@ export function useSingleList({
|
||||||
const initialSelectedKeyRef = useRef(defaultSelectedKey);
|
const initialSelectedKeyRef = useRef(defaultSelectedKey);
|
||||||
|
|
||||||
const setSelection = useEvent((key?: string | null) => {
|
const setSelection = useEvent((key?: string | null) => {
|
||||||
const inputValue = defaultSelectedKey
|
const inputValue = key
|
||||||
? items.find((item) => item.value == defaultSelectedKey)?.label
|
? items.find((item) => item.value == key)?.label
|
||||||
: '';
|
: '';
|
||||||
setSelectedKey(key);
|
setSelectedKey(key);
|
||||||
setInputValue(inputValue ?? '');
|
setInputValue(inputValue ?? '');
|
||||||
|
@ -157,7 +160,10 @@ export function useMultiList({
|
||||||
() => new Set(defaultSelectedKeys ?? [])
|
() => new Set(defaultSelectedKeys ?? [])
|
||||||
);
|
);
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
const items = useMemo(() => defaultItems || [], [defaultItems]);
|
const items = useMemo(
|
||||||
|
() => (defaultItems ? distinctBy(defaultItems, 'value') : []),
|
||||||
|
[defaultItems]
|
||||||
|
);
|
||||||
const itemsIndex = useMemo(() => {
|
const itemsIndex = useMemo(() => {
|
||||||
const index = new Map<string, Item>();
|
const index = new Map<string, Item>();
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
|
@ -473,3 +479,8 @@ export function useOnFormReset(onReset?: () => void) {
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function distinctBy<T>(array: T[], key: keyof T): T[] {
|
||||||
|
const keys = array.map((item) => item[key]);
|
||||||
|
return array.filter((item, index) => keys.indexOf(item[key]) == index);
|
||||||
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ export const SingleComboBoxProps = s.assign(
|
||||||
s.partial(
|
s.partial(
|
||||||
s.object({
|
s.object({
|
||||||
selectedKey: s.nullable(s.string()),
|
selectedKey: s.nullable(s.string()),
|
||||||
emptyFilterKey: s.string()
|
emptyFilterKey: s.nullable(s.string())
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import format from 'date-fns/format';
|
import { format } from 'date-fns/format';
|
||||||
|
|
||||||
import { ApplicationController } from './application_controller';
|
import { ApplicationController } from './application_controller';
|
||||||
|
|
||||||
|
|
|
@ -1,156 +0,0 @@
|
||||||
import type { AxeResults, NodeResult, RelatedNode } from 'axe-core';
|
|
||||||
import axe from 'axe-core';
|
|
||||||
|
|
||||||
domReady().then(() => {
|
|
||||||
axe.run(document.body, { reporter: 'v2' }).then((results) => {
|
|
||||||
logToConsole(results);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// contrasted against Chrome default color of #ffffff
|
|
||||||
const lightTheme = {
|
|
||||||
serious: '#d93251',
|
|
||||||
minor: '#d24700',
|
|
||||||
text: 'black'
|
|
||||||
};
|
|
||||||
|
|
||||||
// contrasted against Safari dark mode color of #535353
|
|
||||||
const darkTheme = {
|
|
||||||
serious: '#ffb3b3',
|
|
||||||
minor: '#ffd500',
|
|
||||||
text: 'white'
|
|
||||||
};
|
|
||||||
|
|
||||||
const theme =
|
|
||||||
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
||||||
? darkTheme
|
|
||||||
: lightTheme;
|
|
||||||
|
|
||||||
const boldCourier = 'font-weight:bold;font-family:Courier;';
|
|
||||||
const critical = `color:${theme.serious};font-weight:bold;`;
|
|
||||||
const serious = `color:${theme.serious};font-weight:normal;`;
|
|
||||||
const moderate = `color:${theme.minor};font-weight:bold;`;
|
|
||||||
const minor = `color:${theme.minor};font-weight:normal;`;
|
|
||||||
const defaultReset = `font-color:${theme.text};font-weight:normal;`;
|
|
||||||
|
|
||||||
function logToConsole(results: AxeResults): void {
|
|
||||||
console.group('%cNew axe issues', serious);
|
|
||||||
results.violations.forEach((result) => {
|
|
||||||
let fmt: string;
|
|
||||||
switch (result.impact) {
|
|
||||||
case 'critical':
|
|
||||||
fmt = critical;
|
|
||||||
break;
|
|
||||||
case 'serious':
|
|
||||||
fmt = serious;
|
|
||||||
break;
|
|
||||||
case 'moderate':
|
|
||||||
fmt = moderate;
|
|
||||||
break;
|
|
||||||
case 'minor':
|
|
||||||
fmt = minor;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fmt = minor;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
console.groupCollapsed(
|
|
||||||
'%c%s: %c%s %s',
|
|
||||||
fmt,
|
|
||||||
result.impact,
|
|
||||||
defaultReset,
|
|
||||||
result.help,
|
|
||||||
result.helpUrl
|
|
||||||
);
|
|
||||||
result.nodes.forEach((node) => {
|
|
||||||
failureSummary(node, 'any');
|
|
||||||
failureSummary(node, 'none');
|
|
||||||
});
|
|
||||||
console.groupEnd();
|
|
||||||
});
|
|
||||||
console.groupEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
function failureSummary(node: NodeResult, key: AxeCoreNodeResultKey): void {
|
|
||||||
if (node[key].length > 0) {
|
|
||||||
logElement(node, console.groupCollapsed);
|
|
||||||
logHtml(node);
|
|
||||||
logFailureMessage(node, key);
|
|
||||||
|
|
||||||
let relatedNodes: RelatedNode[] = [];
|
|
||||||
node[key].forEach((check) => {
|
|
||||||
relatedNodes = relatedNodes.concat(check.relatedNodes ?? []);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (relatedNodes.length > 0) {
|
|
||||||
console.groupCollapsed('Related nodes');
|
|
||||||
relatedNodes.forEach((relatedNode) => {
|
|
||||||
logElement(relatedNode, console.log);
|
|
||||||
logHtml(relatedNode);
|
|
||||||
});
|
|
||||||
console.groupEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
console.groupEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function logFailureMessage(node: NodeResult, key: AxeCoreNodeResultKey): void {
|
|
||||||
// this exists on axe but we don't export it as part of the typescript
|
|
||||||
// namespace, so just let me use it as I need
|
|
||||||
const message: string = (
|
|
||||||
axe as unknown as AxeWithAudit
|
|
||||||
)._audit.data.failureSummaries[key].failureMessage(
|
|
||||||
node[key].map((check) => check.message || '')
|
|
||||||
);
|
|
||||||
|
|
||||||
console.error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function logElement(
|
|
||||||
node: NodeResult | RelatedNode,
|
|
||||||
logFn: (...args: unknown[]) => void
|
|
||||||
): void {
|
|
||||||
const el = document.querySelector(node.target.toString());
|
|
||||||
if (!el) {
|
|
||||||
logFn('Selector: %c%s', boldCourier, node.target.toString());
|
|
||||||
} else {
|
|
||||||
logFn('Element: %o', el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function logHtml(node: NodeResult | RelatedNode): void {
|
|
||||||
console.log('HTML: %c%s', boldCourier, node.html);
|
|
||||||
}
|
|
||||||
|
|
||||||
type AxeCoreNodeResultKey = 'any' | 'all' | 'none';
|
|
||||||
|
|
||||||
interface AxeWithAudit {
|
|
||||||
_audit: {
|
|
||||||
data: {
|
|
||||||
failureSummaries: {
|
|
||||||
any: {
|
|
||||||
failureMessage: (args: string[]) => string;
|
|
||||||
};
|
|
||||||
all: {
|
|
||||||
failureMessage: (args: string[]) => string;
|
|
||||||
};
|
|
||||||
none: {
|
|
||||||
failureMessage: (args: string[]) => string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function domReady() {
|
|
||||||
return new Promise<void>((resolve) => {
|
|
||||||
if (document.readyState == 'loading') {
|
|
||||||
document.addEventListener('DOMContentLoaded', () => resolve(), {
|
|
||||||
once: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
@preserve dataset polyfill for IE < 11. See https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset and http://caniuse.com/#search=dataset
|
|
||||||
|
|
||||||
@author ShirtlessKirk copyright 2015
|
|
||||||
@license WTFPL (http://www.wtfpl.net/txt/copying)
|
|
||||||
*/
|
|
||||||
|
|
||||||
const dash = /-([a-z])/gi;
|
|
||||||
const dataRegEx = /^data-(.+)/;
|
|
||||||
const hasEventListener = !!document.addEventListener;
|
|
||||||
const test = document.createElement('_');
|
|
||||||
const DOMAttrModified = 'DOMAttrModified';
|
|
||||||
|
|
||||||
let mutationSupport = false;
|
|
||||||
|
|
||||||
function clearDataset(event) {
|
|
||||||
delete event.target._datasetCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toCamelCase(string) {
|
|
||||||
return string.replace(dash, function (_, letter) {
|
|
||||||
return letter.toUpperCase();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDataset() {
|
|
||||||
const dataset = {};
|
|
||||||
|
|
||||||
for (let attribute of this.attributes) {
|
|
||||||
let match = attribute.name.match(dataRegEx);
|
|
||||||
if (match) {
|
|
||||||
dataset[toCamelCase(match[1])] = attribute.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataset;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mutation() {
|
|
||||||
if (hasEventListener) {
|
|
||||||
test.removeEventListener(DOMAttrModified, mutation, false);
|
|
||||||
} else {
|
|
||||||
test.detachEvent(`on${DOMAttrModified}`, mutation);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutationSupport = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!test.dataset) {
|
|
||||||
if (hasEventListener) {
|
|
||||||
test.addEventListener(DOMAttrModified, mutation, false);
|
|
||||||
} else {
|
|
||||||
test.attachEvent(`on${DOMAttrModified}`, mutation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// trigger event (if supported)
|
|
||||||
test.setAttribute('foo', 'bar');
|
|
||||||
|
|
||||||
Object.defineProperty(Element.prototype, 'dataset', {
|
|
||||||
get: mutationSupport
|
|
||||||
? function get() {
|
|
||||||
if (!this._datasetCache) {
|
|
||||||
this._datasetCache = getDataset.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._datasetCache;
|
|
||||||
}
|
|
||||||
: getDataset
|
|
||||||
});
|
|
||||||
|
|
||||||
if (mutationSupport && hasEventListener) {
|
|
||||||
// < IE9 supports neither
|
|
||||||
document.addEventListener(DOMAttrModified, clearDataset, false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -107,11 +107,6 @@ class Champ < ApplicationRecord
|
||||||
[to_s]
|
[to_s]
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_value
|
|
||||||
return unless valid_champ_value?
|
|
||||||
value
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
TypeDeChamp.champ_value(type_champ, self)
|
TypeDeChamp.champ_value(type_champ, self)
|
||||||
end
|
end
|
||||||
|
|
|
@ -50,7 +50,7 @@ class Champs::COJOChamp < Champ
|
||||||
|
|
||||||
def update_external_id
|
def update_external_id
|
||||||
if accreditation_number_changed? || accreditation_birthdate_changed?
|
if accreditation_number_changed? || accreditation_birthdate_changed?
|
||||||
if accreditation_number.present? && accreditation_birthdate.present? && /\A\d+\z/.match?(accreditation_number)
|
if accreditation_number.present? && accreditation_birthdate.present? && /\A[\d-]+\z/.match?(accreditation_number)
|
||||||
self.external_id = { accreditation_number:, accreditation_birthdate: }.to_json
|
self.external_id = { accreditation_number:, accreditation_birthdate: }.to_json
|
||||||
else
|
else
|
||||||
self.external_id = nil
|
self.external_id = nil
|
||||||
|
|
|
@ -8,7 +8,8 @@ module TrustedDeviceConcern
|
||||||
cookies.encrypted[TRUSTED_DEVICE_COOKIE_NAME] = {
|
cookies.encrypted[TRUSTED_DEVICE_COOKIE_NAME] = {
|
||||||
value: JSON.generate({ created_at: start_at }),
|
value: JSON.generate({ created_at: start_at }),
|
||||||
expires: start_at + TRUSTED_DEVICE_PERIOD,
|
expires: start_at + TRUSTED_DEVICE_PERIOD,
|
||||||
httponly: true
|
httponly: true,
|
||||||
|
secure: Rails.env.production?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ class TypesDeChamp::DecimalNumberTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||||
private
|
private
|
||||||
|
|
||||||
def champ_formatted_value(champ)
|
def champ_formatted_value(champ)
|
||||||
champ.valid_value&.to_f
|
champ.value&.to_f
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,7 @@ class TypesDeChamp::IntegerNumberTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||||
private
|
private
|
||||||
|
|
||||||
def champ_formatted_value(champ)
|
def champ_formatted_value(champ)
|
||||||
champ.valid_value&.to_i
|
champ.value&.to_i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,12 +66,12 @@ class TypesDeChamp::TypeDeChampBase
|
||||||
when 2
|
when 2
|
||||||
champ_value(champ)
|
champ_value(champ)
|
||||||
else
|
else
|
||||||
champ.valid_value.presence || champ_default_api_value(version)
|
champ.value.presence || champ_default_api_value(version)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def champ_value_for_export(champ, path = :value)
|
def champ_value_for_export(champ, path = :value)
|
||||||
path == :value ? champ.valid_value.presence : champ_default_export_value(path)
|
path == :value ? champ.value.presence : champ_default_export_value(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def champ_value_for_tag(champ, path = :value)
|
def champ_value_for_tag(champ, path = :value)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
= turbo_stream.remove dom_id(@attachment, :persisted_row)
|
= turbo_stream.remove dom_id(@attachment, :persisted_row)
|
||||||
|
|
||||||
- if @champ_id
|
|
||||||
= turbo_stream.show "attachment-multiple-empty-#{@champ_id}"
|
|
||||||
= turbo_stream.focus_all "#attachment-multiple-empty-#{@champ_id} input"
|
|
||||||
|
|
||||||
= turbo_stream.show_all ".attachment-input-#{@attachment.id}"
|
= turbo_stream.show_all ".attachment-input-#{@attachment.id}"
|
||||||
|
|
||||||
|
- if @champ
|
||||||
|
= fields_for @champ.input_name, @champ do |form|
|
||||||
|
= turbo_stream.replace @champ.input_group_id do
|
||||||
|
= render EditableChamp::EditableChampComponent.new champ: @champ, form: form
|
||||||
|
= turbo_stream.focus_all "#attachment-multiple-empty-#{@champ.public_id} input"
|
||||||
|
|
|
@ -13,7 +13,11 @@
|
||||||
#{Current.application_name}
|
#{Current.application_name}
|
||||||
%li= link_to t('views.shared.account.already_user'), commencer_sign_in_path(path: @procedure.path, prefill_token: @prefilled_dossier&.prefill_token), class: 'fr-btn fr-btn--secondary'
|
%li= link_to t('views.shared.account.already_user'), commencer_sign_in_path(path: @procedure.path, prefill_token: @prefilled_dossier&.prefill_token), class: 'fr-btn fr-btn--secondary'
|
||||||
|
|
||||||
|
= render ProcedureDraftWarningComponent.new(revision: @revision, current_administrateur:, extra_class_names: "fr-mb-2w")
|
||||||
|
|
||||||
- else
|
- else
|
||||||
|
= render ProcedureDraftWarningComponent.new(revision: @revision, current_administrateur:, extra_class_names: "fr-mb-2w")
|
||||||
|
|
||||||
- if @prefilled_dossier
|
- if @prefilled_dossier
|
||||||
= render Dsfr::CalloutComponent.new(title: t(".prefilled_draft"), heading_level: 'h2') do |c|
|
= render Dsfr::CalloutComponent.new(title: t(".prefilled_draft"), heading_level: 'h2') do |c|
|
||||||
- c.with_body do
|
- c.with_body do
|
||||||
|
|
|
@ -2,4 +2,9 @@
|
||||||
|
|
||||||
= render partial: 'header', locals: { avis: @avis, dossier: @dossier }
|
= render partial: 'header', locals: { avis: @avis, dossier: @dossier }
|
||||||
|
|
||||||
= render partial: 'shared/dossiers/demande', locals: { dossier: @dossier, demande_seen_at: nil, profile: 'expert' }
|
.fr-container
|
||||||
|
.fr-grid-row.fr-grid-row--center
|
||||||
|
- summary = ViewableChamp::HeaderSectionsSummaryComponent.new(dossier: @dossier, is_private: false)
|
||||||
|
= render summary
|
||||||
|
%div{ class: class_names("fr-col-12", "fr-col-xl-9" => summary.render?, "fr-col-xl-8" => !summary.render?) }
|
||||||
|
= render partial: "shared/dossiers/demande", locals: { dossier: @dossier, demande_seen_at: nil, profile: 'expert' }
|
||||||
|
|
|
@ -6,20 +6,15 @@
|
||||||
.dossier-container.fr-mb-4w
|
.dossier-container.fr-mb-4w
|
||||||
= render partial: 'users/dossiers/show/header', locals: { dossier: @dossier }
|
= render partial: 'users/dossiers/show/header', locals: { dossier: @dossier }
|
||||||
|
|
||||||
- if @dossier.en_construction?
|
|
||||||
.fr-container
|
|
||||||
.fr-grid-row.fr-grid-row--center
|
|
||||||
.fr-col-xl-10
|
|
||||||
= render Dossiers::EnConstructionNotSubmittedComponent.new(dossier: @dossier, user: current_user)
|
|
||||||
.fr-container
|
.fr-container
|
||||||
.fr-grid-row.fr-grid-row--center
|
.fr-grid-row.fr-grid-row--center
|
||||||
.fr-col-md-9
|
.fr-col-md-9
|
||||||
|
- if @dossier.en_construction?
|
||||||
|
= render Dossiers::EnConstructionNotSubmittedComponent.new(dossier: @dossier, user: current_user)
|
||||||
|
|
||||||
= render partial: 'shared/dossiers/demande', locals: { dossier: @dossier, demande_seen_at: nil, profile: 'usager' }
|
= render partial: 'shared/dossiers/demande', locals: { dossier: @dossier, demande_seen_at: nil, profile: 'usager' }
|
||||||
|
|
||||||
|
|
||||||
- if !@dossier.read_only?
|
- if !@dossier.read_only?
|
||||||
.fr-container.fr-mt-2w
|
.fr-px-2w.fr-mt-2w
|
||||||
.fr-grid-row.fr-grid-row--center
|
|
||||||
.fr-col-xl-8.fr-col-offset-xl-2
|
|
||||||
%p= link_to t('views.users.dossiers.demande.edit_dossier'), modifier_dossier_path(@dossier), class: 'fr-btn fr-btn-sm',
|
%p= link_to t('views.users.dossiers.demande.edit_dossier'), modifier_dossier_path(@dossier), class: 'fr-btn fr-btn-sm',
|
||||||
title: t('views.users.dossiers.demande.edit_dossier_title')
|
title: t('views.users.dossiers.demande.edit_dossier_title')
|
||||||
|
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
@ -1,3 +1,3 @@
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
Rails.application.config.session_store :cookie_store, key: '_DS_session'
|
Rails.application.config.session_store :cookie_store, key: '_DS_session', secure: Rails.env.production?, httponly: true
|
||||||
|
|
|
@ -10,7 +10,7 @@ fr:
|
||||||
since: "depuis le %{date}"
|
since: "depuis le %{date}"
|
||||||
closed: "Close"
|
closed: "Close"
|
||||||
published: "Publiée"
|
published: "Publiée"
|
||||||
draft: "En test"
|
draft: "En test"
|
||||||
more_info_on_test: "Pour plus d’information sur la phase de test"
|
more_info_on_test: "Pour plus d’information sur la phase de test"
|
||||||
go_to_FAQ: "consulter la FAQ"
|
go_to_FAQ: "consulter la FAQ"
|
||||||
url_FAQ: "/faq#accordion-administrateur-2"
|
url_FAQ: "/faq#accordion-administrateur-2"
|
||||||
|
|
57
package.json
57
package.json
|
@ -5,9 +5,9 @@
|
||||||
"@coldwired/react": "^0.15.0",
|
"@coldwired/react": "^0.15.0",
|
||||||
"@coldwired/turbo-stream": "^0.13.0",
|
"@coldwired/turbo-stream": "^0.13.0",
|
||||||
"@coldwired/utils": "^0.13.0",
|
"@coldwired/utils": "^0.13.0",
|
||||||
"@frsource/autoresize-textarea": "^2.0.75",
|
"@frsource/autoresize-textarea": "^2.0.82",
|
||||||
"@gouvfr/dsfr": "^1.11.2",
|
"@gouvfr/dsfr": "^1.11.2",
|
||||||
"@graphiql/plugin-explorer": "^3.0.2",
|
"@graphiql/plugin-explorer": "^3.1.0",
|
||||||
"@graphiql/toolkit": "^0.9.1",
|
"@graphiql/toolkit": "^0.9.1",
|
||||||
"@headlessui/react": "^1.6.6",
|
"@headlessui/react": "^1.6.6",
|
||||||
"@heroicons/react": "^1.0.6",
|
"@heroicons/react": "^1.0.6",
|
||||||
|
@ -15,11 +15,11 @@
|
||||||
"@hotwired/turbo": "^7.3.0",
|
"@hotwired/turbo": "^7.3.0",
|
||||||
"@mapbox/mapbox-gl-draw": "^1.3.0",
|
"@mapbox/mapbox-gl-draw": "^1.3.0",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@rails/actiontext": "^7.1.3-2",
|
"@rails/actiontext": "^7.1.3-4",
|
||||||
"@rails/activestorage": "^7.1.3-2",
|
"@rails/activestorage": "^7.1.3-4",
|
||||||
"@rails/ujs": "^7.1.3-2",
|
"@rails/ujs": "^7.1.3-4",
|
||||||
"@reach/slider": "^0.17.0",
|
"@reach/slider": "^0.17.0",
|
||||||
"@sentry/browser": "8.7.0",
|
"@sentry/browser": "8.15.0",
|
||||||
"@tiptap/core": "^2.2.4",
|
"@tiptap/core": "^2.2.4",
|
||||||
"@tiptap/extension-bold": "^2.2.4",
|
"@tiptap/extension-bold": "^2.2.4",
|
||||||
"@tiptap/extension-bullet-list": "^2.2.4",
|
"@tiptap/extension-bullet-list": "^2.2.4",
|
||||||
|
@ -44,26 +44,26 @@
|
||||||
"@tmcw/togeojson": "^5.6.0",
|
"@tmcw/togeojson": "^5.6.0",
|
||||||
"chartkick": "^5.0.1",
|
"chartkick": "^5.0.1",
|
||||||
"core-js": "^3.37.1",
|
"core-js": "^3.37.1",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^3.6.0",
|
||||||
"debounce": "^1.2.1",
|
"debounce": "^2.1.0",
|
||||||
"geojson": "^0.5.0",
|
"geojson": "^0.5.0",
|
||||||
"graphiql": "^3.2.3",
|
"graphiql": "^3.3.2",
|
||||||
"graphql": "^16.8.1",
|
"graphql": "^16.9.0",
|
||||||
"highcharts": "^10.3.3",
|
"highcharts": "^10.3.3",
|
||||||
"lightgallery": "^2.7.2",
|
"lightgallery": "^2.7.2",
|
||||||
"maplibre-gl": "^1.15.2",
|
"maplibre-gl": "^1.15.2",
|
||||||
"match-sorter": "^6.3.4",
|
"match-sorter": "^6.3.4",
|
||||||
"patch-package": "^8.0.0",
|
"patch-package": "^8.0.0",
|
||||||
"react": "^18.3.0",
|
"react": "^18.3.1",
|
||||||
"react-aria-components": "^1.2.0",
|
"react-aria-components": "^1.2.1",
|
||||||
"react-coordinate-input": "^1.0.0",
|
"react-coordinate-input": "^1.0.0",
|
||||||
"react-dom": "^18.3.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-popper": "^2.3.0",
|
"react-popper": "^2.3.0",
|
||||||
"react-use-event-hook": "^0.9.6",
|
"react-use-event-hook": "^0.9.6",
|
||||||
"spectaql": "^2.3.1",
|
"spectaql": "^2.3.1",
|
||||||
"stimulus-use": "^0.52.2",
|
"stimulus-use": "^0.52.2",
|
||||||
"superstruct": "^1.0.4",
|
"superstruct": "^2.0.2",
|
||||||
"terser": "^5.31.0",
|
"terser": "^5.31.1",
|
||||||
"tiny-invariant": "^1.3.3",
|
"tiny-invariant": "^1.3.3",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"trix": "^1.2.3",
|
"trix": "^1.2.3",
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
"@esbuild/darwin-arm64": "=0.19.9",
|
"@esbuild/darwin-arm64": "=0.19.9",
|
||||||
"@esbuild/linux-x64": "=0.19.9",
|
"@esbuild/linux-x64": "=0.19.9",
|
||||||
"@esbuild/win32-x64": "=0.19.9",
|
"@esbuild/win32-x64": "=0.19.9",
|
||||||
"@react-aria/optimize-locales-plugin": "^1.1.0",
|
"@react-aria/optimize-locales-plugin": "^1.1.1",
|
||||||
"@rollup/rollup-darwin-arm64": "=4.9.1",
|
"@rollup/rollup-darwin-arm64": "=4.9.1",
|
||||||
"@rollup/rollup-linux-x64-gnu": "=4.9.1",
|
"@rollup/rollup-linux-x64-gnu": "=4.9.1",
|
||||||
"@rollup/rollup-win32-x64-msvc": "=4.9.1",
|
"@rollup/rollup-win32-x64-msvc": "=4.9.1",
|
||||||
|
@ -83,28 +83,27 @@
|
||||||
"@types/mapbox__mapbox-gl-draw": "^1.2.5",
|
"@types/mapbox__mapbox-gl-draw": "^1.2.5",
|
||||||
"@types/rails__activestorage": "^7.1.1",
|
"@types/rails__activestorage": "^7.1.1",
|
||||||
"@types/rails__ujs": "^6.0.4",
|
"@types/rails__ujs": "^6.0.4",
|
||||||
"@types/react": "^18.2.79",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.2.25",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/sortablejs": "^1.15.8",
|
"@types/sortablejs": "^1.15.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
||||||
"@typescript-eslint/parser": "^7.11.0",
|
"@typescript-eslint/parser": "^7.15.0",
|
||||||
"@vitejs/plugin-react": "^4.3.0",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"axe-core": "^4.8.4",
|
|
||||||
"del-cli": "^5.1.0",
|
"del-cli": "^5.1.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-react": "^7.34.2",
|
"eslint-plugin-react": "^7.34.3",
|
||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
"jsdom": "^22.1.0",
|
"jsdom": "^24.1.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.39",
|
||||||
"prettier": "^3.3.0",
|
"prettier": "^3.3.2",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.5.3",
|
||||||
"vite": "^5.2.12",
|
"vite": "^5.3.3",
|
||||||
"vite-plugin-full-reload": "^1.1.0",
|
"vite-plugin-full-reload": "^1.1.0",
|
||||||
"vite-plugin-ruby": "^5.0.0",
|
"vite-plugin-ruby": "^5.0.0",
|
||||||
"vitest": "^1.6.0"
|
"vitest": "^2.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "del tmp public/graphql && bin/vite clobber",
|
"clean": "del tmp public/graphql && bin/vite clobber",
|
||||||
|
|
|
@ -75,8 +75,8 @@ RSpec.describe Attachment::MultipleComponent, type: :component do
|
||||||
context 'max attachments' do
|
context 'max attachments' do
|
||||||
let(:kwargs) { { max: 1 } }
|
let(:kwargs) { { max: 1 } }
|
||||||
|
|
||||||
it 'does not render visible input file where max attachments has been reached' do
|
it 'renders a disabled input file where max attachments has been reached' do
|
||||||
expect(subject).to have_selector('.hidden input[type=file]')
|
expect(subject).to have_selector('input[type=file][disabled]')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -40,12 +40,6 @@ describe Logic::ChampValue do
|
||||||
|
|
||||||
it { is_expected.to be nil }
|
it { is_expected.to be nil }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with invalid value' do
|
|
||||||
before { champ.value = 'environ 300' }
|
|
||||||
|
|
||||||
it { is_expected.to be nil }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'decimal tdc' do
|
context 'decimal tdc' do
|
||||||
|
@ -53,18 +47,6 @@ describe Logic::ChampValue do
|
||||||
|
|
||||||
it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) }
|
it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) }
|
||||||
it { is_expected.to eq(42.01) }
|
it { is_expected.to eq(42.01) }
|
||||||
|
|
||||||
context 'with invalid value with too many digits after the decimal point' do
|
|
||||||
before { champ.value = '42.1234' }
|
|
||||||
|
|
||||||
it { is_expected.to be nil }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with invalid value' do
|
|
||||||
before { champ.value = 'racine de 2' }
|
|
||||||
|
|
||||||
it { is_expected.to be nil }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'dropdown tdc' do
|
context 'dropdown tdc' do
|
||||||
|
|
|
@ -16,17 +16,11 @@ describe 'administrateurs/procedures/show', type: :view do
|
||||||
render
|
render
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'publish button is visible' do
|
it "render content" do
|
||||||
it { expect(rendered).to have_css('#publish-procedure-link') }
|
expect(rendered).to have_css('#publish-procedure-link')
|
||||||
it { expect(rendered).not_to have_css('#close-procedure-link') }
|
expect(rendered).not_to have_css('#close-procedure-link')
|
||||||
end
|
expect(rendered).to have_content('En test')
|
||||||
|
expect(rendered).not_to have_css('#archive-procedure')
|
||||||
describe 'procedure path is not customized' do
|
|
||||||
it { expect(rendered).to have_content('En test') }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'archive button' do
|
|
||||||
it { expect(rendered).not_to have_css('#archive-procedure') }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,10 +7,15 @@ RSpec.describe 'commencer/show', type: :view do
|
||||||
let(:drafts) { [] }
|
let(:drafts) { [] }
|
||||||
let(:not_drafts) { [] }
|
let(:not_drafts) { [] }
|
||||||
let(:preview_dossiers) { dossiers.take(3) }
|
let(:preview_dossiers) { dossiers.take(3) }
|
||||||
|
let(:user) { nil }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(view).to receive(:current_administrateur).and_return(user&.administrateur)
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
assign(:procedure, procedure)
|
assign(:procedure, procedure)
|
||||||
assign(:revision, procedure.published_revision)
|
assign(:revision, procedure.active_revision)
|
||||||
assign(:dossiers, dossiers)
|
assign(:dossiers, dossiers)
|
||||||
assign(:drafts, drafts)
|
assign(:drafts, drafts)
|
||||||
assign(:not_drafts, not_drafts)
|
assign(:not_drafts, not_drafts)
|
||||||
|
@ -25,8 +30,6 @@ RSpec.describe 'commencer/show', type: :view do
|
||||||
subject { render }
|
subject { render }
|
||||||
|
|
||||||
context 'when no user is signed in' do
|
context 'when no user is signed in' do
|
||||||
let(:user) { nil }
|
|
||||||
|
|
||||||
it 'renders sign-in and sign-up links' do
|
it 'renders sign-in and sign-up links' do
|
||||||
subject
|
subject
|
||||||
expect(rendered).to have_link('Créer un compte')
|
expect(rendered).to have_link('Créer un compte')
|
||||||
|
@ -98,4 +101,35 @@ RSpec.describe 'commencer/show', type: :view do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "procedure is draft" do
|
||||||
|
let(:procedure) { create(:procedure, :draft) }
|
||||||
|
let(:user) { create :user }
|
||||||
|
|
||||||
|
it 'renders a warning' do
|
||||||
|
subject
|
||||||
|
expect(rendered).to have_text("Cette démarche est actuellement en test")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when user is admin" do
|
||||||
|
let(:user) { procedure.administrateurs.first.user }
|
||||||
|
|
||||||
|
it "renders warning about draft" do
|
||||||
|
subject
|
||||||
|
expect(rendered).to have_text("Cette démarche est actuellement en test")
|
||||||
|
expect(rendered).to have_text("Ne communiquez pas ce lien")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "revision is draft" do
|
||||||
|
before {
|
||||||
|
assign(:revision, procedure.draft_revision)
|
||||||
|
}
|
||||||
|
|
||||||
|
it "renders warning about draft" do
|
||||||
|
subject
|
||||||
|
expect(rendered).to have_text("Démarche en test")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { defineConfig } from 'vite';
|
||||||
import ViteReact from '@vitejs/plugin-react';
|
import ViteReact from '@vitejs/plugin-react';
|
||||||
import RubyPlugin from 'vite-plugin-ruby';
|
import RubyPlugin from 'vite-plugin-ruby';
|
||||||
import FullReload from 'vite-plugin-full-reload';
|
import FullReload from 'vite-plugin-full-reload';
|
||||||
import optimizeLocales from '@react-aria/optimize-locales-plugin';
|
//import optimizeLocales from '@react-aria/optimize-locales-plugin';
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
RubyPlugin(),
|
RubyPlugin(),
|
||||||
|
@ -10,13 +10,13 @@ const plugins = [
|
||||||
FullReload(
|
FullReload(
|
||||||
['config/routes.rb', 'app/views/**/*', 'app/components/**/*.haml'],
|
['config/routes.rb', 'app/views/**/*', 'app/components/**/*.haml'],
|
||||||
{ delay: 200 }
|
{ delay: 200 }
|
||||||
),
|
)
|
||||||
{
|
// {
|
||||||
...optimizeLocales.vite({
|
// ...optimizeLocales.vite({
|
||||||
locales: ['en-GB', 'fr-FR']
|
// locales: ['en-GB', 'fr-FR']
|
||||||
}),
|
// }),
|
||||||
enforce: 'pre' as const
|
// enforce: 'pre' as const
|
||||||
}
|
// }
|
||||||
];
|
];
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
|
Loading…
Reference in a new issue