From cb22e26ace5502e07a515e74108a8348a3ebb49d Mon Sep 17 00:00:00 2001 From: Julien Bouquillon Date: Mon, 11 Mar 2024 13:39:15 +0100 Subject: [PATCH] feat: beta branding (#1) * fix: beautify stat tiles * wip * wip * wip * markdown * lint * test * lint * cypress * e2e * e2e * ci * skiplinks * cypress * fix: base link * ci: disable jekyll --- .env.development | 4 +- .env.production | 9 +- .env.staging | 8 +- .eslintrc.json | 3 +- .github/workflows/deactivate.yaml | 23 - .github/workflows/debug-kube.yaml | 22 - .../workflows/{storybook.yml => deploy.yml} | 25 +- .github/workflows/e2e.yml | 6 +- .github/workflows/preproduction.yaml | 19 - .github/workflows/production.yaml | 16 - .github/workflows/release.yml | 4 +- .github/workflows/review-auto.yaml | 16 - .github/workflows/review.yaml | 19 - .husky/pre-commit | 9 +- .talismanrc | 10 +- README.md | 90 +- csp.config.js | 12 - csp.config.mjs | 12 + cypress.json | 4 +- cypress/integration/home.spec.ts | 10 +- mdx-components.tsx | 63 + next.config.js => next.config.mjs | 23 +- package.json | 80 +- public/sitemap.xml | 9 - scripts/__tests__/prebuild.test.ts | 7 +- scripts/prebuild.ts | 9 +- src/components/DeclarationAccessibilite.tsx | 4 +- src/components/StatTile.stories.tsx | 2 +- src/components/StatTile.tsx | 7 +- src/pages/404.tsx | 29 +- src/pages/500.tsx | 44 + src/pages/_app.tsx | 70 +- src/pages/_document.tsx | 9 +- src/pages/article.mdx | 44 + src/pages/budget.tsx | 81 + src/pages/index.tsx | 164 +- src/pages/mentions-legales.tsx | 16 +- src/pages/mui.tsx | 2 +- src/pages/politique-confidentialite.tsx | 87 +- src/pages/sos.tsx | 22 + yarn.lock | 4983 ++++++++++++----- 41 files changed, 4290 insertions(+), 1786 deletions(-) delete mode 100644 .github/workflows/deactivate.yaml delete mode 100644 .github/workflows/debug-kube.yaml rename .github/workflows/{storybook.yml => deploy.yml} (51%) delete mode 100644 .github/workflows/preproduction.yaml delete mode 100644 .github/workflows/production.yaml delete mode 100644 .github/workflows/review-auto.yaml delete mode 100644 .github/workflows/review.yaml delete mode 100644 csp.config.js create mode 100644 csp.config.mjs create mode 100644 mdx-components.tsx rename next.config.js => next.config.mjs (52%) delete mode 100644 public/sitemap.xml create mode 100644 src/pages/500.tsx create mode 100644 src/pages/article.mdx create mode 100644 src/pages/budget.tsx create mode 100644 src/pages/sos.tsx diff --git a/.env.development b/.env.development index 006ab845..fe9f04d5 100644 --- a/.env.development +++ b/.env.development @@ -1,7 +1,7 @@ NEXT_TELEMETRY_DISABLED=1 NEXT_PUBLIC_SITE_URL="" -NEXT_PUBLIC_SENTRY_DSN="https://67a92c8c0f70486d9f36f2352eff1d19@sentry.fabrique.social.gouv.fr/68" +NEXT_PUBLIC_SENTRY_DSN="https://xxx/yy" NEXT_PUBLIC_SENTRY_ENV="dev" NEXT_PUBLIC_MATOMO_URL="" NEXT_PUBLIC_MATOMO_SITE_ID="" -NEXT_PUBLIC_APP_REPOSITORY_URL="https://github.com/SocialGouv/template" \ No newline at end of file +NEXT_PUBLIC_APP_REPOSITORY_URL="https://github.com/betagouv/template" \ No newline at end of file diff --git a/.env.production b/.env.production index f655a790..708f9cc2 100644 --- a/.env.production +++ b/.env.production @@ -1,7 +1,8 @@ NEXT_TELEMETRY_DISABLED=1 -NEXT_PUBLIC_SITE_URL="https://template.fabrique.social.gouv.fr/" -NEXT_PUBLIC_SENTRY_DSN="https://67a92c8c0f70486d9f36f2352eff1d19@sentry.fabrique.social.gouv.fr/68" +NEXT_PUBLIC_SITE_URL="https://template.beta.gouv.fr/" +NEXT_PUBLIC_SENTRY_DSN="https://xxx/yy" NEXT_PUBLIC_SENTRY_ENV="production" -NEXT_PUBLIC_MATOMO_URL="https://matomo.fabrique.social.gouv.fr" +NEXT_PUBLIC_MATOMO_URL="https:/stats.beta.gouv.fr" NEXT_PUBLIC_MATOMO_SITE_ID=63 -NEXT_PUBLIC_APP_REPOSITORY_URL="https://github.com/SocialGouv/template" \ No newline at end of file +NEXT_PUBLIC_APP_REPOSITORY_URL="https://github.com/betagouv/template" +PRODUCTION=true \ No newline at end of file diff --git a/.env.staging b/.env.staging index 5fefb033..a4c7242d 100644 --- a/.env.staging +++ b/.env.staging @@ -1,7 +1,7 @@ NEXT_TELEMETRY_DISABLED=1 -NEXT_PUBLIC_SITE_URL="https://template.fabrique.social.gouv.fr/" -NEXT_PUBLIC_SENTRY_DSN="https://67a92c8c0f70486d9f36f2352eff1d19@sentry.fabrique.social.gouv.fr/68" -NEXT_PUBLIC_SENTRY_ENV="development" +NEXT_PUBLIC_SITE_URL="https://template.incubateur.net/" +NEXT_PUBLIC_SENTRY_DSN="https://xxx/yy" +NEXT_PUBLIC_SENTRY_ENV="staging" NEXT_PUBLIC_MATOMO_URL="" NEXT_PUBLIC_MATOMO_SITE_ID="" -NEXT_PUBLIC_APP_REPOSITORY_URL="https://github.com/SocialGouv/template" \ No newline at end of file +NEXT_PUBLIC_APP_REPOSITORY_URL="https://github.com/betagouv/template" \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index 80500b47..0e0a9f18 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,5 +3,6 @@ "next/core-web-vitals", "plugin:storybook/recommended", "plugin:jsx-a11y/recommended" - ] + ], + "rules": { "react/no-unescaped-entities": "warn" } } diff --git a/.github/workflows/deactivate.yaml b/.github/workflows/deactivate.yaml deleted file mode 100644 index 9f6e3e23..00000000 --- a/.github/workflows/deactivate.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: ♻️ Deactivate -on: - pull_request: - types: [closed] - delete: - branches: - - "**" - - "!v*" - - "!master" - - "!main" - - "!dev" - - "!develop" - - "!**/persist" - - "!persist/**" - - "!**/persist/**" - - "!persist-**" - - "!**-persist" - - "!**-persist-**" - -jobs: - socialgouv: - uses: socialgouv/workflows/.github/workflows/use-ks-gh-deactivate.yaml@v1 - secrets: inherit diff --git a/.github/workflows/debug-kube.yaml b/.github/workflows/debug-kube.yaml deleted file mode 100644 index e1716539..00000000 --- a/.github/workflows/debug-kube.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Debug kube - -on: - workflow_dispatch: - push: - branches: - - "feat/**" - - "fix/**" - - -jobs: - dump: - name: Debug kube - runs-on: ubuntu-latest - steps: - - uses: azure/setup-kubectl@v3 - - name: extract kubeconfig - run: | - echo -n "${{secrets.KUBECONFIG}}" | base64 --decode > kubeconfig - - name: list kube data - run: | - KUBECONFIG=./kubeconfig kubectl config get-contexts \ No newline at end of file diff --git a/.github/workflows/storybook.yml b/.github/workflows/deploy.yml similarity index 51% rename from .github/workflows/storybook.yml rename to .github/workflows/deploy.yml index 964220df..717bb1b7 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/deploy.yml @@ -1,16 +1,16 @@ -name: Storybook +name: Deploy demo on: push: - branches: [main] + branches: [main, next] concurrency: cancel-in-progress: true - group: storybook-${{ github.ref }} + group: deploy-${{ github.ref }} jobs: - storybook: - name: Deployment storybook on gh-pages + build: + name: Deployment demo on gh-pages runs-on: ubuntu-latest steps: - name: Checkout repository @@ -26,9 +26,14 @@ jobs: run: | yarn --immutable - - name: Deploy + - name: Build run: | - git remote set-url origin https://git:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git - yarn storybook:deploy:action - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + yarn build + touch out/.nojekyll + + # deploy build to gh-pages + - name: Deploy 🚀 + uses: JamesIves/github-pages-deploy-action@4.1.9 + with: + branch: gh-pages + folder: out diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index d843041b..251f59fa 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -17,10 +17,6 @@ jobs: uses: cypress-io/github-action@v5 with: build: yarn build - start: yarn start + start: npx serve@latest out component: false install-command: yarn --immutable - env: - NEXTAUTH_URL: "http://keycloak:3000" - NEXTAUTH_SECRET: "A+EQqudlGhqTLDnBbCvohHBfbhUjTXAbZYy1NKsSsys=" - NEXT_PUBLIC_HASURA_GRAPHQL_ENDPOINT_URL: "http://hasura:8082/v1/graphql" diff --git a/.github/workflows/preproduction.yaml b/.github/workflows/preproduction.yaml deleted file mode 100644 index c0028bf1..00000000 --- a/.github/workflows/preproduction.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: 😎 PreProd -on: - workflow_dispatch: - push: - branches: - - "master" - - "main" - tags-ignore: - - v* - -concurrency: - cancel-in-progress: true - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.ref }} - -jobs: - socialgouv: - name: "🇫🇷 SocialGouv" - uses: socialgouv/workflows/.github/workflows/use-ks-gh-preproduction.yaml@v1 - secrets: inherit diff --git a/.github/workflows/production.yaml b/.github/workflows/production.yaml deleted file mode 100644 index 3cae2d52..00000000 --- a/.github/workflows/production.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: 🚀 Production -on: - workflow_dispatch: - push: - tags: - - v* - -concurrency: - cancel-in-progress: true - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.ref }} - -jobs: - socialgouv: - name: "🇫🇷 SocialGouv" - uses: socialgouv/workflows/.github/workflows/use-ks-gh-production.yaml@v1 - secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1cae45ba..74f5d981 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,4 @@ jobs: steps: - uses: socialgouv/workflows/actions/semantic-release@v1 with: - github-token: ${{ secrets.SOCIALGROOVYBOT_BOTO_PAT }} - author-name: ${{ secrets.SOCIALGROOVYBOT_NAME }} - author-email: ${{ secrets.SOCIALGROOVYBOT_EMAIL }} + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/review-auto.yaml b/.github/workflows/review-auto.yaml deleted file mode 100644 index 548cf4e0..00000000 --- a/.github/workflows/review-auto.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: 👓 Review Auto -on: - push: - branches: - - "feat/**" - - "fix/**" - -concurrency: - cancel-in-progress: true - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.ref }} - -jobs: - socialgouv: - name: "🇫🇷 SocialGouv" - uses: socialgouv/workflows/.github/workflows/use-ks-gh-review-auto.yaml@v1 - secrets: inherit diff --git a/.github/workflows/review.yaml b/.github/workflows/review.yaml deleted file mode 100644 index 2f78e3e0..00000000 --- a/.github/workflows/review.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: 👀 Review -on: - push: - branches: - - "**" - - "!master" - - "!main" - - "!feat/**" - - "!fix/**" - -concurrency: - cancel-in-progress: true - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.ref }} - -jobs: - socialgouv: - name: "🇫🇷 SocialGouv" - uses: socialgouv/workflows/.github/workflows/use-ks-gh-review.yaml@v1 - secrets: inherit \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit index a62504ec..e42620d9 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,6 @@ #!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -yarn lint-staged -exec < /dev/tty; yarn node-talisman --githook pre-commit -i +if sh -c ': >/dev/tty' >/dev/null 2>/dev/null; then + exec ⚠️ Le [Système de Design de l'État](https://www.systeme-de-design.gouv.fr/) s'adresse **uniquement** aux développeurs et aux concepteurs, qu'ils soient agents publics ou prestataires pour des sites Internet de l'État (Ministères, Administrations centrales, Préfectures, Ambassades, etc.). cf [conditions d'utilisation](https://www.systeme-de-design.gouv.fr/utilisation-et-organisation/perimetre-d-application). @@ -31,13 +30,6 @@ Template minimal de la [Fabrique des ministères sociaux](https://www.fabrique.s - Healthz - Page 404 -#### En plus dans la branche `hasura` : - -- Page d'authentification -- Page d'inscription -- Page profil -- Interactions avec la base de données - ### D'un point de vue technique - [storybook](https://storybook.js.org/) permettant de réaliser des stories pour les composants @@ -53,20 +45,12 @@ Template minimal de la [Fabrique des ministères sociaux](https://www.fabrique.s - intégration de [sentry](https://sentry.io/) pour gérer les erreurs - intégration de [matomo](https://matomo.org/) pour les statistiques d'utilisation -#### En plus dans la branche `hasura` : - -- [keycloak](https://www.keycloak.org/) qui est un serveur d'authentification (exclusive à `main`) -- [next-auth](https://next-auth.js.org/) qui est un wrapper pour gérer l'authentification au sein de l'application (exclusive à `main`) -- [hasura](https://hasura.io) qui permet d'exposer une API GraphQL sur votre Postgres et de gérer les authorisations (RBAC) - ## Lancer le code Après avoir cloné le projet : ### Développement -:warning: Avant de lancer le projet, vous devez installer `gomplate` - ```bash yarn # to install dependencies yarn dev # to run in dev mode @@ -82,72 +66,6 @@ Le fichier `.env.development` est utilisé pour l'environnement de développemen :warning: Les variables d'environnement sont publiques (utilisées durant le build), ne commitez donc pas de variables privées dans ces fichiers. -#### Variables d'env - -cf .env.development - -en production, les secrets sont chiffrés dans GIT avec sealed-secrets. - -### Branche `Hasura` - -Cette branche propose des composants backends de référence. - ---- - -```mermaid -graph LR -Browser{Browser}-->|JWT|Frontend[Frontend/API Next.js] -Browser-->KeyCloak -Frontend-->|JWT|Hasura -KeyCloak-->PG1[PostgreSQL] -KeyCloak-->|JWT|Browser -Hasura-->|RBAC|PG2[PostgreSQL] -KeyCloak-->FranceConnect -``` - ---- - -Lancer les serveurs Postgres, hasura et keycloak avec `docker-compose up`. - -##### Hasura - -Lancer les seeds : - -```sh -yarn hasura seed apply --file books.sql --project ./hasura --database-name default --endpoint http://127.0.0.1:8082 --admin-secret myadminsecretkey -``` - -Mettre à jour les metadatas et migrations : - -Lancer la console avec `yarn hasura console --project ./hasura --endpoint http://127.0.0.1:8082 --admin-secret myadminsecretkey`. Les modifs faites dans l'UI seront reportées dans les dossiers `hasura/metadata` et `hasura/migrations` - -Cf [migrations documentation](https://hasura.io/docs/latest/migrations-metadata-seeds/manage-migrations/) - -##### KeyCloak - -Le template intègre [Next-auth](https://next-auth.js.org/) et [KeyCloak 20](https://www.keycloak.org/) qui assure tous les workflows d'authentification. - -Le `realm` par défaut est dans [.kontinuous/files/realm-export.json](.kontinuous/files/realm-export.json). Pour générer realm utilisable par `docker-compose` à partir de celui-ci, utilisez `yarn keycloak`. - -Le thème keycloak est basé sur le design-système de l'état, cf [keycloak de sill-web](https://github.com/codegouvfr/sill-web/tree/main/src/keycloak-theme). - -##### FranceConnect - -Cf https://partenaires.franceconnect.gouv.fr/fcp/fournisseur-service - -Dans les URLs de callback définies [sur le compte FranceConnect](), utiliser `https://[votre-hostname]/realms/app-realm/broker/franceconnect-particulier/endpoint` et `https://[votre-hostname]/realms/app-realm/broker/franceconnect-particulier/endpoint/logout_response`. - -## Déploiement sur kubernetes - -Template utilise [kontinuous](https://github.com/socialgouv/kontinuous) pour définir et déployer ses ressources kubernetes. - -Lancer `npx kontinuous build --env dev -o` pour obtenir les manifests de votre environment (`dev`, `preprod` ou `prod`). - -La version dev est déployée sur OVH. - ## Liens -- : Version en production du projet -- : Storybook liés à la branche principale du projet -- : Thème keycloak-DSFR -- : Documentation technique SocialGouv +- : Version initiale du template diff --git a/csp.config.js b/csp.config.js deleted file mode 100644 index 8e210017..00000000 --- a/csp.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const ContentSecurityPolicy = ` - default-src 'self' *.fabrique.social.gouv.fr; - img-src 'self' data: *.fabrique.social.gouv.fr https://dummyimage.com/; - script-src 'self' *.fabrique.social.gouv.fr ${ - process.env.NODE_ENV !== "production" && "'unsafe-eval' 'unsafe-inline'" - }; - frame-src 'self' *.fabrique.social.gouv.fr; - style-src 'self' 'unsafe-inline'; - font-src 'self' data: blob:; -`; - -module.exports = ContentSecurityPolicy; diff --git a/csp.config.mjs b/csp.config.mjs new file mode 100644 index 00000000..365db907 --- /dev/null +++ b/csp.config.mjs @@ -0,0 +1,12 @@ +const ContentSecurityPolicy = ` + default-src 'self' *.gouv.fr; + img-src 'self' data: *.gouv.fr; + script-src 'self' *.gouv.fr ${ + process.env.NODE_ENV !== "production" && "'unsafe-eval' 'unsafe-inline'" + }; + frame-src 'self' *.gouv.fr; + style-src 'self' 'unsafe-inline'; + font-src 'self' data: blob:; +`; + +export default ContentSecurityPolicy; diff --git a/cypress.json b/cypress.json index 17ef242e..968e628c 100644 --- a/cypress.json +++ b/cypress.json @@ -1,3 +1,5 @@ { - "baseUrl": "http://localhost:3000" + "baseUrl": "http://localhost:3000", + "defaultCommandTimeout": 10000, + "requestTimeout": 10000 } diff --git a/cypress/integration/home.spec.ts b/cypress/integration/home.spec.ts index 5828d669..f96fae72 100644 --- a/cypress/integration/home.spec.ts +++ b/cypress/integration/home.spec.ts @@ -1,13 +1,7 @@ describe("Home page", () => { it("should render the main page", () => { cy.visit("http://localhost:3000/"); - cy.title().should( - "equal", - "Template | Fabrique numérique des ministères sociaux" - ); - cy.get("h1").should( - "contain", - "Template de la fabrique des ministères sociaux" - ); + cy.title().should("equal", "Template | beta.gouv.fr"); + cy.get("h1").should("contain", "Template"); }); }); diff --git a/mdx-components.tsx b/mdx-components.tsx new file mode 100644 index 00000000..766f28de --- /dev/null +++ b/mdx-components.tsx @@ -0,0 +1,63 @@ +import type { MDXComponents } from "mdx/types"; +import Image, { ImageProps } from "next/image"; +import Link from "next/link"; + +import { CallOut } from "@codegouvfr/react-dsfr/CallOut"; +import { Table } from "@codegouvfr/react-dsfr/Table"; +import { fr } from "@codegouvfr/react-dsfr"; + +// customize how MDX components are rendered - use DSFR components when possible +export function useMDXComponents(components: MDXComponents): MDXComponents { + return { + h1: ({ children }) =>

{children}

, + h2: ({ children }) => ( +

{children}

+ ), + h3: ({ children }) => ( +

{children}

+ ), + h4: ({ children }) => ( +

{children}

+ ), + // @ts-ignore + table: (props) => { + if ( + props.children && + Array.isArray(props.children) && + props.children.length === 2 + ) { + const [head, body] = props.children; + const headers = head.props.children.props.children.map( + (child: any) => child.props.children + ); + const data = body.props.children.map((row: any) => + row.props.children.map((cell: any) => cell.props.children) + ); + return ; + } + return
; + }, + a: (props) => { + if ( + props.href && + (props.href?.startsWith("http") || props.href?.startsWith("//")) + ) { + //@ts-ignore + return ; + } + //@ts-ignore + return ; + }, + blockquote: (props) => { + if ( + props.children && + Array.isArray(props.children) && + props.children.length === 3 + ) { + return {props.children[1].props.children}; + } + return {props.children}; + }, + ...components, + }; +} diff --git a/next.config.js b/next.config.mjs similarity index 52% rename from next.config.js rename to next.config.mjs index e52b33cb..12c8153e 100644 --- a/next.config.js +++ b/next.config.mjs @@ -1,13 +1,26 @@ -const { withSentryConfig } = require("@sentry/nextjs"); +import { withSentryConfig } from "@sentry/nextjs"; +import createMDX from "@next/mdx"; +import remarkGfm from "remark-gfm"; +import ContentSecurityPolicy from "./csp.config.mjs"; -const { version } = require("./package.json"); +import pkg from "./package.json" assert { type: "json" }; -const ContentSecurityPolicy = require("./csp.config"); +const withMDX = createMDX({ + options: { + remarkPlugins: [remarkGfm], + rehypePlugins: [], + }, +}); + +const version = pkg.version; /** @type {import('next').NextConfig} */ const moduleExports = { + basePath: "/template", + pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"], reactStrictMode: true, swcMinify: true, + output: "export", webpack: (config) => { config.module.rules.push({ test: /\.(woff2|webmanifest)$/, @@ -28,6 +41,6 @@ const moduleExports = { transpilePackages: ["@codegouvfr/react-dsfr", "tss-react"], }; -module.exports = { - ...withSentryConfig(moduleExports, { silent: true }), +export default { + ...withMDX(withSentryConfig(moduleExports, { silent: true })), }; diff --git a/package.json b/package.json index 6bb14ffd..2e05033b 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@socialgouv/template", + "name": "@betagouv/template", "version": "1.15.8", "private": true, "engines": { @@ -25,8 +25,6 @@ "test:e2e:headless": "start-server-and-test dev http://localhost:3000 e2e:headless", "storybook:start": "storybook dev --docs -p 6006", "storybook:build": "yarn build-storybook -c .storybook -o .out", - "storybook:deploy": "npm run storybook:build && gh-pages -d .out", - "storybook:deploy:action": "npm run storybook:build && gh-pages -d .out -u \"github-actions-bot \"", "type-check": "tsc --noEmit", "type-check:watch": "npm run type-check -- --watch", "postinstall": "is-ci || husky install", @@ -34,54 +32,58 @@ "build-storybook": "storybook build" }, "dependencies": { - "@codegouvfr/react-dsfr": "^0.76.0", - "@emotion/react": "^11.11.1", + "@codegouvfr/react-dsfr": "^1.9.1", + "@emotion/react": "^11.11.4", "@emotion/server": "^11.11.0", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.1", - "@mui/material": "^5.14.1", - "@mui/x-data-grid": "^5.17.16", + "@mdx-js/loader": "^3.0.1", + "@mdx-js/react": "^3.0.1", + "@mui/icons-material": "^5.15.12", + "@mui/material": "^5.15.12", + "@mui/x-data-grid": "^5.17.26", "@mui/x-date-pickers": "^5.0.11", - "@sentry/nextjs": "^7.60.0", - "@socialgouv/matomo-next": "^1.6.1", - "next": "13.5.6", + "@next/mdx": "^14.1.3", + "@sentry/nextjs": "^7.106.0", + "@socialgouv/matomo-next": "^1.8.1", + "@types/mdx": "^2.0.11", + "next": "14.1.3", "react": "18.2.0", "react-dom": "18.2.0", - "tss-react": "^4.8.8" + "remark-gfm": "^4.0.0", + "tss-react": "^4.9.4" }, "devDependencies": { - "@babel/core": "^7.22.9", - "@storybook/addon-actions": "^7.6.8", - "@storybook/addon-docs": "^7.6.8", - "@storybook/addon-essentials": "^7.6.8", - "@storybook/addon-interactions": "^7.6.8", - "@storybook/addon-links": "^7.6.8", - "@storybook/addon-onboarding": "^1.0.10", - "@storybook/blocks": "^7.6.8", - "@storybook/nextjs": "^7.6.8", - "@storybook/test": "^7.6.8", + "@babel/core": "^7.24.0", + "@storybook/addon-actions": "^7.6.17", + "@storybook/addon-docs": "^7.6.17", + "@storybook/addon-essentials": "^7.6.17", + "@storybook/addon-interactions": "^7.6.17", + "@storybook/addon-links": "^7.6.17", + "@storybook/addon-onboarding": "^1.0.11", + "@storybook/blocks": "^7.6.17", + "@storybook/nextjs": "^7.6.17", + "@storybook/test": "^7.6.17", "@storybook/testing-library": "^0.2.2", - "@swc-node/register": "^1.6.6", - "@swc/core": "^1.3.70", + "@swc-node/register": "^1.9.0", + "@swc/core": "^1.4.6", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^12.1.2", - "@types/node": "18.19.3", - "@types/react": "18.2.45", - "@types/react-dom": "18.2.17", + "@types/node": "20.11.25", + "@types/react": "18.2.64", + "@types/react-dom": "18.2.21", "cypress": "^9.4.1", - "eslint": "8.55.0", - "eslint-config-next": "13.5.6", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-storybook": "^0.6.15", - "gh-pages": "^5.0.0", - "husky": "^8.0.3", + "eslint": "8.57.0", + "eslint-config-next": "14.1.3", + "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-storybook": "^0.8.0", + "husky": "^9.0.11", "is-ci": "^3.0.1", - "jest": "^29.6.1", - "jest-environment-jsdom": "^29.6.1", - "lint-staged": "^13.2.3", - "node-talisman": "^1.29.10", - "start-server-and-test": "^1.14.0", - "storybook": "^7.6.8", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "lint-staged": "^15.2.2", + "node-talisman": "^1.29.11", + "start-server-and-test": "^2.0.3", + "storybook": "^7.6.17", "storybook-dark-mode": "^3.0.3", "typescript": "4.9.5" }, diff --git a/public/sitemap.xml b/public/sitemap.xml deleted file mode 100644 index 8271747b..00000000 --- a/public/sitemap.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - https://template.fabrique.social.gouv.fr - daily - 1 - 2021-12-25T10:22:17.507Z - - \ No newline at end of file diff --git a/scripts/__tests__/prebuild.test.ts b/scripts/__tests__/prebuild.test.ts index bda6723a..60800f9b 100644 --- a/scripts/__tests__/prebuild.test.ts +++ b/scripts/__tests__/prebuild.test.ts @@ -9,12 +9,7 @@ describe("robots.txt", () => { }); it("should generate production robots.txt", () => { const host = "localhost"; - const robotsProd = [ - "User-agent: *", - "Allow: /", - "", - `Sitemap: https://${host}/sitemap.xml`, - ].join("\n"); + const robotsProd = ["User-agent: *", "Allow: /"].join("\n"); generateRobotsTxt(true, host); expect(fs.writeFileSync).toHaveBeenCalledWith(filePath, robotsProd); }); diff --git a/scripts/prebuild.ts b/scripts/prebuild.ts index 98a31fcb..0afc78cb 100644 --- a/scripts/prebuild.ts +++ b/scripts/prebuild.ts @@ -5,12 +5,7 @@ export const filePath = path.join(__dirname, "../public/robots.txt"); export const generateRobotsTxt = (isOnProduction: boolean, host: string) => { const robotsDev = ["User-agent: *", "Disallow: /"].join("\n"); - const robotsProd = [ - "User-agent: *", - "Allow: /", - "", - `Sitemap: https://${host}/sitemap.xml`, - ].join("\n"); + const robotsProd = ["User-agent: *", "Allow: /"].join("\n"); const robot = isOnProduction ? robotsProd : robotsDev; @@ -22,7 +17,7 @@ const run = () => { process.env.PRODUCTION ? true : false, process.env.NEXT_PUBLIC_SITE_URL ?? "localhost" ); - console.log("Robots.txt generated"); + console.log(`Robots.txt generated, production:${!!process.env.PRODUCTION}`); }; run(); diff --git a/src/components/DeclarationAccessibilite.tsx b/src/components/DeclarationAccessibilite.tsx index c9e46cdc..bbbd196b 100644 --- a/src/components/DeclarationAccessibilite.tsx +++ b/src/components/DeclarationAccessibilite.tsx @@ -1,10 +1,10 @@ export const DeclarationAccessibilite = ({ produit = "[PRODUIT]", - organisme = "Fabrique numérique des ministères sociaux", + organisme = "[SPONSOR]", date = "9 décembre 2021", conformite = "non conforme", audited = false, - email = "contact@fabrique.social.gouv.fr", + email = "contact@xxx.fr", }) => { return (
diff --git a/src/components/StatTile.stories.tsx b/src/components/StatTile.stories.tsx index 1274a8ca..3e24546e 100644 --- a/src/components/StatTile.stories.tsx +++ b/src/components/StatTile.stories.tsx @@ -14,7 +14,7 @@ const Template: ComponentStory = (args) => ( export const Default = Template.bind({}); Default.args = { title: "Nombre de visites", - stats: "1.000.000", + stats: "100.000", }; export const WithDescription = Template.bind({}); diff --git a/src/components/StatTile.tsx b/src/components/StatTile.tsx index 481372c8..9d095b56 100644 --- a/src/components/StatTile.tsx +++ b/src/components/StatTile.tsx @@ -11,7 +11,12 @@ export const StatTile = (props: StatTileProps): JSX.Element => {
- {props.stats} + + {props.stats} +

{props.title}

{props.description && (
diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 61321253..b9645833 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,4 +1,6 @@ import type { NextPage } from "next"; +import Link from "next/link"; + import * as Sentry from "@sentry/nextjs"; import { useEffect } from "react"; import { push } from "@socialgouv/matomo-next"; @@ -10,8 +12,31 @@ const NotFound: NextPage = () => { }, []); return ( -
-

404 - Page non trouvée

+
+
+
+
+

+ Erreur 404 +

+

+ La page n'a pas été trouvée +

+

+ Impossible de trouver la ressource demandée. +
+ Ré-essayez en passant par la Page d'accueil. +

+
+
+ +
+
+
); }; diff --git a/src/pages/500.tsx b/src/pages/500.tsx new file mode 100644 index 00000000..129a2ea1 --- /dev/null +++ b/src/pages/500.tsx @@ -0,0 +1,44 @@ +import type { NextPage } from "next"; +import Link from "next/link"; +import * as Sentry from "@sentry/nextjs"; +import { useEffect } from "react"; +import { push } from "@socialgouv/matomo-next"; + +const Error500: NextPage = () => { + useEffect(() => { + Sentry.captureMessage("Error500"); + push(["trackEvent", "500", "Error500"]); + }, []); + + return ( +
+
+
+
+

+ Erreur 500 +

+

+ Un erreur s'est produite lors de l'execution de la page +

+

+ Nos équipes ont été notifiées et interviendront dans les meilleurs + délais. +
+ Ré-essayez en passant par la Page d'accueil. +

+
+
+ +
+
+
+
+ ); +}; + +export default Error500; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index daddf7a7..2007c109 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -5,14 +5,16 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { createEmotionSsrAdvancedApproach } from "tss-react/next"; +import { useStyles } from "tss-react/dsfr"; import { createNextDsfrIntegrationApi } from "@codegouvfr/react-dsfr/next-pagesdir"; import { Footer } from "@codegouvfr/react-dsfr/Footer"; import { fr } from "@codegouvfr/react-dsfr"; import { Header } from "@codegouvfr/react-dsfr/Header"; import { headerFooterDisplayItem } from "@codegouvfr/react-dsfr/Display"; -import { init } from "@socialgouv/matomo-next"; +import { SkipLinks } from "@codegouvfr/react-dsfr/SkipLinks"; import { MuiDsfrThemeProvider } from "@codegouvfr/react-dsfr/mui"; -import { useStyles } from "tss-react/dsfr"; + +import { init } from "@socialgouv/matomo-next"; declare module "@codegouvfr/react-dsfr/next-pagesdir" { interface RegisterLink { @@ -50,12 +52,14 @@ const { withDsfr, dsfrDocumentApi } = createNextDsfrIntegrationApi({ ], }); -const { augmentDocumentWithEmotionCache, withAppEmotionCache } = +export { dsfrDocumentApi }; + +const { withAppEmotionCache, augmentDocumentWithEmotionCache } = createEmotionSsrAdvancedApproach({ key: "css", }); -export { dsfrDocumentApi, augmentDocumentWithEmotionCache }; +export { augmentDocumentWithEmotionCache }; const brandTop = ( <> @@ -68,7 +72,7 @@ const brandTop = ( const homeLinkPops = { href: "/", title: - "Accueil - Nom de l’entité (ministère, secrétariat d‘état, gouvernement)", + "Accueil - Nom de l’entité (ministère, secrétariat d'état, gouvernement)", }; const bottomLinks = [ @@ -84,12 +88,24 @@ const bottomLinks = [ href: "/stats", }, }, + { + text: "Budget", + linkProps: { + href: "/budget", + }, + }, { text: "Politique de confidentialité", linkProps: { href: "/politique-confidentialite", }, }, + { + text: "SOS", + linkProps: { + href: "/sos", + }, + }, { text: "Contribuer sur GitHub", linkProps: { @@ -112,7 +128,7 @@ const Layout = ({ children }: { children: ReactNode }) => { return ( - Template | Fabrique numérique des ministères sociaux + Template | beta.gouv.fr {contentSecurityPolicy && ( { > )} - + +
{ }, isActive: router.asPath === "/mui", }, + { + text: "Article", + linkProps: { + href: "/article", + }, + isActive: router.asPath === "/article", + }, ]} quickAccessItems={[headerFooterDisplayItem]} />
{children}
@@ -201,6 +232,7 @@ function App({ Component, pageProps }: AppProps) { }} > + {/*@ts-ignore*/}
diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index 793819a1..ea68d013 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -6,14 +6,7 @@ const { getColorSchemeHtmlAttributes, augmentDocumentForDsfr } = export default function Document(props: DocumentProps) { return ( - +
diff --git a/src/pages/article.mdx b/src/pages/article.mdx new file mode 100644 index 00000000..6cedea5a --- /dev/null +++ b/src/pages/article.mdx @@ -0,0 +1,44 @@ +import { Alert } from '@codegouvfr/react-dsfr/Alert' + +# Page au format Markdown(X) + +C'est du texte, que l'on peut enrichir avec des composants, donc éditer facilement. [voir la source de cette page](https://github.com/betagouv/template/blob/main/src/pages/article.tsx) + +## Du texte + +En travaillant _ensemble_, nous pouvons construire des solutions plus solides, sécurisées et innovantes que ce qu'une seule personne ne pourrait réaliser seule. **Notre communauté est généreuse et expérimentée, n'hésitez pas à participer !** + +Vous pouvez **participer aux projets open source**, que ce soit en soumettant des rapports de bugs, en écrivant du code, de la documentation, en testant des fonctionnalités ou simplement en partageant vos idées et votre expertise avec les autres. + +🚀 Ensemble, nous pouvons rendre le web meilleur pour tous et toutes ! + +## Un composant du DSFR + +[Voir tous les composants de @codegouv/react-dsfr](https://components.react-dsfr.codegouv.studio/) + + + +## Un tableau + +| Tables | Are | Cool | +| -------- | --- | ------- | +| col 1 is | 👌 | $1600 | +| col 2 is | 🆗 | $12 | +| col 3 is | 🙀 | **$42** | + +## Une image + +![artwork](https://beta.gouv.fr/assets/home/design.svg) + +## Citation + +> exemple de citation + +## Liens + +- [Lien interne](/dsfr) +- [Lien externe](https://beta.gouv.fr) diff --git a/src/pages/budget.tsx b/src/pages/budget.tsx new file mode 100644 index 00000000..1fde3f40 --- /dev/null +++ b/src/pages/budget.tsx @@ -0,0 +1,81 @@ +import React from "react"; +import type { NextPage } from "next"; +import Head from "next/head"; +import Table from "@codegouvfr/react-dsfr/Table"; +import CallOut from "@codegouvfr/react-dsfr/CallOut"; + +const Budget: NextPage = () => ( +
+ + Budget + + +

Budget

+

+ + [xxx] + {" "} + est un service public numérique, c’est pourquoi nous sommes transparents + sur les ressources allouées et la manière dont elles sont employées. +

+

Principes

+

+ Nous suivons{" "} + le manifeste beta.gouv dont + nous rappelons les principes ici : +

+
+
    +
  • + Les besoins des utilisateurs sont prioritaires sur les besoins de + l’administration +
  • +
  • Le mode de gestion de l’équipe repose sur la confiance
  • +
  • + L’équipe adopte une approche itérative et d’amélioration en continu +
  • +
+
+

Budget consommé

+

Répartition des sources de financements :

+
+
    +
  • + 2021 : le projet est une experimentation financée à + 100% par + + [xxx] + + . +
  • +
  • + 2022 : [xxx] d’assurer le financement du projet. à + hauteur de[xxx] €. +
  • +
+
+

Répartition des dépenses effectuées :

+
+
+ + Contrairement aux entreprises du secteur privé, les administrations ne + peuvent pas récupérer la TVA supportée sur leurs achats dans le cadre de + leur activité. Le montant TTC inclut la TVA au taux de 20%. +
+ La TVA est collectée et reversée à l’État et diminue donc le montant du + budget utilisable sur le projet. +
+ +); + +export default Budget; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 3c8df563..5ca2c907 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,10 +1,13 @@ import * as React from "react"; import Head from "next/head"; import { NextPage } from "next"; +import Stack from "@mui/material/Stack"; + import { push as matomoPush } from "@socialgouv/matomo-next"; +import { Accordion } from "@codegouvfr/react-dsfr/Accordion"; import { Alert } from "@codegouvfr/react-dsfr/Alert"; import { Button } from "@codegouvfr/react-dsfr/Button"; -import Stack from "@mui/material/Stack"; +import { fr } from "@codegouvfr/react-dsfr"; const Home: NextPage = () => { const onClick1 = () => { @@ -14,44 +17,133 @@ const Home: NextPage = () => { return ( <> - Template | Fabrique numérique des ministères sociaux + Template | beta.gouv.fr - -
-
-

- Template - -

Template de la fabrique des ministères sociaux.

-
-

-

- Pariatur veniam ipsum pariatur elit ullamco sit quis ipsum ad veniam - proident sunt. Qui ut irure in quis reprehenderit. Laborum anim ad - laboris ipsum magna ullamco consequat ex consectetur. Duis sit - adipisicing ipsum occaecat commodo consequat officia ea. Cupidatat - fugiat reprehenderit aliqua eiusmod mollit Lorem consectetur. Minim - elit proident eu qui exercitation mollit id esse velit et dolore - velit laboris. Ipsum occaecat Lorem occaecat magna excepteur veniam - ullamco cupidatat irure incididunt velit nulla. -

-
-
- {/* eslint-disable-next-line jsx-a11y/img-redundant-alt*/} - {/* eslint-disable-next-line @next/next/no-img-element*/} - My description + +
+
+

Template

+ Ce template minimal en Next.js met en oeuvre les pratiques + recommandées chez betagouv et peut vous faire gagner du temps. +
+
+ Il permet de déployer rapidement une application web à l'état de + l'art, qui respecte nos standards de{" "} + conformité, accessibilité et sécurité. +
+
+ Vous pouvez vous en servir comme base de départ ou comme référence + d'implémentation.{" "} + + + Les contributions sont bienvenues. + + +
+
+ + Intègre la dernière version du kit{" "} + + @codegouvfr/react-dsfr + + . Compatible avec{" "} + + la librairie MUI + + .
+
+ Le template est livré 100% accessible. +
+ + Intègre le tracker matomo pour analyser l'usage du service. +
+
+ Le lien de désinscription réglementaire est intégré dans la + politique de confidentialité. +
+ + Intègre une sonde sentry pour être alerté en temps réel des erreurs + applicatives et monitorer les performances de votre service. + + + Des modèles pré-rédigés pour : +
    +
  • Déclaration d'accessibilité numérique
  • +
  • Conditions d'utilisation
  • +
  • Mentions légales
  • +
  • Politique de confidentialité
  • +
+
+ +
    +
  • Page de statistiques pour suivres les KPIs
  • +
  • Page de budget pour exposer son budget
  • +
  • Page SOS pour venir en aide aux usager(e)s
  • +
+
+ +
    +
  • Gestion des headers CSP
  • +
  • Image docker root-less
  • +
  • Pre-commit hooks anti fuite de secrets
  • +
+
+ +
    +
  • + Testing unitaire et de bout-en-bout intégré avec{" "} + + Cypress.io + +
  • +
  • + + Storybook + {" "} + pour tester/review les composants en isolation +
  • +
  • CI de lint, test et scan statique
  • +
+
+ +
    +
  • + Workflows de release automatisés ( + + semantic-release + + ) +
  • +
  • + Compatible scalingo, clever cloud avec des reviews-branches +
  • +
+
- + +

Exemples d'intégrations

+ diff --git a/src/pages/mentions-legales.tsx b/src/pages/mentions-legales.tsx index ffd9029c..f96dd824 100644 --- a/src/pages/mentions-legales.tsx +++ b/src/pages/mentions-legales.tsx @@ -19,13 +19,13 @@ const MentionsLegales: NextPage = () => {
- Tour Mirabeau
- 39-43 Quai André Citroën
- 75015 PARIS
- Téléphone: 01 40 56 60 00 + [XXX]
+ [XXX]
+ [XXX]
+ Téléphone: [XXX]
{ description="Ce site est hébergé par :" >

- Microsoft Azure
- 37 Quai du Président Roosevelt
- 92130 Issy-les-Moulineaux + [XXX]
+ [XXX]
+ [XXX]

{ }; return ( - + diff --git a/src/pages/politique-confidentialite.tsx b/src/pages/politique-confidentialite.tsx index 49365d13..075bf632 100644 --- a/src/pages/politique-confidentialite.tsx +++ b/src/pages/politique-confidentialite.tsx @@ -2,6 +2,7 @@ import React from "react"; import type { NextPage } from "next"; import Head from "next/head"; +import { Table } from "@codegouvfr/react-dsfr/Table"; import { Alert } from "@codegouvfr/react-dsfr/Alert"; const URL = [ @@ -42,22 +43,22 @@ const Confidentiality: NextPage = () => { éléments sont indispensables pour nous permettre de retrouver votre recherche - par voie électronique à l’adresse suivante :{" "} - template@fabrique.social.gouv.fr + contact@[produit].beta.gouv.fr
ou par voie postale :

- Direction des systèmes d’information + [XXX]
- Ministère des affaires sociales et de la santé + [XXX]
- 39-43 Quai André Citroën + [XXX]
- 75015 PARIS + [XXX]

Vous êtes également en droit de saisir la Commission Nationale de @@ -71,39 +72,10 @@ const Confidentiality: NextPage = () => { .

Hébergement

- {/* row.name} - data={[ - { - name: "Microsoft Azure", - country: "France", - treatment: "Hébergement", - urlName: "Déclaration de confidentialité Microsoft", - }, - ]} - columns={[ - { name: "name", label: "Partenaire" }, - { name: "country", label: "Pays destinataire" }, - { - name: "treatment", - label: "Traitement réalisé", - }, - { - name: "urlName", - label: "Garantie", - render: ({ urlName }: { urlName: string }) => ( - v.name === urlName)?.value} - > - {urlName} - - ), - }, - ]} - />*/} +

Cookies

Un cookie est un fichier déposé sur votre terminal lors de la visite @@ -115,30 +87,17 @@ const Confidentiality: NextPage = () => { Nous collectons donc des données par l’intermédiaire de dispositifs appelés “cookies” permettant d’établir des mesures statistiques.

- {/*
row.name} - data={[ - { - type: "Mesure d’audience anonymisée", - name: "Matomo", - months: "13 mois", - purpose: "Mesure d’audience", - editor: "Matomo & Fabrique numérique", - country: "France", - }, +
*/} + data={[["[XXX]", "[XXX]", "[XXX]", "[XXX]", "[XXX]"]]} + /> +

L’accès aux informations contenues dans les cookies est limité aux seules personnes autorisées au sein de la Fabrique numérique. En @@ -159,7 +118,7 @@ const Confidentiality: NextPage = () => {