Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tech(pdf): replace wkhtmltopdf (no longer maintained) with grover #2619

Open
wants to merge 22 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"no-use-before-define": "off",
"react/jsx-props-no-spreading": "off",
"jsx-a11y/no-autofocus": "off",
"react/function-component-definition": "off",
"arrow-body-style": "off"
}
}
12 changes: 9 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on: push
jobs:
linters:
name: Linters
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Ruby
Expand All @@ -24,7 +24,7 @@ jobs:
run: yarn lint
test_unit:
name: Unit Tests
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
services:
postgres:
image: postgres:13.2
Expand Down Expand Up @@ -87,7 +87,7 @@ jobs:

test_features:
name: Feature Tests
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
Expand All @@ -114,11 +114,17 @@ jobs:
- 6379:6379
options: --entrypoint redis-server
steps:
- name: Disable AppArmor
# AppArmor restricts unprivileged user namespaces, which Puppeteer requires.
# https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md
Holist marked this conversation as resolved.
Show resolved Hide resolved
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version-file: .node-version
- name: Installing Chrome for Puppeteer test
run: npx puppeteer browsers install chrome
Holist marked this conversation as resolved.
Show resolved Hide resolved
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
5 changes: 2 additions & 3 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ gem "addressable"

gem "agent_connect", github: "gip-inclusion/agent_connect_engine"

# Easily generate PDF from HTML
gem "wicked_pdf"
gem "wkhtmltopdf-binary"
# Easily generate PDF from HTML with puppeteer and headless chrome
gem "grover"

# CORS support
gem "rack-cors"
Expand Down
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ GEM
rake (>= 13)
groupdate (6.5.1)
activesupport (>= 7)
grover (1.2.3)
nokogiri (~> 1)
hashdiff (1.1.2)
hashery (2.1.2)
hashie (5.0.0)
Expand Down Expand Up @@ -672,7 +674,6 @@ GEM
with_advisory_lock (5.1.0)
activerecord (>= 6.1)
zeitwerk (>= 2.6)
wkhtmltopdf-binary (0.12.6.8)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.7.1)
Expand Down Expand Up @@ -709,6 +710,7 @@ DEPENDENCIES
factory_bot_rails
faraday
groupdate
grover
image_processing
jbuilder (~> 2.7)
jsbundling-rails
Expand Down Expand Up @@ -759,9 +761,7 @@ DEPENDENCIES
tzinfo-data
web-console (>= 3.3.0)
webmock
wicked_pdf
with_advisory_lock
wkhtmltopdf-binary

RUBY VERSION
ruby 3.4.1p0
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/invitations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def invite_user
end

def pdf
WickedPdf.new.pdf_from_string(invitation.content, encoding: "utf-8")
Grover.new(invitation.content).to_pdf
end

def pdf_filename
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/notifications_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def notify_participation
end

def pdf
WickedPdf.new.pdf_from_string(notify_participation.notification.content, encoding: "utf-8")
Grover.new(notify_participation.notification.content).to_pdf
end

def pdf_filename
Expand Down
10 changes: 0 additions & 10 deletions app/helpers/pdf_helper.rb

This file was deleted.

