From b2f8b2cb4fa699b76d99eb4279992c765a5bb23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Dr=C3=A9au?= Date: Thu, 31 Aug 2023 15:28:27 +0200 Subject: [PATCH] feat: ajout du filtre secteur professionnel (#3155) --- scripts/preventSensibleFilesCommit.sh | 1 + server/package.json | 6 +- server/scripts/extract-arborescence-rome.ts | 105 +++++++++ server/src/commands.ts | 18 ++ server/src/common/actions/helpers/filters.ts | 5 + server/src/common/model/@types/Effectif.ts | 3 + server/src/common/model/@types/Rncp.ts | 6 + server/src/common/model/collections.ts | 4 + .../model/effectifs.model/effectifs.model.ts | 4 + server/src/common/model/rncp.model.ts | 18 ++ .../effectifs/hydrate-effectifs-computed.ts | 12 + server/src/jobs/hydrate/hydrate-rncp-romes.ts | 100 ++++++++ server/src/jobs/jobs.ts | 3 + server/yarn.lock | 70 ++---- ui/modules/dashboard/SimpleOverlayMenu.tsx | 10 +- ui/modules/dashboard/icons.tsx | 8 + ui/modules/indicateurs/IndicateursForm.tsx | 16 +- .../FiltreFormationSecteurProfessionnel.tsx | 215 ++++++++++++++++++ .../arborescence-rome.ts | 54 +++++ ui/modules/models/effectifs-filters.ts | 4 + ui/package.json | 1 + ui/public/arborescence-rome-14-06-2021.json | 1 + ui/theme/components/checkbox.js | 11 + ui/yarn.lock | 5 + 24 files changed, 612 insertions(+), 68 deletions(-) create mode 100644 server/scripts/extract-arborescence-rome.ts create mode 100644 server/src/common/model/@types/Rncp.ts create mode 100644 server/src/common/model/rncp.model.ts create mode 100644 server/src/jobs/hydrate/hydrate-rncp-romes.ts create mode 100644 ui/modules/indicateurs/filters/FiltreFormationSecteurProfessionnel.tsx create mode 100644 ui/modules/indicateurs/filters/secteur-professionnel/arborescence-rome.ts create mode 100644 ui/public/arborescence-rome-14-06-2021.json diff --git a/scripts/preventSensibleFilesCommit.sh b/scripts/preventSensibleFilesCommit.sh index d0f7f141b..a671bfae6 100755 --- a/scripts/preventSensibleFilesCommit.sh +++ b/scripts/preventSensibleFilesCommit.sh @@ -10,6 +10,7 @@ exception="$exception|open-api.json" exception="$exception|server/src/jobs/hydrate/reference/bassins_emploi_communes.json" exception="$exception|eslintrc.json|app.json|jsconfig.json|tsconfig.json|rome.json" exception="$exception)$|^server/tests)" +exception="$exception|ui/public/arborescence-rome-14-06-2021.json" exception="$exception|ui/public/modele-import.xlsx" if grep -q vault ".infra/ansible/roles/setup/vars/main/vault.yml"; then diff --git a/server/package.json b/server/package.json index 8b824fa11..8bd88106a 100644 --- a/server/package.json +++ b/server/package.json @@ -26,6 +26,7 @@ "@supercharge/promise-pool": "2.4.0", "@types/boom": "7.3.2", "JSONStream": "^1.3.5", + "adm-zip": "^0.5.10", "arg": "5.0.1", "async": "3.2.3", "axios": "0.27.2", @@ -33,9 +34,9 @@ "axios-retry": "3.3.1", "body-parser": "1.20.0", "boom": "7.3.0", + "bson": "5.4.0", "bunyan": "1.8.15", "bunyan-prettystream": "0.1.3", - "bson": "5.4.0", "checksum-stream": "1.0.3", "clamscan": "2.1.2", "cli-progress": "3.11.0", @@ -52,6 +53,7 @@ "express": "4.18.1", "express-async-errors": "3.1.1", "express-list-endpoints": "^6.0.0", + "fast-xml-parser": "^4.2.7", "fs-extra": "10.1.0", "iconv-lite": "0.6.3", "joi": "17.6.0", @@ -94,7 +96,7 @@ "tsx": "3.12.6", "type-fest": "^3.10.0", "uuid": "8.3.2", - "xlsx": "0.18.5", + "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz", "zod": "3.21.4", "zod-express-middleware": "1.4.0", "zod-to-json-schema": "3.21.4" diff --git a/server/scripts/extract-arborescence-rome.ts b/server/scripts/extract-arborescence-rome.ts new file mode 100644 index 000000000..2623e7ee7 --- /dev/null +++ b/server/scripts/extract-arborescence-rome.ts @@ -0,0 +1,105 @@ +/* + Ce script construit l'arborescence des domaines et sous-domaines d'activité à partir du excel officiel téléchargeable + depuis la page https://www.pole-emploi.fr/employeur/vos-recrutements/le-rome-et-les-fiches-metiers.html + + Étapes : + - récupération du fichier https://www.pole-emploi.fr/files/live/sites/PE/files/ROME_ArboPrincipale.xlsx + - transformation en un arbre d'objets + - écriture dans un fichier arborescence-rome.json + + Puis prendre ce fichier et le mettre dans ui/public/arborescence-rome-14-06-2021.json +*/ +import { writeFileSync } from "fs"; + +import axios from "axios"; +import { read, utils } from "xlsx"; + +async function main() { + const res = await axios.get("https://www.pole-emploi.fr/files/live/sites/PE/files/ROME_ArboPrincipale.xlsx", { + responseType: "arraybuffer", + }); + if (res.status !== 200) { + throw new Error(`Invalid response status. Expected 200 but received ${res.status}`); + } + + const workbook = read(res.data); + const arboPrincipaleSheetName = workbook.SheetNames.find((name) => name.includes("Arbo Principale")); + if (!arboPrincipaleSheetName) { + throw new Error(`Onglet Arbo Principale non trouvée. Le fichier a sans doute changé de format.`); + } + console.log(`Données : ${arboPrincipaleSheetName}`); + const arboPrincipaleSheet = workbook.Sheets[arboPrincipaleSheetName]; + + const rawJsonData = utils + .sheet_to_json>( + arboPrincipaleSheet, + { + // exemple : A 11 01 Chauffeur / Chauffeuse de machines agricoles 11987 + header: ["familleMetier", "domaineProfessionnel", "numeroOrdre", "name", "codeOGR"], + } + ) + .slice(1); // removes the header + + const arborescenceRome = rawJsonData.reduce((acc, row) => { + // conditions ordonnées de la plus restrictive à la moins restrictive + if (row.codeOGR !== " ") { + // pas besoin des appellations de métiers + // acc[row.familleMetier].children[row.domaineProfessionnel].children[row.numeroOrdre].children[row.codeOGR] = { + // id: `${row.familleMetier}${row.domaineProfessionnel}${row.numeroOrdre}-${row.codeOGR}`, + // codeOGR: row.codeOGR, + // name: row.name, + // }; + } else if (row.numeroOrdre !== " ") { + acc[row.familleMetier].children[row.domaineProfessionnel].children[row.numeroOrdre] = { + id: `${row.familleMetier}${row.domaineProfessionnel}${row.numeroOrdre}`, + name: row.name, + // children: {}, + }; + } else if (row.domaineProfessionnel !== " ") { + acc[row.familleMetier].children[row.domaineProfessionnel] = { + id: `${row.familleMetier}${row.domaineProfessionnel}`, + name: row.name, + children: {}, + }; + } else { + acc[row.familleMetier] = { + id: row.familleMetier, + name: row.name, + children: {}, + }; + } + return acc; + }, {}); + + const famillesMetiers = Object.keys(arborescenceRome) + .sort() + .map((key) => { + const famille = arborescenceRome[key]; + return { + ...famille, + children: Object.keys(famille.children) + .sort() + .map((key) => { + const domaine = famille.children[key]; + return { + ...domaine, + children: Object.keys(domaine.children) + .sort() + .map((key) => domaine.children[key]), + }; + }), + }; + }); + + famillesMetiers.forEach((familleMetier) => addIdsToNames(familleMetier)); + + writeFileSync("arborescence-rome.json", Buffer.from(JSON.stringify(famillesMetiers), "utf8")); + console.log("Fichier créé : arborescence-rome.json"); +} + +function addIdsToNames(node: any) { + node.name = `${node.id} – ${node.name}`; + node.children?.forEach((node) => addIdsToNames(node)); +} + +main(); diff --git a/server/src/commands.ts b/server/src/commands.ts index a98f05efd..daa839d20 100644 --- a/server/src/commands.ts +++ b/server/src/commands.ts @@ -619,6 +619,24 @@ program } }); +program + .command("hydrate:rncp-romes") + .description("Remplissage du RNCP") + .option("-s, --sync", "Run job synchronously") + .action(async ({ sync }) => { + const exitCode = await addJob( + { + name: "hydrate:rncp-romes", + sync, + }, + { runningLogs: true } + ); + + if (exitCode) { + program.error("Command failed", { exitCode }); + } + }); + program .command("hydrate:organismes-formations") .description("Remplissage des formations des organismes") diff --git a/server/src/common/actions/helpers/filters.ts b/server/src/common/actions/helpers/filters.ts index 159c15f1c..03fe64d08 100644 --- a/server/src/common/actions/helpers/filters.ts +++ b/server/src/common/actions/helpers/filters.ts @@ -185,6 +185,7 @@ export const fullEffectifsFiltersSchema = { .optional(), formation_niveaux: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), formation_cfds: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), + formation_secteursProfessionnels: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), }; export type FullEffectifsFilters = z.infer>; @@ -245,6 +246,10 @@ export const fullEffectifsFiltersConfigurations: { matchKey: "formation.cfd", transformValue: (value) => ({ $in: value }), }, + formation_secteursProfessionnels: { + matchKey: "_computed.formation.codes_rome", + transformValue: (value) => ({ $in: value }), + }, }; export function buildMongoFilters< diff --git a/server/src/common/model/@types/Effectif.ts b/server/src/common/model/@types/Effectif.ts index 54b1fa00e..c9f397d48 100644 --- a/server/src/common/model/@types/Effectif.ts +++ b/server/src/common/model/@types/Effectif.ts @@ -1858,5 +1858,8 @@ export interface Effectif { */ fiable?: boolean; }; + formation?: { + codes_rome?: string[]; + }; }; } diff --git a/server/src/common/model/@types/Rncp.ts b/server/src/common/model/@types/Rncp.ts new file mode 100644 index 000000000..a8bf714b9 --- /dev/null +++ b/server/src/common/model/@types/Rncp.ts @@ -0,0 +1,6 @@ +// auto-generated by bson-schema-to-typescript + +export interface Rncp { + rncp: string; + romes: string[]; +} diff --git a/server/src/common/model/collections.ts b/server/src/common/model/collections.ts index a31d3d131..809aeec11 100644 --- a/server/src/common/model/collections.ts +++ b/server/src/common/model/collections.ts @@ -17,6 +17,7 @@ import { BassinsEmploi } from "./@types/BassinsEmploi"; import { EffectifsQueue } from "./@types/EffectifsQueue"; import { FormationsCatalogue } from "./@types/FormationsCatalogue"; import { OrganismeSoltea } from "./@types/OrganismeSoltea"; +import { Rncp } from "./@types/Rncp"; import { UaisAcceReferentiel } from "./@types/UaisAcceReferentiel.js"; import bassinsEmploiDescriptor from "./bassinsEmploi.model"; import effectifsModelDescriptor from "./effectifs.model/effectifs.model"; @@ -33,6 +34,7 @@ import organisationsModelDescriptor, { Organisation } from "./organisations.mode import OrganismesModelDescriptor from "./organismes.model"; import OrganismesReferentielModelDescriptor from "./organismesReferentiel.model"; import organismesSolteaModelDescriptor from "./organismesSoltea.model"; +import rncpModelDescriptor from "./rncp.model"; import uaisAcceReferentielModelDescriptor from "./uaisAcceReferentiel.model"; import uploadsModelDescriptor from "./uploads.model/uploads.model"; import usersModelDescriptor from "./users.model"; @@ -56,6 +58,7 @@ export const modelDescriptors = [ uploadsModelDescriptor, fiabilisationUaiSiretModelDescriptor, bassinsEmploiDescriptor, + rncpModelDescriptor, ]; export const formationsDb = () => getDbCollection(formationsModelDescriptor.collectionName); @@ -83,3 +86,4 @@ export const fiabilisationUaiSiretDb = () => export const bassinsEmploiDb = () => getDbCollection(bassinsEmploiDescriptor.collectionName); export const organismesSolteaDb = () => getDbCollection(organismesSolteaModelDescriptor.collectionName); +export const rncpDb = () => getDbCollection(rncpModelDescriptor.collectionName); diff --git a/server/src/common/model/effectifs.model/effectifs.model.ts b/server/src/common/model/effectifs.model/effectifs.model.ts index 362c6900d..9f6fff6b6 100644 --- a/server/src/common/model/effectifs.model/effectifs.model.ts +++ b/server/src/common/model/effectifs.model/effectifs.model.ts @@ -79,6 +79,7 @@ const indexes: [IndexSpecification, CreateIndexesOptions][] = [ [{ "_computed.organisme.uai": 1 }, {}], [{ "_computed.organisme.siret": 1 }, {}], [{ "_computed.organisme.fiable": 1 }, {}], + [{ "_computed.formation.codes_rome": 1 }, {}], ]; export const schema = object( @@ -144,6 +145,9 @@ export const schema = object( siret: string({ pattern: SIRET_REGEX_PATTERN, maxLength: 14, minLength: 14 }), fiable: boolean({ description: `organismes.fiabilisation_statut == "FIABLE" && ferme != false` }), }), + formation: object({ + codes_rome: arrayOf(string()), + }), }, { description: "Propriétés calculées ou récupérées d'autres collections", diff --git a/server/src/common/model/rncp.model.ts b/server/src/common/model/rncp.model.ts new file mode 100644 index 000000000..6a9c6de8a --- /dev/null +++ b/server/src/common/model/rncp.model.ts @@ -0,0 +1,18 @@ +import { CreateIndexesOptions, IndexSpecification } from "mongodb"; + +import { arrayOf, object, objectId, string } from "./json-schema/jsonSchemaTypes"; + +const collectionName = "rncp"; + +const indexes: [IndexSpecification, CreateIndexesOptions][] = [[{ rncp: 1 }, { unique: true }]]; + +const schema = object( + { + _id: objectId(), + rncp: string(), + romes: arrayOf(string()), + }, + { required: ["rncp", "romes"], additionalProperties: false } +); + +export default { schema, indexes, collectionName }; diff --git a/server/src/jobs/hydrate/effectifs/hydrate-effectifs-computed.ts b/server/src/jobs/hydrate/effectifs/hydrate-effectifs-computed.ts index 47b70bfa2..fcafaa4a9 100644 --- a/server/src/jobs/hydrate/effectifs/hydrate-effectifs-computed.ts +++ b/server/src/jobs/hydrate/effectifs/hydrate-effectifs-computed.ts @@ -15,6 +15,14 @@ export async function hydrateEffectifsComputed() { as: "_organisme", }, }, + { + $lookup: { + from: "rncp", + localField: "formation.rncp", + foreignField: "rncp", + as: "_rncp", + }, + }, { $addFields: { _computed: { @@ -28,12 +36,16 @@ export async function hydrateEffectifsComputed() { bassinEmploi: { $first: "$_organisme.adresse.bassinEmploi" }, fiable: { $cond: [{ $eq: [{ $first: "$_organisme.fiabilisation_statut" }, "FIABLE"] }, true, false] }, }, + formation: { + codes_rome: { $ifNull: [{ $first: "$_rncp.romes" }, []] }, + }, }, }, }, { $project: { _organisme: 0, + _rncp: 0, }, }, { diff --git a/server/src/jobs/hydrate/hydrate-rncp-romes.ts b/server/src/jobs/hydrate/hydrate-rncp-romes.ts new file mode 100644 index 000000000..f69fd9ee5 --- /dev/null +++ b/server/src/jobs/hydrate/hydrate-rncp-romes.ts @@ -0,0 +1,100 @@ +import { unlink, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { PromisePool } from "@supercharge/promise-pool"; +import AdmZip from "adm-zip"; +import axios from "axios"; +import { XMLParser } from "fast-xml-parser"; + +import parentLogger from "@/common/logger"; +import { Rncp } from "@/common/model/@types/Rncp"; +import { rncpDb } from "@/common/model/collections"; + +const logger = parentLogger.child({ + module: "job:hydrate:rncp-romes", +}); + +/* + Ce job récupère un export du RNCP pour le mettre dans la collection rncp. + Contient pour l'instant uniquement les associations RNCP -> codes ROME. + L'origine des données est "export fiches rncp v3" téléchargées depuis la page https://www.data.gouv.fr/fr/datasets/repertoire-national-des-certifications-professionnelles-et-repertoire-specifique/ + + Étapes : + - récupération du fichier zip export-fiches-rncp-v3 du jour : "https://static.data.gouv.fr/resources/repertoire-national-des-certifications-professionnelles-et-repertoire-specifique/20230830-020022/export-fiches-rncp-v3-0-2023-08-30.zip" + - décompression zip + - parsing du xml + - récupération de la correspondance RNC -> codes ROME uniquement + - écriture dans la collection rncp +*/ +export async function hydrateRNCPRomes() { + let res = await axios.get( + `https://www.data.gouv.fr/api/2/datasets/5eebbc067a14b6fecc9c9976/resources/?page=1&type=update&page_size=10&q=` + ); + if (res.status !== 200) { + throw new Error(`Invalid response status. Expected 200 but received ${res.status}`); + } + const resourceRncpV3 = res.data.data.find((resource) => resource.title.includes("export-fiches-rncp-v3")); + if (!resourceRncpV3) { + throw new Error(`Ressource non trouvée dans la liste`); + } + logger.info(`téléchargement de : ${resourceRncpV3.url}`); + + res = await axios.get(resourceRncpV3.url, { + responseType: "arraybuffer", + }); + if (res.status !== 200) { + throw new Error(`Invalid response status. Expected 200 but received ${res.status}`); + } + + const tempZipFilePath = join(tmpdir(), "fiches-rncp.zip"); + await writeFile(tempZipFilePath, res.data); + + const zip = new AdmZip(tempZipFilePath); + const zipEntries = zip.getEntries(); + + // l'archive contient seulement un fichier : export_fiches_RNCP_V3_0_2023-08-30.xml + const entry = zipEntries.find((entry) => entry.name.includes(".xml")); + if (!entry) { + throw new Error("Fichier non trouvé. Le format a dû changer"); + } + const zipData = entry.getData(); + unlink(tempZipFilePath); + + const parser = new XMLParser({ + isArray(tagName, jPath) { + // force un tableau plutôt qu'un objet si jamais un seul élément + return jPath === "FICHES.FICHE.CODES_ROME.ROME"; + }, + }); + logger.info("parsing du xml"); + const parsedContent = parser.parse(zipData); + + const rncpWithRomes: Rncp[] = parsedContent.FICHES.FICHE.map((fiche) => { + return { + rncp: fiche.NUMERO_FICHE, + // certains RNCP n'ont pas de ROME => undefined + romes: fiche.CODES_ROME?.ROME?.map((rome) => rome.CODE) ?? [], + }; + }); + + logger.info({ count: rncpWithRomes.length }, "import des rncp avec romes"); + + await PromisePool.for(rncpWithRomes) + .withConcurrency(50) + .process(async (rncp) => { + await rncpDb().updateOne( + { + rncp: rncp.rncp, + }, + { + $set: { + romes: rncp.romes, + }, + }, + { + upsert: true, + } + ); + }); +} diff --git a/server/src/jobs/jobs.ts b/server/src/jobs/jobs.ts index 4da010ebe..6f0685a81 100644 --- a/server/src/jobs/jobs.ts +++ b/server/src/jobs/jobs.ts @@ -16,6 +16,7 @@ import { updateOrganismesFiabilisationUaiSiret } from "./fiabilisation/uai-siret import { hydrateEffectifsComputed } from "./hydrate/effectifs/hydrate-effectifs-computed"; import { hydrateEffectifsFormationsNiveaux } from "./hydrate/effectifs/hydrate-effectifs-formations-niveaux"; import { hydrateFormationsCatalogue } from "./hydrate/hydrate-formations-catalogue"; +import { hydrateRNCPRomes } from "./hydrate/hydrate-rncp-romes"; import { hydrateOpenApi } from "./hydrate/open-api/hydrate-open-api"; import { hydrateOrganismesEffectifsCount } from "./hydrate/organismes/hydrate-effectifs_count"; import { hydrateOrganismesFromReferentiel } from "./hydrate/organismes/hydrate-organismes"; @@ -164,6 +165,8 @@ export async function runJob( return hydrateFromReferentiel(); case "hydrate:formations-catalogue": return hydrateFormationsCatalogue(); + case "hydrate:rncp-romes": + return hydrateRNCPRomes(); case "hydrate:organismes-formations": return hydrateOrganismesFormations(); case "hydrate:organismes-relations": diff --git a/server/yarn.lock b/server/yarn.lock index e1d1a30e3..ff913ebc3 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -2105,10 +2105,10 @@ acorn@^8.4.1, acorn@^8.8.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== -adler-32@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2" - integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A== +adm-zip@^0.5.10: + version "0.5.10" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.10.tgz#4a51d5ab544b1f5ce51e1b9043139b639afff45b" + integrity sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ== agent-base@6: version "6.0.2" @@ -2679,14 +2679,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== -cfb@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44" - integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA== - dependencies: - adler-32 "~1.3.0" - crc-32 "~1.2.0" - chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2855,11 +2847,6 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== -codepage@~1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab" - integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA== - collect-v8-coverage@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" @@ -3023,11 +3010,6 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -crc-32@~1.2.0, crc-32@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" - integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== - create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -4000,6 +3982,13 @@ fast-xml-parser@4.1.2: dependencies: strnum "^1.0.5" +fast-xml-parser@^4.2.7: + version "4.2.7" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.2.7.tgz#871f2ca299dc4334b29f8da3658c164e68395167" + integrity sha512-J8r6BriSLO1uj2miOk1NW0YVm8AGOOu3Si2HQp/cSmo6EA4m3fcwu2WKjJ4RK9wMLBtg69y1kS8baDiQBR41Ig== + dependencies: + strnum "^1.0.5" + fastq@^1.6.0: version "1.15.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" @@ -4148,11 +4137,6 @@ fp-ts@^2.8.2: resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.14.0.tgz#97ac3d9f002dcd02f93ca1269ae14a7fcb805582" integrity sha512-QLagLSYAgMA00pZzUzeksH/78Sd14y7+Gc2A8Yaja3/IpGOFMdm/gYBuDMxYqLsJ58iT5lz+bJb953RAeFfp1A== -frac@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b" - integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== - fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -7569,13 +7553,6 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -ssf@~0.11.2: - version "0.11.2" - resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c" - integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g== - dependencies: - frac "~1.1.2" - sshpk@^1.7.0: version "1.17.0" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" @@ -8245,21 +8222,11 @@ which@2.0.2, which@^2.0.1: dependencies: isexe "^2.0.0" -wmf@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da" - integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== - word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -word@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961" - integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== - workerpool@6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" @@ -8287,18 +8254,9 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -xlsx@0.18.5: - version "0.18.5" - resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0" - integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ== - dependencies: - adler-32 "~1.3.0" - cfb "~1.2.1" - codepage "~1.15.0" - crc-32 "~1.2.1" - ssf "~0.11.2" - wmf "~1.0.1" - word "~0.3.0" +"xlsx@https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz": + version "0.20.0" + resolved "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz#ca1826e53a4fe32f8789ae6c584457e7bf10841e" y18n@^5.0.5: version "5.0.8" diff --git a/ui/modules/dashboard/SimpleOverlayMenu.tsx b/ui/modules/dashboard/SimpleOverlayMenu.tsx index 93d23500c..9dc6fbf2d 100644 --- a/ui/modules/dashboard/SimpleOverlayMenu.tsx +++ b/ui/modules/dashboard/SimpleOverlayMenu.tsx @@ -4,9 +4,10 @@ import { ReactNode, useEffect, useRef, useState } from "react"; interface SimpleOverlayMenuProps extends SystemProps { onClose: () => void; children: ReactNode; + limitedHeight?: boolean; } -function SimpleOverlayMenu({ onClose, children, ...props }: SimpleOverlayMenuProps) { +function SimpleOverlayMenu({ onClose, children, limitedHeight = true, ...props }: SimpleOverlayMenuProps) { const menuRef = useRef(); const [menuMaxHeight, setMenuMaxHeight] = useState("100%"); @@ -14,9 +15,10 @@ function SimpleOverlayMenu({ onClose, children, ...props }: SimpleOverlayMenuPro setTimeout(() => { const viewportHeight = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0); // compute max-height for menu considering viewport, current y axis position and the 16px marginTop - const menuHeight = menuRef?.current - ? `${Math.max(viewportHeight - menuRef.current.getBoundingClientRect().y - 16, 200)}px` - : "100%"; + const menuHeight = + menuRef?.current && limitedHeight + ? `${Math.max(viewportHeight - menuRef.current.getBoundingClientRect().y - 16, 200)}px` + : "100%"; setMenuMaxHeight(menuHeight); }, 0); }, []); diff --git a/ui/modules/dashboard/icons.tsx b/ui/modules/dashboard/icons.tsx index 564ce74bb..885ad1cf2 100644 --- a/ui/modules/dashboard/icons.tsx +++ b/ui/modules/dashboard/icons.tsx @@ -92,6 +92,14 @@ export function ChevronRightIcon(props?: SystemProps) { return ; } +export function ArrowTriangleDownIcon(props?: SystemProps) { + return ( + + + + ); +} + export function TeamIcon(props?: SystemProps) { return ( diff --git a/ui/modules/indicateurs/IndicateursForm.tsx b/ui/modules/indicateurs/IndicateursForm.tsx index 93802da48..75f809653 100644 --- a/ui/modules/indicateurs/IndicateursForm.tsx +++ b/ui/modules/indicateurs/IndicateursForm.tsx @@ -39,6 +39,7 @@ import { import IndicateursFilter from "./FilterAccordion"; import FiltreFormationCFD from "./filters/FiltreFormationCFD"; +import FiltreFormationSecteurProfessionnel from "./filters/FiltreFormationSecteurProfessionnel"; import FiltreOrganismeAcademie from "./filters/FiltreOrganismeAcademie"; import FiltreOrganismeBassinEmploi from "./filters/FiltreOrganismeBassinEmploi"; import FiltreOrganismeDepartement from "./filters/FiltreOrganismeDepartement"; @@ -226,12 +227,16 @@ function IndicateursForm(props: IndicateursFormProps) { /> )} - {/* + Domaine d’activité - - Liste des filtres - */} + + + updateState({ formation_secteursProfessionnels: secteursProfessionnels }) + } + /> @@ -480,8 +485,7 @@ function getMessageBandeauMesIndicateurs(organisationType: OrganisationType): JS return ( <> Retrouvez ici les indicateurs et les organismes dont les formations en apprentissage sont{" "} - sous votre gestion - uniquement. + sous votre gestion uniquement. ); diff --git a/ui/modules/indicateurs/filters/FiltreFormationSecteurProfessionnel.tsx b/ui/modules/indicateurs/filters/FiltreFormationSecteurProfessionnel.tsx new file mode 100644 index 000000000..fcd4233bb --- /dev/null +++ b/ui/modules/indicateurs/filters/FiltreFormationSecteurProfessionnel.tsx @@ -0,0 +1,215 @@ +import { SmallCloseIcon } from "@chakra-ui/icons"; +import { + Box, + Button, + Checkbox, + Heading, + HStack, + Input, + InputGroup, + InputLeftElement, + InputRightElement, + Spinner, + Text, +} from "@chakra-ui/react"; +import { useQuery } from "@tanstack/react-query"; +import { useMemo, useState } from "react"; +import TreeView, { flattenTree } from "react-accessible-treeview"; + +import { _get, _post } from "@/common/httpClient"; +import { normalize } from "@/common/utils/stringUtils"; +import InputLegend from "@/components/InputLegend/InputLegend"; +import { ArrowTriangleDownIcon } from "@/modules/dashboard/icons"; +import SimpleOverlayMenu from "@/modules/dashboard/SimpleOverlayMenu"; + +import { FilterButton } from "../FilterButton"; + +import { + FamilleMetier, + filterRomeNodesByTerm, + normalizeRomeNodeInPlace, + RomeNode, +} from "./secteur-professionnel/arborescence-rome"; + +interface FiltreFormationSecteurProfessionnelProps { + value: string[]; + onChange: (value: string[]) => void; +} + +const MINIMUM_CHARS_TO_PERFORM_SEARCH = 3; + +const FiltreFormationSecteurProfessionnel = (props: FiltreFormationSecteurProfessionnelProps) => { + const [isOpen, setIsOpen] = useState(false); + const [searchTerm, setSearchTerm] = useState(""); + + const { data: famillesMetiers, isFetching: isLoading } = useQuery( + ["arborescence-rome-14-06-2021.json"], + async () => { + const famillersMetiers = await _get("/arborescence-rome-14-06-2021.json"); + return famillersMetiers.map((familleMetiers) => normalizeRomeNodeInPlace(familleMetiers)); + }, + { + cacheTime: 99999999, // never expire, change the URL if that must expire + } + ); + + const filteredFamillesMetiers = useMemo(() => { + if (!famillesMetiers) { + return []; + } + if (searchTerm.length < MINIMUM_CHARS_TO_PERFORM_SEARCH) { + return famillesMetiers; + } + const normalizedSearchTerm = normalize(searchTerm); + + return filterRomeNodesByTerm(famillesMetiers, normalizedSearchTerm); + }, [famillesMetiers, searchTerm]); + + const { filteredTreeData } = useMemo(() => { + const treeData = flattenTree({ + name: "", + children: filteredFamillesMetiers, + }); + // expandedIds contient la liste des id de tous les noeuds dès lors qu'il y a une recherche, + // afin de déplier automatiquement les noeuds qui correspondent + // désactivé côté composant car cela ne fonctionne pas quand on change le filtre pour un sous-ensemble + // cad on passe de "hot" = "hote" et une erreur comme quoi certains noeuds ne sont plus trouvés + // sans doute une issue à lever côté react-accessible-treeview + return { + filteredTreeData: treeData, + expandedIds: + searchTerm.length >= MINIMUM_CHARS_TO_PERFORM_SEARCH + ? // hack: reverse pour faire en sorte que l'id root soit en dernier sinon la lib sélectionne + // le dernier élément et on perd le focus de la recherche + treeData.map((node) => node.id).reverse() + : [], + }; + }, [filteredFamillesMetiers]); + + return ( +
+ + + {isOpen && ( + setIsOpen(false)} + limitedHeight={false} + px="8w" + py="3w" + width="var(--chakra-sizes-xl)" + > + + Sélectionner un domaine ou sous-domaine d’activité + + + + + setSearchTerm(event.target.value)} + variant="outline" + size="lg" + autoFocus + fontSize="epsilon" + _placeholder={{ fontSize: "epsilon" }} + /> + + + + + + + {searchTerm.length < MINIMUM_CHARS_TO_PERFORM_SEARCH && ( + + Merci de renseigner au minimum {MINIMUM_CHARS_TO_PERFORM_SEARCH} caractères pour lancer la recherche + + )} + + + + {!isLoading && searchTerm.length >= MINIMUM_CHARS_TO_PERFORM_SEARCH && filteredTreeData?.length === 1 && ( + + Il n’y a aucun résultat pour votre recherche + + )} + {isLoading && } + + {famillesMetiers && ( + + { + props.onChange(treeState ? Array.from(treeState?.selectedIds as Set) : []); + }} + nodeRenderer={({ + element, + isBranch, + isExpanded, + isSelected, + isHalfSelected, + getNodeProps, + level, + handleSelect, + handleExpand, + }) => ( + + {isBranch && ( + + )} + { + handleSelect(e); + e.preventDefault(); // prevents triggering another tick + e.stopPropagation(); // prevents toggling the node + }} + color="#3a3a3a" + > + {element.name} + + + )} + /> + + )} + + )} +
+ ); +}; + +export default FiltreFormationSecteurProfessionnel; diff --git a/ui/modules/indicateurs/filters/secteur-professionnel/arborescence-rome.ts b/ui/modules/indicateurs/filters/secteur-professionnel/arborescence-rome.ts new file mode 100644 index 000000000..82d62cbdf --- /dev/null +++ b/ui/modules/indicateurs/filters/secteur-professionnel/arborescence-rome.ts @@ -0,0 +1,54 @@ +// ROME = Répertoire Opérationnel des Métiers et des Emplois + +import { normalize } from "@/common/utils/stringUtils"; + +export type FamilleMetier = { + id: string; + name: string; + children: DomaineProfessionnel[]; +} & NormalizedName; + +type DomaineProfessionnel = { + id: string; + name: string; + children: FicheMetier[]; +} & NormalizedName; + +type FicheMetier = { + id: string; + name: string; +} & NormalizedName; + +interface NormalizedName { + normalizedName: string; +} + +export type RomeNode = { + id: string; + name: string; + normalizedName: string; + children?: RomeNode[]; +} & NormalizedName; + +export function normalizeRomeNodeInPlace(node: RomeNode): RomeNode { + node.normalizedName = normalize(node.name); + node.children?.forEach((node) => normalizeRomeNodeInPlace(node)); + return node; +} + +/** + * Filtre les noeuds pour une recherche et conserve les ancètres pour garder la hiérarchie de l'arbre. + */ +export function filterRomeNodesByTerm(nodes: RomeNode[], searchTerm: string): RomeNode[] { + return nodes + .map((node) => { + const children = node.children ? filterRomeNodesByTerm(node.children, searchTerm) : []; + return children.length > 0 || node.normalizedName.includes(searchTerm) + ? { + ...node, + children, + } + : null; + }) + .filter((node) => node !== null) as RomeNode[]; +} diff --git a/ui/modules/models/effectifs-filters.ts b/ui/modules/models/effectifs-filters.ts index 3a54ca5c1..578eb5f69 100644 --- a/ui/modules/models/effectifs-filters.ts +++ b/ui/modules/models/effectifs-filters.ts @@ -12,6 +12,7 @@ export interface EffectifsFiltersQuery { formation_annees?: string; formation_niveaux?: string; formation_cfds?: string; + formation_secteursProfessionnels?: string; } export interface EffectifsFilters { @@ -26,6 +27,7 @@ export interface EffectifsFilters { formation_annees: number[]; formation_niveaux: string[]; formation_cfds: string[]; + formation_secteursProfessionnels: string[]; } export function parseEffectifsFiltersFromQuery(query: EffectifsFiltersQuery): EffectifsFilters { @@ -41,6 +43,7 @@ export function parseEffectifsFiltersFromQuery(query: EffectifsFiltersQuery): Ef formation_annees: query.formation_annees?.split(",").map((i) => parseInt(i, 10)) ?? [], formation_niveaux: query.formation_niveaux?.split(",") ?? [], formation_cfds: query.formation_cfds?.split(",") ?? [], + formation_secteursProfessionnels: query.formation_secteursProfessionnels?.split(",") ?? [], }; } @@ -59,5 +62,6 @@ export function convertEffectifsFiltersToQuery( formation_annees: effectifsFilters.formation_annees?.join(","), formation_niveaux: effectifsFilters.formation_niveaux?.join(","), formation_cfds: effectifsFilters.formation_cfds?.join(","), + formation_secteursProfessionnels: effectifsFilters.formation_secteursProfessionnels?.join(","), }); } diff --git a/ui/package.json b/ui/package.json index 74595ae96..a76201341 100644 --- a/ui/package.json +++ b/ui/package.json @@ -49,6 +49,7 @@ "next-plausible": "3.7.2", "prop-types": "15.8.1", "react": "18.2.0", + "react-accessible-treeview": "2.8.0", "react-copy-to-clipboard": "5.1.0", "react-datepicker": "4.11.0", "react-dom": "18.2.0", diff --git a/ui/public/arborescence-rome-14-06-2021.json b/ui/public/arborescence-rome-14-06-2021.json new file mode 100644 index 000000000..e875e0a6a --- /dev/null +++ b/ui/public/arborescence-rome-14-06-2021.json @@ -0,0 +1 @@ +[{"id":"A","name":"A – Agriculture et Pêche, Espaces naturels et Espaces verts, Soins aux animaux","children":[{"id":"A11","name":"A11 – Engins agricoles et forestiers","children":[{"id":"A1101","name":"A1101 – Conduite d'engins agricoles et forestiers"}]},{"id":"A12","name":"A12 – Espaces naturels et espaces verts","children":[{"id":"A1201","name":"A1201 – Bûcheronnage et élagage"},{"id":"A1202","name":"A1202 – Entretien des espaces naturels"},{"id":"A1203","name":"A1203 – Aménagement et entretien des espaces verts"},{"id":"A1204","name":"A1204 – Protection du patrimoine naturel"},{"id":"A1205","name":"A1205 – Sylviculture"}]},{"id":"A13","name":"A13 – Etudes et assistance technique","children":[{"id":"A1301","name":"A1301 – Conseil et assistance technique en agriculture et environnement naturel"},{"id":"A1302","name":"A1302 – Contrôle et diagnostic technique en agriculture"},{"id":"A1303","name":"A1303 – Ingénierie en agriculture et environnement naturel"}]},{"id":"A14","name":"A14 – Production","children":[{"id":"A1401","name":"A1401 – Aide agricole de production fruitière ou viticole"},{"id":"A1402","name":"A1402 – Aide agricole de production légumière ou végétale"},{"id":"A1403","name":"A1403 – Aide d'élevage agricole et aquacole"},{"id":"A1404","name":"A1404 – Aquaculture"},{"id":"A1405","name":"A1405 – Arboriculture et viticulture"},{"id":"A1406","name":"A1406 – Encadrement équipage de la pêche"},{"id":"A1407","name":"A1407 – Élevage bovin ou équin"},{"id":"A1408","name":"A1408 – Élevage d'animaux sauvages ou de compagnie"},{"id":"A1409","name":"A1409 – Élevage de lapins et volailles"},{"id":"A1410","name":"A1410 – Élevage ovin ou caprin"},{"id":"A1411","name":"A1411 – Élevage porcin"},{"id":"A1412","name":"A1412 – Fabrication et affinage de fromages"},{"id":"A1413","name":"A1413 – Fermentation de boissons alcoolisées"},{"id":"A1414","name":"A1414 – Horticulture et maraîchage"},{"id":"A1415","name":"A1415 – Équipage de la pêche"},{"id":"A1416","name":"A1416 – Polyculture, élevage"},{"id":"A1417","name":"A1417 – Saliculture"}]},{"id":"A15","name":"A15 – Soins aux animaux","children":[{"id":"A1501","name":"A1501 – Aide aux soins animaux"},{"id":"A1502","name":"A1502 – Podologie animale"},{"id":"A1503","name":"A1503 – Toilettage des animaux"},{"id":"A1504","name":"A1504 – Santé animale"}]}]},{"id":"B","name":"B – Arts et Façonnage d'ouvrages d'art","children":[{"id":"B11","name":"B11 – Arts plastiques","children":[{"id":"B1101","name":"B1101 – Création en arts plastiques"}]},{"id":"B12","name":"B12 – Céramique","children":[{"id":"B1201","name":"B1201 – Réalisation d'objets décoratifs et utilitaires en céramique et matériaux de synthèse"}]},{"id":"B13","name":"B13 – Décoration","children":[{"id":"B1301","name":"B1301 – Décoration d'espaces de vente et d'exposition"},{"id":"B1302","name":"B1302 – Décoration d'objets d'art et artisanaux"},{"id":"B1303","name":"B1303 – Gravure - ciselure"}]},{"id":"B14","name":"B14 – Fibres et papier","children":[{"id":"B1401","name":"B1401 – Réalisation d'objets en lianes, fibres et brins végétaux"},{"id":"B1402","name":"B1402 – Reliure et restauration de livres et archives"}]},{"id":"B15","name":"B15 – Instruments de musique","children":[{"id":"B1501","name":"B1501 – Fabrication et réparation d'instruments de musique"}]},{"id":"B16","name":"B16 – Métal, verre, bijouterie et horlogerie","children":[{"id":"B1601","name":"B1601 – Métallerie d'art"},{"id":"B1602","name":"B1602 – Réalisation d'objets artistiques et fonctionnels en verre"},{"id":"B1603","name":"B1603 – Réalisation d'ouvrages en bijouterie, joaillerie et orfèvrerie"},{"id":"B1604","name":"B1604 – Réparation - montage en systèmes horlogers"}]},{"id":"B17","name":"B17 – Taxidermie","children":[{"id":"B1701","name":"B1701 – Conservation et reconstitution d'espèces animales"}]},{"id":"B18","name":"B18 – Tissu et cuirs","children":[{"id":"B1801","name":"B1801 – Réalisation d'articles de chapellerie"},{"id":"B1802","name":"B1802 – Réalisation d'articles en cuir et matériaux souples (hors vêtement)"},{"id":"B1803","name":"B1803 – Réalisation de vêtements sur mesure ou en petite série"},{"id":"B1804","name":"B1804 – Réalisation d'ouvrages d'art en fils"},{"id":"B1805","name":"B1805 – Stylisme"},{"id":"B1806","name":"B1806 – Tapisserie - décoration en ameublement"}]}]},{"id":"C","name":"C – Banque, Assurance, Immobilier","children":[{"id":"C11","name":"C11 – Assurance","children":[{"id":"C1101","name":"C1101 – Conception - développement produits d'assurances"},{"id":"C1102","name":"C1102 – Conseil clientèle en assurances"},{"id":"C1103","name":"C1103 – Courtage en assurances"},{"id":"C1104","name":"C1104 – Direction d'exploitation en assurances"},{"id":"C1105","name":"C1105 – Études actuarielles en assurances"},{"id":"C1106","name":"C1106 – Expertise risques en assurances"},{"id":"C1107","name":"C1107 – Indemnisations en assurances"},{"id":"C1108","name":"C1108 – Management de groupe et de service en assurances"},{"id":"C1109","name":"C1109 – Rédaction et gestion en assurances"},{"id":"C1110","name":"C1110 – Souscription d'assurances"}]},{"id":"C12","name":"C12 – Banque","children":[{"id":"C1201","name":"C1201 – Accueil et services bancaires"},{"id":"C1202","name":"C1202 – Analyse de crédits et risques bancaires"},{"id":"C1203","name":"C1203 – Relation clients banque/finance"},{"id":"C1204","name":"C1204 – Conception et expertise produits bancaires et financiers"},{"id":"C1205","name":"C1205 – Conseil en gestion de patrimoine financier"},{"id":"C1206","name":"C1206 – Gestion de clientèle bancaire"},{"id":"C1207","name":"C1207 – Management en exploitation bancaire"}]},{"id":"C13","name":"C13 – Finance","children":[{"id":"C1301","name":"C1301 – Front office marchés financiers"},{"id":"C1302","name":"C1302 – Gestion back et middle-office marchés financiers"},{"id":"C1303","name":"C1303 – Gestion de portefeuilles sur les marchés financiers"}]},{"id":"C14","name":"C14 – Gestion administrative banque et assurances","children":[{"id":"C1401","name":"C1401 – Gestion en banque et assurance"}]},{"id":"C15","name":"C15 – Immobilier","children":[{"id":"C1501","name":"C1501 – Gérance immobilière"},{"id":"C1502","name":"C1502 – Gestion locative immobilière"},{"id":"C1503","name":"C1503 – Management de projet immobilier"},{"id":"C1504","name":"C1504 – Transaction immobilière"}]}]},{"id":"D","name":"D – Commerce, Vente et Grande distribution","children":[{"id":"D11","name":"D11 – Commerce alimentaire et métiers de bouche","children":[{"id":"D1101","name":"D1101 – Boucherie"},{"id":"D1102","name":"D1102 – Boulangerie - viennoiserie"},{"id":"D1103","name":"D1103 – Charcuterie - traiteur"},{"id":"D1104","name":"D1104 – Pâtisserie, confiserie, chocolaterie et glacerie"},{"id":"D1105","name":"D1105 – Poissonnerie"},{"id":"D1106","name":"D1106 – Vente en alimentation"},{"id":"D1107","name":"D1107 – Vente en gros de produits frais"}]},{"id":"D12","name":"D12 – Commerce non alimentaire et de prestations de confort","children":[{"id":"D1201","name":"D1201 – Achat vente d'objets d'art, anciens ou d'occasion"},{"id":"D1202","name":"D1202 – Coiffure"},{"id":"D1203","name":"D1203 – Hydrothérapie"},{"id":"D1204","name":"D1204 – Location de véhicules ou de matériel de loisirs"},{"id":"D1205","name":"D1205 – Nettoyage d'articles textiles ou cuirs"},{"id":"D1206","name":"D1206 – Réparation d'articles en cuir et matériaux souples"},{"id":"D1207","name":"D1207 – Retouches en habillement"},{"id":"D1208","name":"D1208 – Soins esthétiques et corporels"},{"id":"D1209","name":"D1209 – Vente de végétaux"},{"id":"D1210","name":"D1210 – Vente en animalerie"},{"id":"D1211","name":"D1211 – Vente en articles de sport et loisirs"},{"id":"D1212","name":"D1212 – Vente en décoration et équipement du foyer"},{"id":"D1213","name":"D1213 – Vente en gros de matériel et équipement"},{"id":"D1214","name":"D1214 – Vente en habillement et accessoires de la personne"}]},{"id":"D13","name":"D13 – Direction de magasin de détail","children":[{"id":"D1301","name":"D1301 – Management de magasin de détail"}]},{"id":"D14","name":"D14 – Force de vente","children":[{"id":"D1401","name":"D1401 – Assistanat commercial"},{"id":"D1402","name":"D1402 – Relation commerciale grands comptes et entreprises"},{"id":"D1403","name":"D1403 – Relation commerciale auprès de particuliers"},{"id":"D1404","name":"D1404 – Relation commerciale en vente de véhicules"},{"id":"D1405","name":"D1405 – Conseil en information médicale"},{"id":"D1406","name":"D1406 – Management en force de vente"},{"id":"D1407","name":"D1407 – Relation technico-commerciale"},{"id":"D1408","name":"D1408 – Téléconseil et télévente"}]},{"id":"D15","name":"D15 – Grande distribution","children":[{"id":"D1501","name":"D1501 – Animation de vente"},{"id":"D1502","name":"D1502 – Management/gestion de rayon produits alimentaires"},{"id":"D1503","name":"D1503 – Management/gestion de rayon produits non alimentaires"},{"id":"D1504","name":"D1504 – Direction de magasin de grande distribution"},{"id":"D1505","name":"D1505 – Personnel de caisse"},{"id":"D1506","name":"D1506 – Marchandisage"},{"id":"D1507","name":"D1507 – Mise en rayon libre-service"},{"id":"D1508","name":"D1508 – Encadrement du personnel de caisses"},{"id":"D1509","name":"D1509 – Management de département en grande distribution"}]}]},{"id":"E","name":"E – Communication, Média et Multimédia","children":[{"id":"E11","name":"E11 – Edition et communication","children":[{"id":"E1101","name":"E1101 – Animation de site multimédia"},{"id":"E1102","name":"E1102 – Écriture d'ouvrages, de livres"},{"id":"E1103","name":"E1103 – Communication"},{"id":"E1104","name":"E1104 – Conception de contenus multimédias"},{"id":"E1105","name":"E1105 – Coordination d'édition"},{"id":"E1106","name":"E1106 – Journalisme et information média"},{"id":"E1107","name":"E1107 – Organisation d'évènementiel"},{"id":"E1108","name":"E1108 – Traduction, interprétariat"}]},{"id":"E12","name":"E12 – Images et sons","children":[{"id":"E1201","name":"E1201 – Photographie"},{"id":"E1202","name":"E1202 – Production en laboratoire cinématographique"},{"id":"E1203","name":"E1203 – Production en laboratoire photographique"},{"id":"E1204","name":"E1204 – Projection cinéma"},{"id":"E1205","name":"E1205 – Réalisation de contenus multimédias"}]},{"id":"E13","name":"E13 – Industries graphiques","children":[{"id":"E1301","name":"E1301 – Conduite de machines d'impression"},{"id":"E1302","name":"E1302 – Conduite de machines de façonnage routage"},{"id":"E1303","name":"E1303 – Encadrement des industries graphiques"},{"id":"E1304","name":"E1304 – Façonnage et routage"},{"id":"E1305","name":"E1305 – Préparation et correction en édition et presse"},{"id":"E1306","name":"E1306 – Prépresse"},{"id":"E1307","name":"E1307 – Reprographie"},{"id":"E1308","name":"E1308 – Intervention technique en industrie graphique"}]},{"id":"E14","name":"E14 – Publicité","children":[{"id":"E1401","name":"E1401 – Développement et promotion publicitaire"},{"id":"E1402","name":"E1402 – Élaboration de plan média"}]}]},{"id":"F","name":"F – Construction, Bâtiment et Travaux publics","children":[{"id":"F11","name":"F11 – Conception et études","children":[{"id":"F1101","name":"F1101 – Architecture du BTP et du paysage"},{"id":"F1102","name":"F1102 – Conception - aménagement d'espaces intérieurs"},{"id":"F1103","name":"F1103 – Contrôle et diagnostic technique du bâtiment"},{"id":"F1104","name":"F1104 – Dessin BTP et paysage"},{"id":"F1105","name":"F1105 – Études géologiques"},{"id":"F1106","name":"F1106 – Ingénierie et études du BTP"},{"id":"F1107","name":"F1107 – Mesures topographiques"},{"id":"F1108","name":"F1108 – Métré de la construction"}]},{"id":"F12","name":"F12 – Conduite et encadrement de chantier - travaux","children":[{"id":"F1201","name":"F1201 – Conduite de travaux du BTP et de travaux paysagers"},{"id":"F1202","name":"F1202 – Direction de chantier du BTP"},{"id":"F1203","name":"F1203 – Direction et ingénierie d'exploitation de gisements et de carrières"},{"id":"F1204","name":"F1204 – Qualité Sécurité Environnement et protection santé du BTP"}]},{"id":"F13","name":"F13 – Engins de chantier","children":[{"id":"F1301","name":"F1301 – Conduite de grue"},{"id":"F1302","name":"F1302 – Conduite d'engins de terrassement et de carrière"}]},{"id":"F14","name":"F14 – Extraction","children":[{"id":"F1401","name":"F1401 – Extraction liquide et gazeuse"},{"id":"F1402","name":"F1402 – Extraction solide"}]},{"id":"F15","name":"F15 – Montage de structures","children":[{"id":"F1501","name":"F1501 – Montage de structures et de charpentes bois"},{"id":"F1502","name":"F1502 – Montage de structures métalliques"},{"id":"F1503","name":"F1503 – Réalisation - installation d'ossatures bois"}]},{"id":"F16","name":"F16 – Second oeuvre","children":[{"id":"F1601","name":"F1601 – Application et décoration en plâtre, stuc et staff"},{"id":"F1602","name":"F1602 – Électricité bâtiment"},{"id":"F1603","name":"F1603 – Installation d'équipements sanitaires et thermiques"},{"id":"F1604","name":"F1604 – Montage d'agencements"},{"id":"F1605","name":"F1605 – Montage de réseaux électriques et télécoms"},{"id":"F1606","name":"F1606 – Peinture en bâtiment"},{"id":"F1607","name":"F1607 – Pose de fermetures menuisées"},{"id":"F1608","name":"F1608 – Pose de revêtements rigides"},{"id":"F1609","name":"F1609 – Pose de revêtements souples"},{"id":"F1610","name":"F1610 – Pose et restauration de couvertures"},{"id":"F1611","name":"F1611 – Réalisation et restauration de façades"},{"id":"F1612","name":"F1612 – Taille et décoration de pierres"},{"id":"F1613","name":"F1613 – Travaux d'étanchéité et d'isolation"}]},{"id":"F17","name":"F17 – Travaux et gros oeuvre","children":[{"id":"F1701","name":"F1701 – Construction en béton"},{"id":"F1702","name":"F1702 – Construction de routes et voies"},{"id":"F1703","name":"F1703 – Maçonnerie"},{"id":"F1704","name":"F1704 – Préparation du gros oeuvre et des travaux publics"},{"id":"F1705","name":"F1705 – Pose de canalisations"},{"id":"F1706","name":"F1706 – Préfabrication en béton industriel"}]}]},{"id":"G","name":"G – Hôtellerie-Restauration, Tourisme, Loisirs et Animation","children":[{"id":"G11","name":"G11 – Accueil et promotion touristique","children":[{"id":"G1101","name":"G1101 – Accueil touristique"},{"id":"G1102","name":"G1102 – Promotion du tourisme local"}]},{"id":"G12","name":"G12 – Animation d'activités de loisirs","children":[{"id":"G1201","name":"G1201 – Accompagnement de voyages, d'activités culturelles ou sportives"},{"id":"G1202","name":"G1202 – Animation d'activités culturelles ou ludiques"},{"id":"G1203","name":"G1203 – Animation de loisirs auprès d'enfants ou d'adolescents"},{"id":"G1204","name":"G1204 – Éducation en activités sportives"},{"id":"G1205","name":"G1205 – Personnel d'attractions ou de structures de loisirs"},{"id":"G1206","name":"G1206 – Personnel technique des jeux"}]},{"id":"G13","name":"G13 – Conception, commercialisation et vente de produits touristiques","children":[{"id":"G1301","name":"G1301 – Conception de produits touristiques"},{"id":"G1302","name":"G1302 – Optimisation de produits touristiques"},{"id":"G1303","name":"G1303 – Vente de voyages"}]},{"id":"G14","name":"G14 – Gestion et direction","children":[{"id":"G1401","name":"G1401 – Assistance de direction d'hôtel-restaurant"},{"id":"G1402","name":"G1402 – Management d'hôtel-restaurant"},{"id":"G1403","name":"G1403 – Gestion de structure de loisirs ou d'hébergement touristique"},{"id":"G1404","name":"G1404 – Management d'établissement de restauration collective"}]},{"id":"G15","name":"G15 – Personnel d'étage en hôtellerie","children":[{"id":"G1501","name":"G1501 – Personnel d'étage"},{"id":"G1502","name":"G1502 – Personnel polyvalent d'hôtellerie"},{"id":"G1503","name":"G1503 – Management du personnel d'étage"}]},{"id":"G16","name":"G16 – Production culinaire","children":[{"id":"G1601","name":"G1601 – Management du personnel de cuisine"},{"id":"G1602","name":"G1602 – Personnel de cuisine"},{"id":"G1603","name":"G1603 – Personnel polyvalent en restauration"},{"id":"G1604","name":"G1604 – Fabrication de crêpes ou pizzas"},{"id":"G1605","name":"G1605 – Plonge en restauration"}]},{"id":"G17","name":"G17 – Accueil en hôtellerie","children":[{"id":"G1701","name":"G1701 – Conciergerie en hôtellerie"},{"id":"G1702","name":"G1702 – Personnel du hall"},{"id":"G1703","name":"G1703 – Réception en hôtellerie"}]},{"id":"G18","name":"G18 – Service","children":[{"id":"G1801","name":"G1801 – Café, bar brasserie"},{"id":"G1802","name":"G1802 – Management du service en restauration"},{"id":"G1803","name":"G1803 – Service en restauration"},{"id":"G1804","name":"G1804 – Sommellerie"}]}]},{"id":"H","name":"H – Industrie","children":[{"id":"H11","name":"H11 – Affaires et support technique client","children":[{"id":"H1101","name":"H1101 – Assistance et support technique client"},{"id":"H1102","name":"H1102 – Management et ingénierie d'affaires"}]},{"id":"H12","name":"H12 – Conception, recherche, études et développement","children":[{"id":"H1201","name":"H1201 – Expertise technique couleur en industrie"},{"id":"H1202","name":"H1202 – Conception et dessin de produits électriques et électroniques"},{"id":"H1203","name":"H1203 – Conception et dessin produits mécaniques"},{"id":"H1204","name":"H1204 – Design industriel"},{"id":"H1205","name":"H1205 – Études - modèles en industrie des matériaux souples"},{"id":"H1206","name":"H1206 – Management et ingénierie études, recherche et développement industriel"},{"id":"H1207","name":"H1207 – Rédaction technique"},{"id":"H1208","name":"H1208 – Intervention technique en études et conception en automatisme"},{"id":"H1209","name":"H1209 – Intervention technique en études et développement électronique"},{"id":"H1210","name":"H1210 – Intervention technique en études, recherche et développement"}]},{"id":"H13","name":"H13 – Hygiène Sécurité Environnement -HSE- industriels","children":[{"id":"H1301","name":"H1301 – Inspection de conformité"},{"id":"H1302","name":"H1302 – Management et ingénierie Hygiène Sécurité Environnement -HSE- industriels"},{"id":"H1303","name":"H1303 – Intervention technique en Hygiène Sécurité Environnement -HSE- industriel"}]},{"id":"H14","name":"H14 – Méthodes et gestion industrielles","children":[{"id":"H1401","name":"H1401 – Management et ingénierie gestion industrielle et logistique"},{"id":"H1402","name":"H1402 – Management et ingénierie méthodes et industrialisation"},{"id":"H1403","name":"H1403 – Intervention technique en gestion industrielle et logistique"},{"id":"H1404","name":"H1404 – Intervention technique en méthodes et industrialisation"}]},{"id":"H15","name":"H15 – Qualité et analyses industrielles","children":[{"id":"H1501","name":"H1501 – Direction de laboratoire d'analyse industrielle"},{"id":"H1502","name":"H1502 – Management et ingénierie qualité industrielle"},{"id":"H1503","name":"H1503 – Intervention technique en laboratoire d'analyse industrielle"},{"id":"H1504","name":"H1504 – Intervention technique en contrôle essai qualité en électricité et électronique"},{"id":"H1505","name":"H1505 – Intervention technique en formulation et analyse sensorielle"},{"id":"H1506","name":"H1506 – Intervention technique qualité en mécanique et travail des métaux"}]},{"id":"H21","name":"H21 – Alimentaire","children":[{"id":"H2101","name":"H2101 – Abattage et découpe des viandes"},{"id":"H2102","name":"H2102 – Conduite d'équipement de production alimentaire"}]},{"id":"H22","name":"H22 – Bois","children":[{"id":"H2201","name":"H2201 – Assemblage d'ouvrages en bois"},{"id":"H2202","name":"H2202 – Conduite d'équipement de fabrication de l'ameublement et du bois"},{"id":"H2203","name":"H2203 – Conduite d'installation de production de panneaux bois"},{"id":"H2204","name":"H2204 – Encadrement des industries de l'ameublement et du bois"},{"id":"H2205","name":"H2205 – Première transformation de bois d'oeuvre"},{"id":"H2206","name":"H2206 – Réalisation de menuiserie bois et tonnellerie"},{"id":"H2207","name":"H2207 – Réalisation de meubles en bois"},{"id":"H2208","name":"H2208 – Réalisation d'ouvrages décoratifs en bois"},{"id":"H2209","name":"H2209 – Intervention technique en ameublement et bois"}]},{"id":"H23","name":"H23 – Chimie et pharmacie","children":[{"id":"H2301","name":"H2301 – Conduite d'équipement de production chimique ou pharmaceutique"}]},{"id":"H24","name":"H24 – Cuir et textile","children":[{"id":"H2401","name":"H2401 – Assemblage - montage d'articles en cuirs, peaux"},{"id":"H2402","name":"H2402 – Assemblage - montage de vêtements et produits textiles"},{"id":"H2403","name":"H2403 – Conduite de machine de fabrication de produits textiles"},{"id":"H2404","name":"H2404 – Conduite de machine de production et transformation des fils"},{"id":"H2405","name":"H2405 – Conduite de machine de textiles nontissés"},{"id":"H2406","name":"H2406 – Conduite de machine de traitement textile"},{"id":"H2407","name":"H2407 – Conduite de machine de transformation et de finition des cuirs et peaux"},{"id":"H2408","name":"H2408 – Conduite de machine d'impression textile"},{"id":"H2409","name":"H2409 – Coupe cuir, textile et matériaux souples"},{"id":"H2410","name":"H2410 – Mise en forme, repassage et finitions en industrie textile"},{"id":"H2411","name":"H2411 – Montage de prototype cuir et matériaux souples"},{"id":"H2412","name":"H2412 – Patronnage - gradation"},{"id":"H2413","name":"H2413 – Préparation de fils, montage de métiers textiles"},{"id":"H2414","name":"H2414 – Préparation et finition d'articles en cuir et matériaux souples"},{"id":"H2415","name":"H2415 – Contrôle en industrie du cuir et du textile"}]},{"id":"H25","name":"H25 – Direction, encadrement et pilotage de fabrication et production industrielles","children":[{"id":"H2501","name":"H2501 – Encadrement de production de matériel électrique et électronique"},{"id":"H2502","name":"H2502 – Management et ingénierie de production"},{"id":"H2503","name":"H2503 – Pilotage d'unité élémentaire de production mécanique ou de travail des métaux"},{"id":"H2504","name":"H2504 – Encadrement d'équipe en industrie de transformation"},{"id":"H2505","name":"H2505 – Encadrement d'équipe ou d'atelier en matériaux souples"}]},{"id":"H26","name":"H26 – Electronique et électricité","children":[{"id":"H2601","name":"H2601 – Bobinage électrique"},{"id":"H2602","name":"H2602 – Câblage électrique et électromécanique"},{"id":"H2603","name":"H2603 – Conduite d'installation automatisée de production électrique, électronique et microélectronique"},{"id":"H2604","name":"H2604 – Montage de produits électriques et électroniques"},{"id":"H2605","name":"H2605 – Montage et câblage électronique"}]},{"id":"H27","name":"H27 – Energie","children":[{"id":"H2701","name":"H2701 – Pilotage d'installation énergétique et pétrochimique"}]},{"id":"H28","name":"H28 – Matériaux de construction, céramique et verre","children":[{"id":"H2801","name":"H2801 – Conduite d'équipement de transformation du verre"},{"id":"H2802","name":"H2802 – Conduite d'installation de production de matériaux de construction"},{"id":"H2803","name":"H2803 – Façonnage et émaillage en industrie céramique"},{"id":"H2804","name":"H2804 – Pilotage de centrale à béton prêt à l'emploi, ciment, enrobés et granulats"},{"id":"H2805","name":"H2805 – Pilotage d'installation de production verrière"}]},{"id":"H29","name":"H29 – Mécanique, travail des métaux et outillage","children":[{"id":"H2901","name":"H2901 – Ajustement et montage de fabrication"},{"id":"H2902","name":"H2902 – Chaudronnerie - tôlerie"},{"id":"H2903","name":"H2903 – Conduite d'équipement d'usinage"},{"id":"H2904","name":"H2904 – Conduite d'équipement de déformation des métaux"},{"id":"H2905","name":"H2905 – Conduite d'équipement de formage et découpage des matériaux"},{"id":"H2906","name":"H2906 – Conduite d'installation automatisée ou robotisée de fabrication mécanique"},{"id":"H2907","name":"H2907 – Conduite d'installation de production des métaux"},{"id":"H2908","name":"H2908 – Modelage de matériaux non métalliques"},{"id":"H2909","name":"H2909 – Montage-assemblage mécanique"},{"id":"H2910","name":"H2910 – Moulage sable"},{"id":"H2911","name":"H2911 – Réalisation de structures métalliques"},{"id":"H2912","name":"H2912 – Réglage d'équipement de production industrielle"},{"id":"H2913","name":"H2913 – Soudage manuel"},{"id":"H2914","name":"H2914 – Réalisation et montage en tuyauterie"}]},{"id":"H31","name":"H31 – Papier et carton","children":[{"id":"H3101","name":"H3101 – Conduite d'équipement de fabrication de papier ou de carton"},{"id":"H3102","name":"H3102 – Conduite d'installation de pâte à papier"}]},{"id":"H32","name":"H32 – Plastique, caoutchouc","children":[{"id":"H3201","name":"H3201 – Conduite d'équipement de formage des plastiques et caoutchoucs"},{"id":"H3202","name":"H3202 – Réglage d'équipement de formage des plastiques et caoutchoucs"},{"id":"H3203","name":"H3203 – Fabrication de pièces en matériaux composites"}]},{"id":"H33","name":"H33 – Préparation et conditionnement","children":[{"id":"H3301","name":"H3301 – Conduite d'équipement de conditionnement"},{"id":"H3302","name":"H3302 – Opérations manuelles d'assemblage, tri ou emballage"},{"id":"H3303","name":"H3303 – Préparation de matières et produits industriels (broyage, mélange, ...)"}]},{"id":"H34","name":"H34 – Traitements thermiques et traitements de surfaces","children":[{"id":"H3401","name":"H3401 – Conduite de traitement d'abrasion de surface"},{"id":"H3402","name":"H3402 – Conduite de traitement par dépôt de surface"},{"id":"H3403","name":"H3403 – Conduite de traitement thermique"},{"id":"H3404","name":"H3404 – Peinture industrielle"}]}]},{"id":"I","name":"I – Installation et Maintenance","children":[{"id":"I11","name":"I11 – Encadrement","children":[{"id":"I1101","name":"I1101 – Direction et ingénierie en entretien infrastructure et bâti"},{"id":"I1102","name":"I1102 – Management et ingénierie de maintenance industrielle"},{"id":"I1103","name":"I1103 – Supervision d'entretien et gestion de véhicules"}]},{"id":"I12","name":"I12 – Entretien technique","children":[{"id":"I1201","name":"I1201 – Entretien d'affichage et mobilier urbain"},{"id":"I1202","name":"I1202 – Entretien et surveillance du tracé routier"},{"id":"I1203","name":"I1203 – Maintenance des bâtiments et des locaux"}]},{"id":"I13","name":"I13 – Equipements de production, équipements collectifs","children":[{"id":"I1301","name":"I1301 – Installation et maintenance d'ascenseurs"},{"id":"I1302","name":"I1302 – Installation et maintenance d'automatismes"},{"id":"I1303","name":"I1303 – Installation et maintenance de distributeurs automatiques"},{"id":"I1304","name":"I1304 – Installation et maintenance d'équipements industriels et d'exploitation"},{"id":"I1305","name":"I1305 – Installation et maintenance électronique"},{"id":"I1306","name":"I1306 – Installation et maintenance en froid, conditionnement d'air"},{"id":"I1307","name":"I1307 – Installation et maintenance télécoms et courants faibles"},{"id":"I1308","name":"I1308 – Maintenance d'installation de chauffage"},{"id":"I1309","name":"I1309 – Maintenance électrique"},{"id":"I1310","name":"I1310 – Maintenance mécanique industrielle"}]},{"id":"I14","name":"I14 – Equipements domestiques et informatique","children":[{"id":"I1401","name":"I1401 – Maintenance informatique et bureautique"},{"id":"I1402","name":"I1402 – Réparation de biens électrodomestiques et multimédia"}]},{"id":"I15","name":"I15 – Travaux d'accès difficile","children":[{"id":"I1501","name":"I1501 – Intervention en grande hauteur"},{"id":"I1502","name":"I1502 – Intervention en milieu subaquatique"},{"id":"I1503","name":"I1503 – Intervention en milieux et produits nocifs"}]},{"id":"I16","name":"I16 – Véhicules, engins, aéronefs","children":[{"id":"I1601","name":"I1601 – Installation et maintenance en nautisme"},{"id":"I1602","name":"I1602 – Maintenance d'aéronefs"},{"id":"I1603","name":"I1603 – Maintenance d'engins de chantier, levage, manutention et de machines agricoles"},{"id":"I1604","name":"I1604 – Mécanique automobile et entretien de véhicules"},{"id":"I1605","name":"I1605 – Mécanique de marine"},{"id":"I1606","name":"I1606 – Réparation de carrosserie"},{"id":"I1607","name":"I1607 – Réparation de cycles, motocycles et motoculteurs de loisirs"}]}]},{"id":"J","name":"J – Santé","children":[{"id":"J11","name":"J11 – Praticiens médicaux","children":[{"id":"J1101","name":"J1101 – Médecine de prévention"},{"id":"J1102","name":"J1102 – Médecine généraliste et spécialisée"},{"id":"J1103","name":"J1103 – Médecine dentaire"},{"id":"J1104","name":"J1104 – Suivi de la grossesse et de l'accouchement"}]},{"id":"J12","name":"J12 – Praticiens médico-techniques","children":[{"id":"J1201","name":"J1201 – Biologie médicale"},{"id":"J1202","name":"J1202 – Pharmacie"}]},{"id":"J13","name":"J13 – Professionnels médico-techniques","children":[{"id":"J1301","name":"J1301 – Personnel polyvalent des services hospitaliers"},{"id":"J1302","name":"J1302 – Analyses médicales"},{"id":"J1303","name":"J1303 – Assistance médico-technique"},{"id":"J1304","name":"J1304 – Aide en puériculture"},{"id":"J1305","name":"J1305 – Conduite de véhicules sanitaires"},{"id":"J1306","name":"J1306 – Imagerie médicale"},{"id":"J1307","name":"J1307 – Préparation en pharmacie"}]},{"id":"J14","name":"J14 – Rééducation et appareillage","children":[{"id":"J1401","name":"J1401 – Audioprothèses"},{"id":"J1402","name":"J1402 – Diététique"},{"id":"J1403","name":"J1403 – Ergothérapie"},{"id":"J1404","name":"J1404 – Kinésithérapie"},{"id":"J1405","name":"J1405 – Optique - lunetterie"},{"id":"J1406","name":"J1406 – Orthophonie"},{"id":"J1407","name":"J1407 – Orthoptique"},{"id":"J1408","name":"J1408 – Ostéopathie et chiropraxie"},{"id":"J1409","name":"J1409 – Pédicurie et podologie"},{"id":"J1410","name":"J1410 – Prothèses dentaires"},{"id":"J1411","name":"J1411 – Prothèses et orthèses"},{"id":"J1412","name":"J1412 – Rééducation en psychomotricité"}]},{"id":"J15","name":"J15 – Soins paramédicaux","children":[{"id":"J1501","name":"J1501 – Soins d'hygiène, de confort du patient"},{"id":"J1502","name":"J1502 – Coordination de services médicaux ou paramédicaux"},{"id":"J1503","name":"J1503 – Soins infirmiers spécialisés en anesthésie"},{"id":"J1504","name":"J1504 – Soins infirmiers spécialisés en bloc opératoire"},{"id":"J1505","name":"J1505 – Soins infirmiers spécialisés en prévention"},{"id":"J1506","name":"J1506 – Soins infirmiers généralistes"},{"id":"J1507","name":"J1507 – Soins infirmiers spécialisés en puériculture"}]}]},{"id":"K","name":"K – Services à la personne et à la collectivité","children":[{"id":"K11","name":"K11 – Accompagnement de la personne","children":[{"id":"K1101","name":"K1101 – Accompagnement et médiation familiale"},{"id":"K1102","name":"K1102 – Aide aux bénéficiaires d'une mesure de protection juridique"},{"id":"K1103","name":"K1103 – Développement personnel et bien-être de la personne"},{"id":"K1104","name":"K1104 – Psychologie"}]},{"id":"K12","name":"K12 – Action sociale, socio-éducative et socio-culturelle","children":[{"id":"K1201","name":"K1201 – Action sociale"},{"id":"K1202","name":"K1202 – Éducation de jeunes enfants"},{"id":"K1203","name":"K1203 – Encadrement technique en insertion professionnelle"},{"id":"K1204","name":"K1204 – Médiation sociale et facilitation de la vie en société"},{"id":"K1205","name":"K1205 – Information sociale"},{"id":"K1206","name":"K1206 – Intervention socioculturelle"},{"id":"K1207","name":"K1207 – Intervention socioéducative"}]},{"id":"K13","name":"K13 – Aide à la vie quotidienne","children":[{"id":"K1301","name":"K1301 – Accompagnement médicosocial"},{"id":"K1302","name":"K1302 – Assistance auprès d'adultes"},{"id":"K1303","name":"K1303 – Assistance auprès d'enfants"},{"id":"K1304","name":"K1304 – Services domestiques"},{"id":"K1305","name":"K1305 – Intervention sociale et familiale"}]},{"id":"K14","name":"K14 – Conception et mise en oeuvre des politiques publiques","children":[{"id":"K1401","name":"K1401 – Conception et pilotage de la politique des pouvoirs publics"},{"id":"K1402","name":"K1402 – Conseil en Santé Publique"},{"id":"K1403","name":"K1403 – Management de structure de santé, sociale ou pénitentiaire"},{"id":"K1404","name":"K1404 – Mise en oeuvre et pilotage de la politique des pouvoirs publics"},{"id":"K1405","name":"K1405 – Représentation de l'État sur le territoire national ou international"}]},{"id":"K15","name":"K15 – Contrôle public","children":[{"id":"K1501","name":"K1501 – Application des règles financières publiques"},{"id":"K1502","name":"K1502 – Contrôle et inspection des Affaires Sociales"},{"id":"K1503","name":"K1503 – Contrôle et inspection des impôts"},{"id":"K1504","name":"K1504 – Contrôle et inspection du Trésor Public"},{"id":"K1505","name":"K1505 – Protection des consommateurs et contrôle des échanges commerciaux"}]},{"id":"K16","name":"K16 – Culture et gestion documentaire","children":[{"id":"K1601","name":"K1601 – Gestion de l'information et de la documentation"},{"id":"K1602","name":"K1602 – Gestion de patrimoine culturel"}]},{"id":"K17","name":"K17 – Défense, sécurité publique et secours","children":[{"id":"K1701","name":"K1701 – Personnel de la Défense"},{"id":"K1702","name":"K1702 – Direction de la sécurité civile et des secours"},{"id":"K1703","name":"K1703 – Direction opérationnelle de la défense"},{"id":"K1704","name":"K1704 – Management de la sécurité publique"},{"id":"K1705","name":"K1705 – Sécurité civile et secours"},{"id":"K1706","name":"K1706 – Sécurité publique"},{"id":"K1707","name":"K1707 – Surveillance municipale"}]},{"id":"K18","name":"K18 – Développement territorial et emploi","children":[{"id":"K1801","name":"K1801 – Conseil en emploi et insertion socioprofessionnelle"},{"id":"K1802","name":"K1802 – Développement local"}]},{"id":"K19","name":"K19 – Droit","children":[{"id":"K1901","name":"K1901 – Aide et médiation judiciaire"},{"id":"K1902","name":"K1902 – Collaboration juridique"},{"id":"K1903","name":"K1903 – Défense et conseil juridique"},{"id":"K1904","name":"K1904 – Magistrature"}]},{"id":"K21","name":"K21 – Formation initiale et continue","children":[{"id":"K2101","name":"K2101 – Conseil en formation"},{"id":"K2102","name":"K2102 – Coordination pédagogique"},{"id":"K2103","name":"K2103 – Direction d'établissement et d'enseignement"},{"id":"K2104","name":"K2104 – Éducation et surveillance au sein d'établissements d'enseignement"},{"id":"K2105","name":"K2105 – Enseignement artistique"},{"id":"K2106","name":"K2106 – Enseignement des écoles"},{"id":"K2107","name":"K2107 – Enseignement général du second degré"},{"id":"K2108","name":"K2108 – Enseignement supérieur"},{"id":"K2109","name":"K2109 – Enseignement technique et professionnel"},{"id":"K2110","name":"K2110 – Formation en conduite de véhicules"},{"id":"K2111","name":"K2111 – Formation professionnelle"},{"id":"K2112","name":"K2112 – Orientation scolaire et professionnelle"}]},{"id":"K22","name":"K22 – Nettoyage et propreté industriels","children":[{"id":"K2201","name":"K2201 – Blanchisserie industrielle"},{"id":"K2202","name":"K2202 – Lavage de vitres"},{"id":"K2203","name":"K2203 – Management et inspection en propreté de locaux"},{"id":"K2204","name":"K2204 – Nettoyage de locaux"}]},{"id":"K23","name":"K23 – Propreté et environnement urbain","children":[{"id":"K2301","name":"K2301 – Distribution et assainissement d'eau"},{"id":"K2302","name":"K2302 – Management et inspection en environnement urbain"},{"id":"K2303","name":"K2303 – Nettoyage des espaces urbains"},{"id":"K2304","name":"K2304 – Revalorisation de produits industriels"},{"id":"K2305","name":"K2305 – Salubrité et traitement de nuisibles"},{"id":"K2306","name":"K2306 – Supervision d'exploitation éco-industrielle"}]},{"id":"K24","name":"K24 – Recherche","children":[{"id":"K2401","name":"K2401 – Recherche en sciences de l'homme et de la société"},{"id":"K2402","name":"K2402 – Recherche en sciences de l'univers, de la matière et du vivant"}]},{"id":"K25","name":"K25 – Sécurité privée","children":[{"id":"K2501","name":"K2501 – Gardiennage de locaux"},{"id":"K2502","name":"K2502 – Management de sécurité privée"},{"id":"K2503","name":"K2503 – Sécurité et surveillance privées"}]},{"id":"K26","name":"K26 – Services funéraires","children":[{"id":"K2601","name":"K2601 – Conduite d'opérations funéraires"},{"id":"K2602","name":"K2602 – Conseil en services funéraires"},{"id":"K2603","name":"K2603 – Thanatopraxie"}]}]},{"id":"L","name":"L – Spectacle","children":[{"id":"L11","name":"L11 – Animation de spectacles","children":[{"id":"L1101","name":"L1101 – Animation musicale et scénique"},{"id":"L1102","name":"L1102 – Mannequinat et pose artistique"},{"id":"L1103","name":"L1103 – Présentation de spectacles ou d'émissions"}]},{"id":"L12","name":"L12 – Artistes - interprètes du spectacle","children":[{"id":"L1201","name":"L1201 – Danse"},{"id":"L1202","name":"L1202 – Musique et chant"},{"id":"L1203","name":"L1203 – Art dramatique"},{"id":"L1204","name":"L1204 – Arts du cirque et arts visuels"}]},{"id":"L13","name":"L13 – Conception et production de spectacles","children":[{"id":"L1301","name":"L1301 – Mise en scène de spectacles vivants"},{"id":"L1302","name":"L1302 – Production et administration spectacle, cinéma et audiovisuel"},{"id":"L1303","name":"L1303 – Promotion d'artistes et de spectacles"},{"id":"L1304","name":"L1304 – Réalisation cinématographique et audiovisuelle"}]},{"id":"L14","name":"L14 – Sport professionnel","children":[{"id":"L1401","name":"L1401 – Sportif professionnel"}]},{"id":"L15","name":"L15 – Techniciens du spectacle","children":[{"id":"L1501","name":"L1501 – Coiffure et maquillage spectacle"},{"id":"L1502","name":"L1502 – Costume et habillage spectacle"},{"id":"L1503","name":"L1503 – Décor et accessoires spectacle"},{"id":"L1504","name":"L1504 – Éclairage spectacle"},{"id":"L1505","name":"L1505 – Image cinématographique et télévisuelle"},{"id":"L1506","name":"L1506 – Machinerie spectacle"},{"id":"L1507","name":"L1507 – Montage audiovisuel et post-production"},{"id":"L1508","name":"L1508 – Prise de son et sonorisation"},{"id":"L1509","name":"L1509 – Régie générale"},{"id":"L1510","name":"L1510 – Films d'animation et effets spéciaux"}]}]},{"id":"M","name":"M – Support à l'entreprise","children":[{"id":"M11","name":"M11 – Achats","children":[{"id":"M1101","name":"M1101 – Achats"},{"id":"M1102","name":"M1102 – Direction des achats"}]},{"id":"M12","name":"M12 – Comptabilité et gestion","children":[{"id":"M1201","name":"M1201 – Analyse et ingénierie financière"},{"id":"M1202","name":"M1202 – Audit et contrôle comptables et financiers"},{"id":"M1203","name":"M1203 – Comptabilité"},{"id":"M1204","name":"M1204 – Contrôle de gestion"},{"id":"M1205","name":"M1205 – Direction administrative et financière"},{"id":"M1206","name":"M1206 – Management de groupe ou de service comptable"},{"id":"M1207","name":"M1207 – Trésorerie et financement"}]},{"id":"M13","name":"M13 – Direction d'entreprise","children":[{"id":"M1301","name":"M1301 – Direction de grande entreprise ou d'établissement public"},{"id":"M1302","name":"M1302 – Direction de petite ou moyenne entreprise"}]},{"id":"M14","name":"M14 – Organisation et études","children":[{"id":"M1401","name":"M1401 – Conduite d'enquêtes"},{"id":"M1402","name":"M1402 – Conseil en organisation et management d'entreprise"},{"id":"M1403","name":"M1403 – Études et prospectives socio-économiques"},{"id":"M1404","name":"M1404 – Management et gestion d'enquêtes"}]},{"id":"M15","name":"M15 – Ressources humaines","children":[{"id":"M1501","name":"M1501 – Assistanat en ressources humaines"},{"id":"M1502","name":"M1502 – Développement des ressources humaines"},{"id":"M1503","name":"M1503 – Management des ressources humaines"}]},{"id":"M16","name":"M16 – Secrétariat et assistance","children":[{"id":"M1601","name":"M1601 – Accueil et renseignements"},{"id":"M1602","name":"M1602 – Opérations administratives"},{"id":"M1603","name":"M1603 – Distribution de documents"},{"id":"M1604","name":"M1604 – Assistanat de direction"},{"id":"M1605","name":"M1605 – Assistanat technique et administratif"},{"id":"M1606","name":"M1606 – Saisie de données"},{"id":"M1607","name":"M1607 – Secrétariat"},{"id":"M1608","name":"M1608 – Secrétariat comptable"},{"id":"M1609","name":"M1609 – Secrétariat et assistanat médical ou médico-social"}]},{"id":"M17","name":"M17 – Stratégie commerciale, marketing et supervision des ventes","children":[{"id":"M1701","name":"M1701 – Administration des ventes"},{"id":"M1702","name":"M1702 – Analyse de tendance"},{"id":"M1703","name":"M1703 – Management et gestion de produit"},{"id":"M1704","name":"M1704 – Management relation clientèle"},{"id":"M1705","name":"M1705 – Marketing"},{"id":"M1706","name":"M1706 – Promotion des ventes"},{"id":"M1707","name":"M1707 – Stratégie commerciale"}]},{"id":"M18","name":"M18 – Systèmes d'information et de télécommunication","children":[{"id":"M1801","name":"M1801 – Administration de systèmes d'information"},{"id":"M1802","name":"M1802 – Expertise et support en systèmes d'information"},{"id":"M1803","name":"M1803 – Direction des systèmes d'information"},{"id":"M1804","name":"M1804 – Études et développement de réseaux de télécoms"},{"id":"M1805","name":"M1805 – Études et développement informatique"},{"id":"M1806","name":"M1806 – Conseil et maîtrise d'ouvrage en systèmes d'information"},{"id":"M1807","name":"M1807 – Exploitation de systèmes de communication et de commandement"},{"id":"M1808","name":"M1808 – Information géographique"},{"id":"M1809","name":"M1809 – Information météorologique"},{"id":"M1810","name":"M1810 – Production et exploitation de systèmes d'information"}]}]},{"id":"N","name":"N – Transport et Logistique","children":[{"id":"N11","name":"N11 – Magasinage, manutention des charges et déménagement","children":[{"id":"N1101","name":"N1101 – Conduite d'engins de déplacement des charges"},{"id":"N1102","name":"N1102 – Déménagement"},{"id":"N1103","name":"N1103 – Magasinage et préparation de commandes"},{"id":"N1104","name":"N1104 – Manoeuvre et conduite d'engins lourds de manutention"},{"id":"N1105","name":"N1105 – Manutention manuelle de charges"}]},{"id":"N12","name":"N12 – Organisation de la circulation des marchandises","children":[{"id":"N1201","name":"N1201 – Affrètement transport"},{"id":"N1202","name":"N1202 – Gestion des opérations de circulation internationale des marchandises"}]},{"id":"N13","name":"N13 – Personnel d'encadrement de la logistique","children":[{"id":"N1301","name":"N1301 – Conception et organisation de la chaîne logistique"},{"id":"N1302","name":"N1302 – Direction de site logistique"},{"id":"N1303","name":"N1303 – Intervention technique d'exploitation logistique"}]},{"id":"N21","name":"N21 – Personnel navigant du transport aérien","children":[{"id":"N2101","name":"N2101 – Navigation commerciale aérienne"},{"id":"N2102","name":"N2102 – Pilotage et navigation technique aérienne"}]},{"id":"N22","name":"N22 – Personnel sédentaire du transport aérien","children":[{"id":"N2201","name":"N2201 – Personnel d'escale aéroportuaire"},{"id":"N2202","name":"N2202 – Contrôle de la navigation aérienne"},{"id":"N2203","name":"N2203 – Exploitation des pistes aéroportuaires"},{"id":"N2204","name":"N2204 – Préparation des vols"},{"id":"N2205","name":"N2205 – Direction d'escale et exploitation aéroportuaire"}]},{"id":"N31","name":"N31 – Personnel navigant du transport maritime et fluvial","children":[{"id":"N3101","name":"N3101 – Encadrement de la navigation maritime"},{"id":"N3102","name":"N3102 – Équipage de la navigation maritime"},{"id":"N3103","name":"N3103 – Navigation fluviale"}]},{"id":"N32","name":"N32 – Personnel sédentaire du transport maritime et fluvial","children":[{"id":"N3201","name":"N3201 – Exploitation des opérations portuaires et du transport maritime"},{"id":"N3202","name":"N3202 – Exploitation du transport fluvial"},{"id":"N3203","name":"N3203 – Manutention portuaire"}]},{"id":"N41","name":"N41 – Personnel de conduite du transport routier","children":[{"id":"N4101","name":"N4101 – Conduite de transport de marchandises sur longue distance"},{"id":"N4102","name":"N4102 – Conduite de transport de particuliers"},{"id":"N4103","name":"N4103 – Conduite de transport en commun sur route"},{"id":"N4104","name":"N4104 – Courses et livraisons express"},{"id":"N4105","name":"N4105 – Conduite et livraison par tournées sur courte distance"}]},{"id":"N42","name":"N42 – Personnel d'encadrement du transport routier","children":[{"id":"N4201","name":"N4201 – Direction d'exploitation des transports routiers de marchandises"},{"id":"N4202","name":"N4202 – Direction d'exploitation des transports routiers de personnes"},{"id":"N4203","name":"N4203 – Intervention technique d'exploitation des transports routiers de marchandises"},{"id":"N4204","name":"N4204 – Intervention technique d'exploitation des transports routiers de personnes"}]},{"id":"N43","name":"N43 – Personnel navigant du transport terrestre","children":[{"id":"N4301","name":"N4301 – Conduite sur rails"},{"id":"N4302","name":"N4302 – Contrôle des transports en commun"}]},{"id":"N44","name":"N44 – Personnel sédentaire du transport ferroviaire et réseau filo guidé","children":[{"id":"N4401","name":"N4401 – Circulation du réseau ferré"},{"id":"N4402","name":"N4402 – Exploitation et manoeuvre des remontées mécaniques"},{"id":"N4403","name":"N4403 – Manoeuvre du réseau ferré"}]}]}] \ No newline at end of file diff --git a/ui/theme/components/checkbox.js b/ui/theme/components/checkbox.js index 5bd214d3d..67475371e 100644 --- a/ui/theme/components/checkbox.js +++ b/ui/theme/components/checkbox.js @@ -15,6 +15,17 @@ const Checkbox = { border: "1px", }, }, + _indeterminate: { + background: "bluefrance", + color: "white", + borderColor: "#161616", + border: "1px", + _hover: { + background: "bluefrance", + borderColor: "#161616", + border: "1px", + }, + }, }, }, }; diff --git a/ui/yarn.lock b/ui/yarn.lock index 8c806ecdf..f75706593 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -10605,6 +10605,11 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" +react-accessible-treeview@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/react-accessible-treeview/-/react-accessible-treeview-2.8.0.tgz#2ae780b133719e5c6cdf372b1ffd9608b4366dad" + integrity sha512-ZGdXwUNa7gn99gkHknOE5ysqspwTDCzjDzclmN61uzRkVovetW8fBTFQAgddZKprL9lrQBISTof9fahx1FAxmA== + react-clientside-effect@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a"