reflex-icd11ect 0.1.0__py3-none-any.whl
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.
- reflex_icd11ect/__init__.py +105 -0
- reflex_icd11ect/_runtime.py +291 -0
- reflex_icd11ect/constants.py +194 -0
- reflex_icd11ect/handler.py +242 -0
- reflex_icd11ect/icd11ect.py +552 -0
- reflex_icd11ect/icd11ect.pyi +512 -0
- reflex_icd11ect/namespace.py +49 -0
- reflex_icd11ect/namespace.pyi +193 -0
- reflex_icd11ect/py.typed +0 -0
- reflex_icd11ect/token.py +224 -0
- reflex_icd11ect/types.py +164 -0
- reflex_icd11ect-0.1.0.dist-info/METADATA +341 -0
- reflex_icd11ect-0.1.0.dist-info/RECORD +16 -0
- reflex_icd11ect-0.1.0.dist-info/WHEEL +5 -0
- reflex_icd11ect-0.1.0.dist-info/licenses/LICENSE +21 -0
- reflex_icd11ect-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Reflex custom component for the WHO ICD-11 Embedded Classification Tools.
|
|
2
|
+
|
|
3
|
+
Wraps `@whoicd/icd11ect <https://www.npmjs.com/package/@whoicd/icd11ect>`_,
|
|
4
|
+
the WHO's Embedded Coding Tool and Embedded Browser, powered by the ICD-API.
|
|
5
|
+
|
|
6
|
+
Quick start::
|
|
7
|
+
|
|
8
|
+
import reflex as rx
|
|
9
|
+
from reflex_icd11ect import icd11ect
|
|
10
|
+
|
|
11
|
+
class State(rx.State):
|
|
12
|
+
code: str = ""
|
|
13
|
+
|
|
14
|
+
@rx.event
|
|
15
|
+
def on_select(self, entity: dict[str, str]):
|
|
16
|
+
self.code = entity["code"]
|
|
17
|
+
|
|
18
|
+
def index():
|
|
19
|
+
return rx.vstack(
|
|
20
|
+
rx.text(State.code),
|
|
21
|
+
icd11ect.coding_tool(
|
|
22
|
+
api_server_url="https://id.who.int",
|
|
23
|
+
api_secured=True,
|
|
24
|
+
token=State.token,
|
|
25
|
+
on_select=State.on_select,
|
|
26
|
+
),
|
|
27
|
+
)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from reflex_icd11ect import constants, handler, token
|
|
31
|
+
from reflex_icd11ect.constants import (
|
|
32
|
+
ALL_SETTINGS,
|
|
33
|
+
BROWSER_SETTINGS,
|
|
34
|
+
CODING_TOOL_SETTINGS,
|
|
35
|
+
COMMON_SETTINGS,
|
|
36
|
+
ECT_PACKAGE,
|
|
37
|
+
ECT_STYLESHEET,
|
|
38
|
+
ECT_VERSION,
|
|
39
|
+
ICD_TOKEN_ENDPOINT,
|
|
40
|
+
ICD_TOKEN_SCOPE,
|
|
41
|
+
LANGUAGES,
|
|
42
|
+
MMS_CHAPTERS,
|
|
43
|
+
OVERWRITABLE_SETTINGS,
|
|
44
|
+
RTL_LANGUAGES,
|
|
45
|
+
SELECT_BUTTON_MODES,
|
|
46
|
+
SOURCES,
|
|
47
|
+
WHO_CLOUD_API,
|
|
48
|
+
WHO_DEVELOPER_TEST_API,
|
|
49
|
+
)
|
|
50
|
+
from reflex_icd11ect.icd11ect import (
|
|
51
|
+
Icd11ectBrowser,
|
|
52
|
+
Icd11ectCodingTool,
|
|
53
|
+
Icd11ectController,
|
|
54
|
+
browser_window,
|
|
55
|
+
icd11ect_browser,
|
|
56
|
+
icd11ect_coding_tool,
|
|
57
|
+
icd11ect_controller,
|
|
58
|
+
icd11ect_provider,
|
|
59
|
+
result_window,
|
|
60
|
+
search_input,
|
|
61
|
+
)
|
|
62
|
+
from reflex_icd11ect.namespace import icd11ect
|
|
63
|
+
from reflex_icd11ect.token import IcdTokenError, IcdTokenProvider
|
|
64
|
+
from reflex_icd11ect.types import BrowserContent, SelectedEntity
|
|
65
|
+
|
|
66
|
+
__version__ = "0.1.0"
|
|
67
|
+
|
|
68
|
+
__all__ = [
|
|
69
|
+
"ALL_SETTINGS",
|
|
70
|
+
"BROWSER_SETTINGS",
|
|
71
|
+
"CODING_TOOL_SETTINGS",
|
|
72
|
+
"COMMON_SETTINGS",
|
|
73
|
+
"ECT_PACKAGE",
|
|
74
|
+
"ECT_STYLESHEET",
|
|
75
|
+
"ECT_VERSION",
|
|
76
|
+
"ICD_TOKEN_ENDPOINT",
|
|
77
|
+
"ICD_TOKEN_SCOPE",
|
|
78
|
+
"LANGUAGES",
|
|
79
|
+
"MMS_CHAPTERS",
|
|
80
|
+
"OVERWRITABLE_SETTINGS",
|
|
81
|
+
"RTL_LANGUAGES",
|
|
82
|
+
"SELECT_BUTTON_MODES",
|
|
83
|
+
"SOURCES",
|
|
84
|
+
"WHO_CLOUD_API",
|
|
85
|
+
"WHO_DEVELOPER_TEST_API",
|
|
86
|
+
"BrowserContent",
|
|
87
|
+
"Icd11ectBrowser",
|
|
88
|
+
"Icd11ectCodingTool",
|
|
89
|
+
"Icd11ectController",
|
|
90
|
+
"IcdTokenError",
|
|
91
|
+
"IcdTokenProvider",
|
|
92
|
+
"SelectedEntity",
|
|
93
|
+
"__version__",
|
|
94
|
+
"browser_window",
|
|
95
|
+
"constants",
|
|
96
|
+
"handler",
|
|
97
|
+
"icd11ect",
|
|
98
|
+
"icd11ect_browser",
|
|
99
|
+
"icd11ect_coding_tool",
|
|
100
|
+
"icd11ect_controller",
|
|
101
|
+
"icd11ect_provider",
|
|
102
|
+
"result_window",
|
|
103
|
+
"search_input",
|
|
104
|
+
"token",
|
|
105
|
+
]
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""The JavaScript runtime that bridges ECT to Reflex.
|
|
2
|
+
|
|
3
|
+
``@whoicd/icd11ect`` is not a React component: it is an imperative library
|
|
4
|
+
that renders itself into DOM nodes carrying ``data-ctw-ino`` attributes, and
|
|
5
|
+
it keeps a single global configuration plus a single set of callbacks for the
|
|
6
|
+
whole page.
|
|
7
|
+
|
|
8
|
+
This module holds the JavaScript that reconciles that model with Reflex:
|
|
9
|
+
|
|
10
|
+
* a page level singleton (``window.__reflexIcd11ect``) that owns the ECT
|
|
11
|
+
configuration and routes ECT's global callbacks to the right component
|
|
12
|
+
instance, keyed by ``iNo``;
|
|
13
|
+
* ``useIcd11ect``, the hook each component emits, which registers the
|
|
14
|
+
instance, configures ECT once, applies the per instance overrides and binds
|
|
15
|
+
the tool after the DOM has been committed (``autoBind`` is always disabled,
|
|
16
|
+
because ECT's auto binding listens for ``window.onload``, an event that has
|
|
17
|
+
long fired by the time a single page app renders a route);
|
|
18
|
+
* OAUTH 2.0 token plumbing: either a token endpoint fetched from the browser,
|
|
19
|
+
or a round trip to the Reflex backend through the ``on_token_request``
|
|
20
|
+
event.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
|
|
27
|
+
from reflex_icd11ect.constants import OVERWRITABLE_SETTINGS
|
|
28
|
+
|
|
29
|
+
_RUNTIME_TEMPLATE = r"""
|
|
30
|
+
/* reflex-icd11ect runtime. Bridges the imperative @whoicd/icd11ect API to Reflex. */
|
|
31
|
+
const ICD11ECT_OVERWRITABLE = __OVERWRITABLE__;
|
|
32
|
+
|
|
33
|
+
const icd11ectRuntime = () => {
|
|
34
|
+
if (typeof window === "undefined") return null;
|
|
35
|
+
let rt = window.__reflexIcd11ect;
|
|
36
|
+
if (!rt) {
|
|
37
|
+
rt = window.__reflexIcd11ect = {
|
|
38
|
+
instances: {},
|
|
39
|
+
globalSettings: {},
|
|
40
|
+
globalSettingsKey: "",
|
|
41
|
+
configured: false,
|
|
42
|
+
verbose: false,
|
|
43
|
+
token: null,
|
|
44
|
+
tokenVersion: 0,
|
|
45
|
+
tokenAsks: 0,
|
|
46
|
+
tokenConfig: {},
|
|
47
|
+
tokenWaiters: [],
|
|
48
|
+
lastIno: null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
rt.ECT = ECT;
|
|
52
|
+
/* Exposed on the singleton so `rx.call_script` helpers can reach them. */
|
|
53
|
+
rt.setToken = icd11ectSetToken;
|
|
54
|
+
rt.callbacks = icd11ectCallbacks;
|
|
55
|
+
return rt;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const icd11ectLog = (...args) => {
|
|
59
|
+
const rt = icd11ectRuntime();
|
|
60
|
+
if (rt && rt.verbose) console.log("[reflex-icd11ect]", ...args);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const icd11ectSetToken = (token) => {
|
|
64
|
+
const rt = icd11ectRuntime();
|
|
65
|
+
if (!rt || !token || token === rt.token) return;
|
|
66
|
+
rt.token = token;
|
|
67
|
+
rt.tokenVersion += 1;
|
|
68
|
+
const waiters = rt.tokenWaiters;
|
|
69
|
+
rt.tokenWaiters = [];
|
|
70
|
+
waiters.forEach((resolve) => resolve(token));
|
|
71
|
+
icd11ectLog("token updated, version", rt.tokenVersion);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const icd11ectWaitForToken = (rt, timeoutMs) =>
|
|
75
|
+
new Promise((resolve) => {
|
|
76
|
+
let settled = false;
|
|
77
|
+
const finish = (value) => {
|
|
78
|
+
if (settled) return;
|
|
79
|
+
settled = true;
|
|
80
|
+
resolve(value || "");
|
|
81
|
+
};
|
|
82
|
+
const timer = setTimeout(() => finish(rt.token), timeoutMs);
|
|
83
|
+
rt.tokenWaiters.push((token) => {
|
|
84
|
+
clearTimeout(timer);
|
|
85
|
+
finish(token);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const icd11ectDispatch = (iNo, name, ...args) => {
|
|
90
|
+
const rt = icd11ectRuntime();
|
|
91
|
+
if (!rt) return;
|
|
92
|
+
if (iNo === null || iNo === undefined || iNo === "") {
|
|
93
|
+
Object.keys(rt.instances).forEach((key) => icd11ectDispatch(key, name, ...args));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const instance = rt.instances[String(iNo)];
|
|
97
|
+
const handler =
|
|
98
|
+
instance && instance.callbacks && instance.callbacks.current
|
|
99
|
+
? instance.callbacks.current[name]
|
|
100
|
+
: undefined;
|
|
101
|
+
if (handler) handler(...args);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/* ECT does not tell us which instance started or ended a search, so fall back
|
|
105
|
+
to the focused search box, then to the instance that last emitted. */
|
|
106
|
+
const icd11ectActiveIno = () => {
|
|
107
|
+
const rt = icd11ectRuntime();
|
|
108
|
+
if (!rt) return null;
|
|
109
|
+
if (typeof document !== "undefined") {
|
|
110
|
+
const active = document.activeElement;
|
|
111
|
+
if (active && active.classList && active.classList.contains("ctw-input")) {
|
|
112
|
+
const iNo = active.getAttribute("data-ctw-ino");
|
|
113
|
+
if (iNo) return iNo;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return rt.lastIno;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const icd11ectCallbacks = {
|
|
120
|
+
selectedEntityFunction: (selectedEntity) => {
|
|
121
|
+
const rt = icd11ectRuntime();
|
|
122
|
+
if (rt && selectedEntity) rt.lastIno = String(selectedEntity.iNo);
|
|
123
|
+
icd11ectDispatch(selectedEntity && selectedEntity.iNo, "onSelect", selectedEntity);
|
|
124
|
+
},
|
|
125
|
+
browserChangedFunction: (browserContent) => {
|
|
126
|
+
icd11ectDispatch(
|
|
127
|
+
browserContent && browserContent.iNo,
|
|
128
|
+
"onBrowserChange",
|
|
129
|
+
browserContent,
|
|
130
|
+
);
|
|
131
|
+
},
|
|
132
|
+
browserLoadedFunction: () => icd11ectDispatch(null, "onBrowserLoad"),
|
|
133
|
+
searchStartedFunction: () => icd11ectDispatch(icd11ectActiveIno(), "onSearchStart"),
|
|
134
|
+
searchEndedFunction: () => icd11ectDispatch(icd11ectActiveIno(), "onSearchEnd"),
|
|
135
|
+
getNewTokenFunction: async () => {
|
|
136
|
+
const rt = icd11ectRuntime();
|
|
137
|
+
if (!rt) return "";
|
|
138
|
+
const config = rt.tokenConfig || {};
|
|
139
|
+
rt.tokenAsks += 1;
|
|
140
|
+
if (config.endpoint) {
|
|
141
|
+
try {
|
|
142
|
+
const response = await fetch(config.endpoint, config.fetchOptions || {});
|
|
143
|
+
const payload = await response.json();
|
|
144
|
+
const token =
|
|
145
|
+
typeof payload === "string"
|
|
146
|
+
? payload
|
|
147
|
+
: payload[config.field || "token"] || payload.access_token;
|
|
148
|
+
icd11ectSetToken(token);
|
|
149
|
+
return token || "";
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error(
|
|
152
|
+
"[reflex-icd11ect] could not fetch an ICD-API token from " + config.endpoint,
|
|
153
|
+
error,
|
|
154
|
+
);
|
|
155
|
+
return rt.token || "";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/* The token handed over by the backend is still the fresh one on the
|
|
159
|
+
first request, ECT only asks again once it has expired. */
|
|
160
|
+
if (rt.token && rt.tokenAsks === 1) return rt.token;
|
|
161
|
+
const known = rt.tokenVersion;
|
|
162
|
+
icd11ectDispatch(null, "onTokenRequest");
|
|
163
|
+
if (rt.tokenVersion !== known) return rt.token || "";
|
|
164
|
+
const token = await icd11ectWaitForToken(rt, config.timeoutMs || 15000);
|
|
165
|
+
if (!token) {
|
|
166
|
+
console.error(
|
|
167
|
+
"[reflex-icd11ect] the ICD-API is configured with api_secured=True but no " +
|
|
168
|
+
"token was provided. Set the `token` prop, handle `on_token_request`, " +
|
|
169
|
+
"or set `token_endpoint`.",
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
return token;
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/* A prop bound to state can legitimately be empty; treat that as "not set" so
|
|
177
|
+
ECT keeps its own default instead of receiving an empty setting. */
|
|
178
|
+
const icd11ectClean = (settings) =>
|
|
179
|
+
Object.fromEntries(
|
|
180
|
+
Object.entries(settings || {}).filter(
|
|
181
|
+
([, value]) => value !== undefined && value !== null && value !== "",
|
|
182
|
+
),
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const icd11ectConfigure = (rt) => {
|
|
186
|
+
const settings = rt.globalSettings || {};
|
|
187
|
+
if (!settings.apiServerUrl) {
|
|
188
|
+
icd11ectLog("waiting for api_server_url before configuring ECT");
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
const key = JSON.stringify(settings);
|
|
192
|
+
if (rt.configured && rt.globalSettingsKey === key) return true;
|
|
193
|
+
rt.ECT.Handler.configure({ ...settings, autoBind: false }, icd11ectCallbacks);
|
|
194
|
+
rt.configured = true;
|
|
195
|
+
rt.globalSettingsKey = key;
|
|
196
|
+
icd11ectLog("ECT configured", settings);
|
|
197
|
+
return true;
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/* Only the settings ECT can override per instance are worth sending, and only
|
|
201
|
+
when they differ from the page wide configuration. */
|
|
202
|
+
const icd11ectApplyInstance = (rt, iNo, settings) => {
|
|
203
|
+
const overrides = {};
|
|
204
|
+
ICD11ECT_OVERWRITABLE.forEach((key) => {
|
|
205
|
+
const value = settings[key];
|
|
206
|
+
if (value !== undefined && JSON.stringify(value) !== JSON.stringify(rt.globalSettings[key])) {
|
|
207
|
+
overrides[key] = value;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
if (Object.keys(overrides).length === 0) return;
|
|
211
|
+
icd11ectLog("overwriteConfiguration", iNo, overrides);
|
|
212
|
+
rt.ECT.Handler.overwriteConfiguration(String(iNo), overrides, true);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const icd11ectBind = (rt, iNo) => {
|
|
216
|
+
icd11ectLog("bind", iNo);
|
|
217
|
+
rt.ECT.Handler.bind(String(iNo));
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const icd11ectBindAll = (rt) => {
|
|
221
|
+
Object.keys(rt.instances).forEach((iNo) => {
|
|
222
|
+
icd11ectApplyInstance(rt, iNo, rt.instances[iNo].settings || {});
|
|
223
|
+
icd11ectBind(rt, iNo);
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/* Registers one Coding Tool / Embedded Browser instance and keeps ECT in sync
|
|
228
|
+
with its props. */
|
|
229
|
+
const useIcd11ect = (iNo, settings, callbacks, options) => {
|
|
230
|
+
const key = String(iNo);
|
|
231
|
+
const opts = options || {};
|
|
232
|
+
const callbacksRef = useRef(callbacks);
|
|
233
|
+
callbacksRef.current = callbacks;
|
|
234
|
+
const cleanSettings = icd11ectClean(settings);
|
|
235
|
+
const settingsKey = JSON.stringify(cleanSettings);
|
|
236
|
+
const token = opts.token;
|
|
237
|
+
const tokenEndpoint = opts.tokenEndpoint;
|
|
238
|
+
const tokenField = opts.tokenField;
|
|
239
|
+
const tokenTimeout = opts.tokenTimeoutMs;
|
|
240
|
+
const verbose = opts.verbose;
|
|
241
|
+
|
|
242
|
+
useEffect(() => {
|
|
243
|
+
const rt = icd11ectRuntime();
|
|
244
|
+
if (!rt) return;
|
|
245
|
+
if (verbose) rt.verbose = true;
|
|
246
|
+
if (tokenEndpoint || tokenField || tokenTimeout) {
|
|
247
|
+
rt.tokenConfig = {
|
|
248
|
+
...rt.tokenConfig,
|
|
249
|
+
endpoint: tokenEndpoint,
|
|
250
|
+
field: tokenField,
|
|
251
|
+
timeoutMs: tokenTimeout,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}, [tokenEndpoint, tokenField, tokenTimeout, verbose]);
|
|
255
|
+
|
|
256
|
+
useEffect(() => {
|
|
257
|
+
if (token) icd11ectSetToken(token);
|
|
258
|
+
}, [token]);
|
|
259
|
+
|
|
260
|
+
useEffect(() => {
|
|
261
|
+
const rt = icd11ectRuntime();
|
|
262
|
+
if (!rt) return undefined;
|
|
263
|
+
rt.instances[key] = { callbacks: callbacksRef, settings: cleanSettings, kind: opts.kind };
|
|
264
|
+
/* Page wide configuration is the merge of every mounted instance, so an
|
|
265
|
+
unmounted one stops contributing. */
|
|
266
|
+
rt.globalSettings = Object.keys(rt.instances).reduce(
|
|
267
|
+
(merged, instanceKey) => ({ ...merged, ...(rt.instances[instanceKey].settings || {}) }),
|
|
268
|
+
{},
|
|
269
|
+
);
|
|
270
|
+
const needsConfigure =
|
|
271
|
+
!rt.configured || rt.globalSettingsKey !== JSON.stringify(rt.globalSettings);
|
|
272
|
+
const cleanup = () => {
|
|
273
|
+
delete rt.instances[key];
|
|
274
|
+
};
|
|
275
|
+
if (!icd11ectConfigure(rt)) return cleanup;
|
|
276
|
+
if (needsConfigure) {
|
|
277
|
+
/* configure() resets every search box on the page, rebind them all. */
|
|
278
|
+
icd11ectBindAll(rt);
|
|
279
|
+
} else {
|
|
280
|
+
icd11ectApplyInstance(rt, key, cleanSettings);
|
|
281
|
+
icd11ectBind(rt, key);
|
|
282
|
+
}
|
|
283
|
+
return cleanup;
|
|
284
|
+
}, [key, settingsKey]);
|
|
285
|
+
};
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
#: The JavaScript emitted once per page by every ICD-11 ECT component.
|
|
289
|
+
ICD11ECT_RUNTIME_JS: str = _RUNTIME_TEMPLATE.replace(
|
|
290
|
+
"__OVERWRITABLE__", json.dumps(list(OVERWRITABLE_SETTINGS))
|
|
291
|
+
).strip()
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""Constants and setting maps for the ICD-11 Embedded Classification Tools.
|
|
2
|
+
|
|
3
|
+
Every entry of the ``*_SETTINGS`` maps below is ``python_prop_name ->
|
|
4
|
+
ECT setting name``. They are the single source of truth used to build the
|
|
5
|
+
JavaScript settings object handed to ``ECT.Handler.configure`` and
|
|
6
|
+
``ECT.Handler.overwriteConfiguration``.
|
|
7
|
+
|
|
8
|
+
The names were verified against the ``@whoicd/icd11ect`` 1.8.0 bundle
|
|
9
|
+
(the ``Handler.configure`` implementation) and the WHO documentation for
|
|
10
|
+
ECT 1.5 through 1.8.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Final
|
|
16
|
+
|
|
17
|
+
#: Public WHO ICD-API cloud server. Requires OAUTH 2.0 (``api_secured=True``).
|
|
18
|
+
WHO_CLOUD_API: Final[str] = "https://id.who.int"
|
|
19
|
+
|
|
20
|
+
#: WHO test server for software development only. No authentication needed.
|
|
21
|
+
#: Do not use it in production; it is rate limited and may go away.
|
|
22
|
+
WHO_DEVELOPER_TEST_API: Final[str] = (
|
|
23
|
+
"https://icd11restapi-developer-test.azurewebsites.net"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
#: OAUTH 2.0 token endpoint of the ICD-API access management service.
|
|
27
|
+
ICD_TOKEN_ENDPOINT: Final[str] = "https://icdaccessmanagement.who.int/connect/token"
|
|
28
|
+
|
|
29
|
+
#: OAUTH 2.0 scope required by the ICD-API.
|
|
30
|
+
ICD_TOKEN_SCOPE: Final[str] = "icdapi_access"
|
|
31
|
+
|
|
32
|
+
#: npm package wrapped by this component.
|
|
33
|
+
ECT_PACKAGE: Final[str] = "@whoicd/icd11ect"
|
|
34
|
+
|
|
35
|
+
#: npm version range installed in the frontend. ECT is released as
|
|
36
|
+
#: ``1.x`` with occasional breaking changes in the minor, so it is pinned
|
|
37
|
+
#: to the tested minor version.
|
|
38
|
+
ECT_VERSION: Final[str] = "1.8"
|
|
39
|
+
|
|
40
|
+
#: Stylesheet shipped by the npm package; required for the tools to look right.
|
|
41
|
+
ECT_STYLESHEET: Final[str] = f"{ECT_PACKAGE}/style.css"
|
|
42
|
+
|
|
43
|
+
# --------------------------------------------------------------------------- #
|
|
44
|
+
# Settings
|
|
45
|
+
# --------------------------------------------------------------------------- #
|
|
46
|
+
|
|
47
|
+
#: Settings shared by the Embedded Coding Tool and the Embedded Browser.
|
|
48
|
+
COMMON_SETTINGS: Final[dict[str, str]] = {
|
|
49
|
+
"api_server_url": "apiServerUrl",
|
|
50
|
+
"api_secured": "apiSecured",
|
|
51
|
+
"source": "source",
|
|
52
|
+
"minor_version": "minorVersion",
|
|
53
|
+
"language": "language",
|
|
54
|
+
"source_app": "sourceApp",
|
|
55
|
+
"height": "height",
|
|
56
|
+
"hierarchy_title": "hierarchyTitle",
|
|
57
|
+
"hierarchy_resizable": "hierarchyResizable",
|
|
58
|
+
"other_postcoordination": "otherPostcoordination",
|
|
59
|
+
"enable_keyboard": "enableKeyboard",
|
|
60
|
+
"include_diagnostic_criteria": "includeDiagnosticCriteria",
|
|
61
|
+
"verbose": "verbose",
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#: Settings that only affect the Embedded Coding Tool.
|
|
65
|
+
CODING_TOOL_SETTINGS: Final[dict[str, str]] = {
|
|
66
|
+
"popup_mode": "popupMode",
|
|
67
|
+
"simplified_mode": "simplifiedMode",
|
|
68
|
+
"disable_hierarchy": "disableHierarchy",
|
|
69
|
+
"words_available": "wordsAvailable",
|
|
70
|
+
"chapters_available": "chaptersAvailable",
|
|
71
|
+
"chapters_filter": "chaptersFilter",
|
|
72
|
+
"subtrees_filter": "subtreesFilter",
|
|
73
|
+
"flexisearch_available": "flexisearchAvailable",
|
|
74
|
+
"search_by_code_or_uri": "searchByCodeOrURI",
|
|
75
|
+
"medical_coding_mode": "medicalCodingMode",
|
|
76
|
+
"view_selected_uri": "viewSelectedURI",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#: Settings that only affect the Embedded Browser.
|
|
80
|
+
BROWSER_SETTINGS: Final[dict[str, str]] = {
|
|
81
|
+
"enable_select_button": "enableSelectButton",
|
|
82
|
+
"browser_search_available": "browserSearchAvailable",
|
|
83
|
+
"browser_advanced_search_available": "browserAdvancedSearchAvailable",
|
|
84
|
+
"browser_hierarchy_available": "browserHierarchyAvailable",
|
|
85
|
+
"browser_hierarchy_root_uris": "browserHierarchyRootURIs",
|
|
86
|
+
"browser_uri": "browserURI",
|
|
87
|
+
"display_other_foundation_children": "displayOtherFoundationChildren",
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#: Every setting understood by ECT, python name -> ECT name.
|
|
91
|
+
ALL_SETTINGS: Final[dict[str, str]] = {
|
|
92
|
+
**COMMON_SETTINGS,
|
|
93
|
+
**CODING_TOOL_SETTINGS,
|
|
94
|
+
**BROWSER_SETTINGS,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
#: Settings that ``ECT.Handler.overwriteConfiguration`` can change for a
|
|
98
|
+
#: single instance. Anything else is global to the page and is applied
|
|
99
|
+
#: through ``ECT.Handler.configure``.
|
|
100
|
+
OVERWRITABLE_SETTINGS: Final[tuple[str, ...]] = (
|
|
101
|
+
"apiServerUrl",
|
|
102
|
+
"apiSecured",
|
|
103
|
+
"source",
|
|
104
|
+
"minorVersion",
|
|
105
|
+
"language",
|
|
106
|
+
"popupMode",
|
|
107
|
+
"simplifiedMode",
|
|
108
|
+
"disableHierarchy",
|
|
109
|
+
"wordsAvailable",
|
|
110
|
+
"chaptersAvailable",
|
|
111
|
+
"chaptersFilter",
|
|
112
|
+
"subtreesFilter",
|
|
113
|
+
"flexisearchAvailable",
|
|
114
|
+
"searchByCodeOrURI",
|
|
115
|
+
"hierarchyTitle",
|
|
116
|
+
"height",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# --------------------------------------------------------------------------- #
|
|
120
|
+
# Enumerations (plain strings, so they stay usable from rx.Var)
|
|
121
|
+
# --------------------------------------------------------------------------- #
|
|
122
|
+
|
|
123
|
+
#: ``source`` values. ``mms`` is the ICD-11 MMS linearization, ``icf`` the
|
|
124
|
+
#: International Classification of Functioning (ECT >= 1.7), ``foundation``
|
|
125
|
+
#: the ICD-11 Foundation (Embedded Browser only).
|
|
126
|
+
SOURCE_MMS: Final[str] = "mms"
|
|
127
|
+
SOURCE_ICF: Final[str] = "icf"
|
|
128
|
+
SOURCE_FOUNDATION: Final[str] = "foundation"
|
|
129
|
+
SOURCES: Final[tuple[str, ...]] = (SOURCE_MMS, SOURCE_ICF, SOURCE_FOUNDATION)
|
|
130
|
+
|
|
131
|
+
#: ``enable_select_button`` values for the Embedded Browser.
|
|
132
|
+
SELECT_BUTTON_NONE: Final[str] = "none"
|
|
133
|
+
SELECT_BUTTON_CATEGORIES: Final[str] = "categories"
|
|
134
|
+
SELECT_BUTTON_ALL: Final[str] = "all"
|
|
135
|
+
SELECT_BUTTON_ALL_BUT_ROOT: Final[str] = "allButRoot"
|
|
136
|
+
SELECT_BUTTON_MODES: Final[tuple[str, ...]] = (
|
|
137
|
+
SELECT_BUTTON_NONE,
|
|
138
|
+
SELECT_BUTTON_CATEGORIES,
|
|
139
|
+
SELECT_BUTTON_ALL,
|
|
140
|
+
SELECT_BUTTON_ALL_BUT_ROOT,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
#: Languages the ICD-11 API serves, ISO 639-1 code -> English name.
|
|
144
|
+
#: Availability depends on the release and on the server deployment.
|
|
145
|
+
LANGUAGES: Final[dict[str, str]] = {
|
|
146
|
+
"ar": "Arabic",
|
|
147
|
+
"cs": "Czech",
|
|
148
|
+
"en": "English",
|
|
149
|
+
"es": "Spanish",
|
|
150
|
+
"fr": "French",
|
|
151
|
+
"it": "Italian",
|
|
152
|
+
"ja": "Japanese",
|
|
153
|
+
"ko": "Korean",
|
|
154
|
+
"pt": "Portuguese",
|
|
155
|
+
"ru": "Russian",
|
|
156
|
+
"tr": "Turkish",
|
|
157
|
+
"uz": "Uzbek",
|
|
158
|
+
"zh": "Chinese",
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#: Languages written right to left. ECT adds the ``rtl`` class for these.
|
|
162
|
+
RTL_LANGUAGES: Final[tuple[str, ...]] = ("ar", "he")
|
|
163
|
+
|
|
164
|
+
#: ICD-11 MMS chapters, code -> title. Use the keys with ``chapters_filter``.
|
|
165
|
+
MMS_CHAPTERS: Final[dict[str, str]] = {
|
|
166
|
+
"01": "Certain infectious or parasitic diseases",
|
|
167
|
+
"02": "Neoplasms",
|
|
168
|
+
"03": "Diseases of the blood or blood-forming organs",
|
|
169
|
+
"04": "Diseases of the immune system",
|
|
170
|
+
"05": "Endocrine, nutritional or metabolic diseases",
|
|
171
|
+
"06": "Mental, behavioural or neurodevelopmental disorders",
|
|
172
|
+
"07": "Sleep-wake disorders",
|
|
173
|
+
"08": "Diseases of the nervous system",
|
|
174
|
+
"09": "Diseases of the visual system",
|
|
175
|
+
"10": "Diseases of the ear or mastoid process",
|
|
176
|
+
"11": "Diseases of the circulatory system",
|
|
177
|
+
"12": "Diseases of the respiratory system",
|
|
178
|
+
"13": "Diseases of the digestive system",
|
|
179
|
+
"14": "Diseases of the skin",
|
|
180
|
+
"15": "Diseases of the musculoskeletal system or connective tissue",
|
|
181
|
+
"16": "Diseases of the genitourinary system",
|
|
182
|
+
"17": "Conditions related to sexual health",
|
|
183
|
+
"18": "Pregnancy, childbirth or the puerperium",
|
|
184
|
+
"19": "Certain conditions originating in the perinatal period",
|
|
185
|
+
"20": "Developmental anomalies",
|
|
186
|
+
"21": "Symptoms, signs or clinical findings, not elsewhere classified",
|
|
187
|
+
"22": "Injury, poisoning or certain other consequences of external causes",
|
|
188
|
+
"23": "External causes of morbidity or mortality",
|
|
189
|
+
"24": "Factors influencing health status or contact with health services",
|
|
190
|
+
"25": "Codes for special purposes",
|
|
191
|
+
"26": "Supplementary Chapter Traditional Medicine Conditions - Module I",
|
|
192
|
+
"V": "Supplementary section for functioning assessment",
|
|
193
|
+
"X": "Extension Codes",
|
|
194
|
+
}
|