@tekkare/romulus 0.1.254 → 0.1.256
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/assets/styles/shell.css +1 -1
- package/dist/runtime/components/SidebarLeft.vue +110 -2
- package/layer/app/components/OipShell.vue +10 -3
- package/layer/app/components/oip-patients/ConnectionsGraph.vue +354 -0
- package/layer/app/components/oip-patients/PatientFiche.vue +732 -0
- package/layer/app/components/oip-patients/Publications.vue +298 -0
- package/layer/app/components/oip-patients/PubmedDrawer.vue +379 -0
- package/layer/app/components/oip-patients/VaccineFiche.vue +766 -0
- package/layer/app/composables/useOipResourceViews.ts +4 -0
- package/layer/app/oip-patients/cytoscape-fcose.d.ts +2 -0
- package/layer/app/oip-patients/indexes.ts +15 -0
- package/layer/app/oip-patients/kinds.ts +47 -0
- package/layer/app/oip-patients/labels.ts +142 -0
- package/layer/app/oip-patients/patients.css +54 -0
- package/layer/app/oip-patients/types.ts +149 -0
- package/layer/app/oip-patients/useCaseRecord.ts +78 -0
- package/layer/app/oip-patients/vaccineLabels.ts +180 -0
- package/layer/app/oip-science/composables/useEuct.ts +1 -1
- package/layer/app/oip-science/composables/useOipElastic.ts +5 -2
- package/layer/app/oip-science/composables/usePubmed.ts +2 -2
- package/layer/app/oip-science/indexConfig.json +32 -26
- package/layer/app/types/oip.ts +2 -0
- package/layer/app/utils/oipResources.ts +34 -2
- package/layer/nuxt.config.ts +8 -4
- package/layer/server/api/oip/es.post.ts +21 -4
- package/package.json +5 -2
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Libelles des vocabulaires de l'index des cas apres vaccination.
|
|
3
|
+
*
|
|
4
|
+
* Les listes fermees viennent du pipeline (ai-pipelines, backend/app/vaccine.py) :
|
|
5
|
+
* gravite, evolution, avis des auteurs, dose suivante, type de cas, delai. Les
|
|
6
|
+
* cles de produit et d'agent sont derivees du nom ecrit dans l'article ; une
|
|
7
|
+
* cle que ce module ne connait pas s'affiche mise en forme, jamais vide.
|
|
8
|
+
*/
|
|
9
|
+
import type { PatientLang } from "./labels";
|
|
10
|
+
|
|
11
|
+
type Labels = Record<string, { fr: string; en: string }>;
|
|
12
|
+
|
|
13
|
+
/** `sars_cov_2` → « Sars cov 2 » : le dernier recours, pour une cle inconnue. */
|
|
14
|
+
function prettify(value: string): string {
|
|
15
|
+
return value.replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Le libelle d'une valeur, ou la valeur mise en forme quand le vocabulaire ne la connait pas. */
|
|
19
|
+
export function vaccineLabelOf(labels: Labels, value: string | number | null | undefined, lang: PatientLang): string {
|
|
20
|
+
if (value === null || value === undefined || value === "") return "";
|
|
21
|
+
const key = String(value);
|
|
22
|
+
return labels[key]?.[lang] ?? prettify(key);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const SERIOUSNESS_LABELS: Labels = {
|
|
26
|
+
death: { fr: "Décès", en: "Died" },
|
|
27
|
+
life_threatening: { fr: "Pronostic vital engagé", en: "Life-threatening" },
|
|
28
|
+
hospitalisation: { fr: "Hospitalisation", en: "Admitted to hospital" },
|
|
29
|
+
disability: { fr: "Séquelle invalidante", en: "Lasting disability" },
|
|
30
|
+
medically_important: { fr: "Soins médicaux nécessaires", en: "Needed medical care" },
|
|
31
|
+
not_serious: { fr: "Non grave", en: "Not serious" },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** Les gravites qui font un cas « grave » au sens de la pharmacovigilance. */
|
|
35
|
+
export const SERIOUS_KEYS = ["death", "life_threatening", "hospitalisation", "disability"];
|
|
36
|
+
|
|
37
|
+
export const EVENT_OUTCOME_LABELS: Labels = {
|
|
38
|
+
recovered: { fr: "Guéri", en: "Recovered" },
|
|
39
|
+
recovering: { fr: "En voie de guérison", en: "Recovering" },
|
|
40
|
+
sequelae: { fr: "Guéri avec séquelles", en: "Recovered with after-effects" },
|
|
41
|
+
not_recovered: { fr: "Non guéri", en: "Not recovered" },
|
|
42
|
+
fatal: { fr: "Décès", en: "Died" },
|
|
43
|
+
unknown: { fr: "Non précisé", en: "Not reported" },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const CAUSALITY_LABELS: Labels = {
|
|
47
|
+
certain: { fr: "Lien certain", en: "Certain link" },
|
|
48
|
+
probable: { fr: "Lien probable", en: "Probable link" },
|
|
49
|
+
possible: { fr: "Lien possible", en: "Possible link" },
|
|
50
|
+
unlikely: { fr: "Lien peu probable", en: "Unlikely link" },
|
|
51
|
+
temporal_only: { fr: "Chronologie seule, sans conclusion", en: "Timing only, no causal claim" },
|
|
52
|
+
not_assessed: { fr: "Non discuté", en: "Not discussed" },
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const RECHALLENGE_LABELS: Labels = {
|
|
56
|
+
re_vaccinated_no_event: { fr: "Dose suivante reçue, sans récidive", en: "Next dose given, no problem" },
|
|
57
|
+
re_vaccinated_recurrence: { fr: "Dose suivante reçue, récidive", en: "Next dose given, it happened again" },
|
|
58
|
+
not_re_vaccinated: { fr: "Pas de dose suivante", en: "No further dose" },
|
|
59
|
+
advised_against: { fr: "Doses suivantes déconseillées", en: "Further doses advised against" },
|
|
60
|
+
unknown: { fr: "Non précisé", en: "Not reported" },
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const EVENT_CATEGORY_LABELS: Labels = {
|
|
64
|
+
adverse_event: { fr: "Événement après vaccination", en: "Event after vaccination" },
|
|
65
|
+
breakthrough_infection: { fr: "Infection malgré la vaccination", en: "Infection despite vaccination" },
|
|
66
|
+
vaccine_failure: { fr: "Échec de protection", en: "Vaccine did not protect" },
|
|
67
|
+
vaccination_in_special_population: { fr: "Vaccination en situation particulière", en: "Vaccination in a special situation" },
|
|
68
|
+
not_vaccine_related: { fr: "Sans lien avec un vaccin", en: "Not about a vaccine" },
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** Dans l'ordre du temps : la facette les range ainsi, pas par effectif. */
|
|
72
|
+
export const ONSET_BAND_LABELS: Labels = {
|
|
73
|
+
same_day: { fr: "Le jour même", en: "Same day" },
|
|
74
|
+
within_week: { fr: "Dans la semaine", en: "Within a week" },
|
|
75
|
+
within_month: { fr: "1 à 4 semaines", en: "1 to 4 weeks" },
|
|
76
|
+
within_3_months: { fr: "1 à 3 mois", en: "1 to 3 months" },
|
|
77
|
+
later: { fr: "Plus de 3 mois", en: "More than 3 months" },
|
|
78
|
+
unknown: { fr: "Non précisé", en: "Not stated" },
|
|
79
|
+
};
|
|
80
|
+
export const ONSET_BAND_ORDER = Object.keys(ONSET_BAND_LABELS);
|
|
81
|
+
|
|
82
|
+
export const PLATFORM_LABELS: Labels = {
|
|
83
|
+
mrna: { fr: "ARN messager", en: "mRNA" },
|
|
84
|
+
"viral vector": { fr: "Vecteur viral", en: "Viral vector" },
|
|
85
|
+
inactivated: { fr: "Inactivé", en: "Inactivated" },
|
|
86
|
+
"live attenuated": { fr: "Vivant atténué", en: "Live attenuated" },
|
|
87
|
+
subunit: { fr: "Sous-unitaire", en: "Subunit" },
|
|
88
|
+
toxoid: { fr: "Anatoxine", en: "Toxoid" },
|
|
89
|
+
conjugate: { fr: "Conjugué", en: "Conjugate" },
|
|
90
|
+
polysaccharide: { fr: "Polysaccharidique", en: "Polysaccharide" },
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const PATHOGEN_LABELS: Labels = {
|
|
94
|
+
sars_cov_2: { fr: "Covid-19 (SARS-CoV-2)", en: "Covid-19 (SARS-CoV-2)" },
|
|
95
|
+
varicella_zoster: { fr: "Varicelle, zona", en: "Chickenpox, shingles" },
|
|
96
|
+
hpv: { fr: "Papillomavirus (HPV)", en: "Papillomavirus (HPV)" },
|
|
97
|
+
tuberculosis: { fr: "Tuberculose", en: "Tuberculosis" },
|
|
98
|
+
measles: { fr: "Rougeole", en: "Measles" },
|
|
99
|
+
yellow_fever: { fr: "Fièvre jaune", en: "Yellow fever" },
|
|
100
|
+
rabies: { fr: "Rage", en: "Rabies" },
|
|
101
|
+
influenza: { fr: "Grippe", en: "Influenza" },
|
|
102
|
+
pneumococcus: { fr: "Pneumocoque", en: "Pneumococcus" },
|
|
103
|
+
meningococcus: { fr: "Méningocoque", en: "Meningococcus" },
|
|
104
|
+
hepatitis_b: { fr: "Hépatite B", en: "Hepatitis B" },
|
|
105
|
+
hepatitis_a: { fr: "Hépatite A", en: "Hepatitis A" },
|
|
106
|
+
tetanus: { fr: "Tétanos, diphtérie, coqueluche", en: "Tetanus, diphtheria, pertussis" },
|
|
107
|
+
rotavirus: { fr: "Rotavirus", en: "Rotavirus" },
|
|
108
|
+
rsv: { fr: "Virus respiratoire syncytial (VRS)", en: "Respiratory syncytial virus (RSV)" },
|
|
109
|
+
dengue: { fr: "Dengue", en: "Dengue" },
|
|
110
|
+
japanese_encephalitis: { fr: "Encéphalite japonaise", en: "Japanese encephalitis" },
|
|
111
|
+
typhoid: { fr: "Typhoïde", en: "Typhoid" },
|
|
112
|
+
polio: { fr: "Poliomyélite", en: "Polio" },
|
|
113
|
+
mpox: { fr: "Mpox, variole", en: "Mpox, smallpox" },
|
|
114
|
+
ebola: { fr: "Ebola", en: "Ebola" },
|
|
115
|
+
tick_borne_encephalitis: { fr: "Encéphalite à tiques", en: "Tick-borne encephalitis" },
|
|
116
|
+
rubella: { fr: "Rubéole", en: "Rubella" },
|
|
117
|
+
mumps: { fr: "Oreillons", en: "Mumps" },
|
|
118
|
+
cholera: { fr: "Choléra", en: "Cholera" },
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const PRODUCT_LABELS: Labels = {
|
|
122
|
+
comirnaty: { fr: "Comirnaty (Pfizer-BioNTech)", en: "Comirnaty (Pfizer-BioNTech)" },
|
|
123
|
+
spikevax: { fr: "Spikevax (Moderna)", en: "Spikevax (Moderna)" },
|
|
124
|
+
vaxzevria: { fr: "Vaxzevria (AstraZeneca)", en: "Vaxzevria (AstraZeneca)" },
|
|
125
|
+
jcovden: { fr: "Jcovden (Janssen)", en: "Jcovden (Janssen)" },
|
|
126
|
+
nuvaxovid: { fr: "Nuvaxovid (Novavax)", en: "Nuvaxovid (Novavax)" },
|
|
127
|
+
coronavac: { fr: "CoronaVac (Sinovac)", en: "CoronaVac (Sinovac)" },
|
|
128
|
+
bbibp_corv: { fr: "BBIBP-CorV (Sinopharm)", en: "BBIBP-CorV (Sinopharm)" },
|
|
129
|
+
covaxin: { fr: "Covaxin", en: "Covaxin" },
|
|
130
|
+
convidecia: { fr: "Convidecia (CanSino)", en: "Convidecia (CanSino)" },
|
|
131
|
+
sputnik_v: { fr: "Spoutnik V", en: "Sputnik V" },
|
|
132
|
+
other_covid: { fr: "Autre vaccin Covid-19", en: "Other Covid-19 vaccine" },
|
|
133
|
+
unspecified_covid: { fr: "Vaccin Covid-19 non précisé", en: "Unspecified Covid-19 vaccine" },
|
|
134
|
+
shingrix: { fr: "Shingrix", en: "Shingrix" },
|
|
135
|
+
zostavax: { fr: "Zostavax", en: "Zostavax" },
|
|
136
|
+
varicella: { fr: "Varicelle", en: "Varicella" },
|
|
137
|
+
hpv: { fr: "HPV", en: "HPV" },
|
|
138
|
+
bcg: { fr: "BCG", en: "BCG" },
|
|
139
|
+
mmr: { fr: "ROR", en: "MMR" },
|
|
140
|
+
measles: { fr: "Rougeole", en: "Measles" },
|
|
141
|
+
yellow_fever: { fr: "Fièvre jaune", en: "Yellow fever" },
|
|
142
|
+
rabies: { fr: "Rage", en: "Rabies" },
|
|
143
|
+
influenza: { fr: "Grippe", en: "Influenza" },
|
|
144
|
+
pneumococcal: { fr: "Pneumocoque", en: "Pneumococcal" },
|
|
145
|
+
meningococcal: { fr: "Méningocoque", en: "Meningococcal" },
|
|
146
|
+
hepatitis_b: { fr: "Hépatite B", en: "Hepatitis B" },
|
|
147
|
+
hepatitis_a: { fr: "Hépatite A", en: "Hepatitis A" },
|
|
148
|
+
dtp: { fr: "Diphtérie, tétanos, coqueluche", en: "Diphtheria, tetanus, pertussis" },
|
|
149
|
+
rotavirus: { fr: "Rotavirus", en: "Rotavirus" },
|
|
150
|
+
rsv: { fr: "VRS", en: "RSV" },
|
|
151
|
+
dengue: { fr: "Dengue", en: "Dengue" },
|
|
152
|
+
japanese_encephalitis: { fr: "Encéphalite japonaise", en: "Japanese encephalitis" },
|
|
153
|
+
typhoid: { fr: "Typhoïde", en: "Typhoid" },
|
|
154
|
+
polio: { fr: "Poliomyélite", en: "Polio" },
|
|
155
|
+
mpox_smallpox: { fr: "Mpox, variole", en: "Mpox, smallpox" },
|
|
156
|
+
ebola: { fr: "Ebola", en: "Ebola" },
|
|
157
|
+
tbe: { fr: "Encéphalite à tiques", en: "Tick-borne encephalitis" },
|
|
158
|
+
rubella: { fr: "Rubéole", en: "Rubella" },
|
|
159
|
+
mumps: { fr: "Oreillons", en: "Mumps" },
|
|
160
|
+
cholera: { fr: "Choléra", en: "Cholera" },
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/** Ce qui retient une fiche d'etre comptee sans relecture, en clair. */
|
|
164
|
+
export const VACCINE_FLAG_LABELS: Labels = {
|
|
165
|
+
exposure_missing: { fr: "L'article ne nomme aucun vaccin pour cette personne", en: "The paper names no vaccine for this person" },
|
|
166
|
+
exposure_unsupported: { fr: "Le vaccin indiqué ne figure pas dans le texte de l'article", en: "The vaccine named was not found in the paper's own text" },
|
|
167
|
+
event_missing: { fr: "Aucun événement clair n'a été trouvé", en: "No clear event was found" },
|
|
168
|
+
onset_before_vaccination: { fr: "Les troubles ont commencé avant la dose", en: "The problem started before the dose" },
|
|
169
|
+
not_vaccine_related: { fr: "Le cas ne concerne pas un vaccin", en: "The report is not about a vaccine" },
|
|
170
|
+
block_failed: { fr: "Les informations sur le vaccin n'ont pas pu être lues", en: "The vaccine details could not be read" },
|
|
171
|
+
delay_not_from_dose: { fr: "Le délai est compté depuis un traitement ou un événement, pas depuis la dose", en: "The delay is counted from a treatment or event, not from the dose" },
|
|
172
|
+
delay_implausible: { fr: "Le délai dépasse dix ans : probablement un âge plutôt qu'un délai", en: "The delay is over ten years, more likely an age than a delay" },
|
|
173
|
+
reported_elsewhere: { fr: "Cas déjà publié ailleurs : la personne peut être comptée deux fois", en: "Case published elsewhere, so the person may be counted twice" },
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const CHECK_LABELS: Labels = {
|
|
177
|
+
all: { fr: "Toutes les fiches", en: "All records" },
|
|
178
|
+
clean: { fr: "Sans contrôle ouvert", en: "No open check" },
|
|
179
|
+
flagged: { fr: "À vérifier", en: "Needing a check" },
|
|
180
|
+
};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// de recherche) n'a pas de sens ici : les resultats reviennent a l'appelant.
|
|
6
6
|
|
|
7
7
|
import { instrumentSearchClause, searchMatchOf } from "./useOipSearchExplain";
|
|
8
|
+
import indexConfig from "../indexConfig.json";
|
|
8
9
|
|
|
9
10
|
export default function useOipElastic() {
|
|
10
11
|
const config = useRuntimeConfig();
|
|
@@ -459,8 +460,10 @@ export default function useOipElastic() {
|
|
|
459
460
|
};
|
|
460
461
|
|
|
461
462
|
// FETCH. FAS chose the aggregation shape from the current route (/pubmed,
|
|
462
|
-
// /euct); a layer view has no route of its own, the index says the same
|
|
463
|
-
|
|
463
|
+
// /euct); a layer view has no route of its own, the index says the same
|
|
464
|
+
// (indexes are Directus ids, resolved by the proxy).
|
|
465
|
+
const refs = String(index).split(',');
|
|
466
|
+
const currentPath = refs.includes(indexConfig.pubmed.index) ? '/pubmed' : refs.includes(indexConfig.euct.index) ? '/euct' : '';
|
|
464
467
|
const res: any = await esFetch(cluster, index, query);
|
|
465
468
|
|
|
466
469
|
if (!isDisposed && res) {
|
|
@@ -182,7 +182,7 @@ export default function usePubmed() {
|
|
|
182
182
|
const lastUpdatedData = async () => {
|
|
183
183
|
let lastUpdate = null;
|
|
184
184
|
await queryCustomElastic({
|
|
185
|
-
index:
|
|
185
|
+
index: indexConfig.pubmed.index,
|
|
186
186
|
customQuery: {
|
|
187
187
|
from: 0,
|
|
188
188
|
|
|
@@ -241,7 +241,7 @@ export default function usePubmed() {
|
|
|
241
241
|
};
|
|
242
242
|
|
|
243
243
|
queryCustomElastic({
|
|
244
|
-
index:
|
|
244
|
+
index: indexConfig.pubmed.index,
|
|
245
245
|
cluster: 'pubmed',
|
|
246
246
|
customQuery: customQuery ? customQuery : query,
|
|
247
247
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"globalCT": {
|
|
3
|
-
"index": "
|
|
3
|
+
"index": "9ec0c673-7da4-4ead-8359-2d23b7b1318a",
|
|
4
4
|
"nameList": "/ctgov/&ListName=globalCTList",
|
|
5
5
|
"keyName": "globalCTList",
|
|
6
6
|
"cluster": "pubmed",
|
|
@@ -68,7 +68,6 @@
|
|
|
68
68
|
"Keywords": "keywords.keyword_name"
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
|
-
|
|
72
71
|
"Arm and Intervention": {
|
|
73
72
|
"type": "field",
|
|
74
73
|
"values": {
|
|
@@ -78,7 +77,9 @@
|
|
|
78
77
|
},
|
|
79
78
|
"Genes": {
|
|
80
79
|
"type": "field",
|
|
81
|
-
"values": {
|
|
80
|
+
"values": {
|
|
81
|
+
"Genes": "genomics.symbol"
|
|
82
|
+
}
|
|
82
83
|
},
|
|
83
84
|
"Rare Diseases": {
|
|
84
85
|
"type": "nested_field",
|
|
@@ -90,7 +91,7 @@
|
|
|
90
91
|
}
|
|
91
92
|
},
|
|
92
93
|
"globalCTInvestigators": {
|
|
93
|
-
"index": "
|
|
94
|
+
"index": "de97c889-a844-430d-ad39-b42812787f21",
|
|
94
95
|
"nameList": "/ctgov/investigators&ListName=globalCTInvestigatorList",
|
|
95
96
|
"keyName": "globalCTInvestigatorList",
|
|
96
97
|
"cluster": "pubmed",
|
|
@@ -115,7 +116,7 @@
|
|
|
115
116
|
]
|
|
116
117
|
},
|
|
117
118
|
"globalCTCenters": {
|
|
118
|
-
"index": "
|
|
119
|
+
"index": "b1e521b1-8722-406b-88e5-1c49d9cb7fa8",
|
|
119
120
|
"nameList": "/ctgov/centers&ListName=globalCTCenterList",
|
|
120
121
|
"keyName": "globalCTCenterList",
|
|
121
122
|
"cluster": "pubmed",
|
|
@@ -142,7 +143,7 @@
|
|
|
142
143
|
]
|
|
143
144
|
},
|
|
144
145
|
"euct": {
|
|
145
|
-
"index": "
|
|
146
|
+
"index": "c332f362-2311-4025-b5de-327f81913f7d",
|
|
146
147
|
"nameList": "/euct/&ListName=euCTList",
|
|
147
148
|
"keyName": "euCTList",
|
|
148
149
|
"cluster": "pubmed",
|
|
@@ -234,7 +235,7 @@
|
|
|
234
235
|
}
|
|
235
236
|
},
|
|
236
237
|
"euctInvestigators": {
|
|
237
|
-
"index": "
|
|
238
|
+
"index": "fb8896df-8798-4bab-8219-2462d948a7a0",
|
|
238
239
|
"nameList": "/euct/investigators&ListName=euroCTInvestigatorList",
|
|
239
240
|
"keyName": "euroCTInvestigatorList",
|
|
240
241
|
"cluster": "pubmed",
|
|
@@ -247,7 +248,6 @@
|
|
|
247
248
|
"records.therapeutic_area",
|
|
248
249
|
"records.diseases.icd10.combined_label",
|
|
249
250
|
"records.diseases.section.label"
|
|
250
|
-
|
|
251
251
|
],
|
|
252
252
|
"nestedFields": [],
|
|
253
253
|
"SuggFields": [
|
|
@@ -262,7 +262,7 @@
|
|
|
262
262
|
]
|
|
263
263
|
},
|
|
264
264
|
"euctCenters": {
|
|
265
|
-
"index": "
|
|
265
|
+
"index": "7f2e9e35-4bbd-4cbd-afb3-bab35999e17f",
|
|
266
266
|
"nameList": "/euct/centers&ListName=euroCTCenterList",
|
|
267
267
|
"keyName": "euroCTCenterList",
|
|
268
268
|
"cluster": "pubmed",
|
|
@@ -295,7 +295,7 @@
|
|
|
295
295
|
]
|
|
296
296
|
},
|
|
297
297
|
"gene": {
|
|
298
|
-
"index": "
|
|
298
|
+
"index": "78743dbc-1c7d-4f34-8222-026a78d4e8b1",
|
|
299
299
|
"nameList": "/omics/genes&ListName=omicsList",
|
|
300
300
|
"keyName": "omicsList",
|
|
301
301
|
"cluster": "pubmed",
|
|
@@ -366,7 +366,7 @@
|
|
|
366
366
|
}
|
|
367
367
|
},
|
|
368
368
|
"molecule": {
|
|
369
|
-
"index": "
|
|
369
|
+
"index": "64716d7e-eb95-492b-b91d-56c68f4f8911",
|
|
370
370
|
"nameList": "/omics/molecules&ListName=moleculesList",
|
|
371
371
|
"keyName": "moleculesList",
|
|
372
372
|
"cluster": "pubmed",
|
|
@@ -414,7 +414,7 @@
|
|
|
414
414
|
}
|
|
415
415
|
},
|
|
416
416
|
"pubmed": {
|
|
417
|
-
"index": "
|
|
417
|
+
"index": "cf7919cf-3980-4cf1-b192-f4e3b7d52a19",
|
|
418
418
|
"nameList": "/pubmed&ListName=pubMedList",
|
|
419
419
|
"keyName": "pubMedList",
|
|
420
420
|
"cluster": "pubmed",
|
|
@@ -533,7 +533,7 @@
|
|
|
533
533
|
}
|
|
534
534
|
},
|
|
535
535
|
"disease": {
|
|
536
|
-
"index": "
|
|
536
|
+
"index": "40a95d53-f41b-4370-8745-0217684fb5b4",
|
|
537
537
|
"nameList": "/omics/diseases&ListName=diseasesList",
|
|
538
538
|
"keyName": "diseasesList",
|
|
539
539
|
"cluster": "pubmed",
|
|
@@ -545,7 +545,9 @@
|
|
|
545
545
|
"search_text",
|
|
546
546
|
"concat_disease_name_icd10_code"
|
|
547
547
|
],
|
|
548
|
-
"nestedFields": [
|
|
548
|
+
"nestedFields": [
|
|
549
|
+
"icd10.code"
|
|
550
|
+
],
|
|
549
551
|
"SuggFields": [
|
|
550
552
|
"symbol",
|
|
551
553
|
"synonym",
|
|
@@ -587,11 +589,16 @@
|
|
|
587
589
|
}
|
|
588
590
|
},
|
|
589
591
|
"patent": {
|
|
590
|
-
"index": "
|
|
592
|
+
"index": "4587721d-538a-458d-9eb1-fc24911f366d",
|
|
591
593
|
"nameList": "/patents&ListName=patentList",
|
|
592
594
|
"keyName": "patentList",
|
|
593
595
|
"cluster": "pubmed",
|
|
594
|
-
"fields": [
|
|
596
|
+
"fields": [
|
|
597
|
+
"title",
|
|
598
|
+
"abstract",
|
|
599
|
+
"publication_id",
|
|
600
|
+
"family_id"
|
|
601
|
+
],
|
|
595
602
|
"nestedFields": [
|
|
596
603
|
"rare_diseases.concat_disease_name_orpha_code",
|
|
597
604
|
"rare_diseases.disease_synonyms",
|
|
@@ -623,7 +630,6 @@
|
|
|
623
630
|
"Abstract": "abstract"
|
|
624
631
|
}
|
|
625
632
|
},
|
|
626
|
-
|
|
627
633
|
"Classification": {
|
|
628
634
|
"type": "nested_field",
|
|
629
635
|
"values": {
|
|
@@ -654,7 +660,7 @@
|
|
|
654
660
|
}
|
|
655
661
|
},
|
|
656
662
|
"establishments": {
|
|
657
|
-
"index": "
|
|
663
|
+
"index": "919a60df-3447-4404-901b-2d293cfc00e1",
|
|
658
664
|
"nameList": "/establishments/&ListName=establishmentList",
|
|
659
665
|
"keyName": "establishmentList",
|
|
660
666
|
"cluster": "pubmed",
|
|
@@ -675,31 +681,31 @@
|
|
|
675
681
|
]
|
|
676
682
|
},
|
|
677
683
|
"hcpPubmed": {
|
|
678
|
-
"index": "
|
|
684
|
+
"index": "fb956659-f5be-4340-8b1b-07304db96ca7",
|
|
679
685
|
"cluster": "pubmed"
|
|
680
686
|
},
|
|
681
687
|
"hcpNct": {
|
|
682
|
-
"index": "
|
|
688
|
+
"index": "35f34ca6-2450-4dcf-a659-fb33140147ad",
|
|
683
689
|
"cluster": "pubmed"
|
|
684
690
|
},
|
|
685
691
|
"hcpEuct": {
|
|
686
|
-
"index": "
|
|
692
|
+
"index": "c246a516-84c7-4deb-9c0c-5afedf08ffdd",
|
|
687
693
|
"cluster": "pubmed"
|
|
688
694
|
},
|
|
689
695
|
"hcoNct": {
|
|
690
|
-
"index": "
|
|
696
|
+
"index": "bb5bf512-a1c8-4805-b91a-00ae3b9caf64",
|
|
691
697
|
"cluster": "pubmed"
|
|
692
698
|
},
|
|
693
699
|
"hcoEuct": {
|
|
694
|
-
"index": "
|
|
700
|
+
"index": "4efefe73-8421-48b5-8bf8-835cb1ad7e5e",
|
|
695
701
|
"cluster": "pubmed"
|
|
696
702
|
},
|
|
697
703
|
"rpps": {
|
|
698
|
-
"index": "
|
|
704
|
+
"index": "f9bcdd65-ec2a-47ad-b56d-7a59f2aa7898",
|
|
699
705
|
"cluster": "pubmed"
|
|
700
706
|
},
|
|
701
707
|
"hcps": {
|
|
702
|
-
"index": "
|
|
708
|
+
"index": "c8ad547a-6f97-4002-9853-5256308b6cff",
|
|
703
709
|
"nameList": "/hcps/&ListName=hcpList",
|
|
704
710
|
"keyName": "hcpList",
|
|
705
711
|
"cluster": "pubmed",
|
|
@@ -718,7 +724,7 @@
|
|
|
718
724
|
]
|
|
719
725
|
},
|
|
720
726
|
"phrc": {
|
|
721
|
-
"index": "
|
|
727
|
+
"index": "da722bdc-3441-4358-9ab1-61c6afef3b0e",
|
|
722
728
|
"nameList": "/appel-a-projet/&ListName=phrcList",
|
|
723
729
|
"keyName": "phrcList",
|
|
724
730
|
"cluster": "pubmed",
|
package/layer/app/types/oip.ts
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
import type { RmProjectKind, RmProjectLang } from "@tekkare/romulus/utils/projects";
|
|
17
17
|
import scienceIndexConfig from "../oip-science/indexConfig.json";
|
|
18
18
|
import { DRUG_PROJECT_KINDS } from "../oip-drugs/kinds";
|
|
19
|
+
import { OIP_PATIENT_INDEXES } from "../oip-patients/indexes";
|
|
20
|
+
import { PATIENT_KIND, VACCINE_KIND } from "../oip-patients/kinds";
|
|
19
21
|
|
|
20
22
|
/** Les apps qui ont des fiches a montrer, et ou les ouvrir. */
|
|
21
23
|
export const OIP_RESOURCE_APPS = {
|
|
@@ -27,6 +29,10 @@ export const OIP_RESOURCE_APPS = {
|
|
|
27
29
|
name: "France Drugs",
|
|
28
30
|
url: "https://france-drugs.app.tekkare.com",
|
|
29
31
|
},
|
|
32
|
+
ww_oip_patients: {
|
|
33
|
+
name: "OIP Case Atlas",
|
|
34
|
+
url: "https://global-case-atlas.app.tekkare.com",
|
|
35
|
+
},
|
|
30
36
|
} as const;
|
|
31
37
|
|
|
32
38
|
export type OipResourceApp = keyof typeof OIP_RESOURCE_APPS;
|
|
@@ -121,6 +127,28 @@ function drugsSpec(kind: RmProjectKind, view: string): OipResourceSpec {
|
|
|
121
127
|
};
|
|
122
128
|
}
|
|
123
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Une fiche d'OIP Case Atlas (cas de maladie rare, cas apres vaccination),
|
|
132
|
+
* lue sur le cluster `science` et montree d'un seul tenant, ses onglets
|
|
133
|
+
* compris. Elle s'adresse par son `record_id`, que le document donne.
|
|
134
|
+
*/
|
|
135
|
+
function patientsSpec(kind: RmProjectKind, view: string): OipResourceSpec {
|
|
136
|
+
return {
|
|
137
|
+
type: kind.type,
|
|
138
|
+
app: "ww_oip_patients",
|
|
139
|
+
cluster: "science",
|
|
140
|
+
kind,
|
|
141
|
+
routeId: (id) => id,
|
|
142
|
+
base: () => "",
|
|
143
|
+
tabs: [],
|
|
144
|
+
view,
|
|
145
|
+
detailPath: (id, tab, doc) => {
|
|
146
|
+
const path = kind.path!(doc ?? {}, id);
|
|
147
|
+
return tab && tab !== "summary" ? `${path}?tab=${encodeURIComponent(tab)}` : path;
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
124
152
|
/** La vue de chaque famille de fr_drugs_app (cf. useOipResourceViews). */
|
|
125
153
|
const DRUG_VIEWS: Record<string, string> = {
|
|
126
154
|
FrHasBrand: "drugs-brand",
|
|
@@ -159,7 +187,7 @@ export const OIP_RESOURCE_SPECS: OipResourceSpec[] = [
|
|
|
159
187
|
type: "PubMed",
|
|
160
188
|
kind: {
|
|
161
189
|
type: "PubMed",
|
|
162
|
-
index:
|
|
190
|
+
index: scienceIndexConfig.pubmed.index,
|
|
163
191
|
label: { fr: "Publications", en: "Publications" },
|
|
164
192
|
section: { fr: "PubMed", en: "PubMed" },
|
|
165
193
|
icon: "Books",
|
|
@@ -338,6 +366,8 @@ export const OIP_RESOURCE_SPECS: OipResourceSpec[] = [
|
|
|
338
366
|
tabs: [T.trials, T.publications],
|
|
339
367
|
}),
|
|
340
368
|
...DRUG_PROJECT_KINDS.map((kind) => drugsSpec(kind, DRUG_VIEWS[kind.type]!)),
|
|
369
|
+
patientsSpec(PATIENT_KIND, "patients-patient"),
|
|
370
|
+
patientsSpec(VACCINE_KIND, "patients-vaccine"),
|
|
341
371
|
];
|
|
342
372
|
|
|
343
373
|
export function oipResourceSpec(type: string): OipResourceSpec | undefined {
|
|
@@ -370,7 +400,9 @@ export const OIP_SCIENCE_INDEXES: string[] = Object.values(scienceIndexConfig as
|
|
|
370
400
|
/** Les index que le proxy du layer accepte de lire, par cluster. */
|
|
371
401
|
export function oipResourceIndexes(cluster: OipEsCluster): string[] {
|
|
372
402
|
const declared = OIP_RESOURCE_SPECS.filter((spec) => spec.cluster === cluster).map((spec) => spec.kind.index);
|
|
373
|
-
return cluster === "science"
|
|
403
|
+
return cluster === "science"
|
|
404
|
+
? [...new Set([...declared, ...OIP_SCIENCE_INDEXES, ...Object.values(OIP_PATIENT_INDEXES)])]
|
|
405
|
+
: declared;
|
|
374
406
|
}
|
|
375
407
|
|
|
376
408
|
/**
|
package/layer/nuxt.config.ts
CHANGED
|
@@ -22,12 +22,14 @@ export default defineNuxtConfig({
|
|
|
22
22
|
compatibilityVersion: 4,
|
|
23
23
|
},
|
|
24
24
|
// Regles du cadre communes aux apps (bandeau de page, barre de filtres), et
|
|
25
|
-
// classes des fiches de France Augmented Science,
|
|
26
|
-
// (
|
|
25
|
+
// classes des fiches de France Augmented Science, de fr_drugs_app et d'OIP
|
|
26
|
+
// Case Atlas, limitees a leur conteneur (`.oip-science`, `.oip-drugs`,
|
|
27
|
+
// `.oip-patients`).
|
|
27
28
|
css: [
|
|
28
29
|
fileURLToPath(new URL("./app/assets/oip-frame.css", import.meta.url)),
|
|
29
30
|
fileURLToPath(new URL("./app/oip-science/science.css", import.meta.url)),
|
|
30
31
|
fileURLToPath(new URL("./app/oip-drugs/drugs.css", import.meta.url)),
|
|
32
|
+
fileURLToPath(new URL("./app/oip-patients/patients.css", import.meta.url)),
|
|
31
33
|
],
|
|
32
34
|
// Reglages serveur propres au layer. Les cles Directus (directus*Url,
|
|
33
35
|
// directus*Token) restent declarees par l'app, qui les avait deja.
|
|
@@ -57,12 +59,14 @@ export default defineNuxtConfig({
|
|
|
57
59
|
/**
|
|
58
60
|
* Clusters Elasticsearch des vues de ressources (/api/oip/es) : domaine et
|
|
59
61
|
* cle ApiKey. `science` porte les index de France Augmented Science
|
|
60
|
-
* (PubMed, essais), `hcp` l'annuaire, `drugs` ceux de fr_drugs_app. Une
|
|
62
|
+
* (PubMed, essais) et ceux d'OIP Case Atlas (patients), `hcp` l'annuaire, `drugs` ceux de fr_drugs_app. Une
|
|
61
63
|
* app les remplit depuis ses propres variables, ou par
|
|
62
64
|
* NUXT_OIP_ES_SCIENCE_DOMAIN / NUXT_OIP_ES_SCIENCE_AUTH, etc.
|
|
63
65
|
*/
|
|
64
66
|
oipEs: {
|
|
65
|
-
|
|
67
|
+
// Cas apres vaccination d'OIP Case Atlas : une autre cle sur le meme
|
|
68
|
+
// domaine. Vide : la cle principale.
|
|
69
|
+
science: { domain: "", auth: "", authVaccines: "" },
|
|
66
70
|
hcp: { domain: "", auth: "" },
|
|
67
71
|
// Associations et registres d'autorisation etrangers : une autre cle sur
|
|
68
72
|
// le meme domaine, comme dans fr_drugs_app. Vides : la cle principale.
|
|
@@ -3,6 +3,7 @@ import { requireOipSession } from "../../utils/oipAuth";
|
|
|
3
3
|
import { findOipEsIndex, resolveOipEsIndex } from "../../utils/oipEsIndices";
|
|
4
4
|
import { oipResourceIndexes, type OipEsCluster } from "../../../app/utils/oipResources";
|
|
5
5
|
import { ES_INDEX } from "../../../app/oip-drugs/esIndices";
|
|
6
|
+
import { OIP_PATIENT_INDEXES } from "../../../app/oip-patients/indexes";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* POST /api/oip/es?cluster=&index=, servi par le layer OIP.
|
|
@@ -18,9 +19,13 @@ import { ES_INDEX } from "../../../app/oip-drugs/esIndices";
|
|
|
18
19
|
* dans fr_drugs_app. Ses associations et ses registres d'autorisation
|
|
19
20
|
* etrangers demandent une autre cle sur le meme domaine (`authAssociations`,
|
|
20
21
|
* `authApprovals`) ; a defaut, la cle principale.
|
|
22
|
+
*
|
|
23
|
+
* Cluster `science` : les cas apres vaccination d'OIP Case Atlas ne se lisent
|
|
24
|
+
* pas avec la cle PubMed, mais avec une autre sur le meme domaine
|
|
25
|
+
* (`authVaccines`) ; a defaut, la cle principale.
|
|
21
26
|
*/
|
|
22
27
|
|
|
23
|
-
type
|
|
28
|
+
type KeyGroup = "auth" | "authAssociations" | "authApprovals" | "authVaccines";
|
|
24
29
|
|
|
25
30
|
const DRUG_IDS = new Set<string>(Object.values(ES_INDEX) as string[]);
|
|
26
31
|
const ASSOCIATION_IDS = new Set<string>(
|
|
@@ -45,7 +50,7 @@ async function drugsKeyOf(ref: string): Promise<string> {
|
|
|
45
50
|
return id && DRUG_IDS.has(id) ? id : "";
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
function drugsKeyGroup(id: string):
|
|
53
|
+
function drugsKeyGroup(id: string): KeyGroup {
|
|
49
54
|
if (ASSOCIATION_IDS.has(id)) return "authAssociations";
|
|
50
55
|
if (APPROVAL_IDS.has(id)) return "authApprovals";
|
|
51
56
|
return "auth";
|
|
@@ -71,7 +76,7 @@ export default defineEventHandler(async (event) => {
|
|
|
71
76
|
if (!index || !/^[A-Za-z0-9_.,-]+$/.test(index)) throw createError({ status: 400, message: "Invalid index" });
|
|
72
77
|
|
|
73
78
|
const refs = index.split(",");
|
|
74
|
-
let authKey:
|
|
79
|
+
let authKey: KeyGroup = "auth";
|
|
75
80
|
if (cluster === "drugs") {
|
|
76
81
|
// Une requete multi-index part avec une seule cle : ses index en relevent tous.
|
|
77
82
|
const ids = await Promise.all(refs.map(drugsKeyOf));
|
|
@@ -80,8 +85,20 @@ export default defineEventHandler(async (event) => {
|
|
|
80
85
|
if (groups.size > 1) throw createError({ status: 400, message: "Indexes require different credentials" });
|
|
81
86
|
authKey = [...groups][0]!;
|
|
82
87
|
} else {
|
|
88
|
+
// Les fiches designent leurs index par id Directus ; un nom (canonique ou
|
|
89
|
+
// physique) est admis s'il designe un index de la liste.
|
|
83
90
|
const allowed = oipResourceIndexes(cluster as OipEsCluster);
|
|
84
|
-
|
|
91
|
+
const ids = await Promise.all(
|
|
92
|
+
refs.map(async (ref) => (allowed.includes(ref) ? ref : (await findOipEsIndex(ref).catch(() => undefined))?.id)),
|
|
93
|
+
);
|
|
94
|
+
if (ids.some((id) => !id || !allowed.includes(id))) throw createError({ status: 403, message: "Index not allowed" });
|
|
95
|
+
if (cluster === "science") {
|
|
96
|
+
const vaccines = (ref: string, index: number) =>
|
|
97
|
+
ref === OIP_PATIENT_INDEXES.VACCINE_PATIENTS || ids[index] === OIP_PATIENT_INDEXES.VACCINE_PATIENTS;
|
|
98
|
+
const groups = new Set(refs.map((ref, index) => (vaccines(ref, index) ? "authVaccines" : "auth")));
|
|
99
|
+
if (groups.size > 1) throw createError({ status: 400, message: "Indexes require different credentials" });
|
|
100
|
+
authKey = [...groups][0]!;
|
|
101
|
+
}
|
|
85
102
|
}
|
|
86
103
|
|
|
87
104
|
const auth = target[authKey] || target.auth;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekkare/romulus",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.256",
|
|
4
4
|
"description": "Romulus Design System - Nuxt module by Tekkare",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
},
|
|
20
20
|
"./layer": "./layer/nuxt.config.ts",
|
|
21
21
|
"./layer-utils/*": "./layer/app/utils/*.ts",
|
|
22
|
-
"./layer-composables/*": "./layer/app/composables/*.ts"
|
|
22
|
+
"./layer-composables/*": "./layer/app/composables/*.ts",
|
|
23
|
+
"./layer-patients/*": "./layer/app/oip-patients/*.ts"
|
|
23
24
|
},
|
|
24
25
|
"main": "./dist/module.cjs",
|
|
25
26
|
"module": "./dist/module.mjs",
|
|
@@ -48,6 +49,8 @@
|
|
|
48
49
|
"@tiptap/starter-kit": "^3.31.4",
|
|
49
50
|
"@tiptap/suggestion": "^3.31.4",
|
|
50
51
|
"@tiptap/vue-3": "^3.31.4",
|
|
52
|
+
"cytoscape": "^3.33.1",
|
|
53
|
+
"cytoscape-fcose": "^2.2.0",
|
|
51
54
|
"echarts": "^5.6.0",
|
|
52
55
|
"html2canvas-pro": "^1.6.7",
|
|
53
56
|
"jspdf": "^4.2.0",
|