canvas 0.16.0__py3-none-any.whl → 0.18.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.
Potentially problematic release.
This version of canvas might be problematic. Click here for more details.
- {canvas-0.16.0.dist-info → canvas-0.18.0.dist-info}/METADATA +25 -31
- {canvas-0.16.0.dist-info → canvas-0.18.0.dist-info}/RECORD +40 -34
- {canvas-0.16.0.dist-info → canvas-0.18.0.dist-info}/WHEEL +1 -1
- canvas-0.18.0.dist-info/entry_points.txt +2 -0
- canvas_cli/apps/plugin/plugin.py +5 -1
- canvas_generated/messages/events_pb2.py +2 -2
- canvas_generated/messages/events_pb2.pyi +88 -0
- canvas_sdk/commands/tests/protocol/tests.py +12 -2
- canvas_sdk/commands/tests/test_utils.py +4 -9
- canvas_sdk/effects/banner_alert/tests.py +5 -2
- canvas_sdk/effects/surescripts/__init__.py +11 -0
- canvas_sdk/effects/task/__init__.py +3 -0
- canvas_sdk/effects/task/task.py +3 -0
- canvas_sdk/utils/__init__.py +8 -2
- canvas_sdk/utils/http.py +113 -3
- canvas_sdk/v1/data/team.py +76 -0
- plugin_runner/plugin_installer.py +21 -13
- plugin_runner/plugin_runner.py +67 -14
- plugin_runner/tests/test_plugin_runner.py +37 -5
- protobufs/canvas_generated/messages/effects.proto +225 -0
- protobufs/canvas_generated/messages/events.proto +1057 -0
- protobufs/canvas_generated/messages/plugins.proto +9 -0
- protobufs/canvas_generated/services/plugin_runner.proto +12 -0
- settings.py +4 -1
- canvas-0.16.0.dist-info/entry_points.txt +0 -3
- plugin_runner/plugin_synchronizer.py +0 -92
plugin_runner/plugin_runner.py
CHANGED
|
@@ -2,17 +2,17 @@ import asyncio
|
|
|
2
2
|
import json
|
|
3
3
|
import os
|
|
4
4
|
import pathlib
|
|
5
|
+
import pickle
|
|
5
6
|
import pkgutil
|
|
6
|
-
import signal
|
|
7
7
|
import sys
|
|
8
8
|
import time
|
|
9
9
|
import traceback
|
|
10
10
|
from collections import defaultdict
|
|
11
11
|
from collections.abc import AsyncGenerator
|
|
12
|
-
from types import FrameType
|
|
13
12
|
from typing import Any, TypedDict
|
|
14
13
|
|
|
15
14
|
import grpc
|
|
15
|
+
import redis.asyncio as redis
|
|
16
16
|
import statsd
|
|
17
17
|
|
|
18
18
|
from canvas_generated.messages.effects_pb2 import EffectType
|
|
@@ -30,9 +30,15 @@ from canvas_sdk.protocols import ClinicalQualityMeasure
|
|
|
30
30
|
from canvas_sdk.utils.stats import get_duration_ms, tags_to_line_protocol
|
|
31
31
|
from logger import log
|
|
32
32
|
from plugin_runner.authentication import token_for_plugin
|
|
33
|
-
from plugin_runner.
|
|
33
|
+
from plugin_runner.plugin_installer import install_plugins
|
|
34
34
|
from plugin_runner.sandbox import Sandbox
|
|
35
|
-
from settings import
|
|
35
|
+
from settings import (
|
|
36
|
+
CHANNEL_NAME,
|
|
37
|
+
MANIFEST_FILE_NAME,
|
|
38
|
+
PLUGIN_DIRECTORY,
|
|
39
|
+
REDIS_ENDPOINT,
|
|
40
|
+
SECRETS_FILE_NAME,
|
|
41
|
+
)
|
|
36
42
|
|
|
37
43
|
# when we import plugins we'll use the module name directly so we need to add the plugin
|
|
38
44
|
# directory to the path
|
|
@@ -192,14 +198,50 @@ class PluginRunner(PluginRunnerServicer):
|
|
|
192
198
|
self, request: ReloadPluginsRequest, context: Any
|
|
193
199
|
) -> AsyncGenerator[ReloadPluginsResponse, None]:
|
|
194
200
|
"""This is invoked when we need to reload plugins."""
|
|
201
|
+
log.info("Reloading plugins...")
|
|
195
202
|
try:
|
|
196
|
-
publish_message({"action": "
|
|
203
|
+
await publish_message(message={"action": "reload"})
|
|
197
204
|
except ImportError:
|
|
198
205
|
yield ReloadPluginsResponse(success=False)
|
|
199
206
|
else:
|
|
200
207
|
yield ReloadPluginsResponse(success=True)
|
|
201
208
|
|
|
202
209
|
|
|
210
|
+
async def synchronize_plugins(max_iterations: None | int = None) -> None:
|
|
211
|
+
"""Listen for messages on the pubsub channel that will indicate it is necessary to reinstall and reload plugins."""
|
|
212
|
+
client, pubsub = get_client()
|
|
213
|
+
await pubsub.psubscribe(CHANNEL_NAME)
|
|
214
|
+
log.info("Listening for messages on pubsub channel")
|
|
215
|
+
iterations: int = 0
|
|
216
|
+
while (
|
|
217
|
+
max_iterations is None or iterations < max_iterations
|
|
218
|
+
): # max_iterations == -1 means infinite iterations
|
|
219
|
+
iterations += 1
|
|
220
|
+
message = await pubsub.get_message(ignore_subscribe_messages=True, timeout=None)
|
|
221
|
+
if message is not None:
|
|
222
|
+
log.info("Received message from pubsub channel")
|
|
223
|
+
|
|
224
|
+
message_type = message.get("type", "")
|
|
225
|
+
|
|
226
|
+
if message_type != "pmessage":
|
|
227
|
+
continue
|
|
228
|
+
|
|
229
|
+
data = pickle.loads(message.get("data", pickle.dumps({})))
|
|
230
|
+
|
|
231
|
+
if "action" not in data:
|
|
232
|
+
continue
|
|
233
|
+
|
|
234
|
+
if data["action"] == "reload":
|
|
235
|
+
try:
|
|
236
|
+
log.info(
|
|
237
|
+
"plugin-synchronizer: installing and reloading plugins after receiving command"
|
|
238
|
+
)
|
|
239
|
+
install_plugins()
|
|
240
|
+
load_plugins()
|
|
241
|
+
except Exception as e:
|
|
242
|
+
print("plugin-synchronizer: `install_plugins` failed:", e)
|
|
243
|
+
|
|
244
|
+
|
|
203
245
|
def validate_effects(effects: list[Effect]) -> list[Effect]:
|
|
204
246
|
"""Validates the effects based on predefined rules.
|
|
205
247
|
Keeps only the first AUTOCOMPLETE_SEARCH_RESULTS effect and preserve all non-search-related effects.
|
|
@@ -237,12 +279,6 @@ def apply_effects_to_context(effects: list[Effect], event: Event) -> Event:
|
|
|
237
279
|
return event
|
|
238
280
|
|
|
239
281
|
|
|
240
|
-
def handle_hup_cb(_signum: int, _frame: FrameType | None) -> None:
|
|
241
|
-
"""handle_hup_cb."""
|
|
242
|
-
log.info("Received SIGHUP, reloading plugins...")
|
|
243
|
-
load_plugins()
|
|
244
|
-
|
|
245
|
-
|
|
246
282
|
def find_modules(base_path: pathlib.Path, prefix: str | None = None) -> list[str]:
|
|
247
283
|
"""Find all modules in the specified package path."""
|
|
248
284
|
modules: list[str] = []
|
|
@@ -273,6 +309,22 @@ def sandbox_from_module(base_path: pathlib.Path, module_name: str) -> Any:
|
|
|
273
309
|
return sandbox.execute()
|
|
274
310
|
|
|
275
311
|
|
|
312
|
+
async def publish_message(message: dict) -> None:
|
|
313
|
+
"""Publish a message to the pubsub channel."""
|
|
314
|
+
log.info("Publishing message to pubsub channel")
|
|
315
|
+
client, _ = get_client()
|
|
316
|
+
|
|
317
|
+
await client.publish(CHANNEL_NAME, pickle.dumps(message))
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def get_client() -> tuple[redis.Redis, redis.client.PubSub]:
|
|
321
|
+
"""Return an async Redis client and pubsub object."""
|
|
322
|
+
client = redis.Redis.from_url(REDIS_ENDPOINT)
|
|
323
|
+
pubsub = client.pubsub()
|
|
324
|
+
|
|
325
|
+
return client, pubsub
|
|
326
|
+
|
|
327
|
+
|
|
276
328
|
def load_or_reload_plugin(path: pathlib.Path) -> None:
|
|
277
329
|
"""Given a path, load or reload a plugin."""
|
|
278
330
|
log.info(f"Loading {path}")
|
|
@@ -415,6 +467,7 @@ async def serve(specified_plugin_paths: list[str] | None = None) -> None:
|
|
|
415
467
|
|
|
416
468
|
log.info(f"Starting server, listening on port {port}")
|
|
417
469
|
|
|
470
|
+
install_plugins()
|
|
418
471
|
load_plugins(specified_plugin_paths)
|
|
419
472
|
|
|
420
473
|
await server.start()
|
|
@@ -434,10 +487,10 @@ def run_server(specified_plugin_paths: list[str] | None = None) -> None:
|
|
|
434
487
|
|
|
435
488
|
asyncio.set_event_loop(loop)
|
|
436
489
|
|
|
437
|
-
signal.signal(signal.SIGHUP, handle_hup_cb)
|
|
438
|
-
|
|
439
490
|
try:
|
|
440
|
-
loop.run_until_complete(
|
|
491
|
+
loop.run_until_complete(
|
|
492
|
+
asyncio.gather(serve(specified_plugin_paths), synchronize_plugins())
|
|
493
|
+
)
|
|
441
494
|
except KeyboardInterrupt:
|
|
442
495
|
pass
|
|
443
496
|
finally:
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import logging
|
|
3
|
+
import pickle
|
|
2
4
|
import shutil
|
|
3
5
|
from pathlib import Path
|
|
4
|
-
from unittest.mock import MagicMock, patch
|
|
6
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
5
7
|
|
|
6
8
|
import pytest
|
|
7
9
|
|
|
@@ -14,6 +16,7 @@ from plugin_runner.plugin_runner import (
|
|
|
14
16
|
PluginRunner,
|
|
15
17
|
load_or_reload_plugin,
|
|
16
18
|
load_plugins,
|
|
19
|
+
synchronize_plugins,
|
|
17
20
|
)
|
|
18
21
|
|
|
19
22
|
|
|
@@ -229,24 +232,53 @@ async def test_handle_plugin_event_returns_expected_result(
|
|
|
229
232
|
|
|
230
233
|
|
|
231
234
|
@pytest.mark.asyncio
|
|
232
|
-
@pytest.mark.parametrize("install_test_plugin", ["example_plugin"], indirect=True)
|
|
233
235
|
async def test_reload_plugins_event_handler_successfully_publishes_message(
|
|
234
|
-
|
|
236
|
+
plugin_runner: PluginRunner,
|
|
235
237
|
) -> None:
|
|
236
238
|
"""Test ReloadPlugins Event handler successfully publishes a message with restart action."""
|
|
237
|
-
with patch(
|
|
239
|
+
with patch(
|
|
240
|
+
"plugin_runner.plugin_runner.publish_message", new_callable=AsyncMock
|
|
241
|
+
) as mock_publish_message:
|
|
238
242
|
request = ReloadPluginsRequest()
|
|
239
243
|
|
|
240
244
|
result = []
|
|
241
245
|
async for response in plugin_runner.ReloadPlugins(request, None):
|
|
242
246
|
result.append(response)
|
|
243
247
|
|
|
244
|
-
mock_publish_message.assert_called_once_with({"action": "
|
|
248
|
+
mock_publish_message.assert_called_once_with(message={"action": "reload"})
|
|
245
249
|
|
|
246
250
|
assert len(result) == 1
|
|
247
251
|
assert result[0].success is True
|
|
248
252
|
|
|
249
253
|
|
|
254
|
+
@pytest.mark.asyncio
|
|
255
|
+
async def test_synchronize_plugins_calls_install_and_load_plugins() -> None:
|
|
256
|
+
"""Test that synchronize_plugins calls install_plugins and load_plugins."""
|
|
257
|
+
with (
|
|
258
|
+
patch("plugin_runner.plugin_runner.get_client", new_callable=MagicMock) as mock_get_client,
|
|
259
|
+
patch(
|
|
260
|
+
"plugin_runner.plugin_runner.install_plugins", new_callable=AsyncMock
|
|
261
|
+
) as mock_install_plugins,
|
|
262
|
+
patch(
|
|
263
|
+
"plugin_runner.plugin_runner.load_plugins", new_callable=AsyncMock
|
|
264
|
+
) as mock_load_plugins,
|
|
265
|
+
):
|
|
266
|
+
mock_client = AsyncMock()
|
|
267
|
+
mock_pubsub = AsyncMock()
|
|
268
|
+
mock_get_client.return_value = (mock_client, mock_pubsub)
|
|
269
|
+
mock_pubsub.get_message.return_value = {
|
|
270
|
+
"type": "pmessage",
|
|
271
|
+
"data": pickle.dumps({"action": "reload"}),
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
task = asyncio.create_task(synchronize_plugins(max_iterations=1))
|
|
275
|
+
await asyncio.sleep(0.1) # Give some time for the coroutine to run
|
|
276
|
+
task.cancel()
|
|
277
|
+
|
|
278
|
+
mock_install_plugins.assert_called_once()
|
|
279
|
+
mock_load_plugins.assert_called_once()
|
|
280
|
+
|
|
281
|
+
|
|
250
282
|
@pytest.mark.asyncio
|
|
251
283
|
@pytest.mark.parametrize("install_test_plugin", ["test_module_imports_plugin"], indirect=True)
|
|
252
284
|
async def test_changes_to_plugin_modules_should_be_reflected_after_reload(
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
syntax = 'proto3';
|
|
2
|
+
|
|
3
|
+
package canvas;
|
|
4
|
+
|
|
5
|
+
enum EffectType {
|
|
6
|
+
UNKNOWN_EFFECT = 0;
|
|
7
|
+
|
|
8
|
+
LOG = 1;
|
|
9
|
+
ADD_PLAN_COMMAND = 2;
|
|
10
|
+
|
|
11
|
+
AUTOCOMPLETE_SEARCH_RESULTS = 3;
|
|
12
|
+
|
|
13
|
+
ADD_BANNER_ALERT = 4;
|
|
14
|
+
REMOVE_BANNER_ALERT = 5;
|
|
15
|
+
|
|
16
|
+
ORIGINATE_ASSESS_COMMAND = 6;
|
|
17
|
+
EDIT_ASSESS_COMMAND = 7;
|
|
18
|
+
DELETE_ASSESS_COMMAND = 8;
|
|
19
|
+
COMMIT_ASSESS_COMMAND = 9;
|
|
20
|
+
ENTER_IN_ERROR_ASSESS_COMMAND = 10;
|
|
21
|
+
|
|
22
|
+
ORIGINATE_DIAGNOSE_COMMAND = 11;
|
|
23
|
+
EDIT_DIAGNOSE_COMMAND = 12;
|
|
24
|
+
DELETE_DIAGNOSE_COMMAND = 13;
|
|
25
|
+
COMMIT_DIAGNOSE_COMMAND = 14;
|
|
26
|
+
ENTER_IN_ERROR_DIAGNOSE_COMMAND = 15;
|
|
27
|
+
|
|
28
|
+
ORIGINATE_GOAL_COMMAND = 16;
|
|
29
|
+
EDIT_GOAL_COMMAND = 17;
|
|
30
|
+
DELETE_GOAL_COMMAND = 18;
|
|
31
|
+
COMMIT_GOAL_COMMAND = 19;
|
|
32
|
+
ENTER_IN_ERROR_GOAL_COMMAND = 20;
|
|
33
|
+
|
|
34
|
+
ORIGINATE_HPI_COMMAND = 21;
|
|
35
|
+
EDIT_HPI_COMMAND = 22;
|
|
36
|
+
DELETE_HPI_COMMAND = 23;
|
|
37
|
+
COMMIT_HPI_COMMAND = 24;
|
|
38
|
+
ENTER_IN_ERROR_HPI_COMMAND = 25;
|
|
39
|
+
|
|
40
|
+
ORIGINATE_MEDICATION_STATEMENT_COMMAND = 26;
|
|
41
|
+
EDIT_MEDICATION_STATEMENT_COMMAND = 27;
|
|
42
|
+
DELETE_MEDICATION_STATEMENT_COMMAND = 28;
|
|
43
|
+
COMMIT_MEDICATION_STATEMENT_COMMAND = 29;
|
|
44
|
+
ENTER_IN_ERROR_MEDICATION_STATEMENT_COMMAND = 30;
|
|
45
|
+
|
|
46
|
+
ORIGINATE_PLAN_COMMAND = 31;
|
|
47
|
+
EDIT_PLAN_COMMAND = 32;
|
|
48
|
+
DELETE_PLAN_COMMAND = 33;
|
|
49
|
+
COMMIT_PLAN_COMMAND = 34;
|
|
50
|
+
ENTER_IN_ERROR_PLAN_COMMAND = 35;
|
|
51
|
+
|
|
52
|
+
ORIGINATE_PRESCRIBE_COMMAND = 36;
|
|
53
|
+
EDIT_PRESCRIBE_COMMAND = 37;
|
|
54
|
+
DELETE_PRESCRIBE_COMMAND = 38;
|
|
55
|
+
COMMIT_PRESCRIBE_COMMAND = 39;
|
|
56
|
+
ENTER_IN_ERROR_PRESCRIBE_COMMAND = 40;
|
|
57
|
+
|
|
58
|
+
ORIGINATE_QUESTIONNAIRE_COMMAND = 41;
|
|
59
|
+
EDIT_QUESTIONNAIRE_COMMAND = 42;
|
|
60
|
+
DELETE_QUESTIONNAIRE_COMMAND = 43;
|
|
61
|
+
COMMIT_QUESTIONNAIRE_COMMAND = 44;
|
|
62
|
+
ENTER_IN_ERROR_QUESTIONNAIRE_COMMAND = 45;
|
|
63
|
+
|
|
64
|
+
ORIGINATE_REASON_FOR_VISIT_COMMAND = 46;
|
|
65
|
+
EDIT_REASON_FOR_VISIT_COMMAND = 47;
|
|
66
|
+
DELETE_REASON_FOR_VISIT_COMMAND = 48;
|
|
67
|
+
COMMIT_REASON_FOR_VISIT_COMMAND = 49;
|
|
68
|
+
ENTER_IN_ERROR_REASON_FOR_VISIT_COMMAND = 50;
|
|
69
|
+
|
|
70
|
+
ORIGINATE_STOP_MEDICATION_COMMAND = 51;
|
|
71
|
+
EDIT_STOP_MEDICATION_COMMAND = 52;
|
|
72
|
+
DELETE_STOP_MEDICATION_COMMAND = 53;
|
|
73
|
+
COMMIT_STOP_MEDICATION_COMMAND = 54;
|
|
74
|
+
ENTER_IN_ERROR_STOP_MEDICATION_COMMAND = 55;
|
|
75
|
+
|
|
76
|
+
ORIGINATE_UPDATE_GOAL_COMMAND = 56;
|
|
77
|
+
EDIT_UPDATE_GOAL_COMMAND = 57;
|
|
78
|
+
DELETE_UPDATE_GOAL_COMMAND = 58;
|
|
79
|
+
COMMIT_UPDATE_GOAL_COMMAND = 59;
|
|
80
|
+
ENTER_IN_ERROR_UPDATE_GOAL_COMMAND = 60;
|
|
81
|
+
|
|
82
|
+
ORIGINATE_PERFORM_COMMAND = 61;
|
|
83
|
+
EDIT_PERFORM_COMMAND = 62;
|
|
84
|
+
DELETE_PERFORM_COMMAND = 63;
|
|
85
|
+
COMMIT_PERFORM_COMMAND = 64;
|
|
86
|
+
ENTER_IN_ERROR_PERFORM_COMMAND = 65;
|
|
87
|
+
|
|
88
|
+
ORIGINATE_INSTRUCT_COMMAND = 66;
|
|
89
|
+
EDIT_INSTRUCT_COMMAND = 67 ;
|
|
90
|
+
DELETE_INSTRUCT_COMMAND = 68;
|
|
91
|
+
COMMIT_INSTRUCT_COMMAND = 69;
|
|
92
|
+
ENTER_IN_ERROR_INSTRUCT_COMMAND = 70;
|
|
93
|
+
|
|
94
|
+
ORIGINATE_LAB_ORDER_COMMAND = 71;
|
|
95
|
+
EDIT_LAB_ORDER_COMMAND = 72;
|
|
96
|
+
DELETE_LAB_ORDER_COMMAND = 73;
|
|
97
|
+
COMMIT_LAB_ORDER_COMMAND = 74;
|
|
98
|
+
ENTER_IN_ERROR_LAB_ORDER_COMMAND = 75;
|
|
99
|
+
|
|
100
|
+
ORIGINATE_FAMILY_HISTORY_COMMAND = 76;
|
|
101
|
+
EDIT_FAMILY_HISTORY_COMMAND = 77;
|
|
102
|
+
DELETE_FAMILY_HISTORY_COMMAND = 78;
|
|
103
|
+
COMMIT_FAMILY_HISTORY_COMMAND = 79;
|
|
104
|
+
ENTER_IN_ERROR_FAMILY_HISTORY_COMMAND = 80;
|
|
105
|
+
|
|
106
|
+
ORIGINATE_ALLERGY_COMMAND = 81;
|
|
107
|
+
EDIT_ALLERGY_COMMAND = 82;
|
|
108
|
+
DELETE_ALLERGY_COMMAND = 83;
|
|
109
|
+
COMMIT_ALLERGY_COMMAND = 84;
|
|
110
|
+
ENTER_IN_ERROR_ALLERGY_COMMAND = 85;
|
|
111
|
+
|
|
112
|
+
ORIGINATE_REMOVE_ALLERGY_COMMAND = 86;
|
|
113
|
+
EDIT_REMOVE_ALLERGY_COMMAND = 87;
|
|
114
|
+
DELETE_REMOVE_ALLERGY_COMMAND = 88;
|
|
115
|
+
COMMIT_REMOVE_ALLERGY_COMMAND = 89;
|
|
116
|
+
ENTER_IN_ERROR_REMOVE_ALLERGY_COMMAND = 90;
|
|
117
|
+
|
|
118
|
+
ORIGINATE_SURGICAL_HISTORY_COMMAND = 91;
|
|
119
|
+
EDIT_SURGICAL_HISTORY_COMMAND = 92;
|
|
120
|
+
DELETE_SURGICAL_HISTORY_COMMAND = 93;
|
|
121
|
+
COMMIT_SURGICAL_HISTORY_COMMAND = 94;
|
|
122
|
+
ENTER_IN_ERROR_SURGICAL_HISTORY_COMMAND = 95;
|
|
123
|
+
|
|
124
|
+
CREATE_TASK = 100;
|
|
125
|
+
UPDATE_TASK = 101;
|
|
126
|
+
CREATE_TASK_COMMENT = 102;
|
|
127
|
+
|
|
128
|
+
ORIGINATE_MEDICAL_HISTORY_COMMAND = 103;
|
|
129
|
+
EDIT_MEDICAL_HISTORY_COMMAND = 104;
|
|
130
|
+
DELETE_MEDICAL_HISTORY_COMMAND = 105;
|
|
131
|
+
COMMIT_MEDICAL_HISTORY_COMMAND = 106;
|
|
132
|
+
ENTER_IN_ERROR_MEDICAL_HISTORY_COMMAND = 107;
|
|
133
|
+
|
|
134
|
+
ADD_OR_UPDATE_PROTOCOL_CARD = 110;
|
|
135
|
+
|
|
136
|
+
ORIGINATE_TASK_COMMAND = 133;
|
|
137
|
+
EDIT_TASK_COMMAND = 134;
|
|
138
|
+
DELETE_TASK_COMMAND = 135;
|
|
139
|
+
COMMIT_TASK_COMMAND = 136;
|
|
140
|
+
ENTER_IN_ERROR_TASK_COMMAND = 137;
|
|
141
|
+
|
|
142
|
+
ORIGINATE_REFILL_COMMAND = 113;
|
|
143
|
+
EDIT_REFILL_COMMAND = 114;
|
|
144
|
+
DELETE_REFILL_COMMAND = 115;
|
|
145
|
+
COMMIT_REFILL_COMMAND = 116;
|
|
146
|
+
ENTER_IN_ERROR_REFILL_COMMAND = 117;
|
|
147
|
+
|
|
148
|
+
ORIGINATE_VITALS_COMMAND = 118;
|
|
149
|
+
EDIT_VITALS_COMMAND = 119;
|
|
150
|
+
DELETE_VITALS_COMMAND = 120;
|
|
151
|
+
COMMIT_VITALS_COMMAND = 121;
|
|
152
|
+
ENTER_IN_ERROR_VITALS_COMMAND = 122;
|
|
153
|
+
|
|
154
|
+
ORIGINATE_UPDATE_DIAGNOSIS_COMMAND = 123;
|
|
155
|
+
EDIT_UPDATE_DIAGNOSIS_COMMAND = 124;
|
|
156
|
+
DELETE_UPDATE_DIAGNOSIS_COMMAND = 125;
|
|
157
|
+
COMMIT_UPDATE_DIAGNOSIS_COMMAND = 126;
|
|
158
|
+
ENTER_IN_ERROR_UPDATE_DIAGNOSIS_COMMAND = 127;
|
|
159
|
+
|
|
160
|
+
ORIGINATE_CLOSE_GOAL_COMMAND = 128;
|
|
161
|
+
EDIT_CLOSE_GOAL_COMMAND = 129;
|
|
162
|
+
DELETE_CLOSE_GOAL_COMMAND = 130;
|
|
163
|
+
COMMIT_CLOSE_GOAL_COMMAND = 131;
|
|
164
|
+
ENTER_IN_ERROR_CLOSE_GOAL_COMMAND = 132;
|
|
165
|
+
|
|
166
|
+
CREATE_QUESTIONNAIRE_RESULT = 138;
|
|
167
|
+
|
|
168
|
+
ANNOTATE_PATIENT_CHART_CONDITION_RESULTS = 200;
|
|
169
|
+
|
|
170
|
+
ANNOTATE_CLAIM_CONDITION_RESULTS = 300;
|
|
171
|
+
|
|
172
|
+
SHOW_PATIENT_CHART_SUMMARY_SECTIONS = 400;
|
|
173
|
+
|
|
174
|
+
SHOW_PATIENT_PROFILE_SECTIONS = 500;
|
|
175
|
+
|
|
176
|
+
PATIENT_PROFILE__ADD_PHARMACY__POST_SEARCH_RESULTS = 501;
|
|
177
|
+
|
|
178
|
+
SEND_SURESCRIPTS_ELIGIBILITY_REQUEST = 600;
|
|
179
|
+
SEND_SURESCRIPTS_MEDICATION_HISTORY_REQUEST = 601;
|
|
180
|
+
SEND_SURESCRIPTS_BENEFITS_REQUEST = 602;
|
|
181
|
+
|
|
182
|
+
ORIGINATE_EXAM_COMMAND = 700;
|
|
183
|
+
EDIT_EXAM_COMMAND = 701;
|
|
184
|
+
DELETE_EXAM_COMMAND = 702;
|
|
185
|
+
COMMIT_EXAM_COMMAND = 703;
|
|
186
|
+
ENTER_IN_ERROR_EXAM_COMMAND = 704;
|
|
187
|
+
|
|
188
|
+
ORIGINATE_ROS_COMMAND = 800;
|
|
189
|
+
EDIT_ROS_COMMAND = 801;
|
|
190
|
+
DELETE_ROS_COMMAND = 802;
|
|
191
|
+
COMMIT_ROS_COMMAND = 803;
|
|
192
|
+
ENTER_IN_ERROR_ROS_COMMAND = 804;
|
|
193
|
+
|
|
194
|
+
ORIGINATE_STRUCTURED_ASSESSMENT_COMMAND = 900;
|
|
195
|
+
EDIT_STRUCTURED_ASSESSMENT_COMMAND = 901;
|
|
196
|
+
DELETE_STRUCTURED_ASSESSMENT_COMMAND = 902;
|
|
197
|
+
COMMIT_STRUCTURED_ASSESSMENT_COMMAND = 903;
|
|
198
|
+
ENTER_IN_ERROR_STRUCTURED_ASSESSMENT_COMMAND = 904;
|
|
199
|
+
|
|
200
|
+
SHOW_ACTION_BUTTON = 1000;
|
|
201
|
+
|
|
202
|
+
PATIENT_PORTAL__INTAKE_FORM_RESULTS = 2000;
|
|
203
|
+
PATIENT_PORTAL__APPOINTMENT_IS_CANCELABLE = 2001;
|
|
204
|
+
PATIENT_PORTAL__APPOINTMENT_IS_RESCHEDULABLE = 2002;
|
|
205
|
+
|
|
206
|
+
PATIENT_PORTAL__APPOINTMENTS__SLOTS__POST_SEARCH_RESULTS = 2005;
|
|
207
|
+
PATIENT_PORTAL__APPOINTMENTS__FORM_APPOINTMENT_TYPES__PRE_SEARCH_RESULTS = 2006;
|
|
208
|
+
PATIENT_PORTAL__APPOINTMENTS__FORM_APPOINTMENT_TYPES__POST_SEARCH_RESULTS = 2007;
|
|
209
|
+
PATIENT_PORTAL__APPOINTMENTS__FORM_LOCATIONS__PRE_SEARCH_RESULTS = 2008;
|
|
210
|
+
PATIENT_PORTAL__APPOINTMENTS__FORM_LOCATIONS__POST_SEARCH_RESULTS = 2009;
|
|
211
|
+
PATIENT_PORTAL__APPOINTMENTS__FORM_PROVIDERS__PRE_SEARCH_RESULTS = 2010;
|
|
212
|
+
PATIENT_PORTAL__APPOINTMENTS__FORM_PROVIDERS__POST_SEARCH_RESULTS = 2011;
|
|
213
|
+
|
|
214
|
+
LAUNCH_MODAL = 3000;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
message Effect {
|
|
218
|
+
EffectType type = 1;
|
|
219
|
+
string payload = 2;
|
|
220
|
+
string plugin_name = 3;
|
|
221
|
+
string classname = 4;
|
|
222
|
+
//Oneof effect_payload {
|
|
223
|
+
// ...
|
|
224
|
+
//}
|
|
225
|
+
}
|