96 changes: 47 additions & 49 deletions app/javascript/react/components/user/InvitationCell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,55 +32,53 @@ export default observer(({ user, format }) => {

return (
user.list.canBeInvitedBy(format) && (
<>
<td>
{user.activeErrors.includes(actionType) ? (
<button
type="submit"
className="btn btn-danger"
onClick={() => handleInvitationClick()}
>
Afficher les erreurs
</button>
) : (
<Tippy
onShow={() => user.lastInvitationDate(format) !== undefined}
content={
<span>
{user.lastInvitationDate(format) &&
`Dernière invitation ${format} le ${getFrenchFormatDateString(user.lastInvitationDate(format))}`
}
{user.lastInvitationDate(format) && user.lastParticipationRdvStartsAt() && <br />}
{user.lastParticipationRdvStartsAt() &&
`Dernier rendez-vous le ${getFrenchFormatDateString(user.lastParticipationRdvStartsAt())}`
}
</span>
}
>
<div className="d-flex justify-content-center">
{user.lastInvitationDate(format) !== undefined && (
<i className="ri-check-line d-block p-1" />
)}
<button
type="submit"
disabled={
user.triggers[actionType] ||
!user.createdAt ||
!user.requiredAttributeToInviteBy(format) ||
!user.belongsToCurrentOrg()
}
className={
user.lastInvitationDate(format) === undefined ? `btn btn-primary btn-blue invitation-${format}` : `reinvitation-${format}`
}
onClick={() => handleInvitationClick()}
>
{inviteButtonContent()}
</button>
</div>
</Tippy>
)}
</td>
</>
<td>
{user.activeErrors.includes(actionType) ? (
<button
type="submit"
className="btn btn-danger"
onClick={() => handleInvitationClick()}
>
Afficher les erreurs
</button>
) : (
<Tippy
onShow={() => user.lastInvitationDate(format) !== undefined}
content={
<span>
{user.lastInvitationDate(format) &&
`Dernière invitation ${format} le ${getFrenchFormatDateString(user.lastInvitationDate(format))}`
}
{user.lastInvitationDate(format) && user.lastParticipationRdvStartsAt() && <br />}
{user.lastParticipationRdvStartsAt() &&
`Dernier rendez-vous le ${getFrenchFormatDateString(user.lastParticipationRdvStartsAt())}`
}
</span>
}
>
<div className="d-flex justify-content-center">
{user.lastInvitationDate(format) !== undefined && (
<i className="ri-check-line d-block p-1" />
)}
<button
type="submit"
disabled={
user.triggers[actionType] ||
!user.createdAt ||
!user.requiredAttributeToInviteBy(format) ||
!user.belongsToCurrentOrg()
}
className={
user.lastInvitationDate(format) === undefined ? `btn btn-primary btn-blue invitation-${format}` : `reinvitation-${format}`
}
onClick={() => handleInvitationClick()}
>
{inviteButtonContent()}
</button>
</div>
</Tippy>
)}
</td>
)
);
});
18 changes: 8 additions & 10 deletions app/javascript/react/components/user/InvitationCells.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ export default function InvitationCells({ user }) {
/* ----------------------------- Disabled invitations cases -------------------------- */
user.isArchived() ? (
<td colSpan={user.list.invitationsColSpan}>
Dossier archivé
Dossier archivé
{user.isArchivedInCurrentOrganisation() && (
<Tippy
content={
<>
<span>
Usager archivé pour le motif suivant : {user.archiveInCurrentOrganisation().archiving_reason}
</>
</span>
}
>
<i className="ms-2 ri-information-fill" />
Expand All @@ -28,21 +28,19 @@ export default function InvitationCells({ user }) {
L'usager n'appartient pas à une organisation qui gère ce type de rdv{" "}
<Tippy
content={
<>
<span>
Ajoutez l'usager à une organisation qui gère ces rdvs en appuyant sur le boutton
"Ajouter à une organisation" sur sa fiche, puis rechargez le fichier
</>
</span>
}
>
<i className="ri-question-line" />
</Tippy>
</td>
) : user.currentFollowUpStatus === "rdv_pending" ? (
<>
<td colSpan={user.list.invitationsColSpan}>
{user.currentFollowUp.human_status} (le {getFrenchFormatDateString(user.currentPendingRdv.starts_at)})
</td>
</>
<td colSpan={user.list.invitationsColSpan}>
{user.currentFollowUp.human_status} (le {getFrenchFormatDateString(user.currentPendingRdv.starts_at)})
</td>
) : (
/* ----------------------------- Enabled invitations cases --------------------------- */

Expand Down
42 changes: 20 additions & 22 deletions app/javascript/react/components/user/ReferentAssignationCell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,25 @@ export default observer(({ user }) => {
};

return (
<>
{user.referentAlreadyAssigned() ? (
<Tippy
content={`Référent: ${user.referentFullName()}`}
>
<i className="ri-check-line" />
</Tippy>
) : (
<button
type="submit"
disabled={!user.createdAt || user.triggers.referentAssignation}
className="btn btn-primary btn-blue"
onClick={() => handleReferentAssignationClick()}
>
<small>
{user.triggers.referentAssignation
? "Assignation..."
: `Assigner ${user.referentEmail}`}
</small>
</button>
)}
</>
user.referentAlreadyAssigned() ? (
<Tippy
content={`Référent: ${user.referentFullName()}`}
>
<i className="ri-check-line" />
</Tippy>
) : (
<button
type="submit"
disabled={!user.createdAt || user.triggers.referentAssignation}
className="btn btn-primary btn-blue"
onClick={() => handleReferentAssignationClick()}
>
<small>
{user.triggers.referentAssignation
? "Assignation..."
: `Assigner ${user.referentEmail}`}
</small>
</button>
)
);
});
Loading
Loading