Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73a3f07e2b | ||
|
|
4ea239a953 | ||
|
|
625d5d70a7 | ||
|
|
5c3d8b37b6 | ||
|
|
8bbbf3a889 | ||
|
|
d5bf72851a | ||
|
|
2914c83032 | ||
|
|
31e542dfd9 | ||
|
|
25599a2e2a | ||
|
|
1cf7015511 | ||
|
|
756f70cc54 | ||
|
|
ded2e61913 | ||
|
|
b58aa4575a | ||
|
|
f78abe2afa | ||
|
|
f48157117f | ||
|
|
6f8bd0dff8 | ||
|
|
943af89df2 | ||
|
|
cd2da349e5 | ||
|
|
14e86dcddd | ||
|
|
2c8b93656d | ||
|
|
6932468206 | ||
|
|
7bc9efb0f5 | ||
|
|
5d47cc43c1 | ||
|
|
e46a11a01e | ||
|
|
27a950d956 | ||
|
|
03d4c10adc | ||
|
|
7a0c369006 | ||
|
|
8c946a4742 | ||
|
|
30b9e44220 | ||
|
|
380abe2705 | ||
|
|
f4570c96c2 | ||
|
|
1fe951a71e | ||
|
|
ebe1af8d4f | ||
|
|
5cda5159da | ||
|
|
115a3ec0b0 | ||
|
|
ac82a111e7 | ||
|
|
a22fd67e13 | ||
|
|
91f0af058f | ||
|
|
5a1186388d | ||
|
|
2f0f92c095 | ||
|
|
5c686268ab | ||
|
|
974aabc9b2 | ||
|
|
17e3b49b06 | ||
|
|
e3c119489a | ||
|
|
17447baf44 | ||
|
|
daa3ddccdb | ||
|
|
c91b6dddd8 | ||
|
|
92548191e4 | ||
|
|
68fcaef19a | ||
|
|
ef611e4849 | ||
|
|
d128fd6bf0 | ||
|
|
3bdd434488 | ||
|
|
29bac8df7a | ||
|
|
319c67c389 | ||
|
|
b9836f6c71 | ||
|
|
6a6e2d7df3 | ||
|
|
2f8c408ed2 | ||
|
|
27910239e0 | ||
|
|
719bfd02eb | ||
|
|
994818faeb | ||
|
|
f06ef53e83 | ||
|
|
c7008621e4 | ||
|
|
55a580659e | ||
|
|
fd7620ced9 | ||
|
|
cd1cbf0f85 | ||
|
|
08055398de | ||
|
|
f6db7fade6 | ||
|
|
58d2bf1d12 | ||
|
|
87f5eca659 | ||
|
|
922ba8cc42 | ||
|
|
777ff88f3d | ||
|
|
68858db4b6 | ||
|
|
ab106afae3 | ||
|
|
ac69b0a656 | ||
|
|
8edba24eec | ||
|
|
aae232fc3e | ||
|
|
8fad8ceb80 | ||
|
|
f00f48da2b | ||
|
|
076b89ef83 | ||
|
|
4920b527d1 | ||
|
|
482041f053 | ||
|
|
674edf85f0 | ||
|
|
33a1a465ea | ||
|
|
6e04de30b6 | ||
|
|
19117167ac | ||
|
|
22e3c5d953 | ||
|
|
9a34877be4 | ||
|
|
b1b66429b6 | ||
|
|
78e522fbf6 | ||
|
|
830cb82965 | ||
|
|
9a71edda6a | ||
|
|
7a8ae23839 | ||
|
|
6873c4f065 | ||
|
|
6ea16eccd9 | ||
|
|
ff381c6521 | ||
|
|
26cd695b8b | ||
|
|
a4f1b2195c | ||
|
|
c8df17b032 | ||
|
|
f1a4c09b74 | ||
|
|
02572b4928 | ||
|
|
fd1d29820a | ||
|
|
6c63a917d3 | ||
|
|
caa6062c41 | ||
|
|
7f9743a020 | ||
|
|
a2c4161477 | ||
|
|
42cfce60f5 | ||
|
|
244949bab6 | ||
|
|
e87ec7b7f5 | ||
|
|
d98889f1eb | ||
|
|
817d43ee62 | ||
|
|
f396b30166 | ||
|
|
0bb3eeb068 | ||
|
|
1df21a9e07 | ||
|
|
fd1a9e2abe | ||
|
|
e34a057263 | ||
|
|
27e02825a4 | ||
|
|
8fd3af1e13 | ||
|
|
1334ba8eb0 | ||
|
|
a870b3cc60 | ||
|
|
52687a7113 | ||
|
|
421de23ba3 | ||
|
|
adc8d9ea0f | ||
|
|
f65639c2b0 | ||
|
|
cdd75bda2a | ||
|
|
d92fe44d3c | ||
|
|
d90c2ac024 | ||
|
|
7ce5e1d2d3 | ||
|
|
a3bf47f9bf | ||
|
|
81f79a26ad | ||
|
|
60b4b5d7cf | ||
|
|
69c54d4f49 | ||
|
|
0f8868a232 | ||
|
|
1bbfee4087 | ||
|
|
33c7b59611 | ||
|
|
b17f753e62 | ||
|
|
c77a2ef5c9 | ||
|
|
348edd4717 | ||
|
|
407060658a | ||
|
|
fc00f9d505 | ||
|
|
bc3d080672 | ||
|
|
09353354c3 | ||
|
|
0a12320083 | ||
|
|
813ee5ed4d | ||
|
|
6085b5f733 | ||
|
|
ffe12789dd | ||
|
|
0b68429dfb | ||
|
|
b747ea5144 | ||
|
|
caadf089df | ||
|
|
e0fc69c181 | ||
|
|
2b9765304f | ||
|
|
57730483e9 | ||
|
|
731b64e321 | ||
|
|
e97a09b0f4 | ||
|
|
f63d8a73d8 | ||
|
|
f10adf82f4 | ||
|
|
6174109d5a | ||
|
|
244e822afc | ||
|
|
cbdeeae597 | ||
|
|
7f6de72e8e | ||
|
|
1f514e5f1b | ||
|
|
f3fed511b9 | ||
|
|
31796d272c | ||
|
|
b41e6f93f3 | ||
|
|
882a45d398 | ||
|
|
fb0cd9355f | ||
|
|
2b12193020 | ||
|
|
9a626a2064 | ||
|
|
903777044a | ||
|
|
5e4725860d | ||
|
|
670470119f | ||
|
|
0d4f90f3cd | ||
|
|
43dd87c2c1 | ||
|
|
98f8583fba | ||
|
|
97a9a505ca | ||
|
|
bb74f3a761 | ||
|
|
aa33397fe6 | ||
|
|
8ae731fe4c | ||
|
|
add3416e11 | ||
|
|
136969bf18 | ||
|
|
e3e039ad47 | ||
|
|
0797eff0b7 | ||
|
|
55a5f04923 | ||
|
|
ed9e4d6751 | ||
|
|
b6119f8e29 | ||
|
|
2e38f4b2e4 | ||
|
|
e03abc45f5 | ||
|
|
f03d64ce39 | ||
|
|
e895bfb1aa | ||
|
|
17358c3f4b | ||
|
|
ec7337e801 | ||
|
|
538ea2516d | ||
|
|
fe687cd2f9 | ||
|
|
bdb9af5c4b | ||
|
|
db0f751a68 | ||
|
|
08fdb10f6d | ||
|
|
95c18b4986 | ||
|
|
e684558783 | ||
|
|
9104e7be50 | ||
|
|
81ad25b39f | ||
|
|
54d2cde6da | ||
|
|
9edc366ff7 | ||
|
|
79c10bb424 | ||
|
|
d8055e458f | ||
|
|
5c04e34c8f | ||
|
|
c59c5b3f14 | ||
|
|
c4adcfd39e | ||
|
|
0fbaf95971 | ||
|
|
a2a7e05e7d | ||
|
|
9da8647c84 | ||
|
|
e62f5f8dd2 | ||
|
|
dc6e9d6bb5 | ||
|
|
84a097212b | ||
|
|
2381810ba9 | ||
|
|
31b1adfa59 | ||
|
|
cd28877ed8 | ||
|
|
e81a39f5be | ||
|
|
9a2cf70504 | ||
|
|
d70eae3eb0 | ||
|
|
8481e94d4d | ||
|
|
19b22c39ae | ||
|
|
05802a3cf1 | ||
|
|
75d88bc454 | ||
|
|
9827d1bf84 | ||
|
|
e208f2e6a9 | ||
|
|
9c1a3c3183 | ||
|
|
ecaf578f92 | ||
|
|
d26adf92bd | ||
|
|
5ee832b195 | ||
|
|
8baba22a2e | ||
|
|
1d86b1a102 | ||
|
|
25e6817248 | ||
|
|
681384b742 | ||
|
|
54e07c281f | ||
|
|
9dedccc7f9 | ||
|
|
621e63b3e1 | ||
|
|
64cf3b324d | ||
|
|
b7f315ca47 | ||
|
|
caaa032c4b | ||
|
|
22127a8f59 | ||
|
|
50ca2bde97 | ||
|
|
c73cfbc110 | ||
|
|
5716b71d40 | ||
|
|
a3028ad1f6 | ||
|
|
352407c71a | ||
|
|
1b5a5a2963 | ||
|
|
cf5136899e | ||
|
|
8c4e96bb3d | ||
|
|
5b334175c3 | ||
|
|
20bfc829f7 | ||
|
|
0d498ba17d | ||
|
|
a0180a9f0c | ||
|
|
2cdef4b984 | ||
|
|
70532a6cc6 | ||
|
|
f0519920fa | ||
|
|
0d21cc6ad0 | ||
|
|
dc502190ed | ||
|
|
7d009ef1d9 | ||
|
|
777cca7471 | ||
|
|
e4bbbfbbe4 | ||
|
|
10059adc57 | ||
|
|
c522ff3dda | ||
|
|
980516fcfc | ||
|
|
2677170d67 | ||
|
|
3452f1b91e | ||
|
|
450e0981a5 | ||
|
|
8cf1e54490 | ||
|
|
85f836cd91 | ||
|
|
f5560c11b0 | ||
|
|
bef50f9298 | ||
|
|
986b7ae2bf | ||
|
|
86c479ac04 | ||
|
|
460e375f0a | ||
|
|
78344c2c66 | ||
|
|
b451ce4407 | ||
|
|
21b586b08f | ||
|
|
3bbeb1c521 | ||
|
|
7668b69f20 | ||
|
|
3a12138134 | ||
|
|
97786b808c | ||
|
|
cd1baa1b36 | ||
|
|
3ae3bee452 | ||
|
|
fd017c4512 | ||
|
|
c680720ce5 | ||
|
|
dfc4e89a91 | ||
|
|
13d337aaab | ||
|
|
4f26940005 | ||
|
|
9d08e81aa5 | ||
|
|
1a539d04c2 | ||
|
|
5cc78c867f | ||
|
|
cefa480979 | ||
|
|
66537bf1b9 | ||
|
|
862d426c71 | ||
|
|
e62f403fe9 | ||
|
|
dea0ceab57 | ||
|
|
a6c1e6c717 | ||
|
|
b03739428f | ||
|
|
2a52d9f05d | ||
|
|
d5e21bb5bb | ||
|
|
04ffe3ec76 | ||
|
|
9cdf8b690b | ||
|
|
8d49b31d03 | ||
|
|
e4cfae7ad9 | ||
|
|
e53041f630 | ||
|
|
35c54eac56 | ||
|
|
e7be573328 | ||
|
|
8a7706b286 | ||
|
|
c217b8bbde | ||
|
|
74f3cbc4b2 | ||
|
|
d091cd604c | ||
|
|
3a4280163d | ||
|
|
2d75e01ea0 | ||
|
|
5c5a49486d | ||
|
|
a8a57132a7 | ||
|
|
92c8996ed4 | ||
|
|
f07dca5fa4 | ||
|
|
c99e0d8a23 | ||
|
|
84144bc3ef | ||
|
|
5cbdd0c616 | ||
|
|
fc015326c7 | ||
|
|
01860b6094 | ||
|
|
cfdf827ff0 | ||
|
|
ceb6837153 | ||
|
|
b01b0108b0 | ||
|
|
d6862e7418 | ||
|
|
beb7083e55 | ||
|
|
412fe4e23f | ||
|
|
659649e10b | ||
|
|
f431b277dd | ||
|
|
2bc361cdca | ||
|
|
c6f306c0de | ||
|
|
c0ea27f6b3 | ||
|
|
df8d4029f1 | ||
|
|
a36cb63926 | ||
|
|
e51529e6c9 | ||
|
|
750a150644 | ||
|
|
a9d28d85da | ||
|
|
6ee5094cbe | ||
|
|
6bfb9bb140 | ||
|
|
db5b760432 | ||
|
|
e7de8be2d8 | ||
|
|
cb2088daf7 | ||
|
|
2a743554b6 | ||
|
|
a28984ef1f | ||
|
|
95e5e11d09 | ||
|
|
ff9f199850 | ||
|
|
1cc94f36a7 | ||
|
|
5c5223fcf1 | ||
|
|
8513ad9ef3 | ||
|
|
66d8bc6d6f | ||
|
|
0064a4b1cd | ||
|
|
74ce89b22b | ||
|
|
c92975f555 | ||
|
|
ce6c0533a0 | ||
|
|
4df624b8c4 | ||
|
|
e064fd353e | ||
|
|
458d310c78 | ||
|
|
73bc4d9094 | ||
|
|
7709ebb107 | ||
|
|
559b637290 | ||
|
|
36910f2b47 | ||
|
|
9e10c2b2de | ||
|
|
c5cbd77cb9 | ||
|
|
b3b4c10e4c | ||
|
|
855020d730 | ||
|
|
8503cbce4e | ||
|
|
c8667fb2d6 | ||
|
|
674ca9f96f | ||
|
|
7a4b97b4e8 | ||
|
|
c79c0c301d | ||
|
|
ff5060f276 | ||
|
|
dafb26b34b | ||
|
|
c4f9d5e750 | ||
|
|
cf40a8388c | ||
|
|
d596ab5c3d | ||
|
|
72198eee7d | ||
|
|
057f68a9b4 | ||
|
|
034ca64d6b | ||
|
|
4a0901aee9 | ||
|
|
d0ec9cf0e0 | ||
|
|
71bea0d4d8 | ||
|
|
e607ed2aa0 | ||
|
|
4939f43509 | ||
|
|
c80ea17cc2 | ||
|
|
aa7dc1e2c1 | ||
|
|
e7e1a8a6cd | ||
|
|
e66c27affb | ||
|
|
ae26904885 | ||
|
|
8bb730318a | ||
|
|
69b96478cb | ||
|
|
816666df7b | ||
|
|
e375a4ab11 | ||
|
|
7f4d71e412 | ||
|
|
a90605c82d | ||
|
|
5b523c2afa | ||
|
|
5551f817e3 | ||
|
|
a9ca3fa026 | ||
|
|
89380353d2 | ||
|
|
edb86fad55 | ||
|
|
395a1be3fb | ||
|
|
65d852b9e4 | ||
|
|
e797a3a141 | ||
|
|
246936f90b | ||
|
|
c57298475a | ||
|
|
6a5ebb3e25 | ||
|
|
291b23aee1 | ||
|
|
72427fe2ff | ||
|
|
882d04c9bf | ||
|
|
d1a24bc9d9 | ||
|
|
16a87fa75f | ||
|
|
6fdac4d605 | ||
|
|
6192502fe0 | ||
|
|
2341b32638 | ||
|
|
45aeaec916 | ||
|
|
66b84ae9c2 | ||
|
|
bc28fe26ac | ||
|
|
7f642a05da | ||
|
|
66a0aadcce | ||
|
|
808af7ee96 | ||
|
|
10b5e071f4 | ||
|
|
fe1969b071 | ||
|
|
16b2a8295f | ||
|
|
d33bb4210d | ||
|
|
ab681b9929 | ||
|
|
f52daca5e5 | ||
|
|
4afc88c0e5 | ||
|
|
f519f8609c | ||
|
|
e27d5b58a4 | ||
|
|
a18b292a9d | ||
|
|
7bd1507a89 | ||
|
|
a634177578 | ||
|
|
fe4d71ad0b | ||
|
|
f723546e6b | ||
|
|
348b8949d4 | ||
|
|
26e037dee7 | ||
|
|
26be96783d | ||
|
|
029ba1fb4a | ||
|
|
56d658f02d | ||
|
|
64921b905f | ||
|
|
d00d7daf41 | ||
|
|
144a173306 | ||
|
|
e40cbae113 | ||
|
|
698d274c64 | ||
|
|
c221dd86d2 | ||
|
|
a8c3d1b9a2 | ||
|
|
6cce8e6720 | ||
|
|
e8dbe3e1b6 | ||
|
|
ac5dbda3b2 | ||
|
|
bf77b3959a | ||
|
|
c6a6bce0b8 | ||
|
|
3f9decc6d5 | ||
|
|
1b1ff8068d | ||
|
|
eb1a900b13 | ||
|
|
e8938111d5 | ||
|
|
73122e717c | ||
|
|
300fe06b60 | ||
|
|
37e5387cf0 | ||
|
|
7c2860789d | ||
|
|
df35b1bc06 | ||
|
|
0460a487ec | ||
|
|
0195a3d860 | ||
|
|
2740e34ad3 | ||
|
|
61d2caef96 | ||
|
|
a88f37595d | ||
|
|
42d80a3e60 | ||
|
|
51143ffe35 | ||
|
|
76f7b00b65 | ||
|
|
64ca61745b | ||
|
|
ababe63a55 | ||
|
|
6c2217f2e5 | ||
|
|
cf9bec3ffa | ||
|
|
32bc47d315 | ||
|
|
1fb98884d2 | ||
|
|
7f8f9dc073 | ||
|
|
c6f89495b2 | ||
|
|
bad987a06b | ||
|
|
c73abb518f | ||
|
|
d12d01215e | ||
|
|
86adb5113a | ||
|
|
5220cd371c | ||
|
|
16b063a504 | ||
|
|
d0d75987f7 | ||
|
|
7c4ee734fa | ||
|
|
a187783e0d | ||
|
|
ada05b01a7 | ||
|
|
1a44d78277 | ||
|
|
691a073b86 | ||
|
|
5a54564bff | ||
|
|
94b625d4e6 | ||
|
|
8f730a5124 | ||
|
|
0ff4d90878 | ||
|
|
c10342c05c | ||
|
|
a047994e3d | ||
|
|
672ad2d0e7 | ||
|
|
98bd960014 | ||
|
|
9cf30eacb2 | ||
|
|
373b01ac50 | ||
|
|
9120db49f1 | ||
|
|
f02e0339a8 | ||
|
|
20d6680e06 | ||
|
|
2735b0a6eb | ||
|
|
2b1f2104cd | ||
|
|
d03d9e9a09 | ||
|
|
f9eb2c0ae1 | ||
|
|
974367834a | ||
|
|
4aa7cbd641 | ||
|
|
ee88672d37 | ||
|
|
dffe1d51cf | ||
|
|
c5936d412e | ||
|
|
d588ddd830 | ||
|
|
81c2f60731 | ||
|
|
a715c4bd1b | ||
|
|
f3d0a4de3c | ||
|
|
5a74321952 | ||
|
|
27869a9cf6 | ||
|
|
8df6cc55cb | ||
|
|
9e74151b52 | ||
|
|
192cc03842 | ||
|
|
c791750f36 | ||
|
|
080183c712 | ||
|
|
d1289540bd | ||
|
|
7c5b182130 | ||
|
|
f38605f04c | ||
|
|
3498037163 | ||
|
|
e2196b1aaf |
No files matched your search
@@ -62,7 +62,7 @@ echo "Done generating documentation output"
|
||||
echo 'STARTING PUBLISH'
|
||||
|
||||
# WILL ALWAYS FAIL IF INITIATED FROM PR BRANCH
|
||||
./node_modules/.bin/gh-pages \
|
||||
npx gh-pages \
|
||||
--silent \
|
||||
--repo https://$GITHUB_TOKEN@github.com/OHIF/Viewers.git \
|
||||
--message 'Autogenerated Message: [ci skip]' \
|
||||
|
||||
@@ -9,25 +9,29 @@ version: 2.1
|
||||
# create pull request previews and to update `https://docs.ohif.org`
|
||||
###
|
||||
|
||||
## https://github.com/cypress-io/circleci-orb
|
||||
##
|
||||
orbs:
|
||||
codecov: codecov/codecov@1.0.5
|
||||
cypress: cypress-io/cypress@1.8.0
|
||||
cypress: cypress-io/cypress@1.13.0
|
||||
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: circleci/node:10.16.0
|
||||
- image: circleci/node:12.9.1
|
||||
environment:
|
||||
TERM: xterm # Enable colors in term
|
||||
QUICK_BUILD: true
|
||||
working_directory: ~/repo
|
||||
|
||||
jobs:
|
||||
PR_UNIT_TESTS:
|
||||
###
|
||||
# Workflow: PR_CHECKS
|
||||
###
|
||||
UNIT_TESTS:
|
||||
<<: *defaults
|
||||
|
||||
steps:
|
||||
# Enable yarn workspaces
|
||||
- run: yarn config set workspaces-experimental true
|
||||
|
||||
# Update yarn
|
||||
- run: yarn -v
|
||||
# Checkout code and ALL Git Tags
|
||||
- checkout:
|
||||
post:
|
||||
@@ -36,9 +40,8 @@ jobs:
|
||||
name: Restore Yarn and Cypress Package Cache
|
||||
keys:
|
||||
# when lock file changes, use increasingly general patterns to restore cache
|
||||
- yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-v1-{{ .Branch }}-
|
||||
- yarn-packages-v1-
|
||||
- yarn-packages-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: yarn install --frozen-lockfile
|
||||
@@ -46,13 +49,11 @@ jobs:
|
||||
name: Save Yarn Package Cache
|
||||
paths:
|
||||
- ~/.cache ## Cache yarn and Cypress
|
||||
key: yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
|
||||
key: yarn-packages-{{ checksum "yarn.lock" }}
|
||||
# RUN TESTS
|
||||
- run:
|
||||
name: 'JavaScript Test Suite'
|
||||
command: yarn run test:unit:ci
|
||||
|
||||
# PLATFORM/VIEWER
|
||||
- run:
|
||||
name: 'VIEWER: Combine report output'
|
||||
@@ -66,7 +67,6 @@ jobs:
|
||||
- codecov/upload:
|
||||
file: '/home/circleci/repo/platform/viewer/coverage/reports'
|
||||
flags: 'viewer'
|
||||
|
||||
# PLATFORM/CORE
|
||||
- run:
|
||||
name: 'CORE: Combine report output'
|
||||
@@ -81,14 +81,11 @@ jobs:
|
||||
file: '/home/circleci/repo/platform/core/coverage/reports'
|
||||
flags: 'core'
|
||||
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths: .
|
||||
|
||||
MERGE_UNIT_TESTS:
|
||||
###
|
||||
# Workflow: PR_OPTIONAL_DOCKER_PUBLISH
|
||||
###
|
||||
DOCKER_PR_PUBLISH:
|
||||
<<: *defaults
|
||||
|
||||
steps:
|
||||
# Enable yarn workspaces
|
||||
- run: yarn config set workspaces-experimental true
|
||||
@@ -97,13 +94,49 @@ jobs:
|
||||
- checkout:
|
||||
post:
|
||||
- git fetch --all
|
||||
|
||||
- restore_cache:
|
||||
name: Restore Yarn and Cypress Package Cache
|
||||
keys:
|
||||
# when lock file changes, use increasingly general patterns to restore cache
|
||||
- yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-v1-{{ .Branch }}-
|
||||
- yarn-packages-v1-
|
||||
- yarn-packages-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-
|
||||
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: yarn install --frozen-lockfile
|
||||
|
||||
- setup_remote_docker:
|
||||
docker_layer_caching: false
|
||||
|
||||
- run:
|
||||
name: Build and push Docker image
|
||||
command: |
|
||||
# Remove npm config
|
||||
rm -f ./.npmrc
|
||||
# Set our version number using vars
|
||||
echo $CIRCLE_BUILD_NUM
|
||||
# Build our image, auth, and push
|
||||
docker build --tag ohif/viewer:PR_BUILD-$CIRCLE_BUILD_NUM .
|
||||
echo $DOCKER_PWD | docker login -u $DOCKER_LOGIN --password-stdin
|
||||
docker push ohif/viewer:PR_BUILD-$CIRCLE_BUILD_NUM
|
||||
|
||||
###
|
||||
# Workflow: DEPLOY
|
||||
###
|
||||
BUILD:
|
||||
<<: *defaults
|
||||
steps:
|
||||
# Checkout code and ALL Git Tags
|
||||
- checkout:
|
||||
post:
|
||||
- git fetch --all
|
||||
- restore_cache:
|
||||
name: Restore Yarn and Cypress Package Cache
|
||||
keys:
|
||||
# when lock file changes, use increasingly general patterns to restore cache
|
||||
- yarn-packages-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: yarn install --frozen-lockfile
|
||||
@@ -111,106 +144,154 @@ jobs:
|
||||
name: Save Yarn Package Cache
|
||||
paths:
|
||||
- ~/.cache ## Cache yarn and Cypress
|
||||
key: yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
|
||||
# RUN TESTS
|
||||
key: yarn-packages-{{ checksum "yarn.lock" }}
|
||||
# Build & Test
|
||||
- run:
|
||||
name: 'JavaScript Test Suite'
|
||||
command: yarn run test:unit:ci
|
||||
|
||||
# PLATFORM/VIEWER
|
||||
- run:
|
||||
name: 'VIEWER: Combine report output'
|
||||
command: |
|
||||
viewerCov="/home/circleci/repo/platform/viewer/coverage"
|
||||
touch "${viewerCov}/reports"
|
||||
cat "${viewerCov}/clover.xml" >> "${viewerCov}/reports"
|
||||
echo "\<<\<<\<< EOF" >> "${viewerCov}/reports"
|
||||
cat "${viewerCov}/lcov.info" >>"${viewerCov}/reports"
|
||||
echo "\<<\<<\<< EOF" >> "${viewerCov}/reports"
|
||||
- codecov/upload:
|
||||
file: '/home/circleci/repo/platform/viewer/coverage/reports'
|
||||
flags: 'viewer'
|
||||
|
||||
# PLATFORM/CORE
|
||||
- run:
|
||||
name: 'CORE: Combine report output'
|
||||
command: |
|
||||
coreCov="/home/circleci/repo/platform/core/coverage"
|
||||
touch "${coreCov}/reports"
|
||||
cat "${coreCov}/clover.xml" >> "${coreCov}/reports"
|
||||
echo "\<<\<<\<< EOF" >> "${coreCov}/reports"
|
||||
cat "${coreCov}/lcov.info" >> "${coreCov}/reports"
|
||||
echo "\<<\<<\<< EOF" >> "${coreCov}/reports"
|
||||
- codecov/upload:
|
||||
file: '/home/circleci/repo/platform/core/coverage/reports'
|
||||
flags: 'core'
|
||||
|
||||
name: 'Build the OHIF Viewer'
|
||||
command: yarn run build
|
||||
no_output_timeout: 45m
|
||||
# - run:
|
||||
# name: 'Upload SourceMaps, Send Deploy Notification'
|
||||
# command: |
|
||||
# # export FILE_1=$(find ./build/static/js -type f -name "2.*.js" -exec basename {} \;)
|
||||
# # export FILE_MAIN=$(find ./build/static/js -type f -name "main.*.js" -exec basename {} \;)
|
||||
# # export FILE_RUNTIME_MAIN=$(find ./build/static/js -type f -name "runtime~main.*.js" -exec basename {} \;)
|
||||
# # curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_1.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_1
|
||||
# # curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_MAIN
|
||||
# # curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_RUNTIME_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_RUNTIME_MAIN
|
||||
# curl --request POST https://api.rollbar.com/api/1/deploy/ -F access_token=$ROLLBAR_TOKEN -F environment=$GOOGLE_STORAGE_BUCKET -F revision=$CIRCLE_SHA1 -F local_username=CircleCI
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths: .
|
||||
paths:
|
||||
- platform/viewer/dist
|
||||
- netlify.toml
|
||||
- .netlify
|
||||
|
||||
npm_publish:
|
||||
<<: *defaults
|
||||
DEPLOY_TO_DEV:
|
||||
docker:
|
||||
- image: circleci/node:12.9.1
|
||||
environment:
|
||||
TERM: xterm
|
||||
NETLIFY_SITE_ID: 32708787-c9b0-4634-b50f-7ca41952da77
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- run: cd .netlify && npm install
|
||||
- run:
|
||||
cp .netlify/deploy-workflow/_redirects platform/viewer/dist/_redirects
|
||||
- run: cd .netlify && npm run deploy
|
||||
|
||||
DEPLOY_TO_STAGING:
|
||||
docker:
|
||||
- image: circleci/node:12.9.1
|
||||
environment:
|
||||
TERM: xterm
|
||||
NETLIFY_SITE_ID: c7502ae3-b150-493c-8422-05701e44a969
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- run: cd .netlify && npm install
|
||||
- run:
|
||||
cp .netlify/deploy-workflow/_redirects platform/viewer/dist/_redirects
|
||||
- run: cd .netlify && npm run deploy
|
||||
|
||||
DEPLOY_TO_PRODUCTION:
|
||||
docker:
|
||||
- image: circleci/node:12.9.1
|
||||
environment:
|
||||
TERM: xterm
|
||||
NETLIFY_SITE_ID: 79c4a5da-5c95-4dc9-84f7-45fd9dfe21b0
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- run: cd .netlify && npm install
|
||||
- run:
|
||||
cp .netlify/deploy-workflow/_redirects platform/viewer/dist/_redirects
|
||||
- run: cd .netlify && npm run deploy
|
||||
|
||||
###
|
||||
# Workflow: RELEASE
|
||||
###
|
||||
NPM_PUBLISH:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- run: yarn -v
|
||||
# Checkout code and ALL Git Tags
|
||||
- checkout:
|
||||
post:
|
||||
- git fetch --all
|
||||
# Use increasingly general patterns to restore cache
|
||||
- restore_cache:
|
||||
name: Restore Yarn and Cypress Package Cache
|
||||
keys:
|
||||
- yarn-packages-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: yarn install --frozen-lockfile
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
key: yarn-packages-{{ checksum "yarn.lock" }}
|
||||
- run:
|
||||
name: Avoid hosts unknown for github
|
||||
command:
|
||||
mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking
|
||||
no\n" > ~/.ssh/config
|
||||
- run: git config --global user.email "danny.ri.brown+ohif-bot@gmail.com"
|
||||
- run: git config --global user.name "ohif-bot"
|
||||
command: |
|
||||
rm -rf ~/.ssh
|
||||
mkdir ~/.ssh/
|
||||
echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config
|
||||
git config --global user.email "danny.ri.brown+ohif-bot@gmail.com"
|
||||
git config --global user.name "ohif-bot"
|
||||
- run:
|
||||
name: Authenticate with registry
|
||||
name: Authenticate with NPM registry
|
||||
command:
|
||||
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/repo/.npmrc
|
||||
- run: npx lerna version
|
||||
- run: npx lerna publish from-package
|
||||
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths: .
|
||||
|
||||
docs_publish:
|
||||
DOCS_PUBLISH:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- checkout
|
||||
- run:
|
||||
name: Avoid hosts unknown for github
|
||||
command:
|
||||
mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking
|
||||
no\n" > ~/.ssh/config
|
||||
- run: git config --global user.email "danny.ri.brown+ohif-bot@gmail.com"
|
||||
- run: git config --global user.name "ohif-bot"
|
||||
- run: yarn global add gitbook-cli
|
||||
- run: yarn global add gh-pages
|
||||
command: |
|
||||
rm -rf ~/.ssh
|
||||
mkdir ~/.ssh/
|
||||
echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config
|
||||
git config --global user.email "danny.ri.brown+ohif-bot@gmail.com"
|
||||
git config --global user.name "ohif-bot"
|
||||
- run: yarn global add gitbook-cli gh-pages
|
||||
- run: chmod +x ~/repo/.circleci/build-and-publish-docs.sh
|
||||
- run: ~/repo/.circleci/build-and-publish-docs.sh
|
||||
|
||||
docker_publish:
|
||||
DOCKER_MASTER_PUBLISH:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- setup_remote_docker:
|
||||
docker_layer_caching: true
|
||||
docker_layer_caching: false
|
||||
- run:
|
||||
name: Build and push Docker image
|
||||
command: |
|
||||
# This file will exist if a new version was published by
|
||||
# our `semantic-release` command in the previous job
|
||||
if [[ ! -e tmp/updated-version.txt ]]; then
|
||||
# our command in the previous job. Created in npm postpublish hook
|
||||
# in the `platform/viewer` project.
|
||||
if [[ ! -e platform/viewer/success_version.txt ]]; then
|
||||
exit 0
|
||||
else
|
||||
# Remove npm config
|
||||
rm -f ./.npmrc
|
||||
# Set our version number using vars
|
||||
export IMAGE_VERSION=$(cat tmp/updated-version.txt)
|
||||
export IMAGE_VERSION=$(cat platform/viewer/success_version.txt)
|
||||
export IMAGE_VERSION_FULL=v$IMAGE_VERSION.${CIRCLE_BUILD_NUM}
|
||||
echo $IMAGE_VERSION
|
||||
echo $IMAGE_VERSION_FULL
|
||||
@@ -221,122 +302,175 @@ jobs:
|
||||
docker push ohif/$IMAGE_NAME:latest
|
||||
fi
|
||||
|
||||
viewer_demo_build:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
# Build & Test
|
||||
- run:
|
||||
name: 'Build Demo Site'
|
||||
command: yarn run build:demo
|
||||
no_output_timeout: 30m
|
||||
- run:
|
||||
name: 'Upload SourceMaps, Send Deploy Notification'
|
||||
command: |
|
||||
# export FILE_1=$(find ./build/static/js -type f -name "2.*.js" -exec basename {} \;)
|
||||
# export FILE_MAIN=$(find ./build/static/js -type f -name "main.*.js" -exec basename {} \;)
|
||||
# export FILE_RUNTIME_MAIN=$(find ./build/static/js -type f -name "runtime~main.*.js" -exec basename {} \;)
|
||||
# curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_1.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_1
|
||||
# curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_MAIN
|
||||
# curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_RUNTIME_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_RUNTIME_MAIN
|
||||
curl --request POST https://api.rollbar.com/api/1/deploy/ -F access_token=$ROLLBAR_TOKEN -F environment=$GOOGLE_STORAGE_BUCKET -F revision=$CIRCLE_SHA1 -F local_username=CircleCI
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths: .
|
||||
|
||||
viewer_demo_publish:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: google/cloud-sdk
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- setup_remote_docker:
|
||||
docker_layer_caching: true
|
||||
- run:
|
||||
name: Deploy latest version to viewer.ohif.org
|
||||
command: |
|
||||
# https://circleci.com/docs/2.0/google-auth/#authorization
|
||||
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
|
||||
gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
|
||||
gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}
|
||||
# Remove all files in Storage Bucket; Push latest
|
||||
gsutil -m rm gs://$GOOGLE_STORAGE_BUCKET/**
|
||||
gsutil -m rsync -R platform/viewer/dist gs://$GOOGLE_STORAGE_BUCKET
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
# PULL REQUESTS
|
||||
PR_CHECKS:
|
||||
jobs:
|
||||
- PR_UNIT_TESTS:
|
||||
- UNIT_TESTS:
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- master
|
||||
- feature/*
|
||||
- hotfix/*
|
||||
# Cypress job added by `cypress-io` orb
|
||||
# E2E: PWA
|
||||
- cypress/run:
|
||||
name: 'E2E: PWA'
|
||||
executor: cypress/browsers-chrome76
|
||||
browser: chrome
|
||||
pre-steps:
|
||||
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
|
||||
add wait-on' # Use yarn latest
|
||||
yarn: true
|
||||
store_artifacts: true
|
||||
start: yarn run dev
|
||||
wait-on: 'http://localhost:3000'
|
||||
no-workspace: true # Don't persist workspace
|
||||
record: false
|
||||
store_artifacts: false
|
||||
working_directory: platform/viewer
|
||||
cache-key: 'yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}'
|
||||
build: npx cross-env QUICK_BUILD=true yarn run build
|
||||
start: yarn run test:e2e:serve
|
||||
wait-on: 'http://localhost:3000'
|
||||
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
|
||||
no-workspace: true # Don't persist workspace
|
||||
post-steps:
|
||||
- store_test_results:
|
||||
path: cypress/results
|
||||
- store_artifacts:
|
||||
path: platform/viewer/cypress/screenshots
|
||||
- store_artifacts:
|
||||
path: platform/viewer/cypress/videos
|
||||
requires:
|
||||
- PR_UNIT_TESTS
|
||||
- UNIT_TESTS
|
||||
# E2E: script-tag
|
||||
- cypress/run:
|
||||
name: 'E2E: Script Tag'
|
||||
executor: cypress/browsers-chrome76
|
||||
browser: chrome
|
||||
pre-steps:
|
||||
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
|
||||
add wait-on' # Use yarn latest
|
||||
yarn: true
|
||||
record: false
|
||||
store_artifacts: false
|
||||
working_directory: platform/viewer
|
||||
build: npx cross-env QUICK_BUILD=true yarn run build:package
|
||||
start: yarn run test:e2e:serve
|
||||
spec: 'cypress/integration/common/**/*'
|
||||
wait-on: 'http://localhost:3000'
|
||||
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
|
||||
no-workspace: true # Don't persist workspace
|
||||
post-steps:
|
||||
- store_artifacts:
|
||||
path: platform/viewer/cypress/screenshots
|
||||
- store_artifacts:
|
||||
path: platform/viewer/cypress/videos
|
||||
requires:
|
||||
- UNIT_TESTS
|
||||
|
||||
# MERGE TO MASTER
|
||||
RELEASE:
|
||||
PR_OPTIONAL_VISUAL_TESTS:
|
||||
jobs:
|
||||
- MERGE_UNIT_TESTS:
|
||||
- AWAIT_APPROVAL:
|
||||
type: approval
|
||||
# Update hub.docker.org
|
||||
- cypress/run:
|
||||
name: 'Generate Percy Snapshots'
|
||||
executor: cypress/browsers-chrome76
|
||||
browser: chrome
|
||||
pre-steps:
|
||||
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
|
||||
add wait-on' # Use yarn latest
|
||||
yarn: true
|
||||
store_artifacts: false
|
||||
working_directory: platform/viewer
|
||||
build: npx cross-env QUICK_BUILD=true yarn run build
|
||||
# start server --> verify running --> percy + chrome + cypress
|
||||
command: yarn run test:e2e:dist
|
||||
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
|
||||
no-workspace: true # Don't persist workspace
|
||||
post-steps:
|
||||
- store_artifacts:
|
||||
path: platform/viewer/cypress/screenshots
|
||||
- store_artifacts:
|
||||
path: platform/viewer/cypress/videos
|
||||
requires:
|
||||
- AWAIT_APPROVAL
|
||||
|
||||
PR_OPTIONAL_DOCKER_PUBLISH:
|
||||
jobs:
|
||||
# https://circleci.com/docs/2.0/workflows/#holding-a-workflow-for-a-manual-approval
|
||||
- AWAIT_APPROVAL:
|
||||
type: approval
|
||||
# Update hub.docker.org
|
||||
- DOCKER_PR_PUBLISH:
|
||||
context: Docker Hub
|
||||
requires:
|
||||
- AWAIT_APPROVAL
|
||||
|
||||
###
|
||||
# Our workflow for building, deploying, and promoting builds across our
|
||||
# development, staging, and production environments.
|
||||
###
|
||||
DEPLOY:
|
||||
jobs:
|
||||
- BUILD:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
# Cypress job added by `cypress-io` orb
|
||||
- DEPLOY_TO_DEV:
|
||||
requires:
|
||||
- BUILD
|
||||
- PROMOTE_TO_STAGING:
|
||||
type: approval
|
||||
requires:
|
||||
- DEPLOY_TO_DEV
|
||||
- DEPLOY_TO_STAGING:
|
||||
requires:
|
||||
- PROMOTE_TO_STAGING
|
||||
- PROMOTE_TO_PRODUCTION:
|
||||
type: approval
|
||||
requires:
|
||||
- DEPLOY_TO_STAGING
|
||||
- DEPLOY_TO_PRODUCTION:
|
||||
requires:
|
||||
- PROMOTE_TO_PRODUCTION
|
||||
###
|
||||
# Unit and E2E tests have already run for PR_CHECKS
|
||||
# Re-running should not gain us any confidence here
|
||||
###
|
||||
RELEASE:
|
||||
jobs:
|
||||
- NPM_PUBLISH:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- DOCS_PUBLISH:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
# Update base branch snapshots
|
||||
# and record a Cypress dashboard test run
|
||||
- cypress/run:
|
||||
name: 'Generate Percy Snapshots'
|
||||
executor: cypress/browsers-chrome76
|
||||
browser: chrome
|
||||
pre-steps:
|
||||
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
|
||||
add wait-on' # Use yarn latest
|
||||
yarn: true
|
||||
record: true
|
||||
store_artifacts: true
|
||||
start: yarn run dev
|
||||
wait-on: 'http://localhost:3000'
|
||||
store_artifacts: false
|
||||
working_directory: platform/viewer
|
||||
cache-key: 'yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}'
|
||||
build: npx cross-env QUICK_BUILD=true yarn run build
|
||||
# start server --> verify running --> percy + chrome + cypress
|
||||
command: yarn run test:e2e:dist
|
||||
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
|
||||
no-workspace: true # Don't persist workspace
|
||||
post-steps:
|
||||
- store_artifacts:
|
||||
path: platform/viewer/cypress/screenshots
|
||||
- store_artifacts:
|
||||
path: platform/viewer/cypress/videos
|
||||
- store_test_results:
|
||||
path: cypress/results
|
||||
path: platform/viewer/cypress/results
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- DOCKER_MASTER_PUBLISH:
|
||||
requires:
|
||||
- MERGE_UNIT_TESTS
|
||||
# Update NPM
|
||||
- npm_publish:
|
||||
requires:
|
||||
- cypress/run
|
||||
# Update docs.ohif.org
|
||||
- docs_publish:
|
||||
requires:
|
||||
- cypress/run
|
||||
# Update hub.docker.org
|
||||
# - docker_publish:
|
||||
# requires:
|
||||
# - npm_publish
|
||||
# Update viewer.ohif.org
|
||||
- viewer_demo_build:
|
||||
requires:
|
||||
- cypress/run
|
||||
- viewer_demo_publish:
|
||||
requires:
|
||||
- viewer_demo_build
|
||||
- NPM_PUBLISH
|
||||
@@ -8,11 +8,13 @@ coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 0.10%
|
||||
threshold: 0.5%
|
||||
core:
|
||||
flags: core
|
||||
threshold: 0.5%
|
||||
viewer:
|
||||
flags: viewer
|
||||
threshold: 0.5%
|
||||
patch: off
|
||||
flags:
|
||||
core:
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
server {
|
||||
listen 80;
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
# If CLIENT_ID is specified, use the google.js configuration with the modified ID
|
||||
if [ ! -z "$CLIENT_ID" ]
|
||||
then
|
||||
echo "Google Cloud Healthcare $CLIENT_ID has been provided: "
|
||||
echo $CLIENT_ID
|
||||
echo "Updating config..."
|
||||
|
||||
# - Use SED to replace the CLIENT_ID that is currently in google.js
|
||||
sed -i -e "s/YOURCLIENTID.apps.googleusercontent.com/$CLIENT_ID/g" /usr/share/nginx/html/google.js
|
||||
|
||||
# - Copy google.js to overwrite app-config.js
|
||||
cp /usr/share/nginx/html/google.js /usr/share/nginx/html/app-config.js
|
||||
fi
|
||||
|
||||
echo "Starting Nginx to serve the OHIF Viewer..."
|
||||
|
||||
exec "$@"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Reduces size of context and hides
|
||||
# files from Docker (can't COPY or ADD these)
|
||||
|
||||
# Output
|
||||
dist/
|
||||
build/
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
# Root
|
||||
README.md
|
||||
Dockerfile
|
||||
dockerfile
|
||||
|
||||
# Misc. Config
|
||||
.git
|
||||
.DS_Store
|
||||
.gitignore
|
||||
.vscode
|
||||
.circleci
|
||||
|
||||
# Unnecessary things to pull into container
|
||||
.circleci/
|
||||
.github/
|
||||
.netlify/
|
||||
.scripts/
|
||||
.vscode/
|
||||
coverage/
|
||||
docs/
|
||||
@@ -0,0 +1 @@
|
||||
PERCY_TOKEN=<your token here>
|
||||
@@ -16,6 +16,7 @@
|
||||
},
|
||||
"globals": {
|
||||
"cy": true,
|
||||
"before": true,
|
||||
"context": true,
|
||||
"Cypress": true,
|
||||
"assert": true
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: "\U0001F41B Bug report"
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: 'Community: Report :bug:'
|
||||
labels: 'Community: Report :bug:, Awaiting Reproduction, Triage :white_flag:'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: "\U0001F680 Feature request"
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: 'Community: Request :hand:'
|
||||
labels: 'Community: Request :hand:, Triage :white_flag:'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: "\U0001F917 Support Question"
|
||||
about: "I have a question \U0001F4AC"
|
||||
title: ''
|
||||
labels: 'Community: Question :question:'
|
||||
labels: 'Community: Question :question:, Triage :white_flag:'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
### PR Checklist
|
||||
|
||||
- [ ] Brief description of changes
|
||||
- [ ] Links to any relevant issues
|
||||
- [ ] Required status checks are passing
|
||||
- [ ] User cases if changes impact the user's experience
|
||||
- [ ] `@mention` a maintainer to request a review
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[blog]: https://circleci.com/blog/triggering-trusted-ci-jobs-on-untrusted-forks/
|
||||
[script]: https://github.com/jklukas/git-push-fork-to-upstream-branch
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -7,15 +7,15 @@ daysUntilStale: 21
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- 'Story 🙌'
|
||||
- 'Bug: Verified 🐛'
|
||||
- 'Task: CI/Tooling 🤖'
|
||||
- 'Story :raised_hands:'
|
||||
- 'Bug: Verified :bug:'
|
||||
- 'Task: CI/Tooling :robot:'
|
||||
- 'Task: Docs 📖'
|
||||
- 'Task: Docs :book:'
|
||||
- 'Task: Refactor 🛠'
|
||||
- 'Task: Tests 🔬'
|
||||
- 'Task: Tests :microscope:'
|
||||
- 'PR: Awaiting Review 👀'
|
||||
- 'Triage 🏳️'
|
||||
- 'Triage :white_flag:'
|
||||
- 'Announcement 🎉'
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: 'Stale :baguette_bread:'
|
||||
|
||||
@@ -21,6 +21,7 @@ npm-debug.log
|
||||
package-lock.json
|
||||
yarn-error.log
|
||||
.DS_Store
|
||||
.env
|
||||
|
||||
# Common Example Data Directories
|
||||
sampledata/
|
||||
@@ -28,7 +29,7 @@ example/deps/
|
||||
docker/dcm4che/dcm4che-arc
|
||||
|
||||
# Cypress test results
|
||||
cypress/videos/
|
||||
videos/
|
||||
|
||||
# Locize settings
|
||||
.locize
|
||||
.locize
|
||||
@@ -0,0 +1,5 @@
|
||||
# Specific to our non-deploy-preview deploys
|
||||
# Confgure redirects using netlify.toml
|
||||
|
||||
# PWA Redirect
|
||||
/* /index.html 200
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "root",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1.16.0"
|
||||
},
|
||||
"scripts": {
|
||||
"deploy": "netlify deploy --prod --dir ./../platform/viewer/dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
"netlify-cli": "^2.21.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
# Specific to our deploy-preview
|
||||
# Our docs are published using CircleCI + GitBook
|
||||
# Confgure redirects using netlify.toml
|
||||
|
||||
# PWA Demo
|
||||
/pwa/* /pwa/index.html 200
|
||||
@@ -1,10 +1,8 @@
|
||||
{
|
||||
"editor.rulers": [80, 120],
|
||||
|
||||
// ===
|
||||
// Spacing
|
||||
// ===
|
||||
|
||||
"editor.insertSpaces": true,
|
||||
"editor.tabSize": 2,
|
||||
"editor.trimAutoWhitespace": true,
|
||||
@@ -12,19 +10,23 @@
|
||||
"files.eol": "\n",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
|
||||
// ===
|
||||
// Event Triggers
|
||||
// ===
|
||||
|
||||
"editor.formatOnSave": true,
|
||||
"eslint.autoFixOnSave": true,
|
||||
"eslint.run": "onSave",
|
||||
"eslint.validate": [
|
||||
{ "language": "javascript", "autoFix": true },
|
||||
{ "language": "javascriptreact", "autoFix": true }
|
||||
{
|
||||
"language": "javascript",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "javascriptreact",
|
||||
"autoFix": true
|
||||
}
|
||||
],
|
||||
"prettier.disableLanguages": [],
|
||||
"prettier.disableLanguages": ["html"],
|
||||
"prettier.endOfLine": "lf",
|
||||
"workbench.colorCustomizations": {}
|
||||
}
|
||||
@@ -1,23 +1,54 @@
|
||||
// ~~ ENV
|
||||
const dotenv = require('dotenv');
|
||||
//
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const PACKAGE = require('../platform/viewer/package.json');
|
||||
// ~~ RULES
|
||||
const loadShadersRule = require('./rules/loadShaders.js');
|
||||
const loadWebWorkersRule = require('./rules/loadWebWorkers.js');
|
||||
const transpileJavaScriptRule = require('./rules/transpileJavaScript.js');
|
||||
// ~~ PLUGINS
|
||||
const TerserJSPlugin = require('terser-webpack-plugin');
|
||||
// ~~ ENV VARS
|
||||
const NODE_ENV = process.env.NODE_ENV;
|
||||
const QUICK_BUILD = process.env.QUICK_BUILD;
|
||||
const BUILD_NUM = process.env.CIRCLE_BUILD_NUM || '0';
|
||||
|
||||
//
|
||||
dotenv.config();
|
||||
|
||||
module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
if (!process.env.NODE_ENV) {
|
||||
throw new Error('process.env.NODE_ENV not set');
|
||||
}
|
||||
|
||||
const mode =
|
||||
process.env.NODE_ENV === 'production' ? 'production' : 'development';
|
||||
const mode = NODE_ENV === 'production' ? 'production' : 'development';
|
||||
const isProdBuild = NODE_ENV === 'production';
|
||||
const isQuickBuild = QUICK_BUILD === 'true';
|
||||
|
||||
return {
|
||||
mode,
|
||||
const config = {
|
||||
mode: isProdBuild ? 'production' : 'development',
|
||||
devtool: isProdBuild ? 'source-map' : 'cheap-module-eval-source-map',
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
optimization: {
|
||||
minimize: isProdBuild,
|
||||
sideEffects: true,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
modules: false,
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
transpileJavaScriptRule(mode),
|
||||
@@ -41,10 +72,17 @@ module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
/* Application */
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
'process.env.DEBUG': JSON.stringify(process.env.DEBUG),
|
||||
'process.env.APP_CONFIG': JSON.stringify(process.env.APP_CONFIG || ''),
|
||||
'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL || '/'),
|
||||
'process.env.VERSION_NUMBER': JSON.stringify(PACKAGE.version || ''),
|
||||
'process.env.BUILD_NUM': JSON.stringify(BUILD_NUM),
|
||||
/* i18n */
|
||||
'process.env.USE_LOCIZE': JSON.stringify(process.env.USE_LOCIZE || ''),
|
||||
'process.env.LOCIZE_PROJECTID': JSON.stringify(process.env.LOCIZE_PROJECTID || ''),
|
||||
'process.env.LOCIZE_API_KEY': JSON.stringify(process.env.LOCIZE_API_KEY || ''),
|
||||
}),
|
||||
],
|
||||
// Fix: https://github.com/webpack-contrib/css-loader/issues/447#issuecomment-285598881
|
||||
@@ -53,4 +91,23 @@ module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
fs: 'empty',
|
||||
},
|
||||
};
|
||||
|
||||
if (isProdBuild) {
|
||||
config.optimization.minimizer = [
|
||||
new TerserJSPlugin({
|
||||
// Supports:
|
||||
// source-map and inline-source-map
|
||||
sourceMap: isProdBuild && !isQuickBuild,
|
||||
parallel: true,
|
||||
terserOptions: {},
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
if (isQuickBuild) {
|
||||
config.optimization.minimize = false;
|
||||
config.devtool = false;
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
const merge = require('webpack-merge');
|
||||
const webpackBase = require('./webpack.base.js');
|
||||
const cssToJavaScriptRule = require('./rules/cssToJavaScript.js');
|
||||
const stylusToJavaScriptRule = require('./rules/stylusToJavaScript.js');
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at danny.ri.brown+OHIFcoc@gmail.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
@@ -0,0 +1 @@
|
||||
See our contributing guidelines at [`https://docs.ohif.org`](https://docs.ohif.org/development/contributing.html)
|
||||
@@ -0,0 +1,65 @@
|
||||
# This dockerfile is used to publish the `ohif/viewer` image on dockerhub.
|
||||
#
|
||||
# It's a good example of how to build our static application and package it
|
||||
# with a web server capable of hosting it as static content.
|
||||
#
|
||||
# docker build
|
||||
# --------------
|
||||
# If you would like to use this dockerfile to build and tag an image, make sure
|
||||
# you set the context to the project's root directory:
|
||||
# https://docs.docker.com/engine/reference/commandline/build/
|
||||
#
|
||||
#
|
||||
# SUMMARY
|
||||
# --------------
|
||||
# This dockerfile has two stages:
|
||||
#
|
||||
# 1. Building the React application for production
|
||||
# 2. Setting up our Nginx (Alpine Linux) image w/ step one's output
|
||||
#
|
||||
|
||||
|
||||
# Stage 1: Build the application
|
||||
# docker build -t ohif/viewer:latest .
|
||||
FROM node:10.16.3-slim as builder
|
||||
|
||||
RUN mkdir /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy Files
|
||||
COPY .docker /usr/src/app/.docker
|
||||
COPY .webpack /usr/src/app/.webpack
|
||||
COPY extensions /usr/src/app/extensions
|
||||
COPY platform /usr/src/app/platform
|
||||
COPY .browserslistrc /usr/src/app/.browserslistrc
|
||||
COPY aliases.config.js /usr/src/app/aliases.config.js
|
||||
COPY babel.config.js /usr/src/app/babel.config.js
|
||||
COPY lerna.json /usr/src/app/lerna.json
|
||||
COPY package.json /usr/src/app/package.json
|
||||
COPY postcss.config.js /usr/src/app/postcss.config.js
|
||||
COPY yarn.lock /usr/src/app/yarn.lock
|
||||
|
||||
# Run the install before copying the rest of the files
|
||||
RUN yarn config set workspaces-experimental true
|
||||
RUN yarn install
|
||||
|
||||
ENV PATH /usr/src/app/node_modules/.bin:$PATH
|
||||
ENV QUICK_BUILD true
|
||||
# ENV GENERATE_SOURCEMAP=false
|
||||
# ENV REACT_APP_CONFIG=config/default.js
|
||||
|
||||
RUN yarn run build
|
||||
|
||||
# Stage 2: Bundle the built application into a Docker container
|
||||
# which runs Nginx using Alpine Linux
|
||||
FROM nginx:1.15.5-alpine
|
||||
RUN apk add --no-cache bash
|
||||
RUN rm -rf /etc/nginx/conf.d
|
||||
COPY .docker/Viewer-v2.x /etc/nginx/conf.d
|
||||
COPY .docker/Viewer-v2.x/entrypoint.sh /usr/src/
|
||||
RUN chmod 777 /usr/src/entrypoint.sh
|
||||
COPY --from=builder /usr/src/app/platform/viewer/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
ENTRYPOINT ["/usr/src/entrypoint.sh"]
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -22,74 +22,119 @@
|
||||
[![NPM downloads][npm-downloads-image]][npm-url]
|
||||
[![Pulls][docker-pulls-img]][docker-image-url]
|
||||
[![MIT License][license-image]][license-url]
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2FOHIF%2FViewers?ref=badge_shield)
|
||||
|
||||
[![Netlify Status][netlify-image]][netlify-url]
|
||||
[![CircleCI][circleci-image]][circleci-url]
|
||||
[![codecov][codecov-image]][codecov-url]
|
||||
[![This project is using Percy.io for visual regression testing.][percy-image]](percy-url)
|
||||
[](#contributors)
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## What?
|
||||
## About
|
||||
|
||||
The OHIF Medical Imaging Viewer is for viewing medical images. It can retrieve and load images from most sources and formats; render sets in 2D, 3D, and reconstructed representations; allows for the manipulation, annotation, and serialization of observations; supports internationalization, OpenID Connect, offline use, hotkeys, and many more features.
|
||||
The OHIF Medical Imaging Viewer is for viewing medical images. It can retrieve
|
||||
and load images from most sources and formats; render sets in 2D, 3D, and
|
||||
reconstructed representations; allows for the manipulation, annotation, and
|
||||
serialization of observations; supports internationalization, OpenID Connect,
|
||||
offline use, hotkeys, and many more features.
|
||||
|
||||
Almost everything offers some degree of customization and configuration. If it doesn't support something you need, we accept pull requests and have an ever improving Extension System.
|
||||
Almost everything offers some degree of customization and configuration. If it
|
||||
doesn't support something you need, we accept pull requests and have an ever
|
||||
improving Extension System.
|
||||
|
||||
## Why Choose Us
|
||||
|
||||
### Community & Experience
|
||||
|
||||
The OHIF Viewer is a collaborative effort that has served as the basis for many active, production, and FDA Cleared medical imaging viewers. It benefits from our extensive community's collective experience, and from the sponsored contributions of individuals, research groups, and commercial organizations.
|
||||
The OHIF Viewer is a collaborative effort that has served as the basis for many
|
||||
active, production, and FDA Cleared medical imaging viewers. It benefits from
|
||||
our extensive community's collective experience, and from the sponsored
|
||||
contributions of individuals, research groups, and commercial organizations.
|
||||
|
||||
### Built to Adapt
|
||||
|
||||
...
|
||||
After more than 5-years of integrating with many companies and organizations,
|
||||
The OHIF Viewer has been rebuilt from the ground up to better address the
|
||||
varying workflow and configuration needs of its many users. All of the Viewer's
|
||||
core features are built using it's own extension system. The same extensibility
|
||||
that allows us to offer:
|
||||
|
||||
- 2D and 3D medical image viewing
|
||||
- Multiplanar Reconstruction (MPR)
|
||||
- Maximum Intensity Project (MIP)
|
||||
- Whole slide microscopy viewing
|
||||
- PDF and Dicom Structured Report rendering
|
||||
- User Access Control (UAC)
|
||||
- Context specific toolbar and side panel content
|
||||
- and many others
|
||||
|
||||
Can be leveraged by you to customize the viewer for your workflow, and to add
|
||||
any new functionality you may need (and wish to maintain privately without
|
||||
forking).
|
||||
|
||||
### Support
|
||||
|
||||
...
|
||||
We offer support through
|
||||
[GitHub Issues](https://github.com/OHIF/Viewers/issues/new/choose). You can:
|
||||
|
||||
- [Report a Bug 🐛](https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Community%3A+Report+%3Abug%3A&template=---bug-report.md)
|
||||
- [Request a Feature 🚀](https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Community%3A+Request+%3Ahand%3A&template=---feature-request.md)
|
||||
- [Ask a Question 🤗](https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Community%3A+Question+%3Aquestion%3A&template=---support-question.md)
|
||||
|
||||
For commercial support, academic collaberations, and answers to common
|
||||
questions; please read our
|
||||
[documented FAQ](https://docs.ohif.org/faq/index.html#does-ohif-offer-commercial-support).
|
||||
|
||||
## Quick Start Deployment
|
||||
|
||||
> This is only one of many ways to configure and deploy the OHIF Viewer. To learn more about your options, and how to choose the best one for your requirements, check out [our deployment recipes and documentation](https://docs.ohif.org/deployment/).
|
||||
> This is only one of many ways to configure and deploy the OHIF Viewer. To
|
||||
> learn more about your options, and how to choose the best one for your
|
||||
> requirements, check out
|
||||
> [our deployment recipes and documentation](https://docs.ohif.org/deployment/).
|
||||
|
||||
The fastest and easiest way to get started is to include the OHIF Viewer with a script tag. In practice, this is as simple as:
|
||||
The fastest and easiest way to get started is to include the OHIF Viewer with a
|
||||
script tag. In practice, this is as simple as:
|
||||
|
||||
- Including the following dependencies with script tags:
|
||||
- [React](https://unpkg.com/react@16/umd/react.production.min.js)
|
||||
- [React Dom](https://unpkg.com/react-dom@16/umd/react-dom.production.min.js)
|
||||
- The [OHIF Viewer](https://unpkg.com/@ohif/viewer)
|
||||
- [React](https://unpkg.com/react@16/umd/react.production.min.js)
|
||||
- [React Dom](https://unpkg.com/react-dom@16/umd/react-dom.production.min.js)
|
||||
- The [OHIF Viewer](https://unpkg.com/@ohif/viewer)
|
||||
- Have an element with an ID of `root` on the page
|
||||
- Configure the OHIF Viewer at `window.config`:
|
||||
|
||||
```js
|
||||
window.config = {
|
||||
routerBasename: "/",
|
||||
routerBasename: '/',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: "DCM4CHEE",
|
||||
qidoRoot: "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs",
|
||||
wadoRoot: "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs",
|
||||
name: 'DCM4CHEE',
|
||||
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
qidoSupportsIncludeField: true,
|
||||
imageRendering: "wadors",
|
||||
thumbnailRendering: "wadors"
|
||||
}
|
||||
]
|
||||
}
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
- Install the viewer: `window.OHIFStandaloneViewer.installViewer(window.config);`
|
||||
- Install the viewer:
|
||||
`window.OHIFStandaloneViewer.installViewer(window.config);`
|
||||
|
||||
This exact setup is demonstrated in this [CodeSandbox](https://codesandbox.io/s/ohif-viewer-script-tag-usage-c4u4t) and in our [Embedding The Viewer](https://docs.ohif.org/deployment/recipes/embedded-viewer.html) deployment recipe.
|
||||
This exact setup is demonstrated in this
|
||||
[CodeSandbox](https://codesandbox.io/s/viewer-script-tag-tprch) and in our
|
||||
[Embedding The Viewer](https://docs.ohif.org/deployment/recipes/embedded-viewer.html)
|
||||
deployment recipe.
|
||||
|
||||
## Developing
|
||||
|
||||
### Requirements
|
||||
|
||||
- [Yarn 1.17.3+](https://yarnpkg.com/en/docs/install)
|
||||
- [Node 8+](https://nodejs.org/en/)
|
||||
- [Node 10+](https://nodejs.org/en/)
|
||||
- Yarn Workspaces should be enabled on your machine:
|
||||
- `yarn config set workspaces-experimental true`
|
||||
|
||||
@@ -117,21 +162,23 @@ yarn install
|
||||
|
||||
## Commands
|
||||
|
||||
These commands are available from the root directory. Each project directory also supports a number of commands that can be found in their respective `README.md` and `project.json` files.
|
||||
These commands are available from the root directory. Each project directory
|
||||
also supports a number of commands that can be found in their respective
|
||||
`README.md` and `project.json` files.
|
||||
|
||||
| Yarn Commands | Description |
|
||||
| -------------------- | ------------------------------------------------------------- |
|
||||
| **Develop** | |
|
||||
| `dev` or `start` | Default development experience for Viewer |
|
||||
| Yarn Commands | Description |
|
||||
| ---------------------------- | ------------------------------------------------------------- |
|
||||
| **Develop** | |
|
||||
| `dev` or `start` | Default development experience for Viewer |
|
||||
| `dev:project <package-name>` | Replace with `core`, `ui`, `i18n`, `cornerstone`, `vtk`, etc. |
|
||||
| `test:unit` | Jest multi-project test runner; overall coverage |
|
||||
| **Deploy** | |
|
||||
| `build`* | Builds production output for our PWA Viewer |
|
||||
| `build:package`* | Builds production `commonjs` output for our Viewer |
|
||||
| `build:package-all`* | Builds commonjs bundles for all projects |
|
||||
| `test:unit` | Jest multi-project test runner; overall coverage |
|
||||
| **Deploy** | |
|
||||
| `build`\* | Builds production output for our PWA Viewer |
|
||||
| `build:package`\* | Builds production `commonjs` output for our Viewer |
|
||||
| `build:package-all`\* | Builds commonjs bundles for all projects |
|
||||
|
||||
|
||||
\* - For more information on our different builds, check out our [Deploy Docs][deployment-docs]
|
||||
\* - For more information on our different builds, check out our [Deploy
|
||||
Docs][deployment-docs]
|
||||
|
||||
## Projects
|
||||
|
||||
@@ -169,24 +216,26 @@ more about it in our [Architecture Documentation][ohif-architecture].
|
||||
|
||||
These projects comprise the
|
||||
|
||||
| Name | Description | Links |
|
||||
| ------------------------------- | ----------- | ----- |
|
||||
| [@ohif/core][platform-core] | | NPM |
|
||||
| [@ohif/i18n][platform-i18n] | | NPM |
|
||||
| [@ohif/viewer][platform-viewer] | | NPM |
|
||||
| [@ohif/ui][platform-ui] | | NPM |
|
||||
| Name | Description | Links |
|
||||
| ------------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------- |
|
||||
| [@ohif/core][platform-core] | Business logic and classes that model the data, services, and extensions that are framework agnostic | [NPM][core-npm] |
|
||||
| [@ohif/i18n][platform-i18n] | Language files and small API for wrapping component/ui text for translations | [NPM][i18n-npm] |
|
||||
| [@ohif/viewer][platform-viewer] | The OHIF Viewer. Where we consume and configure all platform library's and extensions | [NPM][viewer-npm] |
|
||||
| [@ohif/ui][platform-ui] | Reusable React components we consume and compose to build our Viewer's UI | [NPM][ui-npm] |
|
||||
|
||||
### Extensions
|
||||
|
||||
This is a list of Extensions maintained by the OHIF Core team. It's possible to customize and configure these extensions, and you can even create your own. You can [read more about extensions here][ohif-extensions].
|
||||
This is a list of Extensions maintained by the OHIF Core team. It's possible to
|
||||
customize and configure these extensions, and you can even create your own. You
|
||||
can [read more about extensions here][ohif-extensions].
|
||||
|
||||
| Name | Description | Links |
|
||||
| -------------------------------------------------------------- | ----------- | ----- |
|
||||
| [@ohif/extension-cornestone][extension-cornerstone] | | NPM |
|
||||
| [@ohif/extension-dicom-html][extension-dicom-html] | | NPM |
|
||||
| [@ohif/extension-dicom-microscopy][extension-dicom-microscopy] | | NPM |
|
||||
| [@ohif/extension-dicom-pdf][extension-dicom-pdf] | | NPM |
|
||||
| [@ohif/extension-vtk][extension-vtk] | | NPM |
|
||||
| Name | Description | Links |
|
||||
| -------------------------------------------------------------- | ------------------------------------------------------- | ---------------------- |
|
||||
| [@ohif/extension-cornestone][extension-cornerstone] | 2D image viewing, annotation, and segementation tools | [NPM][cornerstone-npm] |
|
||||
| [@ohif/extension-dicom-html][extension-dicom-html] | Support for viewing DICOM SR as rendered HTML | [NPM][html-npm] |
|
||||
| [@ohif/extension-dicom-microscopy][extension-dicom-microscopy] | Whole slide microscopy viewing | [NPM][microscopy-npm] |
|
||||
| [@ohif/extension-dicom-pdf][extension-dicom-pdf] | View DICOM wrapped PDFs in a viewport | [NPM][pdf-npm] |
|
||||
| [@ohif/extension-vtk][extension-vtk] | Volume rendering, reconstruction, and 3D visualizations | [NPM][vtk-npm] |
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
@@ -222,14 +271,13 @@ MIT © [OHIF](https://github.com/OHIF)
|
||||
<!-- Badges -->
|
||||
[lerna-image]: https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg
|
||||
[lerna-url]: https://lerna.js.org/
|
||||
[netlify-image]: https://api.netlify.com/api/v1/badges/a5d369ab-18a6-41c3-bcde-83805205ac7f/deploy-status
|
||||
[netlify-url]: https://app.netlify.com/sites/ohif/deploys
|
||||
[netlify-image]: https://api.netlify.com/api/v1/badges/32708787-c9b0-4634-b50f-7ca41952da77/deploy-status
|
||||
[netlify-url]: https://app.netlify.com/sites/ohif-dev/deploys
|
||||
[all-contributors-image]: https://img.shields.io/badge/all_contributors-0-orange.svg?style=flat-square
|
||||
[contributing-url]: https://github.com/OHIF/Viewers/blob/react/CONTRIBUTING.md
|
||||
[circleci-image]: https://circleci.com/gh/OHIF/Viewers.svg?style=svg
|
||||
[circleci-url]: https://circleci.com/gh/OHIF/Viewers
|
||||
[codecov-image]: https://codecov.io/gh/OHIF/Viewers/branch/react/graph/badge.svg
|
||||
[codecov-url]: https://codecov.io/gh/OHIF/Viewers/branch/react
|
||||
[codecov-image]: https://codecov.io/gh/OHIF/Viewers/branch/master/graph/badge.svg
|
||||
[codecov-url]: https://codecov.io/gh/OHIF/Viewers/branch/master
|
||||
[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
|
||||
[prettier-url]: https://github.com/prettier/prettier
|
||||
[semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
|
||||
@@ -242,27 +290,40 @@ MIT © [OHIF](https://github.com/OHIF)
|
||||
[docker-image-url]: https://hub.docker.com/r/ohif/viewer
|
||||
[license-image]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square
|
||||
[license-url]: LICENSE
|
||||
[percy-image]: https://percy.io/static/images/percy-badge.svg
|
||||
[percy-url]: https://percy.io/Open-Health-Imaging-Foundation/OHIF-Viewer
|
||||
<!-- Links -->
|
||||
[monorepo]: https://en.wikipedia.org/wiki/Monorepo
|
||||
[how-to-fork]: https://help.github.com/en/articles/fork-a-repo
|
||||
[how-to-clone]: https://help.github.com/en/articles/fork-a-repo#step-2-create-a-local-clone-of-your-fork
|
||||
[ohif-architecture]: https://docs.ohif.org/advanced/architecture.html
|
||||
[ohif-extensions]: https://docs.ohif.org/advanced/architecture.html
|
||||
[ohif-architecture]: https://docs.ohif.org/architecture/index.html
|
||||
[ohif-extensions]: https://docs.ohif.org/architecture/index.html
|
||||
[deployment-docs]: https://docs.ohif.org/deployment/
|
||||
[react-url]: https://reactjs.org/
|
||||
[pwa-url]: https://developers.google.com/web/progressive-web-apps/
|
||||
[ohif-viewer-url]: https://www.npmjs.com/package/@ohif/viewer
|
||||
[configuration-url]: https://docs.ohif.org/essentials/configuration.html
|
||||
[extensions-url]: https://docs.ohif.org/advanced/extensions.html
|
||||
[configuration-url]: https://docs.ohif.org/configuring/
|
||||
[extensions-url]: https://docs.ohif.org/extensions/
|
||||
<!-- Platform -->
|
||||
[platform-core]: platform/core/README.md
|
||||
[core-npm]: https://www.npmjs.com/package/@ohif/core
|
||||
[platform-i18n]: platform/i18n/README.md
|
||||
[i18n-npm]: https://www.npmjs.com/package/@ohif/i18n
|
||||
[platform-ui]: platform/ui/README.md
|
||||
[ui-npm]: https://www.npmjs.com/package/@ohif/ui
|
||||
[platform-viewer]: platform/viewer/README.md
|
||||
[viewer-npm]: https://www.npmjs.com/package/@ohif/viewer
|
||||
<!-- Extensions -->
|
||||
[extension-cornerstone]: extensions/cornerstone/README.md
|
||||
[cornerstone-npm]: https://www.npmjs.com/package/@ohif/extension-cornerstone
|
||||
[extension-dicom-html]: extensions/dicom-html/README.md
|
||||
[html-npm]: https://www.npmjs.com/package/@ohif/extension-dicom-html
|
||||
[extension-dicom-microscopy]: extensions/dicom-microscopy/README.md
|
||||
[microscopy-npm]: https://www.npmjs.com/package/@ohif/extension-dicom-microscopy
|
||||
[extension-dicom-pdf]: extensions/dicom-pdf/README.md
|
||||
[pdf-npm]: https://www.npmjs.com/package/@ohif/extension-dicom-pdf
|
||||
[extension-vtk]: extensions/vtk/README.md
|
||||
[vtk-npm]: https://www.npmjs.com/package/@ohif/extension-vtk
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2FOHIF%2FViewers?ref=badge_large)
|
||||
@@ -0,0 +1,3 @@
|
||||
# Netlify redirects
|
||||
# SPA rules for our docs
|
||||
/* /index.html 200
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class='row'>
|
||||
<div class='column' style='text-align: right; padding: 0 20px'>
|
||||
<strong>Looking for a Deploy Preview?</strong>
|
||||
<a onclick="function redirect() { window.location.href='/demo/'; } redirect();">Deploy Preview for Viewer</a>
|
||||
<strong>Looking for a Live Demo?</strong>
|
||||
<a href="http://viewer.ohif.org/">Preview The OHIF Viewer</a>
|
||||
</div>
|
||||
<div class='column' style='text-align: left; padding: 0 20px'>
|
||||
<a href="https://www.netlify.com">
|
||||
@@ -33,14 +33,14 @@ yourself unable to extend the viewer for your purposes, please reach out via our
|
||||
[GitHub issues][gh-issues]. We are actively seeking feedback on ways to improve
|
||||
our integration and extension points.
|
||||
|
||||
## Where to Next?
|
||||
## Where to next?
|
||||
|
||||
Check out these helpful links:
|
||||
|
||||
- Ready to dive into some code? Check out our
|
||||
[Getting Started Guide](./essentials/getting-started.md).
|
||||
[Getting Started Guide](./development/getting-started.md).
|
||||
- We're an active, vibrant community.
|
||||
[Learn how you can be more involved.](./contributing.md)
|
||||
[Learn how you can be more involved.](./development/contributing.md)
|
||||
- Feeling lost? Read our [help page](./help.md).
|
||||
|
||||
<!--
|
||||
|
||||
@@ -1,31 +1,39 @@
|
||||
# OHIF Viewers
|
||||
|
||||
- Essentials
|
||||
- [Getting Started](essentials/getting-started.md)
|
||||
- [Installation](essentials/installation.md)
|
||||
- [Data Source](essentials/data-source.md)
|
||||
- [Configuration](essentials/configuration.md)
|
||||
- [Themeing](essentials/themeing.md)
|
||||
- [Translating](essentials/translating.md)
|
||||
- [Troubleshooting](essentials/troubleshooting.md)
|
||||
- [Scope of Project](essentials/scope-of-project.md)
|
||||
- [Our Process](our-process.md)
|
||||
- Development
|
||||
- [Getting Started](development/getting-started.md)
|
||||
- [Contributing](development/contributing.md)
|
||||
- [Continuous Integration](development/continous-integration.md)
|
||||
- [Configuring](configuring/index.md)
|
||||
- [Data Source](configuring/data-source.md)
|
||||
|
||||
---
|
||||
|
||||
- [Advanced](advanced/index.md)
|
||||
- [Architecture](advanced/architecture.md)
|
||||
- [Overview](advanced/architecture.md#overview)
|
||||
- [Business Logic](advanced/architecture.md#business-logic)
|
||||
- [Component Library](advanced/architecture.md#react-component-library)
|
||||
- [Extensions](advanced/architecture.md#misc-extensions)
|
||||
- [Diagram](advanced/architecture.md#diagram)
|
||||
- [Common Questions](advanced/architecture.md#common-questions)
|
||||
- [Extensions](advanced/extensions.md)
|
||||
- [Overview](advanced/extensions.md#overview)
|
||||
- [Modules](advanced/extensions.md#modules)
|
||||
- [Registering](advanced/extensions.md#registering-extensions)
|
||||
- [OHIF Maintained](advanced/extensions.md#ohif-maintained-extensions)
|
||||
- [Custom Tools](advanced/custom-tools.md)
|
||||
- [Architecture](architecture/index.md)
|
||||
- [Viewer](viewer/index.md)
|
||||
- [Configuration](viewer/configuration.md)
|
||||
- [Themeing](viewer/themeing.md)
|
||||
- [Internationalization](viewer/internationalization.md)
|
||||
- [Extensions](extensions/index.md)
|
||||
- [Registering](extensions/index.md#registering-an-extension)
|
||||
- [Lifecycle Hooks](extensions/index.md#lifecycle-hooks)
|
||||
- [preRegistration](extensions/lifecycle/pre-registration.md)
|
||||
- [Modules](extensions/index.md#modules)
|
||||
- [Commands](extensions/modules/commands.md)
|
||||
- [Panel](extensions/modules/panel.md)
|
||||
- [SOP Class Handler](extensions/modules/sop-class-handler.md)
|
||||
- [Toolbar](extensions/modules/toolbar.md)
|
||||
- [Viewport](extensions/modules/viewport.md)
|
||||
- [Contexts](extensions/index.md#contexts)
|
||||
- [ExtensionManager](extensions/index.md#extensionmanager)
|
||||
- [OHIF Maintained](extensions/index.md#maintained-extensions)
|
||||
- [Services](services/index.md)
|
||||
- [Default](services/default/index.md)
|
||||
- [UI](services/ui/index.md)
|
||||
- [Dialog Service](services/ui/ui-dialog-service.md)
|
||||
- [Modal Service](services/ui/ui-modal-service.md)
|
||||
- [Notification Service](services/ui/ui-notification-service.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -45,7 +53,8 @@
|
||||
|
||||
---
|
||||
|
||||
- [FAQ](frequently-asked-questions.md)
|
||||
- [Contributing](contributing.md)
|
||||
- [Browser Support](browser-support.md)
|
||||
- [FAQ](faq/index.md)
|
||||
- [Scope of Project](faq/scope-of-project.md)
|
||||
- [Browser Support](faq/browser-support.md)
|
||||
- [PWA vs Packaged](faq/pwa-vs-packaged.md)
|
||||
- [Help](help.md)
|
||||
@@ -1,109 +0,0 @@
|
||||
# Architecture
|
||||
|
||||
Looking to extend your instance of the OHIF Viewer? Want learn how to reuse _a
|
||||
portion_ of the Viewer in your own application? Or maybe you want to get
|
||||
involved and draft or suggest a new feature? Regardless, you're in the right
|
||||
place!
|
||||
|
||||
The OHIF Viewer aims to be decoupled, configurable, and extensible; while this
|
||||
allows our code to be used in more ways, it also increases complexity. Below, we
|
||||
aim to demistify that complexity by providing insight into how our Viewer is
|
||||
architected, and the role each of it's dependent libraries plays.
|
||||
|
||||
## Overview
|
||||
|
||||
The [`OHIF/Viewers`][viewers-project] project contains the source code for the
|
||||
OHIF Medical Imaging Viewer. It is effectively a React [progressive web
|
||||
app][pwa] (PWA) that combines the business logic housed in
|
||||
[`OHIF/ohif-core`][core] and the components in our React Component library
|
||||
[`OHIF/react-viewerbase`][component-library]. It provides customization for
|
||||
common use cases through [configuration][configuration] and for adding
|
||||
functionality via [extensions][extensions].
|
||||
|
||||
### Business Logic
|
||||
|
||||
Our goal is to maintain the majority of our business logic in
|
||||
[`OHIF/ohif-core`](https://github.com/OHIF/ohif-core). `ohif-core` offers
|
||||
pre-packaged solutions for features common to Web-based medical imaging viewers.
|
||||
For example:
|
||||
|
||||
- Hotkeys
|
||||
- DICOM Web
|
||||
- Hanging Protocols
|
||||
- Managing a study's measurements
|
||||
- Managing a study's DICOM metadata
|
||||
- A flexible pattern for extensions
|
||||
- [And many others](https://github.com/OHIF/ohif-core/blob/master/src/index.js#L49-L69)
|
||||
|
||||
It does this while remaining decoupled from any particular view library or
|
||||
rendering logic. While we use it to power our React Viewer, it can be used with
|
||||
Vue, React, Vanilla JS, or any number of other frameworks.
|
||||
|
||||
### React Component Library
|
||||
|
||||
[`OHIF/react-viewerbase`](https://github.com/OHIF/react-viewerbase) is a React
|
||||
Component library that contains the reusable components that power the OHIF
|
||||
Viewer. It allows us to build, compose, and test components in isolation; easing
|
||||
the development process by reducing the need to stand-up a local PACS with test
|
||||
case data.
|
||||
|
||||
[Check out our component library!](https://react.ohif.org/)
|
||||
|
||||
### Misc. Extensions
|
||||
|
||||
Want to add custom logic or UI Components to the OHIF Viewer, but don't want to
|
||||
maintain a fork? We expose common integration points via
|
||||
[extensions](./extensions.md) to make that possible. For a list of extensions
|
||||
maintained by OHIF,
|
||||
[check out this helpful table](./extensions.html#ohif-maintained-extensions).
|
||||
|
||||
If you find yourself thinking "I wish the Viewer could do X", and you can't
|
||||
accomplish it with an extension today, create a GitHub issue! We're actively
|
||||
looking for ways to improve our extensibility ^\_^
|
||||
|
||||
[Click here to read more about extensions!](./extensions.md)
|
||||
|
||||
### Diagram
|
||||
|
||||
This diagram is a conceptual illustration of how the Viewer is architected.
|
||||
|
||||
1. (optional) `extensions` can be registered with `ohif-core`'s extension
|
||||
manager
|
||||
2. `ohif-core` provides bussiness logic and a way for `viewer` to access
|
||||
registered extensions
|
||||
3. The `viewer` composes and provides data to components from our component
|
||||
library (`react-viewerbase`)
|
||||
4. The `viewer` can be built and served as a stand-alone PWA, or as an
|
||||
embeddable package
|
||||
([`ohif-viewer`](https://www.npmjs.com/package/ohif-viewer))
|
||||
|
||||

|
||||
|
||||
<center><i>architecture diagram</i></center>
|
||||
|
||||
## Common Questions
|
||||
|
||||
> When should I use the packaged source `ohif-viewer` versus building a PWA from
|
||||
> the source?
|
||||
|
||||
...
|
||||
|
||||
> Can I create my own Viewer using Vue.js or Angular.js?
|
||||
|
||||
You can, but you will not be able to leverage as much of the existing code and
|
||||
components. `ohif-core` could still be used for business logic, and to provide a
|
||||
model for extensions. `react-viewerbase` would then become a guide for the
|
||||
components you would need to recreate.
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[viewers-project]: https://github.com/OHIF/Viewers
|
||||
[pwa]: https://developers.google.com/web/progressive-web-apps/
|
||||
[core]: https://github.com/OHIF/ohif-core
|
||||
[component-library]: https://github.com/OHIF/react-viewerbase
|
||||
[configuration]: ../essentials/configuration.md
|
||||
[extensions]: ./extensions.m
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -1,8 +0,0 @@
|
||||
# Tool Management
|
||||
|
||||
This is not yet exposed in an easy/convenient way. Most tools are currently
|
||||
added by creating new Viewport, Toolbar, and SOPInstanceHandler extension
|
||||
modules. You can read more about that approach in [extensions](./extensions.md).
|
||||
|
||||
In the near future, we intend to improve the extensibility of tools for existing
|
||||
Viewports (like our Cornerstone.js and VTK.js viewports).
|
||||
@@ -1,230 +0,0 @@
|
||||
# Extensions
|
||||
|
||||
Extensions add new functionality to the viewer by registering one or more
|
||||
modules. They go one step further than configuration in that they allow us to
|
||||
inject custom React components, so long as they adhere to the module's
|
||||
interface. This can be something as simple as adding a new button to the
|
||||
toolbar, or as complex as a new viewport capable of rendering volumes in 3D.
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Modules](#modules)
|
||||
- [Commands](#commands)
|
||||
- [Hotkeys](#hotkeys)
|
||||
- [Toolbar](#toolbar)
|
||||
- [Panel](#panel)
|
||||
- [Viewport](#viewport)
|
||||
- [SOP Class Handler](#sopclasshandler)
|
||||
|
||||
## Overview
|
||||
|
||||
At a glance, an extension is a javascript object that has an `id` property, and
|
||||
one or more "module" methods. You can find an abbreviated extension below, or
|
||||
[view the source][example-ext-src] of our example extension.
|
||||
|
||||
```js
|
||||
export default {
|
||||
/**
|
||||
* Only required property. Should be a unique value across all extensions.
|
||||
*/
|
||||
id: 'example-extension',
|
||||
|
||||
/**
|
||||
* Registers one or more named commands scoped to a context. Commands are
|
||||
* the primary means for...
|
||||
*/
|
||||
getCommandsModule() {
|
||||
return {
|
||||
defaultContext: 'VIEWER'
|
||||
actions: { ... },
|
||||
definitions: { ... }
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows you to provide toolbar definitions that will be merged with any
|
||||
* existing application toolbar configuration. Used to determine which
|
||||
* buttons should be visible when, their order, what happens when they're
|
||||
* clicked, etc.
|
||||
*/
|
||||
getToolbarModule() {
|
||||
return {
|
||||
definitions: [ ... ],
|
||||
defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not yet implemented
|
||||
*/
|
||||
getPanelModule: () => null,
|
||||
|
||||
/**
|
||||
* Registers a ReactComponent that should be used to render data in a
|
||||
* Viewport. The first registered viewport is our "default viewport". If
|
||||
* more than one viewport is registered, we use `SopClassHandlers` to
|
||||
* determine which viewport should be used.
|
||||
*/
|
||||
getViewportModule: () => reactViewportComponent,
|
||||
|
||||
/** Provides a whitelist of SOPClassUIDs the viewport is capable of rendering.
|
||||
* Can modify default behavior for methods like `getDisplaySetFromSeries` */
|
||||
getSopClassHandler: () => {
|
||||
id: 'some-other-unique-id',
|
||||
sopClassUids: [ ... ],
|
||||
getDisplaySetFromSeries: (series, study, dicomWebClient, authorizationHeaders) => { ... }
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Modules
|
||||
|
||||
There are a few different module types. Each module type allows us to extend the
|
||||
viewer in a different way, and provides a consistent API for us to do so. You
|
||||
can find a full list of the different types of modules
|
||||
[`in ohif-core`][module-types]. Information on each type of module, it's API,
|
||||
and how we determine when/where it should be used is included below.
|
||||
|
||||
> NOTE: Modifying the extensions/modules registered to the OHIF Viewer currently
|
||||
> requires us to import and pass extensions to the ExtensionManager in
|
||||
> `src/App.js`, then rebuild the application. Long-term, we intend to make it
|
||||
> possible to accomplish this without a build step.
|
||||
|
||||
#### Commands
|
||||
|
||||
The Commands Module allows us to register one or more commands scoped to
|
||||
specific contexts. Commands can be run by [hotkeys][#], [toolbar buttons][#],
|
||||
and any registered custom react component (like a [viewport][#] or [panel][#]).
|
||||
Here is a simple example commands module:
|
||||
|
||||
```js
|
||||
{
|
||||
getCommandsModule() {
|
||||
return {
|
||||
actions: {
|
||||
speak: ({ viewports, words }) => {
|
||||
console.log(viewports, words);
|
||||
},
|
||||
},
|
||||
definitions: {
|
||||
rotateViewportCW: {
|
||||
commandFn: actions.rotateViewport,
|
||||
storeContexts: ['viewports'],
|
||||
options: { rotation: 90 }
|
||||
},
|
||||
rotateViewportCCW: {
|
||||
commandFn: actions.rotateViewport,
|
||||
storeContexts: ['viewports'],
|
||||
options: { rotation: -90 },
|
||||
context: 'ACTIVE_VIEWER::CORNERSTONE'
|
||||
},
|
||||
},
|
||||
defaultContext: 'VIEWER'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Viewport
|
||||
|
||||
An extension can register a Viewport Module by providing a `getViewportModule()`
|
||||
method that returns a React Component. The React component will receive the
|
||||
following props:
|
||||
|
||||
```js
|
||||
children: PropTypes.arrayOf(PropTypes.element)
|
||||
studies: PropTypes.object,
|
||||
displaySet: PropTypes.object,
|
||||
viewportData: PropTypes.object, // { studies, displaySet }
|
||||
viewportIndex: PropTypes.number,
|
||||
children: PropTypes.node,
|
||||
customProps: PropTypes.object
|
||||
```
|
||||
|
||||
Viewport components are managed by the `LayoutManager`. Which Viewport component
|
||||
is used depends on:
|
||||
|
||||
- The Layout Configuration
|
||||
- Registered SopClassHandlers
|
||||
- The SopClassUID for visible/selected datasets
|
||||
|
||||

|
||||
|
||||
<center><i>An example of three Viewports</i></center>
|
||||
|
||||
For a complete example implementation,
|
||||
[check out the OHIFCornerstoneViewport](https://github.com/OHIF/Viewers/blob/master/extensions/cornerstone/src/OHIFCornerstoneViewport.js).
|
||||
|
||||
#### Toolbar
|
||||
|
||||
An extension can register a Toolbar Module by providing a `getToolbarModule()`
|
||||
method that returns a React Component. The component does not receive any props.
|
||||
If you want to modify or react to state, you will need to connect to the redux
|
||||
store.
|
||||
|
||||

|
||||
|
||||
<center><i>A toolbar extension example</i></center>
|
||||
|
||||
Toolbar components are rendered in the `ToolbarRow` component.
|
||||
|
||||
For a complete example implementation,
|
||||
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/master/extensions/cornerstone/src/toolbarModule.js).
|
||||
|
||||
#### SopClassHandler
|
||||
|
||||
...
|
||||
|
||||
#### Panel
|
||||
|
||||
> The panel module is not yet in use.
|
||||
|
||||
#### Hotkeys
|
||||
|
||||
...
|
||||
|
||||
### Registering Extensions
|
||||
|
||||
Extensions are registered for the application at startup. The
|
||||
`ExtensionManager`, exposed by `ohif-core`, registers a list of extensions with
|
||||
our application's store. Each module provided by the extension becomes available
|
||||
via `state.plugins.availablePlugins`, and consists of three parts: id, type
|
||||
([PLUGIN_TYPE](https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6)),
|
||||
and the return value of the module method.
|
||||
|
||||
In a future version, we will likely expose a way to provide the extensions you
|
||||
would like included at startup.
|
||||
|
||||
_app.js_
|
||||
|
||||
```js
|
||||
import { createStore, combineReducers } from 'redux';
|
||||
import OHIF from '@ohif/core';
|
||||
import OHIFCornerstoneExtension from 'ohif-cornerstone-extension';
|
||||
|
||||
const combined = combineReducers(OHIF.redux.reducers);
|
||||
const store = createStore(combined);
|
||||
const extensions = [new OHIFCornerstoneExtension()];
|
||||
|
||||
// Dispatches the `addPlugin` action to the store
|
||||
// Adding extension modules to `state.plugins.availablePlugins`
|
||||
ExtensionManager.registerExtensions(store, extensions);
|
||||
```
|
||||
|
||||
## OHIF Maintained Extensions
|
||||
|
||||
A small number of powerful extensions for popular use cases are maintained by
|
||||
OHIF. They're co-located in the
|
||||
[`OHIF/Viewers`](https://github.com/OHIF/Viewers) repository, in the top level
|
||||
[`extensions/`](https://github.com/OHIF/Viewers/tree/master/extensions)
|
||||
directory.
|
||||
|
||||
{% include "./_maintained-extensions-table.md" %}
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[example-ext-src]: https://github.com/OHIF/Viewers/tree/master/extensions/_example/src
|
||||
[module-types]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/extensions/MODULE_TYPES.js
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -1,3 +0,0 @@
|
||||
# Advanced
|
||||
|
||||
Advanced topics go beyond basic configuration and deployment. Their goal is to provide insight into this project's architecture and guidance on leveraging extensions.
|
||||
@@ -1,23 +0,0 @@
|
||||
# MonoRepos: A Crash Course
|
||||
|
||||
- [Lerna][lerna]
|
||||
|
||||
Solutions:
|
||||
|
||||
## Semantic-Release
|
||||
|
||||
- [Semantic-Release](https://github.com/semantic-release/semantic-release/issues/193#issuecomment-462063871)
|
||||
- [Multi-semantic-release](https://github.com/dhoulb/multi-semantic-release)
|
||||
- [semantic-release-monorepo](https://github.com/Updater/semantic-release-monorepo)
|
||||
|
||||
# Netlify
|
||||
|
||||
- https://community.netlify.com/t/best-practices-for-deploying-sites-from-monorepos/818
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[lerna]: https://github.com/lerna/lerna
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,158 @@
|
||||
# Architecture
|
||||
|
||||
Looking to extend your instance of the OHIF Viewer? Want learn how to reuse _a
|
||||
portion_ of the Viewer in your own application? Or maybe you want to get
|
||||
involved and draft or suggest a new feature? Regardless, you're in the right
|
||||
place!
|
||||
|
||||
The OHIF Viewer aims to be decoupled, configurable, and extensible; while this
|
||||
allows our code to be used in more ways, it also increases complexity. Below, we
|
||||
aim to demistify that complexity by providing insight into how our Viewer is
|
||||
architected, and the role each of it's dependent libraries plays.
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Business Logic](#business-logic)
|
||||
- [Component Library](#react-component-library)
|
||||
- [Internationalization](#internationalization-i18n)
|
||||
- [Extensions & Configuration](#extensions--configuration)
|
||||
- [Common Questions](#common-questions)
|
||||
|
||||
## Overview
|
||||
|
||||
The [OHIF Medical Image Viewing Platform][viewers-project] is maintained as a
|
||||
[`monorepo`][monorepo]. This means that this repository, instead of containing a
|
||||
single project, contains many projects. If you explore our project structure,
|
||||
you'll see the following:
|
||||
|
||||
```bash
|
||||
.
|
||||
├── extensions
|
||||
│ ├── _example # Skeleton of example extension
|
||||
│ ├── cornerstone # 2D images w/ Cornerstone.js
|
||||
│ ├── dicom-html # Structured Reports as HTML in viewport
|
||||
│ ├── dicom-microscopy # Whole slide microscopy viewing
|
||||
│ ├── dicom-pdf # View DICOM wrapped PDFs in viewport
|
||||
│ └── vtk # MPR and Volume support w/ VTK.js
|
||||
│
|
||||
├── platform
|
||||
│ ├── core # Business Logic
|
||||
│ ├── i18n # Internationalization Support
|
||||
│ ├── ui # React component library
|
||||
│ └── viewer # Connects platform and extension projects
|
||||
│
|
||||
├── ... # misc. shared configuration
|
||||
├── lerna.json # MonoRepo (Lerna) settings
|
||||
├── package.json # Shared devDependencies and commands
|
||||
└── README.md
|
||||
```
|
||||
|
||||
The `platform` directory contains the business logic library, component library,
|
||||
and the application library that combines them to create a powerful medical
|
||||
imaging viewer.
|
||||
|
||||
The `extensions` directory contains many packages that can be registered with
|
||||
`@ohif/core`'s `ExtensionManager` to expand an application's supported features
|
||||
and functionality.
|
||||
|
||||

|
||||
|
||||
<center><i>architecture diagram</i></center>
|
||||
|
||||
This diagram is a conceptual illustration of how the Viewer is architected.
|
||||
|
||||
1. (optional) `extensions` can be registered with `@ohif/core`'s
|
||||
`ExtensionManager`
|
||||
2. `@ohif/core` provides bussiness logic and a way for `@ohif/viewer` to access
|
||||
registered extensions
|
||||
3. The `@ohif/viewer` composes and provides data to components from our
|
||||
component library (`@ohif/ui`)
|
||||
4. The `@ohif/viewer` can be built and served as a stand-alone PWA, or as an
|
||||
embeddable package ([`@ohif/viewer`][viewer-npm])
|
||||
|
||||
## Business Logic
|
||||
|
||||
The [`@ohif/core`][core-github] project offers pre-packaged solutions for
|
||||
features common to Web-based medical imaging viewers. For example:
|
||||
|
||||
- [Hotkeys](#)
|
||||
- DICOM Web requests
|
||||
- Hanging Protocols
|
||||
- [Managing a study's measurements](../services/default/measurements.md)
|
||||
- Managing a study's DICOM metadata
|
||||
- [A flexible pattern for extensions](../extensions/index.md)
|
||||
- And many others
|
||||
|
||||
It does this while remaining decoupled from any particular view library or
|
||||
rendering logic. While we use it to power our React Viewer, it can be used with
|
||||
Vue, React, Vanilla JS, or any number of other frameworks.
|
||||
|
||||
## React Component Library
|
||||
|
||||
[`@ohif/ui`][ui-github] is a React Component library that contains the reusable
|
||||
components that power the OHIF Viewer. It allows us to build, compose, and test
|
||||
components in isolation; easing the development process by reducing the need to
|
||||
stand-up a local PACS with test case data.
|
||||
|
||||
Extension authors can also use these same components when building their
|
||||
extension's UI; allowing for a consistent look and feel with the rest of the
|
||||
application.
|
||||
|
||||
[Check out our component library!](https://react.ohif.org/)
|
||||
|
||||
## Internationalization (i18n)
|
||||
|
||||
...
|
||||
|
||||
## Extensions & Configuration
|
||||
|
||||
While OHIF maintains several high value and commonly requested features in its
|
||||
own extensions, there are many instances where one may wish to further extend
|
||||
the viewer. Some common use cases include:
|
||||
|
||||
- Adding AI/ML tools and insights
|
||||
- Custom workflows for guided diagnosis
|
||||
- Collecting specific annotations for training data or reports
|
||||
- Authentication and granular permissions
|
||||
- Teleconsultation workflow, image comments, and tracking
|
||||
- Adding surgical templating tools and reports
|
||||
- and many others
|
||||
|
||||
We expose common integration points via [extensions](../extensions/index.md) to
|
||||
make this possible. The viewer and many of our own extensions also offer
|
||||
[configuration][configuration]. For a list of extensions maintained by OHIF,
|
||||
[check out this helpful table](../extensions/index.mdl#maintained-extensions).
|
||||
|
||||
If you find yourself thinking "I wish the Viewer could do X", and you can't
|
||||
accomplish it with an extension today, create a GitHub issue! We're actively
|
||||
looking for ways to improve our extensibility ^\_^
|
||||
|
||||
[Click here to read more about extensions!](../extensions/index.md)
|
||||
|
||||
## Common Questions
|
||||
|
||||
> When should I use the packaged source `@ohif/viewer` versus building a PWA
|
||||
> from the source?
|
||||
|
||||
...
|
||||
|
||||
> Can I create my own Viewer using Vue.js or Angular.js?
|
||||
|
||||
You can, but you will not be able to leverage as much of the existing code and
|
||||
components. `@ohif/core` could still be used for business logic, and to provide
|
||||
a model for extensions. `@ohif/ui` would then become a guide for the components
|
||||
you would need to recreate.
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[monorepo]: #
|
||||
[viewers-project]: https://github.com/OHIF/Viewers
|
||||
[viewer-npm]: https://www.npmjs.com/package/@ohif/viewer
|
||||
[pwa]: https://developers.google.com/web/progressive-web-apps/
|
||||
[configuration]: ../configuring/index.md
|
||||
[extensions]: ../extensions/index.md
|
||||
[core-github]: https://github.com/OHIF/viewers/platform/core
|
||||
[ui-github]: https://github.com/OHIF/Viewers/platform/ui
|
||||
<!-- prettier-ignore-end -->
|
||||
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 260.4 82.9" enable-background="new 0 0 260.4 82.9" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#525DF9" d="M31.7,8.9c9.6,0,16.5,4.9,19,13.4l0.1,0.4h9.6l-0.1-0.6C57.6,8.5,46.7,0,31.8,0C13.7,0,0,14.1,0,32.9 s13.7,32.9,31.8,32.9c14.9,0,25.8-8.5,28.6-22.1l0.1-0.6h-9.6l-0.1,0.4c-2.5,8.5-9.5,13.4-19,13.4c-13.1,0-21.9-9.6-21.9-24 C9.8,18.6,18.6,8.9,31.7,8.9z"/>
|
||||
<path fill="#525DF9" d="M110.1,58c-2.3,0-3.5-1.4-3.5-4.2V32.7c0-8.8-7.2-14.7-17.9-14.7c-7.5,0-16.7,3.9-18.3,14.9l-0.1,0.6h8.4 l0.1-0.4c1.4-5.7,5.8-6.9,9.3-6.9c6,0,9.5,2.7,9.5,7.4v2.6l-13.6,1.4c-7.6,0.8-15.7,5-15.7,14.6c0,8.1,6,13.5,14.8,13.5 c6.5,0,11.8-3.4,15-6.8c1.3,4.2,4.5,6.5,9.1,6.5c1.7,0,3.2-0.3,5.2-0.9l0.3-0.1v-7l-0.6,0.2C111.5,57.9,110.9,58,110.1,58z M97.7,43.5v7.3c-4.6,4.6-8.9,6.7-13.5,6.7c-2,0-6.8-0.6-6.8-5.7c0-3.8,2.8-6.3,7.4-6.9L97.7,43.5z"/>
|
||||
<path fill="#525DF9" d="M146.5,18c-6.5,0-12,3.1-15.2,6.1v-5.2h-8.9v46h8.9V34.3c2.2-3.2,6.7-8.3,13-8.3c5.6,0,8.7,3.1,8.7,8.8 v30.1h8.9V33.3C161.9,23.7,156.1,18,146.5,18z"/>
|
||||
<path fill="#525DF9" d="M195.8,18c-6.5,0-12,3.1-15.2,6.1v-5.2h-8.9v46h8.9V34.3c2.2-3.2,6.7-8.3,13-8.3c5.6,0,8.7,3.1,8.7,8.8 v30.1h8.9V33.3C211.2,23.7,205.4,18,195.8,18z"/>
|
||||
<polygon fill="#525DF9" points="251.3,18.9 238.6,51.8 237.8,47.9 225.6,18.9 216.2,18.9 234.3,62.4 226,82.9 235,82.9 260.4,18.9 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 445.9 638" enable-background="new 0 0 445.9 638" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#5F5DF9" d="M224.5,638C101.1,638,0,537.8,0,414.7V223.3C0,100.2,101.1,0,224.5,0c109.6,0,202.8,78.3,220.9,186.1
|
||||
c2.9,17.4-8.6,33.8-26,36.8c-17.4,2.9-33.7-8.8-36.7-26.2c-13-77-78.6-132.9-157-132.9c-88.2,0-159.3,71.6-159.3,159.5v191.4
|
||||
c0,88,71.1,159.5,159.3,159.5c78.3,0,144.2-55.9,157.1-132.9c2.9-17.4,19.3-29.1,36.6-26.2c17.4,2.9,28.6,19.4,25.7,36.7
|
||||
C427.2,559.7,334,638,224.5,638z"/>
|
||||
</g>
|
||||
<g opacity="0.5">
|
||||
<path fill="#5F5DF9" d="M153.6,347.7c-17.6,0-30.7-14.3-30.7-31.9v-92.3c0-56.8,45.8-103,102.8-103c38.9,0,73.9,21.6,91.7,56.4
|
||||
c8,15.7,1.7,34.9-14,42.9c-15.7,8-35,1.8-43-13.9c-6.8-13.4-21-21.7-35.8-21.7c-21.8,0-40.2,17.6-40.2,39.2v92.3
|
||||
C184.3,333.4,171.2,347.7,153.6,347.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 422 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 26 KiB |
@@ -1,8 +1,9 @@
|
||||
# Data Source
|
||||
|
||||
After following the steps outlined in [Getting Started](./getting-started.md),
|
||||
you'll notice that the OHIF Viewer has data for several studies and their
|
||||
images. You didn't add this data, so where is it coming from?
|
||||
After following the steps outlined in
|
||||
[Getting Started](./../development/getting-started.md), you'll notice that the
|
||||
OHIF Viewer has data for several studies and their images. You didn't add this
|
||||
data, so where is it coming from?
|
||||
|
||||
By default, the viewer is configured to connect to a remote server hosted by the
|
||||
nice folks over at [dcmjs.org][dcmjs-org]. While convenient for getting started,
|
||||
@@ -35,10 +36,10 @@ For our purposes, we will be using `Orthanc`, but you can see a list of
|
||||
_Not sure if you have `docker` installed already? Try running `docker --version`
|
||||
in command prompt or terminal_
|
||||
|
||||
> If you are using `Docker Toolbox` you need to change the _proxy_ parameter in
|
||||
> _package.json_ to http://192.168.99.100:8042 or the ip docker-machine ip
|
||||
> throws. This is the value [`react-scripts`][react-proxy] uses to proxy
|
||||
> requests
|
||||
> If you are using `Docker Toolbox` you need to change the _PROXY_DOMAIN_
|
||||
> parameter in _platform/viewer/package.json_ to http://192.168.99.100:8042 or
|
||||
> the ip docker-machine ip throws. This is the value [`WebPack`][webpack-proxy]
|
||||
> uses to proxy requests
|
||||
|
||||
### Running Orthanc
|
||||
|
||||
@@ -51,8 +52,9 @@ yarn run orthanc:up
|
||||
|
||||
_Upload your first Study:_
|
||||
|
||||
1. Navigate to [Orthanc's web interface](http://localhost:8899) at
|
||||
`http://localhost:8899` in a web browser.
|
||||
1. Navigate to
|
||||
[Orthanc's web interface](http://localhost:8042/app/explorer.html) at
|
||||
`http://localhost:8042/app/explorer.html` in a web browser.
|
||||
2. In the top right corner, click "Upload"
|
||||
3. Click "Select files to upload..." and select one or more DICOM files
|
||||
4. Click "Start the upload"
|
||||
@@ -60,17 +62,20 @@ _Upload your first Study:_
|
||||
#### Orthanc: Learn More
|
||||
|
||||
You can see the `docker-compose.yml` file this command runs at
|
||||
[`<project-root>/platform/viewer/.recipes/Nginx-Orthanc/`](https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes/Nginx-Orthanc),
|
||||
and more on Orthanc for Docker in [Orthanc's documentation][orthanc-docker].
|
||||
[`<project-root>/.docker/Nginx-Orthanc/`][orthanc-docker-compose], and more on
|
||||
Orthanc for Docker in [Orthanc's documentation][orthanc-docker].
|
||||
|
||||
### Connecting to Orthanc
|
||||
|
||||
Now that we have a local Orthanc instance up and running, we need to configure
|
||||
our web application to connect to it. Open a new terminal window, navigate to
|
||||
this project's root directory, and run:
|
||||
this repository's root directory, and run:
|
||||
|
||||
```bash
|
||||
# If you haven't already, restore dependencies
|
||||
# If you haven't already, enable yarn workspaces
|
||||
yarn config set workspaces-experimental true
|
||||
|
||||
# Restore dependencies
|
||||
yarn install
|
||||
|
||||
# Run our dev command, but with the local orthanc config
|
||||
@@ -80,25 +85,31 @@ yarn run dev:orthanc
|
||||
#### Configuration: Learn More
|
||||
|
||||
> For more configuration fun, check out the
|
||||
> [Essentials Configuration](./configuration.md) guide.
|
||||
> [Essentials Configuration](./index.md) guide.
|
||||
|
||||
Let's take a look at what's going on under the hood here. `yarn run dev:orthanc`
|
||||
is running the `dev:orthanc` script in our project's `package.json`. That script
|
||||
is:
|
||||
|
||||
```js
|
||||
cross-env PORT=5000 APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start
|
||||
cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack-dev-server --config .webpack/webpack.pwa.js -w
|
||||
```
|
||||
|
||||
- `cross-env` sets two environment variables
|
||||
- PORT: 5000
|
||||
- `cross-env` sets three environment variables
|
||||
- PROXY_TARGET: `/dicom-web`
|
||||
- PROXY_DOMAIN: `http://localhost:8042`
|
||||
- APP_CONFIG: `config/docker_nginx-orthanc.js`
|
||||
- `react-scripts` runs it's `start` script. This is [the de-facto
|
||||
way][cra-start] to run a "Create React App" in development mode.
|
||||
- `webpack-dev-server` runs using the `.webpack/webpack.pwa.js` configuration
|
||||
file. It will watch for changes and update as we develop.
|
||||
|
||||
`PROXY_TARGET` and `PROXY_DOMAIN` tell our development server to proxy requests
|
||||
to `Orthanc`. This allows us to bypass CORS issues that normally occur when
|
||||
requesting resources that live at a different domain.
|
||||
|
||||
The `APP_CONFIG` value tells our app which file to load on to `window.config`.
|
||||
By default, our app uses the file at `<project-root>/public/config/default.js`.
|
||||
Here is what that configuration looks like:
|
||||
By default, our app uses the file at
|
||||
`<project-root>/platform/viewer/public/config/default.js`. Here is what that
|
||||
configuration looks like:
|
||||
|
||||
```js
|
||||
window.config = {
|
||||
@@ -120,7 +131,7 @@ window.config = {
|
||||
```
|
||||
|
||||
To learn more about how you can configure the OHIF Viewer, check out our
|
||||
[Configuration Guide](./configuration.md).
|
||||
[Configuration Guide](./index.md).
|
||||
|
||||
## Open Source DICOM Image Archives
|
||||
|
||||
@@ -145,8 +156,8 @@ _Feel free to make a Pull Request if you want to add to this list._
|
||||
[dcmjs-org]: https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado
|
||||
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
|
||||
[storescu]: http://support.dcmtk.org/docs/storescu.html
|
||||
[cra-start]: https://github.com/facebook/create-react-app#npm-start-or-yarn-start
|
||||
[react-proxy]: https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development#configuring-the-proxy-manually
|
||||
[webpack-proxy]: https://webpack.js.org/configuration/dev-server/#devserverproxy
|
||||
[orthanc-docker-compose]: https://github.com/OHIF/Viewers/tree/master/.docker/Nginx-Orthanc
|
||||
<!-- Archives -->
|
||||
[dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light
|
||||
[dcm4chee-docker]: https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
|
||||
@@ -0,0 +1,126 @@
|
||||
# Configuration
|
||||
|
||||
> This step assumes you have an imaging archive. If you need assistance setting
|
||||
> one up, check out the [`Data Source` Guide](./data-source.md) or a deployment
|
||||
> recipe that contains an open Image Archive
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Configuration Files](#configuration-files)
|
||||
- [Environment Variables](#environment-variables)
|
||||
- [How do I configure my project?](#how-do-i-configure-my-project)
|
||||
|
||||
## Overview
|
||||
|
||||
### Configuration Files
|
||||
|
||||
The configuration for our viewer is in the `<root>platform/viewer/public/config`
|
||||
directory. Our build process knows which configuration file to use based on the
|
||||
`APP_CONFIG` environment variable. By default, its value is
|
||||
[`config/default.js`][default-config]. The majority of the viewer's features,
|
||||
and registered extension's features, are configured using this file.
|
||||
|
||||
**Embedded Use Note:**
|
||||
|
||||
Alternatively, when using the `umd` bundle for embedded use cases, these same
|
||||
values are what you'll pass to `installViewer` method:
|
||||
|
||||
`OHIFStandaloneViewer.installViewer(window.config)`
|
||||
|
||||
### Environment Variables
|
||||
|
||||
We use environment variables at build and dev time to change the Viewer's
|
||||
behavior. We can update the `HTML_TEMPLATE` to easily change which extensions
|
||||
are registered, and specify a different `APP_CONFIG` to connect to an
|
||||
alternative data source (or even specify different default hotkeys).
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
| -------------------- | -------------------------------------------------------------------------------------------------- | ------------------- |
|
||||
| `HTML_TEMPLATE` | Which [HTML template][html-templates] to use as our web app's entry point. Specific to PWA builds. | `index.html` |
|
||||
| `PUBLIC_URL` | The route relative to the host that the app will be served from. Specific to PWA builds. | `/` |
|
||||
| `APP_CONFIG` | Which [configuration file][config-file] to copy to output as `app-config.js` | `config/default.js` |
|
||||
| `PROXY_TARGET` | When developing, proxy requests that match this pattern to `PROXY_DOMAIN` | `undefined` |
|
||||
| `PROXY_DOMAIN` | When developing, proxy requests from `PROXY_TARGET` to `PROXY_DOMAIN` | `undefined` |
|
||||
|
||||
## How do I configure my project?
|
||||
|
||||
The simplest way is to update the existing default config:
|
||||
|
||||
_/platform/viewer/public/config/default.js_
|
||||
|
||||
```js
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: 'DCM4CHEE',
|
||||
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
|
||||
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
qidoSupportsIncludeField: true,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
The configuration can also be written as a JS Function in case you need to inject dependencies like external services:
|
||||
|
||||
```js
|
||||
window.config = ({ servicesManager } = {}) => {
|
||||
const { UIDialogService } = servicesManager.services;
|
||||
return {
|
||||
cornerstoneExtensionConfig: {
|
||||
tools: {
|
||||
ArrowAnnotate: {
|
||||
configuration: {
|
||||
getTextCallback: (callback, eventDetails) => UIDialogService.create({...
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
routerBasename: '/',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: 'DCM4CHEE',
|
||||
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
|
||||
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
qidoSupportsIncludeField: true,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
You can also create a new config file and specify its path relative to the build
|
||||
output's root by setting the `APP_CONFIG` environment variable. You can set the
|
||||
value of this environment variable a few different ways:
|
||||
|
||||
- ~[Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)~
|
||||
- Previous `react-scripts` functionality that we need to duplicate with
|
||||
`dotenv-webpack`
|
||||
- ~[Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)~
|
||||
- Previous `react-scripts` functionality that we need to duplicate with
|
||||
`dotenv-webpack`
|
||||
- Using the `cross-env` package in an npm script:
|
||||
- `"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"`
|
||||
|
||||
After updating the configuration, `yarn run build` to generate updated build
|
||||
output.
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[default-config]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js
|
||||
[html-templates]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/public/html-templates
|
||||
[config-files]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/public/config
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -1,103 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
## I would like to contribute code - how do I do this?
|
||||
|
||||
Fork the repository, make your change and submit a pull request.
|
||||
|
||||
- The OHIF Viewer consists of code from three different repositories. Make sure
|
||||
your change is modifying the appropriate one:
|
||||
- `ohif-core`: Business Logic
|
||||
- `react-viewerbase`: Reusable React Component Library
|
||||
- `Viewers`: The glue, PWA, and primary extension point
|
||||
- At a minimum, you may want to read the following documentation:
|
||||
- [Essentials: Getting Started](./essentials/getting-started.md)
|
||||
- [Advanced: Architecture](./advanced/architecture.md)
|
||||
|
||||
### When changes impact multiple repositories
|
||||
|
||||
This is a particularly tricky scenario. We don't want to publish code in one
|
||||
repository, just so we can test and complete the other half of its requirements
|
||||
in another. Thankfully, there are a couple of ways you can test unpublished
|
||||
dependent changes locally before publishing:
|
||||
|
||||
- [Use `yarn link`](https://yarnpkg.com/en/docs/cli/link)
|
||||
|
||||
For example if you are working on `ohif-core` and would like to use your local
|
||||
version to debug a problem in `Viewers`, simply run yarn link inside of the
|
||||
`ohif-core` project.
|
||||
|
||||
- If you're experiencing issues with `yarn link`,
|
||||
[try `yalc`](https://github.com/whitecolor/yalc)
|
||||
|
||||
Yalc provides an improved workflow as we add more and more dependent packages
|
||||
that are "in-progress". This comes into play as we begin working on extensions
|
||||
and their dependencies.
|
||||
|
||||
```js
|
||||
// Install yalc for the first time
|
||||
yarn global add yalc
|
||||
|
||||
// EXAMPLE: using an in-development version of ohif-core w/ Viewers locally
|
||||
// 1. Navigate to ohif-core's project root
|
||||
yarn install
|
||||
yalc publish
|
||||
|
||||
// 2. Run the following after each change to ohif-core
|
||||
yarn build
|
||||
yalc push .
|
||||
|
||||
// 3. Use the local package in our Viewers project. Navigate to the Viewers
|
||||
// Project root.
|
||||
yarn install
|
||||
yalc add ohif-core
|
||||
yarn run dev
|
||||
```
|
||||
|
||||
## Any guidance on submitting changes?
|
||||
|
||||
While we do appreciate code contributions, triaging and integrating contributed
|
||||
code changes can be very time consuming. Please consider the following tips when
|
||||
working on your pull requests:
|
||||
|
||||
- Functionality is appropriate for the repository. Consider creating a GitHub
|
||||
issue to discuss your suggested changes.
|
||||
- The scope of the pull request is not too large. Please consider separate pull
|
||||
requests for each feature as big pull requests are very time consuming to
|
||||
understand.
|
||||
|
||||
We will provide feedback on your pull requests as soon as possible. Following
|
||||
the tips above will help ensure your changes are reviewed.
|
||||
|
||||
## Testing contribution pull requests
|
||||
|
||||
OHIF uses [netlify](netlify.com) so that pull requests are autogenerated and
|
||||
available for testing.
|
||||
|
||||
For example, [this url][example-url] allows you to test [pull request 237, the
|
||||
request that created this FAQ entry,][pr-237] using data pulled from Amazon S3.
|
||||
|
||||
Replacing the number 237 in the link below with your pull request number should
|
||||
let you test it as well and you can use this link for discussions on github
|
||||
without requiring reviewers to download and build your branch.
|
||||
|
||||
```bash
|
||||
https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
|
||||
```
|
||||
|
||||
If you have made a documentation change, a link like this will let you preview
|
||||
the gitbook generated by the pull request:
|
||||
|
||||
```bash
|
||||
https://deploy-preview-237--ohif.netlify.com/contributing.html
|
||||
```
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
[example-url]: https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
|
||||
[pr-237]: https://github.com/OHIF/Viewers/pull/237
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -1,18 +1,18 @@
|
||||
# Deployment
|
||||
|
||||
The OHIF Viewer can be embedded in other web applications via it's [packaged
|
||||
script source][ohif-viewer-npm], or served up as a stand-alone PWA ([progressive
|
||||
web application][pwa-url]) by building and hosting a collection of static
|
||||
assets. In either case, you will need to configure your instance of the Viewer
|
||||
so that it can connect to your data source (the database or PACS that provides
|
||||
the data your Viewer will display).
|
||||
script source][viewer-npm], or served up as a stand-alone PWA ([progressive web
|
||||
application][pwa-url]) by building and hosting a collection of static assets. In
|
||||
either case, you will need to configure your instance of the Viewer so that it
|
||||
can connect to your data source (the database or PACS that provides the data
|
||||
your Viewer will display).
|
||||
|
||||
## Overview
|
||||
|
||||
Our goal is to make deployment as simple and painless as possible; however,
|
||||
there is an inherent amount of complexity in customizing, optimizing, and
|
||||
deploying web applications. If you find yourself a little lost, please don't
|
||||
hesitate to [reach out for help](/help.md)
|
||||
there is an inherent amount of complexity in configuring and deploying web
|
||||
applications. If you find yourself a little lost, please don't hesitate to
|
||||
[reach out for help](/help.md)
|
||||
|
||||
## Deployment Scenarios
|
||||
|
||||
@@ -35,8 +35,7 @@ benefits, but comes at the cost of time and complexity. Some benefits include:
|
||||
|
||||
_Today:_
|
||||
|
||||
- Leverage [extensions](/advanced/extensions.md) to drop-in powerful new
|
||||
features
|
||||
- Leverage [extensions](/extensions/index.md) to drop-in powerful new features
|
||||
- Add routes and customize the viewer's workflow
|
||||
- Finer control over styling and whitelabeling
|
||||
|
||||
@@ -97,12 +96,12 @@ support it yet, but it is gaining wider adoption.
|
||||
If you have an existing archive and intend to host the OHIF Viewer at the same
|
||||
domain name as your archive, then connecting the two is as simple as following
|
||||
the steps layed out in our
|
||||
[Configuration Essentials Guide](./../essentials/configuration.md).
|
||||
[Configuration Essentials Guide](./../configuring/index.md).
|
||||
|
||||
#### What if I don't have an imaging archive?
|
||||
|
||||
We provide some guidance on configuring a local image archive in our
|
||||
[Data Source Essentials](./../essentials/data-source.md) guide. Hosting an
|
||||
[Data Source Essentials](./../configuring/data-source.md) guide. Hosting an
|
||||
archive remotely is a little trickier. You can check out some of our
|
||||
[advanced recipes](#recipes) for modeled setups that may work for you.
|
||||
|
||||
@@ -143,7 +142,7 @@ The OHIF Viewer can be configured to work with authorization servers that
|
||||
support one or more of the OpenID-Connect authorization flows. The Viewer finds
|
||||
it's OpenID-Connect settings on the `oidc` configuration key. You can set these
|
||||
values following the instructions laid out in the
|
||||
[Configuration Essentials Guide](./../essentials/configuration.md).
|
||||
[Configuration Essentials Guide](./../configuring/index.md).
|
||||
|
||||
_Example OpenID-Connect Settings:_
|
||||
|
||||
@@ -196,8 +195,7 @@ Please feel free to suggest or contribute your own recipes.
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
[ohif-viewer-npm]: https://www.npmjs.com/package/ohif-viewer
|
||||
[viewer-npm]: https://www.npmjs.com/package/@ohif/viewer
|
||||
[pwa-url]: https://developers.google.com/web/progressive-web-apps/
|
||||
[static-assets-url]: https://www.maxcdn.com/one/visual-glossary/static-content/
|
||||
[app-store]: https://medium.freecodecamp.org/i-built-a-pwa-and-published-it-in-3-app-stores-heres-what-i-learned-7cb3f56daf9b
|
||||
@@ -206,5 +204,5 @@ Please feel free to suggest or contribute your own recipes.
|
||||
[host-static-assets]: https://www.netlify.com/blog/2016/05/18/9-reasons-your-site-should-be-static/
|
||||
[cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
[code-flows]: https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660
|
||||
[code-sandbox]: https://codesandbox.io/s/ohif-viewer-script-tag-usage-b3st9
|
||||
[code-sandbox]: https://codesandbox.io/s/viewer-script-tag-tprch
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -1,7 +1,7 @@
|
||||
# Build for Production
|
||||
|
||||
> If you've already followed the
|
||||
> ["Getting Started" Guide](/essentials/getting-started.md), you can skip ahead
|
||||
> ["Getting Started" Guide](/development/getting-started.md), you can skip ahead
|
||||
> to [Configuration](#configuration)
|
||||
|
||||
## Overview
|
||||
@@ -19,9 +19,6 @@ _With Git:_
|
||||
```bash
|
||||
# Clone the remote repository to your local machine
|
||||
git clone https://github.com/OHIF/Viewers.git
|
||||
|
||||
# Make sure the local code reflects the `react` version of the OHIF Viewer
|
||||
git checkout react
|
||||
```
|
||||
|
||||
More on: _[`git clone`](https://git-scm.com/docs/git-clone),
|
||||
@@ -29,7 +26,7 @@ More on: _[`git clone`](https://git-scm.com/docs/git-clone),
|
||||
|
||||
_From .zip:_
|
||||
|
||||
[OHIF/Viewers: react.zip](https://github.com/OHIF/Viewers/archive/react.zip)
|
||||
[OHIF/Viewers: react.zip](https://github.com/OHIF/Viewers/archive/master.zip)
|
||||
|
||||
### Restore Dependencies & Build
|
||||
|
||||
@@ -37,20 +34,24 @@ Open your terminal, and navigate to the directory containing the source files.
|
||||
Next run these commands:
|
||||
|
||||
```js
|
||||
// If you haven't already, enable yarn workspaces
|
||||
yarn config set workspaces-experimental true
|
||||
|
||||
// Restore dependencies
|
||||
yarn install
|
||||
|
||||
// Build source code for production
|
||||
yarn run build:web
|
||||
yarn run build
|
||||
```
|
||||
|
||||
If everything worked as expected, you should have a new `build/` directory in
|
||||
the project's folder. It should roughly resemble the following:
|
||||
If everything worked as expected, you should have a new `dist/` directory in the
|
||||
project's folder. It should roughly resemble the following:
|
||||
|
||||
```bash
|
||||
build
|
||||
├── config/
|
||||
├── static/
|
||||
<root>platform/viewer/dist/
|
||||
├── app-config.js
|
||||
├── app.bundle.js
|
||||
├── app.css
|
||||
├── index.html
|
||||
├── manifest.json
|
||||
├── service-worker.js
|
||||
@@ -64,60 +65,15 @@ how to configure the project for your own imaging archive below.
|
||||
|
||||
### Configuration
|
||||
|
||||
> This step assumes you have an imaging archive. If you need assistance setting
|
||||
> one up, check out the [`Data Source` Guide](./../../essentials/data-source.md)
|
||||
> or a deployment recipe that contains an open source Image Archive
|
||||
The configuration for our viewer is in the `<root>platform/viewer/public/config`
|
||||
directory. Our build process knows which configuration file to use based on the
|
||||
`APP_CONFIG` environment variable. By default, its value is
|
||||
[`config/default.js`][default-config]. The majority of the viewer's features,
|
||||
and registered extension's features, are configured using this file.
|
||||
|
||||
#### How it Works
|
||||
|
||||
The configuration for our project is in the `/public/config` directory. Our
|
||||
build process knows which configuration file to use based on the `APP_CONFIG`
|
||||
environment variable. By default, its value is
|
||||
[`default.js`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js).
|
||||
When we build, the `%APP_CONFIG%` value in
|
||||
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/index.html)
|
||||
file is substituted for the correct configuration file's name. This sets
|
||||
the`window.config` equal to our configuration file's value.
|
||||
|
||||
#### How do I configure my project?
|
||||
|
||||
The simplest way is to update the existing default config:
|
||||
|
||||
_/public/config/default.js_
|
||||
|
||||
```js
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: 'DCM4CHEE',
|
||||
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
|
||||
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
qidoSupportsIncludeField: true,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
requestOptions: {
|
||||
requestFromBrowser: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
You can also create a new config file and specify its path relative to the build
|
||||
output's root by setting the `APP_CONFIG` environment variable. You can set the
|
||||
value of this environment variable a few different ways:
|
||||
|
||||
- [Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)
|
||||
- [Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)
|
||||
- Using the `cross-env` package in an npm script:
|
||||
- `"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"`
|
||||
|
||||
After updating the configuration, `yarn run build:web` to generate updated build
|
||||
output.
|
||||
The easiest way to apply your own configuration is to modify the `default.js`
|
||||
file. For more advanced cofiguration options, check out our
|
||||
[configuration essentials guide](/configuring/index.md).
|
||||
|
||||
## Next Steps
|
||||
|
||||
@@ -141,7 +97,7 @@ _Advanced_
|
||||
### Testing Build Output Locally
|
||||
|
||||
A quick way to test your build output locally is to spin up a small webserver.
|
||||
You can do this by running the following commands in the `build/` output
|
||||
You can do this by running the following commands in the `dist/` output
|
||||
directory:
|
||||
|
||||
```js
|
||||
@@ -162,8 +118,7 @@ web application. For a starting point, check out this repository's own use of:
|
||||
|
||||
- [CircleCI][circleci]: [config.yaml][circleci-config]
|
||||
- [Netlify][netlify]: [netlify.toml][netlify.toml] |
|
||||
[generateStaticSite.sh][generatestaticsite.sh]
|
||||
- [Semantic-Release][semantic-release]: [.releaserc][releaserc]
|
||||
[build-deploy-preview.sh][build-deploy-preview.sh]
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -173,10 +128,8 @@ web application. For a starting point, check out this repository's own use of:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[circleci]: https://circleci.com/gh/OHIF/Viewers
|
||||
[circleci-config]: https://github.com/OHIF/Viewers/blob/react/.circleci/config.yml
|
||||
[circleci-config]: https://github.com/OHIF/Viewers/blob/master/.circleci/config.yml
|
||||
[netlify]: https://app.netlify.com/sites/ohif/deploys
|
||||
[netlify.toml]: https://github.com/OHIF/Viewers/blob/react/netlify.toml
|
||||
[generateStaticSite.sh]: https://github.com/OHIF/Viewers/blob/react/generateStaticSite.sh
|
||||
[semantic-release]: https://semantic-release.gitbook.io/semantic-release/
|
||||
[releaserc]: https://github.com/OHIF/Viewers/blob/react/.releaserc
|
||||
[netlify.toml]: https://github.com/OHIF/Viewers/blob/master/netlify.toml
|
||||
[build-deploy-preview.sh]: https://github.com/OHIF/Viewers/blob/master/.netlify/build-deploy-preview.sh
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -12,41 +12,24 @@ include tags. Here's how it works:
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||
<code>bootstrap@3.3.7</code>
|
||||
<a href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700&display=swap">
|
||||
<code>Google Font: Roboto</code>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700|Sanchez&display=swap">
|
||||
<code>Google Fonts, Sanchez & Roboto</code>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://unpkg.com/react@16/umd/react.production.min.js">
|
||||
<code>react@16.8.6</code>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js">
|
||||
<code>react-dom@16.8.6</code>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://unpkg.com/ohif-viewer/dist/index.umd.js">
|
||||
<code>ohif-viewer@latest</code>
|
||||
<a href="https://unpkg.com/@ohif/viewer">
|
||||
<code>@ohif/viewer@latest</code>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ol start="2">
|
||||
<li>The <a href="">WADO Image Loader Codecs and Web Worker source code</a>
|
||||
should be accessible from your server's root</li>
|
||||
<li>Create a JS Object to hold the OHIF Viewer's configuration. Here are some
|
||||
<li>Create a JS Object or Function to hold the OHIF Viewer's configuration. Here are some
|
||||
example values that would allow the viewer to hit our public PACS:</li>
|
||||
</ol>
|
||||
|
||||
```js
|
||||
// Set before importing `ohif-viewer`
|
||||
// Set before importing `ohif-viewer` (JS Object)
|
||||
window.config = {
|
||||
// default: '/'
|
||||
routerBasename: '/',
|
||||
@@ -60,28 +43,67 @@ window.config = {
|
||||
qidoSupportsIncludeField: true,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
requestOptions: {
|
||||
requestFromBrowser: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
<ol start="5"><li>
|
||||
To learn more about how you can configure the OHIF Viewer, check out our
|
||||
[Configuration Guide](./index.md).
|
||||
|
||||
<ol start="3"><li>
|
||||
Render the viewer in the web page's target <code>div</code>
|
||||
</li></ol>
|
||||
|
||||
```js
|
||||
// Made available by the `ohif-viewer` script included in step 1
|
||||
var Viewer = window.OHIFStandaloneViewer.App;
|
||||
var app = React.createElement(Viewer, window.config, null);
|
||||
|
||||
ReactDOM.render(app, document.getElementById('ohif-viewer-target'));
|
||||
// Made available by the `@ohif/viewer` script included in step 1
|
||||
var containerId = 'id-of-div-to-render-component-to';
|
||||
var componentRenderedOrUpdatedCallback = function() {
|
||||
console.log('OHIF Viewer rendered/updated');
|
||||
};
|
||||
window.OHIFViewer.installViewer(
|
||||
window.config,
|
||||
containerId,
|
||||
componentRenderedOrUpdatedCallback
|
||||
);
|
||||
```
|
||||
|
||||
#### Tips & Tricks
|
||||
You can see a live example of this recipe in [this CodeSandbox][code-sandbox].
|
||||
|
||||
## Add Extensions
|
||||
|
||||
The UMD build of the OHIF Viewer is a "light weight" build that only contains
|
||||
the core extensions required for basic 2D image viewing. It's possible to add
|
||||
other extensions at runtime.
|
||||
|
||||
This only requires us to include a single script tag, and add it using the
|
||||
`extensions` key to our config. In this practical example, we register our
|
||||
popular whole slide microscopy extension:
|
||||
|
||||
```html
|
||||
<script
|
||||
src="https://unpkg.com/@ohif/extension-dicom-microscopy@0.50.5/dist/index.umd.js"
|
||||
crossorigin
|
||||
></script>
|
||||
|
||||
<!-- --->
|
||||
<script>
|
||||
window.config = {
|
||||
// ...
|
||||
extensions: [OHIFExtDicomMicroscopy],
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
You can see an example of a slide microscopy study in the viewer [with the
|
||||
extension enabled here][whole-slide-ext-demo] ([source code][ext-code-sandbox])
|
||||
and [without it here][whole-slide-base-demo] ([source code][code-sandbox]).
|
||||
|
||||
You can read more about extensions and how to create your own in our
|
||||
[extensions guide](/extensions/index.md).
|
||||
|
||||
#### FAQ
|
||||
|
||||
> I'm having trouble getting this to work. Where can I go for help?
|
||||
|
||||
@@ -89,16 +111,34 @@ First, check out this fully functional [CodeSandbox][code-sandbox] example. If
|
||||
you're still having trouble, feel free to search or GitHub issues. Can't find
|
||||
anything related your problem? Create a new one.
|
||||
|
||||
> When I include bootstrap, other styles on my page no longer work correctly.
|
||||
> What can I do?
|
||||
> My application's styles are impacting the OHIF Viewer's look and feel. What
|
||||
> can I do?
|
||||
|
||||
When we include `bootsrap` (and the other dependencies), they are added
|
||||
globally. This has the potential of causing conflicts with other scripts and
|
||||
styles on the page. To prevent this, `embed` the viewer in a new/empty web page.
|
||||
Have that working? Good. Now `embed` that new page using an
|
||||
When you include stylesheets and scripts, they are added globally. This has the
|
||||
potential of causing conflicts with other scripts and styles on the page. To
|
||||
prevent this, `embed` the viewer in a new/empty web page. Have that working?
|
||||
Good. Now `embed` that new page using an
|
||||
[`<iframe>` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe).
|
||||
|
||||
This should produce the expected result while also protecting your page from any
|
||||
globally defined styles/scripts.
|
||||
|
||||
[code-sandbox]: https://codesandbox.io/s/ohif-viewer-script-tag-usage-b3st9
|
||||
> We're trying to embed the OHIF Viewer into an existing React App, but seeing
|
||||
> react-dom and react conflicts. What can we do?
|
||||
|
||||
`installViewer` is a convenience method that pulls in some dependencies that may
|
||||
not be compatible with existing `react` apps. `@ohif/viewer` also exports `App`
|
||||
which is a react component that takes the `configuration` outlined above as
|
||||
props. You can use it as a reusable component, and to avoid `react` version
|
||||
conflict issues.
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[code-sandbox]: https://codesandbox.io/s/viewer-script-tag-tprch
|
||||
[whole-slide-base-demo]: https://tprch.csb.app/viewer/1.2.392.200140.2.1.1.1.2.799008771.2020.1519719354.757
|
||||
[ext-code-sandbox]: https://codesandbox.io/s/viewer-script-tag-microscopy-extension-44unk
|
||||
[whole-slide-ext-demo]: https://44unk.csb.app/viewer/1.2.392.200140.2.1.1.1.2.799008771.2448.1519719572.518
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -121,11 +121,7 @@ likely want to update:
|
||||
|
||||
#### OHIF Viewer
|
||||
|
||||
The OHIF Viewer's configuration is imported from a static `.js` file and made
|
||||
available globally at `window.config`. The configuration we use is set to a
|
||||
specific file when we build the viewer, and determined by the env variable:
|
||||
`APP_CONFIG`. You can see where we set its value in the `dockerfile` for this
|
||||
solution:
|
||||
The OHIF Viewer's configuration is imported from a static `.js` file. The configuration we use is set to a specific file when we build the viewer, and determined by the env variable: `APP_CONFIG`. You can see where we set its value in the `dockerfile` for this solution:
|
||||
|
||||
`ENV APP_CONFIG=config/docker_openresty-orthanc.js`
|
||||
|
||||
|
||||
@@ -122,11 +122,7 @@ likely want to update:
|
||||
|
||||
#### OHIF Viewer
|
||||
|
||||
The OHIF Viewer's configuration is imported from a static `.js` file and made
|
||||
available globally at `window.config`. The configuration we use is set to a
|
||||
specific file when we build the viewer, and determined by the env variable:
|
||||
`APP_CONFIG`. You can see where we set its value in the `dockerfile` for this
|
||||
solution:
|
||||
The OHIF Viewer's configuration is imported from a static `.js` file. The configuration we use is set to a specific file when we build the viewer, and determined by the env variable: `APP_CONFIG`. You can see where we set its value in the `dockerfile` for this solution:
|
||||
|
||||
`ENV APP_CONFIG=config/docker_openresty-orthanc-keycloak.js`
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
# Continous Integration (CI)
|
||||
|
||||
This repository uses `CircleCI` and `Netlify` for continous integration.
|
||||
|
||||
## Deploy Previews
|
||||
|
||||
[Netlify Deploy previews][deploy-previews] are generated for every pull request.
|
||||
They allow pull request authors and reviewers to "Preview" the OHIF Viewer as if
|
||||
the changes had been merged.
|
||||
|
||||
Deploy previews can be configured by modifying the `netlify.toml` file in the
|
||||
root of the repository. Some additional scripts/assets for netlify are included
|
||||
in the root `.netlify` directory.
|
||||
|
||||
## Workflows
|
||||
|
||||
[CircleCI Workflows][circleci-workflows] are a set of rules for defining a
|
||||
collection of jobs and their run order. They are self-documenting and their
|
||||
configuration can be found in our CircleCI configuration file:
|
||||
`.circleci/config.yml`.
|
||||
|
||||
### Workflow: PR_CHECKS
|
||||
|
||||
The PR_CHECKS workflow (Pull Request Checks) runs our automated unit and
|
||||
end-to-end tests for every code check-in. These tests must all pass before code
|
||||
can be merged to our `master` branch.
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/WORKFLOW_PR_CHECKS.png">
|
||||
<img src="/assets/img/WORKFLOW_PR_CHECKS.png" alt="workflow diagram" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>Workflow diagram for PR_CHECKS</i></div>
|
||||
</div>
|
||||
|
||||
### Workflow: PR_OPTIONAL_DOCKER_PUBLISH
|
||||
|
||||
The PR_OPTIONAL_DOCKER_PUBLISH workflow allows for "manual approval" to publish
|
||||
the pull request as a tagged docker image. This is helpful when changes need to
|
||||
be tested with the Google Adapter before merging to `master`.
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/WORKFLOW_PR_OPTIONAL_DOCKER_PUBLISH.png">
|
||||
<img src="/assets/img/WORKFLOW_PR_OPTIONAL_DOCKER_PUBLISH.png" alt="workflow diagram" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>Workflow diagram for PR_WORKFLOW_PR_OPTIONAL_DOCKER_PUBLISH</i></div>
|
||||
</div>
|
||||
|
||||
> NOTE: This workflow will fail unless it's for a branch on our `upstream`
|
||||
> repository. If you need this functionality, but the branch is from a fork,
|
||||
> merge the changes to a short-lived `feature/` branch on `upstream`
|
||||
|
||||
### Workflow: DEPLOY
|
||||
|
||||
The DEPLOY workflow deploys the OHIF Viewer when changes are merged to master.
|
||||
It uses the Netlify CLI to deploy assets created as part of the repository's PWA
|
||||
Build process (`yarn run build`). The workflow allows for "Manual Approval" to
|
||||
promote the build to `STAGING` and `PRODUCTION` environments.
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/WORKFLOW_DEPLOY.png">
|
||||
<img src="/assets/img/WORKFLOW_DEPLOY.png" alt="workflow diagram" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>Workflow diagram for WORKFLOW_DEPLOY</i></div>
|
||||
</div>
|
||||
|
||||
| Environment | Description | URL |
|
||||
| ----------- | ---------------------------------------------------------------------------------- | --------------------------------------------- |
|
||||
| Development | Always reflects latest changes on `master` branch. | [Netlify][netlify-dev] / [OHIF][ohif-dev] |
|
||||
| Staging | For manual testing before promotion to prod. Keeps development workflow unblocked. | [Netlify][netlify-stage] / [OHIF][ohif-stage] |
|
||||
| Production | Stable, tested, updated less frequently. | [Netlify][netlify-prod] / [OHIF][ohif-prod] |
|
||||
|
||||
### Workflow: RELEASE
|
||||
|
||||
The RELEASE workflow publishes our `npm` packages, updated documentation, and
|
||||
`docker` image when changes are merged to master. `Lerna` and "Semantic Commit
|
||||
Syntax" are used to independently version and publish the many packages in our
|
||||
monorepository. If a new version is cut/released, a Docker image is created.
|
||||
Documentation is generated with `gitbook` and pushed to our `gh-pages` branch.
|
||||
GitHub hosts the `gh-pages` branch with GitHub Pages.
|
||||
|
||||
- Platform Packages: https://github.com/ohif/viewers/#platform
|
||||
- Extension Packages: https://github.com/ohif/viewers/#extensions
|
||||
- Documentation: https://docs.ohif.org/
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/WORKFLOW_RELEASE.png">
|
||||
<img src="/assets/img/WORKFLOW_RELEASE.png" alt="workflow diagram" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>Workflow diagram for WORKFLOW_RELEASE</i></div>
|
||||
</div>
|
||||
|
||||
### HOTFIX
|
||||
|
||||
_Not yet implemented_
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[deploy-previews]: https://www.netlify.com/blog/2016/07/20/introducing-deploy-previews-in-netlify/
|
||||
[circleci-workflows]: https://circleci.com/docs/2.0/workflows/
|
||||
[netlify-dev]: https://ohif-dev.netlify.com
|
||||
[netlify-stage]: https://ohif-stage.netlify.com
|
||||
[netlify-prod]: https://ohif-prod.netlify.com
|
||||
[ohif-dev]: https://viewer-dev.ohif.org
|
||||
[ohif-stage]: https://viewer-stage.ohif.org
|
||||
[ohif-prod]: https://viewer-prod.ohif.org
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,146 @@
|
||||
# Contributing
|
||||
|
||||
## How can I help?
|
||||
|
||||
Fork the repository, make your change and submit a pull request. If you would
|
||||
like to discuss the changes you intend to make to clarify where or how they
|
||||
should be implemented, please don't hesitate to create a new issue. At a
|
||||
minimum, you may want to read the following documentation:
|
||||
|
||||
- [Getting Started](/development/getting-started.md)
|
||||
- [Architecture](/architecture/index.md)
|
||||
|
||||
Pull requests that are:
|
||||
|
||||
- Small
|
||||
- [Well tested](./testing.md)
|
||||
- Decoupled
|
||||
|
||||
Are much more likely to get reviewed and merged in a timely manner.
|
||||
|
||||
## When changes impact multiple repositories
|
||||
|
||||
While this can be tricky, we've tried to reduce how often this situation crops
|
||||
up this with our [recent switch to a monorepo][monorepo]. Our maintained
|
||||
extensions, ui components, internationalization library, and business logic can
|
||||
all be developed by simply running `yarn run dev` from the repository root.
|
||||
|
||||
Testing the viewer with locally developed, unpublished package changes from a
|
||||
package outside of the monorepo is most common with extension development. Let's
|
||||
demonstrate how to accomplish this with two commonly forked extension
|
||||
dependencies:
|
||||
|
||||
### `cornerstone-tools`
|
||||
|
||||
On your local file system:
|
||||
|
||||
```bash
|
||||
# code/my-projects/
|
||||
.
|
||||
├── cornerstonejs/cornerstone-tools
|
||||
└── ohif/viewers
|
||||
```
|
||||
|
||||
- Open a terminal/shell
|
||||
- Navigate to `cornerstonejs/cornerstone-tools`
|
||||
- `npm install`
|
||||
- [`yarn link`](https://yarnpkg.com/en/docs/cli/link)
|
||||
- `npm run dev`
|
||||
- Open a new terminal/shell
|
||||
- Navigate to `ohif/viewers`.
|
||||
- `yarn install`
|
||||
- [`yarn link cornerstone-tools`](https://yarnpkg.com/en/docs/cli/link)
|
||||
- `yarn run dev`
|
||||
|
||||
As you make changed to `cornerstone-tools`, and it's output is rebuilt, you
|
||||
should see the following behavior:
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/cornerstone-tools-link.gif">
|
||||
<img src="/assets/img/cornerstone-tools-link.gif" alt="Example of linked cornerstone-tools package" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>example of linked cornerstone-tools package</i></div>
|
||||
</div>
|
||||
|
||||
If you wish to stop using your local package, run the following commands in the
|
||||
`ohif/viewers` repository root:
|
||||
|
||||
- `yarn unlink cornerstone-tools`
|
||||
- `yarn install --force`
|
||||
|
||||
### `react-vtkjs-viewport`
|
||||
|
||||
On your local file system:
|
||||
|
||||
```bash
|
||||
# code/my-projects/
|
||||
.
|
||||
├── ohif/react-vtkjs-viewport
|
||||
└── ohif/viewers
|
||||
```
|
||||
|
||||
- Open a terminal/shell
|
||||
- Navigate to `ohif/react-vtkjs-viewport`
|
||||
- `yarn install`
|
||||
- [`yarn link`](https://yarnpkg.com/en/docs/cli/link)
|
||||
- `yarn run start`
|
||||
- Open a new terminal/shell
|
||||
- Navigate to `ohif/viewers`.
|
||||
- `yarn install`
|
||||
- [`yarn link react-vtkjs-viewport`](https://yarnpkg.com/en/docs/cli/link)
|
||||
- `yarn run dev`
|
||||
|
||||
#### Other linkage notes
|
||||
|
||||
We're still working out some of the kinks with local package development as
|
||||
there are a lot of factors that can influence the behavior of our development
|
||||
server and bundler. If you encounter issues not addressed here, please don't
|
||||
hesitate to reach out on GitHub.
|
||||
|
||||
## Any guidance on submitting changes?
|
||||
|
||||
While we do appreciate code contributions, triaging and integrating contributed
|
||||
code changes can be very time consuming. Please consider the following tips when
|
||||
working on your pull requests:
|
||||
|
||||
- Functionality is appropriate for the repository. Consider creating a GitHub
|
||||
issue to discuss your suggested changes.
|
||||
- The scope of the pull request is not too large. Please consider separate pull
|
||||
requests for each feature as big pull requests are very time consuming to
|
||||
understand.
|
||||
|
||||
We will provide feedback on your pull requests as soon as possible. Following
|
||||
the tips above will help ensure your changes are reviewed.
|
||||
|
||||
## Testing contribution pull requests
|
||||
|
||||
OHIF uses [netlify](netlify.com) so that pull requests are autogenerated and
|
||||
available for testing.
|
||||
|
||||
For example, [this url][example-url] allows you to test [pull request 237, the
|
||||
request that created this FAQ entry,][pr-237] using data pulled from Amazon S3.
|
||||
|
||||
Replacing the number 237 in the link below with your pull request number should
|
||||
let you test it as well and you can use this link for discussions on github
|
||||
without requiring reviewers to download and build your branch.
|
||||
|
||||
```bash
|
||||
https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
|
||||
```
|
||||
|
||||
If you have made a documentation change, a link like this will let you preview
|
||||
the gitbook generated by the pull request:
|
||||
|
||||
```bash
|
||||
https://deploy-preview-237--ohif.netlify.com/contributing.html
|
||||
```
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[example-url]: https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
|
||||
[pr-237]: https://github.com/OHIF/Viewers/pull/237
|
||||
[monorepo]: https://github.com/OHIF/Viewers/issues/768
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -24,8 +24,7 @@ graphic that illustrates this setup][triangular-workflow].
|
||||
Alternatively, if you intend to use the OHIF Viewer as a starting point, and you
|
||||
aren't as concerned with syncing updates, then follow these steps:
|
||||
|
||||
1. Navigate to the [OHIF/Viewers/tree/react][ohif-viewers-react-repo] repository
|
||||
and branch
|
||||
1. Navigate to the [OHIF/Viewers][ohif-viewers] repository
|
||||
2. Click `Clone or download`, and then `Download ZIP`
|
||||
3. Use the contents of the `.zip` file as a starting point for your viewer
|
||||
|
||||
@@ -39,6 +38,8 @@ aren't as concerned with syncing updates, then follow these steps:
|
||||
|
||||
- [Node.js & NPM](https://nodejs.org/en/)
|
||||
- [Yarn](https://yarnpkg.com/en/)
|
||||
- Yarn workspaces should be enabled:
|
||||
- `yarn config set workspaces-experimental true`
|
||||
|
||||
### Kick the tires
|
||||
|
||||
@@ -50,21 +51,18 @@ following commands:
|
||||
yarn install
|
||||
|
||||
# Start local development server
|
||||
yarn start
|
||||
yarn run dev
|
||||
```
|
||||
|
||||
You should see the following output:
|
||||
|
||||
```bash
|
||||
Compiled successfully!
|
||||
@ohif/viewer: i 「wds」: Project is running at http://localhost:3000/
|
||||
@ohif/viewer: i 「wds」: webpack output is served from /
|
||||
@ohif/viewer: i 「wds」: Content not from webpack is served from D:\code\ohif\Viewers\platform\viewer
|
||||
@ohif/viewer: i 「wds」: 404s will fallback to /index.html
|
||||
|
||||
You can now view ohif-viewer in the browser.
|
||||
|
||||
Local: http://localhost:3000/
|
||||
On Your Network: http://10.74.20.83:3000/
|
||||
|
||||
Note that the development build is not optimized.
|
||||
To create a production build, use yarn build.
|
||||
# And a list of all generated files
|
||||
```
|
||||
|
||||
### 🎉 Celebrate 🎉
|
||||
@@ -81,24 +79,18 @@ To create a production build, use yarn build.
|
||||
|
||||
```bash
|
||||
# Build static assets to host a PWA
|
||||
yarn run build:web
|
||||
yarn run build
|
||||
|
||||
# Build packaged output
|
||||
# Build packaged output (script-tag use)
|
||||
yarn run build:package
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
...
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If you receive a _"No Studies Found"_ message and do not see your studies, try
|
||||
changing the Study Date filters to a wider range.
|
||||
- If you see a 'Loading' message which never resolves, check your browser
|
||||
JavaScript console inside the Developer Tools to identify any errors.
|
||||
- If you see any errors in your server console, check the
|
||||
[Troubleshooting](./troubleshooting.md) page for more in depth advice.
|
||||
|
||||
<!--
|
||||
Links
|
||||
@@ -111,5 +103,5 @@ yarn run build:package
|
||||
[sync-changes]: https://help.github.com/en/articles/syncing-a-fork
|
||||
[triangular-workflow]: https://github.blog/2015-07-29-git-2-5-including-multiple-worktrees-and-triangular-workflows/#improved-support-for-triangular-workflows
|
||||
[ohif-viewers-repo]: https://github.com/OHIF/Viewers
|
||||
[ohif-viewers-react-repo]: https://github.com/OHIF/Viewers/tree/react
|
||||
[ohif-viewers]: https://github.com/OHIF/Viewers
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -1,56 +0,0 @@
|
||||
# Configuration
|
||||
|
||||
> This step assumes you have an imaging archive. If you need assistance setting
|
||||
> one up, check out the [`Data Source` Guide](./data-source.md) or a deployment
|
||||
> recipe that contains an open source Image Archive
|
||||
|
||||
## How it Works
|
||||
|
||||
The configuration for our project is in the `/public/config` directory. Our
|
||||
build process knows which configuration file to use based on the `APP_CONFIG`
|
||||
environment variable. By default, its value is
|
||||
[`default.js`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js).
|
||||
When we build, the `%APP_CONFIG%` value in
|
||||
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/index.html)
|
||||
file is substituted for the correct configuration file's name. This sets the
|
||||
`window.config` equal to our configuration file's value.
|
||||
|
||||
## How do I configure my project?
|
||||
|
||||
The simplest way is to update the existing default config:
|
||||
|
||||
_/public/config/default.js_
|
||||
|
||||
```js
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: 'DCM4CHEE',
|
||||
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
|
||||
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
qidoSupportsIncludeField: true,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
requestOptions: {
|
||||
requestFromBrowser: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
You can also create a new config file and specify its path relative to the build
|
||||
output's root by setting the `APP_CONFIG` environment variable. You can set the
|
||||
value of this environment variable a few different ways:
|
||||
|
||||
- [Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)
|
||||
- [Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)
|
||||
- Using the `cross-env` package in an npm script:
|
||||
- `"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"`
|
||||
|
||||
After updating the configuration, `yarn run build:web` to generate updated build
|
||||
output.
|
||||
@@ -1,42 +0,0 @@
|
||||
# Installation
|
||||
|
||||
It's important to know that the OHIF Viewer project provides two different build
|
||||
processes:
|
||||
|
||||
```bash
|
||||
# Static Asset output: For deploying PWAs
|
||||
yarn run build:web
|
||||
|
||||
# Single `.js` script, for embedding viewer into existing apps
|
||||
yarn run build:package
|
||||
```
|
||||
|
||||
## create-react-app (PWA)
|
||||
|
||||
> [create-react-app](https://github.com/facebook/create-react-app) provides
|
||||
> pre-configured build process for developing front-end applications with
|
||||
> [React](https://reactjs.org/).
|
||||
|
||||
The ohif-viewer package can be run as a create-react-app application. This is
|
||||
useful for development, debugging, or evolving the OHIF Viewer into your own
|
||||
custom imaging application.
|
||||
|
||||
You can read more about this particular strategy in our
|
||||
[Build for Production Deployment Guide](./../deployment/recipes/build-for-production.md)
|
||||
|
||||
## Rollup (Packaged Script)
|
||||
|
||||
> [Rollup](https://rollupjs.org/guide/en) is a module bundler for JavaScript. It
|
||||
> uses the new standardized format for code modules included in the ES6 revision
|
||||
> of JavaScript.
|
||||
|
||||
The [ohif-viewer](https://www.npmjs.com/package/ohif-viewer) package can be
|
||||
built with Rollup to provide a set of React components which can be dropped into
|
||||
a larger application. Specifically, the ohif-viewer package provides a React
|
||||
component named `OHIFViewer` which is the entire viewer, configurable via React
|
||||
`props`. This is useful for including the OHIF Viewer in a larger web
|
||||
application, as the entire application can be provided via a `<script>` tag with
|
||||
no build process required.
|
||||
|
||||
You can read more about this particular strategy in our
|
||||
[Embedded Viewer Deployment Guide](./../deployment/recipes/embedded-viewer.md)
|
||||
@@ -1,20 +0,0 @@
|
||||
# Troubleshooting
|
||||
|
||||
Common GitHub issues that are not easily remedied with cleaner code or
|
||||
documentation will be recorded here. Please feel free to make PRs to update this
|
||||
page.
|
||||
|
||||
## Common Problems
|
||||
|
||||
| Problem | Most Common Reasons |
|
||||
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ** Can't retrieve Study List over DICOMWeb** | 1. QIDO root URL is incorrect<br> 2. DICOM Web is not enabled on PACS |
|
||||
| ** Can't retrieve images** | 1. WADO Root URL is incorrect<br> 2. DICOM Web is not enabled on PACS<br> 3. HTTP Basic Authentication username and password are incorrect or not provided. |
|
||||
|
||||
## Debugging Steps
|
||||
|
||||
### Can't retrieve Study List over DICOMWeb
|
||||
|
||||
1. Check that you can query your PACS using an alternative DICOM Web client
|
||||
(e.g. cURL, or a Web Browser). If you cannot, then your PACS is configured
|
||||
incorrectly. Refer to the documentation of the image archive.
|
||||
@@ -0,0 +1,237 @@
|
||||
# Extensions
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Concepts](#concepts)
|
||||
- [Extension Skeleton](#extension-skeleton)
|
||||
- [Registering an Extension](#registering-an-extension)
|
||||
- [Lifecylce Hooks](#lifecycle-hooks)
|
||||
- [Modules](#modules)
|
||||
- [Contexts](#contexts)
|
||||
- [Consuming Extensions](#consuming-extensions)
|
||||
- [Extension Manager](#extensionmanager)
|
||||
- [Maintained Extensions](#maintained-extensions)
|
||||
|
||||
## Overview
|
||||
|
||||
We use extensions to help us isolate and package groups of related features.
|
||||
Extensions provide functionality, ui components, and new behaviors. Ideally,
|
||||
they're built in a way that allows them to extend entirely different
|
||||
implementations of the `@ohif/viewer` project.
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/extensions-diagram.png">
|
||||
<img src="/assets/img/extensions-diagram.png" alt="Extensions Diagram" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>Diagram showing how extensions are configured and accessed.</i></div>
|
||||
</div>
|
||||
|
||||
The `@ohif/viewer`'s application level configuration gives us the ability to add
|
||||
and configure extensions. When the application starts, extensions are registered
|
||||
with the `ExtensionManager`. Different portions of the `@ohif/viewer` project
|
||||
will use registered extensions to influence application behavior.
|
||||
|
||||
Extensions allow us to:
|
||||
|
||||
- Wrap and integrate functionality of 3rd party dependencies in a reusable way
|
||||
- Change how application data is mapped and transformed
|
||||
- Display a consistent/cohesive UI
|
||||
- Inject custom components to override built-in components
|
||||
|
||||
Practical examples of extensions include:
|
||||
|
||||
- A set of segmentation tools that build on top of the `cornerstone` viewport
|
||||
- Showing ML/AI report summaries for the selected study/series/image
|
||||
- Support for parsing DICOM structured reports and displaying them in a user
|
||||
friendly way
|
||||
- [See our maintained extensions for more examples of what's possible](#maintained-extensions)
|
||||
|
||||
## Concepts
|
||||
|
||||
### Extension Skeleton
|
||||
|
||||
An extension is a plain JavaScript object that has an `id` property, and one or
|
||||
more [modules](#modules) and/or [lifecycle hooks](#lifecycle-hooks).
|
||||
|
||||
```js
|
||||
// prettier-ignore
|
||||
export default {
|
||||
/**
|
||||
* Only required property. Should be a unique value across all extensions.
|
||||
*/
|
||||
id: 'example-extension',
|
||||
|
||||
// Lifecyle
|
||||
preRegistration() { /* */ },
|
||||
// Modules
|
||||
getCommandsModule() { /* */ },
|
||||
getToolbarModule() { /* */ },
|
||||
getPanelModule() { /* */ },
|
||||
getSopClassHandler() { /* */ },
|
||||
getViewportModule() { /* */ },
|
||||
}
|
||||
```
|
||||
|
||||
### Registering an Extension
|
||||
|
||||
There are two different ways to register and configure extensions: At
|
||||
[runtime](#runtime-extensions) and at [build time](#bundled-extensions).
|
||||
|
||||
You can leverage one or both strategies. Which one(s) you choose depend on your
|
||||
application's requirements. Each [module](#modules) defined by the extension
|
||||
becomes available to the core application via the `ExtensionManager`.
|
||||
|
||||
#### Registering at Runtime
|
||||
|
||||
The `@ohif/viewer` uses a [configuration file](#) at startup. The schema for
|
||||
that file includes an `Extensions` key that supports an array of extensions to
|
||||
register.
|
||||
|
||||
```js
|
||||
// prettier-ignore
|
||||
const config = {
|
||||
extensions: [
|
||||
MyFirstExtension,
|
||||
[
|
||||
MySecondExtension,
|
||||
{ /* MySecondExtensions Configuration */ },
|
||||
],
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
#### Registering at Build Time
|
||||
|
||||
The `@ohif/viewer` works best when built as a "Progressive Web Application"
|
||||
(PWA). If you know the extensions your application will need, you can specify
|
||||
them at "build time" to leverage advantages afforded to us by modern tooling:
|
||||
|
||||
- Code Splitting (dynamic imports)
|
||||
- Tree Shaking
|
||||
- Dependency deduplication
|
||||
|
||||
You can update the list of bundled extensions by:
|
||||
|
||||
1. Having your `@ohif/viewer` project depend on the extension
|
||||
2. Importing and adding it to the list of extensions in the
|
||||
`<repo-root>/platform/src/index.js` entrypoint.
|
||||
|
||||
### Lifecycle Hooks
|
||||
|
||||
Currently, there is only a single lifecycle hook for extensions:
|
||||
[`preRegistration`](./lifecycle/pre-registration.md)
|
||||
|
||||
If an extension defines the [`preRegistration`](./lifecycle/pre-registration.md)
|
||||
lifecycle hook, it is called before any modules are registered in the
|
||||
`ExtensionManager`. It's most commonly used to wire up extensions to
|
||||
[services](./../services/index.md) and [commands](./modules/commands.md), and to
|
||||
bootstrap 3rd party libraries.
|
||||
|
||||
### Modules
|
||||
|
||||
Modules are the meat of extensions. They provide "definitions", components, and
|
||||
filtering/mapping logic that are then made available by various managers and
|
||||
services.
|
||||
|
||||
Each module type has a special purpose, and is consumed by our viewer
|
||||
differently.
|
||||
|
||||
| Type | Description | Examples |
|
||||
| ------------------------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------- |
|
||||
| [Commands](./modules/commands.md) | Adds named commands, scoped to a context, to the CommandsManager | `setToolActive()`, `nextSeries()` |
|
||||
| [Panel](./modules/panel.md) | Adds left or right hand side panels | `<ThumbnailList />`, `<MeasurementsTable />` |
|
||||
| [SOPClassHandler](./modules/sop-class-handler.md) | Determines how retrieved study data is split into "DisplaySets" | `getDisplaySetFromSeries()` |
|
||||
| [Toolbar](./modules/toolbar.md) | Adds buttons or custom components to the toolbar | Toolbar button, nested buttons, custom |
|
||||
| [Viewport](./modules/viewport.md) | Adds a component responsible for rendering a "DisplaySet" | `<CornerstoneViewport />`, `<DicomPdfViewport />` |
|
||||
|
||||
<figure style="text-align: center; font-style: italic;">Tbl. Module types with abridged descriptions and examples. Each module links to a dedicated documentation page.</figure>
|
||||
|
||||
### Contexts
|
||||
|
||||
The `@ohif/viewer` tracks "active contexts" that extensions can use to scope
|
||||
their functionality. Some example contexts being:
|
||||
|
||||
- Route: `ROUTE:VIEWER`, `ROUTE:STUDY_LIST`
|
||||
- Active Viewport: `ACTIVE_VIEWPORT:CORNERSTONE`, `ACTIVE_VIEWPORT:VTK`
|
||||
|
||||
An extension module can use these to say "Only show this Toolbar Button if the
|
||||
active viewport is a Cornerstone viewport." This helps us use the appropriate UI
|
||||
and behaviors depending on the current contexts.
|
||||
|
||||
For example, if we have hotkey that "rotates the active viewport", each Viewport
|
||||
module that supports this behavior can add a command with the same name, scoped
|
||||
to the appropriate context. When the `command` is fired, the "active contexts"
|
||||
are used to determine the appropriate implementation of the rotate behavior.
|
||||
|
||||
## Consuming Extensions
|
||||
|
||||
We consume extensions, via the `ExtensionManager`, in our `@ohif/viewer`
|
||||
project.
|
||||
|
||||
```js
|
||||
const extensionManager = new ExtensionManager({
|
||||
commandsManager,
|
||||
servicesManager,
|
||||
});
|
||||
|
||||
// prettier-ignore
|
||||
extensionManager.registerExtensions([ /** **/ ]);
|
||||
```
|
||||
|
||||
The `@ohif/viewer` project handles data fetching, basic routing, wires up UI
|
||||
services, and is the home to the more bespoke application logic that doesn't
|
||||
make as much sense to make reusable.
|
||||
|
||||
Long-term, replacing the `@ohif/viewer` application and consuming extensions
|
||||
(and the `ExtensionManager`) in your own project is the ideal path for
|
||||
applications requiring a high degree of customization that can't be achieved
|
||||
with current theming, configuration, extension, and services support.
|
||||
|
||||
If you're not sure how to achieve your goals with the extensibility available
|
||||
today, create a GitHub issue!
|
||||
|
||||
### `ExtensionManager`
|
||||
|
||||
The `ExtensionManager` is a class made available to us via the `@ohif/core`
|
||||
project (platform/core). Our application instantiates a single instance of it,
|
||||
and provides a `ServicesManager` and `CommandsManager` along with the application's
|
||||
configuration through the appConfig key (optional).
|
||||
|
||||
```js
|
||||
const commandsManager = new CommandsManager();
|
||||
const servicesManager = new ServicesManager();
|
||||
const extensionManager = new ExtensionManager({
|
||||
commandsManager,
|
||||
servicesManager,
|
||||
appConfig
|
||||
});
|
||||
```
|
||||
|
||||
The `ExtensionManager` only has a few public members:
|
||||
|
||||
- `registerExtension` - Registers a single extension
|
||||
- `registerExtensions` - Registers an array of extensions
|
||||
- `modules` - An object containing registered extensions by `MODULE_TYPE`
|
||||
|
||||
During registration, lifecycle hooks and modules have access to the extension's config,
|
||||
the application's config and `ExtensionManager`'s `ServicesManager` and `CommandsManager` instances.
|
||||
|
||||
Our `@ohif/viewer` uses the `modules` member to access registered extensions at
|
||||
appropriate places in our application.
|
||||
|
||||
## Maintained Extensions
|
||||
|
||||
A small number of powerful extensions for popular use cases are maintained by
|
||||
OHIF. They're co-located in the [`OHIF/Viewers`][viewers-repo] repository, in
|
||||
the top level [`extensions/`][ext-source] directory.
|
||||
|
||||
{% include "./_maintained-extensions-table.md" %}
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[viewers-repo]: https://github.com/OHIF/Viewers
|
||||
[ext-source]: https://github.com/OHIF/Viewers/tree/master/extensions
|
||||
[module-types]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/extensions/MODULE_TYPES.js
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,40 @@
|
||||
# Lifecylce Hook: preRegistration
|
||||
|
||||
If an extension defines the `preRegistration` lifecycle hook, it is called
|
||||
before any modules are registered in the `ExtensionManager`. This hook can be
|
||||
used to:
|
||||
|
||||
- initialize 3rd party libraries
|
||||
- register event listeners
|
||||
- add or call services
|
||||
- add or call commands
|
||||
|
||||
The `preRegistration` hook receives an object containing the
|
||||
`ExtensionManager`'s associated `ServicesManager`, `CommandsManager`, and any
|
||||
`configuration` that was provided with the extension at time of registration.
|
||||
|
||||
_Example `preRegistration` hook implementation_
|
||||
|
||||
```js
|
||||
export default {
|
||||
id: 'MyExampleExtension',
|
||||
|
||||
/**
|
||||
* @param {object} params
|
||||
* @param {object} params.configuration
|
||||
* @param {ServicesManager} params.servicesManager
|
||||
* @param {CommandsManager} params.commandsManager
|
||||
* @returns void
|
||||
*/
|
||||
preRegistration({ servicesManager, commandsManager, configuration }) {
|
||||
console.log('Wiring up important stuff.');
|
||||
|
||||
window.importantStuff = () => {
|
||||
console.log(configuration);
|
||||
};
|
||||
|
||||
console.log('Important stuff has been wired.');
|
||||
window.importantStuff();
|
||||
},
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,158 @@
|
||||
# Module: Commands
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Command Definitions](#command-definitions)
|
||||
- [Commands Manager](#commands-manager)
|
||||
- [Instantiating](#instatiating)
|
||||
- [Public API](#public-api)
|
||||
- [Contexts](#contexts)
|
||||
|
||||
## Overview
|
||||
|
||||
An extension can register a Commands Module by defining a `getCommandsModule`
|
||||
method. The Commands Module allows us to register one or more commands scoped to
|
||||
specific [contexts](./../index.md#contexts). Commands have several unique
|
||||
characteristics that make them tremendously powerful:
|
||||
|
||||
- Multiple implementations for the same command can be defined
|
||||
- Only the correct command's implementation will be run, dependent on the
|
||||
application's "context"
|
||||
- Commands can be called from extensions, modules, and the consuming application
|
||||
|
||||
Here is a simple example commands module:
|
||||
|
||||
```js
|
||||
export default {
|
||||
id: 'example-commands-module',
|
||||
|
||||
/**
|
||||
* @param {object} params
|
||||
* @param {ServicesManager} params.servicesManager
|
||||
* @param {CommandsManager} params.commandsManager
|
||||
*/
|
||||
getCommandsModule({ servicesManager, commandsManager }) {
|
||||
return {
|
||||
definitions: {
|
||||
sayHello: {
|
||||
commandFn: ({ words }) => {
|
||||
console.log(words);
|
||||
},
|
||||
options: { words: 'Hello!' },
|
||||
},
|
||||
},
|
||||
defaultContext: 'VIEWER',
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Each definition returned by the Commands Module is registered to the
|
||||
`ExtensionManager`'s `CommandsManager`.
|
||||
|
||||
## Command Definitions
|
||||
|
||||
The command definition consists of a named command (`myCommandName` below) and a
|
||||
`commandFn`. The command name is used to call the command, and the `commandFn`
|
||||
is the "command" that is actioned.
|
||||
|
||||
```js
|
||||
myCommandName: {
|
||||
commandFn: ({ viewports, other, options }) => { },
|
||||
storeContexts: ['viewports'],
|
||||
options: { words: 'Just kidding! Goodbye!' },
|
||||
context: 'ACTIVE_VIEWPORT::CORNERSTONE',
|
||||
}
|
||||
```
|
||||
|
||||
| Property | Type | Description |
|
||||
| --------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `commandFn` | func | The function to call when command is run. Receives `options` and `storeContexts`. |
|
||||
| `storeContexts` | string[] | (optional) Expected state objects to be passed in as props. Located using `getAppState` fn defined at `CommandsManager`'s instatiation. |
|
||||
| `options` | object | (optional) Arguments to pass at the time of calling to the `commandFn` |
|
||||
| `context` | string[] or string | (optional) Overrides the `defaultContext`. Let's us know if command is currently "available" to be run. |
|
||||
|
||||
## Command Behavior
|
||||
|
||||
**I have many similar commands. How can I share their `commandFn` and make it
|
||||
reusable?**
|
||||
|
||||
This is where `storeContexts` and `options` come in. We use these in our
|
||||
`setToolActive` command. `storeContexts` helps us identify our `activeViewport`,
|
||||
and `options` allow us to pass in the name of a tool we would like to set as
|
||||
active.
|
||||
|
||||
**If there are multiple valid commands for the application's active contexts**
|
||||
|
||||
- What happens: all commands are run
|
||||
- When to use: A `clearData` command that cleans up state for multiple
|
||||
extensions
|
||||
|
||||
**If no commands are valid for the application's active contexts**
|
||||
|
||||
- What happens: a warning is printed to the console
|
||||
- When to use: a `hotkey` (like "invert") that doesn't make sense for the
|
||||
current viewport (PDF or HTML)
|
||||
|
||||
## `CommandsManager`
|
||||
|
||||
The `CommandsManager` is a class defined in the `@ohif/core` project. A single
|
||||
instance of it should be defined in the consuming application, and it should be
|
||||
used when constructing the `ExtensionManager`.
|
||||
|
||||
### Instantiating
|
||||
|
||||
When we instantiate the `CommandsManager`, we need to pass it two methods:
|
||||
|
||||
- `getAppState` - Should return the application's state when called
|
||||
- `getActiveContexts` - Should return the application's active contexts when
|
||||
called
|
||||
|
||||
These methods are used internally to help determine which commands are currently
|
||||
valid, and how to provide them with any state they may need at the time they are
|
||||
called.
|
||||
|
||||
```js
|
||||
const commandsManager = new CommandsManager({
|
||||
getAppState,
|
||||
getActiveContexts,
|
||||
});
|
||||
```
|
||||
|
||||
### Public API
|
||||
|
||||
If you would like to run a command in the consuming app or an extension, you can
|
||||
use one of the following methods:
|
||||
|
||||
```js
|
||||
// Returns all commands for a given context
|
||||
commandsManager.getContext('string');
|
||||
|
||||
// Attempts to run a command
|
||||
commandsManager.runCommand('speak', { command: 'hello' });
|
||||
|
||||
// Run command, but override the active contexts
|
||||
commandsManager.runCommand('speak', { command: 'hello' }, ['VIEWER']);
|
||||
```
|
||||
|
||||
The `ExtensionManager` handles registering commands and creating contexts, so
|
||||
most consumer's won't need these methods. If you find yourself using these, ask
|
||||
yourself "why can't I register these commands via an extension?"
|
||||
|
||||
```js
|
||||
// Used by the `ExtensionManager` to register new commands
|
||||
commandsManager.registerCommand('context', 'name', commandDefinition);
|
||||
|
||||
// Creates a new context; clears the context if it already exists
|
||||
commandsManager.createContext('string');
|
||||
```
|
||||
|
||||
### Contexts
|
||||
|
||||
It is up to the consuming application to define what contexts are possible, and
|
||||
which ones are currently active. As extensions depend heavily on these, we will
|
||||
likely publish guidance around creating contexts, and ways to override extension
|
||||
defined contexts in the near future. If you would like to discuss potential
|
||||
changes to how contexts work, please don't hesistate to createa new GitHub
|
||||
issue.
|
||||
|
||||
[Some additional information on Contexts can be found here.](./../index.md#contexts)
|
||||
@@ -0,0 +1,57 @@
|
||||
# Module: Panel
|
||||
|
||||
An extension can register a Panel Module by defining a `getPanelModule` method.
|
||||
The panel module provides the ability to define `menuOptions` and `components`
|
||||
that can be used by the consuming application. `components` are React Components
|
||||
that can be displayed in the consuming application's "Panel" Component.
|
||||
|
||||

|
||||
|
||||
<center><i>A panel extension example</i></center>
|
||||
|
||||
The `menuOptions`'s `target` key points to a registered `components`'s `id`. A
|
||||
`defaultContext` is applied to all `menuOption`s; however, each `menuOption` can
|
||||
optional provide it's own `context` value.
|
||||
|
||||
The `getPanelModule` receives an object containing the `ExtensionManager`'s
|
||||
associated `ServicesManager` and `CommandsManager`.
|
||||
|
||||
```js
|
||||
import MyComponent from './MyComponent.js';
|
||||
|
||||
export default {
|
||||
id: 'example-panel-module',
|
||||
|
||||
/**
|
||||
* @param {object} params
|
||||
* @param {ServicesManager} params.servicesManager
|
||||
* @param {CommandsManager} params.commandsManager
|
||||
*/
|
||||
getPanelModule({ servicesManager, commandsManager }) {
|
||||
return {
|
||||
menuOptions: [
|
||||
{
|
||||
// A suggested icon
|
||||
// Available icons determined by consuming app
|
||||
icon: 'list',
|
||||
// A suggested label
|
||||
label: 'Magic',
|
||||
// 'right' or 'left'
|
||||
from: 'right',
|
||||
// The target component to toggle open/close
|
||||
target: 'target-component-id',
|
||||
// Overrides `defaultContext`, if specified
|
||||
context: ['ACTIVE_VIEWPORT:MAGIC'],
|
||||
},
|
||||
],
|
||||
components: [
|
||||
{
|
||||
id: 'target-component-id',
|
||||
component: MyComponent,
|
||||
},
|
||||
],
|
||||
defaultContext: ['ROUTE:VIEWER'],
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,90 @@
|
||||
# Module: SOP Class Handler
|
||||
|
||||
An extension can register a SOP Class Handler Module by defining a
|
||||
`getSopClassHandlerModule` method. The SOP Class Handler is a bit different from
|
||||
the other modules, as it doesn't provide a `1:1` schema for UI or provide it's
|
||||
own components. It instead defines:
|
||||
|
||||
- `sopClassUids`: an array of string SOP Class UIDs that the
|
||||
`getDisplaySetFromSeries` method should be applied to.
|
||||
- `getDisplaySetFromSeries`: a method that maps series and study metadata to a
|
||||
display set
|
||||
|
||||
A `displaySet` has the following shape:
|
||||
|
||||
```js
|
||||
return {
|
||||
plugin: 'html',
|
||||
modality: 'SR',
|
||||
displaySetInstanceUid: 0,
|
||||
wadoRoot: study.getData().wadoRoot,
|
||||
wadoUri: instance.getData().wadouri,
|
||||
sopInstanceUid: instance.getSOPInstanceUID(),
|
||||
seriesInstanceUid: series.getSeriesInstanceUID(),
|
||||
studyInstanceUid: study.getStudyInstanceUID(),
|
||||
authorizationHeaders,
|
||||
};
|
||||
```
|
||||
|
||||
Where the `plugin` key is used to influence the default `ViewportComponent` for
|
||||
rendering the `displaySet`. Additional properties are passed to the
|
||||
`ViewportComponent` and used by the default `StudyBrowser` to render
|
||||
"thumbnails" for each `displaySet`
|
||||
|
||||
## Example SOP Class Handler Module
|
||||
|
||||
```js
|
||||
const SOP_CLASS_UIDS = {
|
||||
BASIC_TEXT_SR: '1.2.840.10008.5.1.4.1.1.88.11',
|
||||
ENHANCED_SR: '1.2.840.10008.5.1.4.1.1.88.22',
|
||||
};
|
||||
|
||||
export default {
|
||||
id: 'example-sop-class-handler-module',
|
||||
|
||||
/**
|
||||
* @param {object} params
|
||||
* @param {ServicesManager} params.servicesManager
|
||||
* @param {CommandsManager} params.commandsManager
|
||||
*/
|
||||
getSopClassHandlerModule({ servicesManager, commandsManager }) {
|
||||
return {
|
||||
id: 'OHIFDicomHtmlSopClassHandler',
|
||||
sopClassUids: Object.values(SOP_CLASS_UIDS),
|
||||
|
||||
/**
|
||||
* @param {object} series -
|
||||
* @param {object} study -
|
||||
* @param {object} dicomWebClient -
|
||||
* @param {object} authorizationHeaders -
|
||||
*/
|
||||
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
|
||||
const instance = series.getFirstInstance();
|
||||
|
||||
return {
|
||||
plugin: 'html',
|
||||
displaySetInstanceUid: 0,
|
||||
wadoRoot: study.getData().wadoRoot,
|
||||
wadoUri: instance.getData().wadouri,
|
||||
sopInstanceUid: instance.getSOPInstanceUID(),
|
||||
seriesInstanceUid: series.getSeriesInstanceUID(),
|
||||
studyInstanceUid: study.getStudyInstanceUID(),
|
||||
authorizationHeaders,
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## `@ohif/viewer` usage
|
||||
|
||||
We use the `sopClassHandlerModule`s in three different places:
|
||||
|
||||
- `ViewerLocalFileData.js`
|
||||
- `ViewerRetrieveStudyData.js`
|
||||
- `StandaloneRouting.js`
|
||||
|
||||
Each time, it is used to map study and series data to `displaySets`. It does
|
||||
this by working alongside the `StudyMetadataManager` in `@ohif/core`. That
|
||||
manager has the method `createDisplaySets` that takes an array of
|
||||
`sopClassHandlerModules`.
|
||||
@@ -0,0 +1,130 @@
|
||||
# Module: Toolbar
|
||||
|
||||
An extension can register a Toolbar Module by defining a `getToolbarModule`
|
||||
method. This module is commonly used to define:
|
||||
|
||||
- [Toolbar buttons](#button-definitions)
|
||||
- [Nested toolbar menus](#nested-toolbar-menus)
|
||||
- [Custom components](#custom-components)
|
||||
|
||||

|
||||
|
||||
<center><i>Example toolbar button using the Dialog Service to show CINE controls.</i></center>
|
||||
|
||||
## Example Toolbar Module
|
||||
|
||||
The Toolbar Module should return an array of `definitions` and a
|
||||
`defaultContext`. There are currently a few different variations of definitions,
|
||||
each one is detailed further down.
|
||||
|
||||
```js
|
||||
export default {
|
||||
id: 'example-toolbar-module',
|
||||
|
||||
/**
|
||||
* @param {object} params
|
||||
* @param {ServicesManager} params.servicesManager
|
||||
* @param {CommandsManager} params.commandsManager
|
||||
*/
|
||||
getToolbarModule({ servicesManager, commandsManager }) {
|
||||
return {
|
||||
definitions: [
|
||||
/* Array of definitions */
|
||||
],
|
||||
defaultContext: ['ROUTE:VIEWER'],
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Button Definitions
|
||||
|
||||
The simplest definition has the following properties:
|
||||
|
||||
```js
|
||||
{
|
||||
id: 'StackScroll',
|
||||
label: 'Stack Scroll',
|
||||
icon: 'bars',
|
||||
type: 'setToolActive',
|
||||
commandName: 'setToolActive',
|
||||
commandOptions: { toolName: 'StackScroll' },
|
||||
},
|
||||
```
|
||||
|
||||
| property | description | values |
|
||||
| ---------------- | ----------------------------------------------------------------- | ----------------------------------------- |
|
||||
| `id` | Unique string identifier for the definition | \* |
|
||||
| `label` | User/display friendly to show in UI | \* |
|
||||
| `icon` | A string name for an icon supported by the consuming application. | \* |
|
||||
| `type` | Used to determine the button's component and behavior | `"setToolActive"`, `"command"` |
|
||||
| `commandName` | (optional) The command to run when the button is used. | Any command registed by a `CommandModule` |
|
||||
| `commandOptions` | (optional) Options to pass the target `commandName` | \* |
|
||||
| `context` | (optional) Overrides module's `defaultContext` | Array of string context names |
|
||||
|
||||
Where a button with a `type` of `setToolActive` has an "active" styling applied
|
||||
when clicked; removing the active styling from all other buttons.
|
||||
|
||||
## Nested Toolbar Menus
|
||||
|
||||
You can indicate that buttons should be grouped and nested in a submenu by
|
||||
including `buttons` property in a definition:
|
||||
|
||||
```js
|
||||
{
|
||||
id: 'More',
|
||||
label: 'More',
|
||||
icon: 'ellipse-circle',
|
||||
buttons: [
|
||||
{
|
||||
id: 'cstInvert',
|
||||
label: 'Invert',
|
||||
icon: 'circle',
|
||||
type: 'command',
|
||||
commandName: 'invertViewport',
|
||||
},
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||

|
||||
|
||||
<center><i>Example toolbar button demonstrating nested buttons.</i></center>
|
||||
|
||||
## Custom Components
|
||||
|
||||
The Toolbar Modules supports rendering custom components in place of the
|
||||
application's default. In place of the `type`, `commandName`, and
|
||||
`commandOptions` properties, we instead specify a `CustomComponent`.
|
||||
|
||||
```js
|
||||
{
|
||||
id: 'Custom',
|
||||
label: 'Custom',
|
||||
icon: 'custom-icon',
|
||||
CustomComponent: CustomToolbarComponent,
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The `CustomComponent` components will receive the following props:
|
||||
|
||||
```html
|
||||
<CustomComponent
|
||||
parentContext="{parentContext}"
|
||||
toolbarClickCallback="{_handleToolbarButtonClick.bind(this)}"
|
||||
button="{button}"
|
||||
key="{button.id}"
|
||||
activeButtons="{activeButtonsIds}"
|
||||
isActive="{isActive}"
|
||||
/>
|
||||
```
|
||||
|
||||
| Property | Type | Description |
|
||||
| ---------------------- | -------- | ------------------------------- |
|
||||
| `activeButtons` | string[] | list of active buttons |
|
||||
| `button` | object | its own definition object |
|
||||
| `key` | string | React key prop |
|
||||
| `isActive` | boolean | If current button is active |
|
||||
| `parentContext` | ? | The parent component's context? |
|
||||
| `toolbarClickCallback` | func | Callback method for clicks |
|
||||
@@ -0,0 +1,46 @@
|
||||
# Module: Viewport
|
||||
|
||||
An extension can register a Viewport Module by defining a `getViewportModule`
|
||||
method that returns a React component. Currently, we use viewport components to
|
||||
add support for:
|
||||
|
||||
- 2D Medical Image Viewing (cornerstone ext.)
|
||||
- Structured Reports as HTML (dicom html ext.)
|
||||
- Encapsulated PDFs as PDFs (dicom pdf ext.)
|
||||
- Whole Slide Microscopy Viewing (whole slide ext.)
|
||||
- etc.
|
||||
|
||||
The general pattern is, the [`sopClassHandlerModule`](#) helps us determine
|
||||
which Viewport Component a set of `sopClassUIDs` should default to. The Viewport
|
||||
Component receives props containing a display set it should know how to render.
|
||||
|
||||
## Viewport Component Props
|
||||
|
||||
Each `ViewportComponent` will receive the following props:
|
||||
|
||||
```html
|
||||
<viewportComponent
|
||||
viewportData="{viewportData}"
|
||||
viewportIndex="{viewportIndex}"
|
||||
children="{[children]}"
|
||||
/>
|
||||
```
|
||||
|
||||
| Property | Type | Description |
|
||||
| --------------- | --------------- | --------------------------------- |
|
||||
| `children` | React.element[] | |
|
||||
| `viewportData` | object | `viewportSpecificData` (probably) |
|
||||
| `viewportIndex` | number | |
|
||||
|
||||
### `@ohif/viewer`
|
||||
|
||||
Viewport components are managed by the `ViewportGrid` Component. Which Viewport
|
||||
component is used depends on:
|
||||
|
||||
- The Layout Configuration
|
||||
- Registered SopClassHandlers
|
||||
- The SopClassUID for visible/selected datasets
|
||||
|
||||

|
||||
|
||||
<center><i>An example of three cornerstone Viewports</i></center>
|
||||
@@ -19,10 +19,10 @@ Follow the steps outlined in the [Bug Report Template][bug-report-template].
|
||||
At the moment we are in the process of defining our roadmap and will do our best
|
||||
to communicate this to the community. If your requested feature is on the
|
||||
roadmap, then it will most likely be built at some point. If it is not, you are
|
||||
welcome to build it yourself and [contribute it](contributing.md). If you have
|
||||
resources and would like to fund the development of a feature, please
|
||||
[contact us](http://www.ohif.org) or work with community members that offer
|
||||
[consulting services][commercial-support].
|
||||
welcome to build it yourself and [contribute it](development/contributing.md).
|
||||
If you have resources and would like to fund the development of a feature,
|
||||
please [contact us](http://www.ohif.org) or work with community members that
|
||||
offer [consulting services][commercial-support].
|
||||
|
||||
### Who should I contact about Academic Collaborations?
|
||||
|
||||
@@ -54,7 +54,7 @@ for a product built using the platform.
|
||||
If you have gone this route (or are going there), please let us know because we
|
||||
would be interested to hear about your experience.
|
||||
|
||||
### Is The OHIF Viewer [HIPAA][hipaa] Compliant?
|
||||
### Is The OHIF Viewer [HIPAA][hipaa-def] Compliant?
|
||||
|
||||
**NO.** The OHIF Viewer **DOES NOT** fulfill all of the criteria to become HIPAA
|
||||
Compliant. It is the users responsibility to ensure compliance with applicable
|
||||
@@ -75,7 +75,7 @@ rules and regulations.
|
||||
<!-- OTHER -->
|
||||
[501k-clearance]: https://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/HowtoMarketYourDevice/PremarketSubmissions/PremarketNotification510k/
|
||||
[ce-marking]: https://ec.europa.eu/growth/single-market/ce-marking_en
|
||||
[hipaa]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act
|
||||
[hipaa-def]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act
|
||||
[new-issue]: https://github.com/OHIF/Viewers/issues/new/choose
|
||||
[bug-report-template]: https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Bug+Report+%3Abug%3A&template=---bug-report.md&title=
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,56 @@
|
||||
# PWA vs Packaged
|
||||
|
||||
It's important to know that the OHIF Viewer project provides two different build
|
||||
processes:
|
||||
|
||||
```bash
|
||||
# Static Asset output: For deploying PWAs
|
||||
yarn run build
|
||||
|
||||
# Single `.js` script, for embedding viewer into existing apps
|
||||
yarn run build:package
|
||||
```
|
||||
|
||||
## Progressive Web Application (PWA)
|
||||
|
||||
> [Progressive Web Apps][pwa] are a new breed of web applications that meet the
|
||||
> [following requirements][pwa-checklist]. Notably, targeting a PWA allows us
|
||||
> provide a reliable, fast, and engaging experience across different devices and
|
||||
> network conditions.
|
||||
|
||||
The OHIF Viewer is maintained as a [monorepo][monorepo]. We use WebPack to build
|
||||
the many small static assets that comprise our application. Also generated is an
|
||||
`index.html` that will serve as an entry point for loading configuration and the
|
||||
application, as well as a `service-worker` that can intelligently cache files so
|
||||
that subsequent requests are from the local file system instead of over the
|
||||
network.
|
||||
|
||||
You can read more about this particular strategy in our
|
||||
[Build for Production Deployment Guide](./../deployment/recipes/build-for-production.md)
|
||||
|
||||
## Commonjs Bundle (Packaged Script)
|
||||
|
||||
The [@ohif/viewer][viewer-npm] package is built with WebPack to provide a React
|
||||
component that can be dropped into a larger application. The `OHIFViewer`
|
||||
component is the entire viewer, configurable via React `props`. This is useful
|
||||
for including the OHIF Viewer in a larger web application, as the entire
|
||||
application can be provided via a `<script>` tag with no build process required.
|
||||
|
||||
The bundle is not as performant or as optimized as the PWA build. It includes
|
||||
fonts, styles, and the core extensions. If you find yourself facing performance
|
||||
issues, you may wish to tweak what's included in this bundle or switch to the
|
||||
PWA build.
|
||||
|
||||
You can read more about this particular strategy in our
|
||||
[Embedded Viewer Deployment Guide](./../deployment/recipes/embedded-viewer.md)
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[pwa]: https://developers.google.com/web/progressive-web-apps/
|
||||
[pwa-checklist]: https://developers.google.com/web/progressive-web-apps/checklist
|
||||
[monorepo]: https://github.com/OHIF/Viewers/issues/768
|
||||
[viewer-npm]: https://www.npmjs.com/package/@ohif/viewer
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -36,7 +36,7 @@ many data sources. The OHIF Viewer's scope **DOES** include configuration and
|
||||
support for services that are protected with OpenID-Connect.
|
||||
|
||||
In an effort to aide our users and contributors, we attempt to provide several
|
||||
[deployment and hosting recipes](./../deployment/index.md) as potential starting
|
||||
[deployment and hosting recipes](./deployment/index.md) as potential starting
|
||||
points. These are not meant to be rock solid, production ready, solutions; like
|
||||
most recipes, they should be augmented to best fit you and your organization's
|
||||
taste, preferences, etc.
|
||||
@@ -3,7 +3,7 @@
|
||||
We all need a little help sometimes. Don't let a few roadblocks stand in the way
|
||||
of you building something awesome.
|
||||
|
||||
## Free
|
||||
## Community Support
|
||||
|
||||
If you're a developer looking to contribute code, documentation, or discussion;
|
||||
we are more than happy to help provide clarification and answer questions via
|
||||
@@ -21,7 +21,7 @@ resources and must be judicious with how we allocate them. If you find yourself
|
||||
in this situation and in need of assistance, it may be in your best interest to
|
||||
persue paid support.
|
||||
|
||||
## Paid / Commercial
|
||||
## Commercial Support
|
||||
|
||||
The Open Health Imaging Foundation does not offer commercial support, however,
|
||||
some community members do offer consulting services:
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
# Our Process
|
||||
|
||||
Our process is a living, breathing thing. We strive to have regular
|
||||
[retrospectives][retrospective] that help us shape and adapt our process to our
|
||||
team's current needs. This document attempts to capture the broad strokes of
|
||||
that process in an effort to:
|
||||
|
||||
- Strengthen community member involvement and understanding
|
||||
- Welcome feedback and helpful suggestions
|
||||
|
||||
## Overview
|
||||
|
||||
- [Issue Triage](#issue-triage)
|
||||
- [Issue Curation ("backlog grooming")](#issue-curation-backlog-grooming)
|
||||
- [Contributions (Pull Requests)](#contributions-pull-requests)
|
||||
- [Releases](#releases)
|
||||
|
||||
_Include issue lifecycle diagram_
|
||||
|
||||
## Issue Triage
|
||||
|
||||
[GitHub issues][gh-issues] are the best way to provide feedback, ask questions,
|
||||
and suggest changes to the OHIF Viewer's core team. Community issues generally
|
||||
fall into one of three categories, and are marked with a `triage` label when
|
||||
created.
|
||||
|
||||
| Issue Template Name | Description |
|
||||
| ---------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| Community: Report 🐛 | Describe a new issue; Provide steps to reproduce; Expected versus actual result? |
|
||||
| Community: Request ✋ | Describe a proposed new feature. Why should it be implemented? What is the impact/value? |
|
||||
| Community: Question ❓ | Seek clarification or assistance relevant to the repository. |
|
||||
|
||||
_table 1. issue template names and descriptions_
|
||||
|
||||
Issues that require `triage` are akin to support tickets. As this is often our
|
||||
first contact with would-be adopters and contributors, it's important that we
|
||||
strive for timely responses and satisfactory resolutions. We attempt to
|
||||
accomplish this by:
|
||||
|
||||
1. Responding to issues requiring `triage` at least once a week
|
||||
2. Create new "official issues" from "community issues"
|
||||
3. Provide clear guidance and next steps (when applicable)
|
||||
4. Regularly clean up old (stale) issues
|
||||
|
||||
> :pencil: Less obviously, patterns in the issues being reported can highlight
|
||||
> areas that need improvement. For example, users often have difficulty
|
||||
> navigating CORS issues when deploying the OHIF Viewer -- how do we best reduce
|
||||
> our ticket volume for this issue?
|
||||
|
||||
### Backlogged Issues
|
||||
|
||||
Community issues serve as vehicles of discussion that lead us to "backlogged
|
||||
issues". Backlogged issues are the distilled and actionable information
|
||||
extracted from community issues. They contain the scope and requirements
|
||||
necessary for hand-off to a core-team (or community) contributor ^\_^
|
||||
|
||||
| Category | Description | Labels |
|
||||
| -------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Bugs | An issue with steps that produce a bug (an unexpected result). | [Bug: Verified 🐛][label-bug] |
|
||||
| Stories | A feature/enhancement with a clear benefit, boundaries, and requirements. | [Story 🙌][label-story] |
|
||||
| Tasks | Changes that improve [UX], [DX], or test coverage; but don't impact application behavior | [Task: CI/Tooling 🤖][label-tooling], [Task: Docs 📖][label-docs], [Task: Refactor 🛠][label-refactor], [Task: Tests 🔬][label-tests] |
|
||||
|
||||
_table 2. backlogged issue types ([full list of labels][gh-labels])_
|
||||
|
||||
## Issue Curation (["backlog grooming"][groom-backlog])
|
||||
|
||||
If a [GitHub issue][gh-issues] has a `bug`, `story`, or `task` label; it's on
|
||||
our backlog. If an issue is on our backlog, it means we are, at the very least,
|
||||
committed to reviewing any community drafted Pull Requests to complete the
|
||||
issue. If you're interested in seeing an issue completed but don't know where to
|
||||
start, please don't hesitate to leave a comment!
|
||||
|
||||
While we don't yet have a long-term or quarterly road map, we do regularly add
|
||||
items to our ["Active Development" GitHub Project Board][gh-board]. Items on
|
||||
this project board are either in active development by Core Team members, or
|
||||
queued up for development as in-progress items are completed.
|
||||
|
||||
> :pencil: Want to contribute but not sure where to start? Check out [Up for
|
||||
> grabs][label-grabs] issues and our [Contributing
|
||||
> documentation][contributing-docs]
|
||||
|
||||
## Contributions (Pull Requests)
|
||||
|
||||
Incoming Pull Requests (PRs) are triaged using the following labels. Code review
|
||||
is performed on all PRs where the bug fix or added functionality is deemed
|
||||
appropriate:
|
||||
|
||||
| Labels | Description |
|
||||
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| **Classification** | |
|
||||
| [PR: Bug Fix][label-bug] | Filed to address a Bug. |
|
||||
| [PR: Draft][draft] | Filed to gather early feedback from the core team, but which is not intended for merging in the short term. |
|
||||
| **Review Workflow** | |
|
||||
| [PR: Awaiting Response 💬][awaiting-response] | The core team is waiting for additional information from the author. |
|
||||
| [PR: Awaiting Review 👀][awaiting-review] | The core team has not yet performed a code review. |
|
||||
| [PR: Awaiting Revisions 🖊][awaiting-revisions] | Following code review, this label is applied until the author has made sufficient changes. |
|
||||
| **QA** | |
|
||||
| [PR: Awaiting User Cases 💃][awaiting-stories] | The PR code changes need common language descriptions of impact to end users before the review can start |
|
||||
| [PR: No UX Impact 🙃][no-ux-impact] | The PR code changes do not impact the user's experience |
|
||||
|
||||
We rely on GitHub Checks and integrations with third party services to evaluate
|
||||
changes in code quality and test coverage. Tests must pass and User cases must
|
||||
be present (when applicable) before a PR can be merged to master, and code
|
||||
quality and test coverage must not changed by a significant margin. For some
|
||||
repositories, visual screenshot-based tests are also included, and video
|
||||
recordings of end-to-end tests are stored for later review.
|
||||
|
||||
[You can read more about our continous integration efforts here](/development/continous-integration.md)
|
||||
|
||||
## Releases
|
||||
|
||||
Releases are made automatically based on the type of commits which have been
|
||||
merged (major.minor.patch). Releases are automatically pushed to NPM. Release
|
||||
notes are automatically generated. Users can subscribe to GitHub and NPM
|
||||
releases.
|
||||
|
||||
We host development, staging, and production environments for the Progressive
|
||||
Web Application version of the OHIF Viewer. [Development][ohif-dev] always
|
||||
reflects the latest changes on our master branch. [Staging][ohif-stage] is used
|
||||
to regression test a release before a bi-weekly deploy to our [Production
|
||||
environment][ohif-prod].
|
||||
|
||||
Important announcements are made on GitHub, tagged as Announcement, and pinned
|
||||
so that they remain at the top of the Issue page.
|
||||
|
||||
The Core team occasionally performs full manual testing to begin the process of
|
||||
releasing a Stable version. Once testing is complete, the known issues are
|
||||
addressed and a Stable version is released.
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[groom-backlog]: https://www.agilealliance.org/glossary/backlog-grooming
|
||||
[retrospective]: https://www.atlassian.com/team-playbook/plays/retrospective
|
||||
[gh-issues]: https://github.com/OHIF/Viewers/issues/new/choose
|
||||
[gh-labels]: https://github.com/OHIF/Viewers/labels
|
||||
<!-- Issue Labels -->
|
||||
[label-story]: https://github.com/OHIF/Viewers/labels/Story%20%3Araised_hands%3A
|
||||
[label-tooling]: https://github.com/OHIF/Viewers/labels/Task%3A%20CI%2FTooling%20%3Arobot%3A
|
||||
[label-docs]: https://github.com/OHIF/Viewers/labels/Task%3A%20Docs%20%3Abook%3A
|
||||
[label-refactor]: https://github.com/OHIF/Viewers/labels/Task%3A%20Refactor%20%3Ahammer_and_wrench%3A
|
||||
[label-tests]: https://github.com/OHIF/Viewers/labels/Task%3A%20Tests%20%3Amicroscope%3A
|
||||
[label-bug]: https://github.com/OHIF/Viewers/labels/Bug%3A%20Verified%20%3Abug%3A
|
||||
<!-- PR Labels -->
|
||||
[draft]: https://github.com/OHIF/Viewers/labels/PR%3A%20Draft
|
||||
[awaiting-response]: https://github.com/OHIF/Viewers/labels/PR%3A%20Awaiting%20Response%20%3Aspeech_balloon%3A
|
||||
[awaiting-review]: https://github.com/OHIF/Viewers/labels/PR%3A%20Awaiting%20Review%20%3Aeyes%3A
|
||||
[awaiting-stories]: https://github.com/OHIF/Viewers/labels/PR%3A%20Awaiting%20UX%20Stories%20%3Adancer%3A
|
||||
[awaiting-revisions]: https://github.com/OHIF/Viewers/labels/PR%3A%20Awaiting%20Revisions%20%3Apen%3A
|
||||
[no-ux-impact]: https://github.com/OHIF/Viewers/labels/PR%3A%20No%20UX%20Impact%20%3Aupside_down_face%3A
|
||||
<!-- -->
|
||||
[ohif-dev]: https://viewer-dev.ohif.org
|
||||
[ohif-stage]: https://viewer-stage.ohif.org
|
||||
[ohif-prod]: https://viewer.ohif.org
|
||||
[gh-board]: https://github.com/OHIF/Viewers/projects/4
|
||||
[label-grabs]: https://github.com/OHIF/Viewers/issues?q=is%3Aissue+is%3Aopen+label%3A%22Up+For+Grabs+%3Araising_hand_woman%3A%22
|
||||
[contributing-docs]: https://docs.ohif.org/contributing/
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,28 @@
|
||||
# Quick Start
|
||||
|
||||
This page details how to get an instance of the OHIF Viewer up and running as
|
||||
fast as possible. It shows how to grab a pre-built version of the application,
|
||||
point it at your data source (PACS), and plop it on a web server.
|
||||
|
||||
## Options
|
||||
|
||||
### 1. Pre-built PWA
|
||||
|
||||
...
|
||||
|
||||
### 2. Script-Tag
|
||||
|
||||
...
|
||||
|
||||
### 3. Docker
|
||||
|
||||
...
|
||||
|
||||
## Security Concerns
|
||||
|
||||
- Secure your data
|
||||
|
||||
## Common Issues
|
||||
|
||||
- Missing server rewrite rules
|
||||
- CORS issues when requesting data from PACS
|
||||
@@ -0,0 +1,65 @@
|
||||
# Services (default)
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Example](#example)
|
||||
|
||||
## Overview
|
||||
|
||||
Services are a work in progress. As we are still in the progress of creating a
|
||||
non-ui maintained service, this usage may change.
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/services.png">
|
||||
<img src="/assets/img/services.png" alt="UI Services Diagram" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>Diagram showing relationship between React Context and UI Service</i></div>
|
||||
</div>
|
||||
|
||||
## Example
|
||||
|
||||
The simplest service return a new object that has a `name` property, and
|
||||
methods/properties that give the service its functionality. The "Factory
|
||||
Function" that creates the service is provided with the implementation (this is
|
||||
slightly different for UI Services).
|
||||
|
||||
```js
|
||||
const _speak = () => {
|
||||
console.warn('Speak is not implemented');
|
||||
};
|
||||
|
||||
/**
|
||||
* Factory function to create `HelloWorldService`
|
||||
*
|
||||
* @param {object} implementation
|
||||
* @param {function} implementation.speak - Speak's implementation
|
||||
* @returns HelloWorldService
|
||||
*/
|
||||
export default function createHelloWorldService({ speak }) {
|
||||
return {
|
||||
name: 'HelloWorldService',
|
||||
speak: speak || _speak,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
A service, once created, can be registered with the `ServicesManager` to make it
|
||||
accessible to extensions. Similarly, the application code can access named
|
||||
services from the `ServicesManager`.
|
||||
|
||||
```js
|
||||
// In the application
|
||||
const speak = () => {
|
||||
window.alert('HELLO WORLD');
|
||||
};
|
||||
const HelloWorldService = createHelloWorldService({ speak });
|
||||
const servicesManager = new ServicesManager();
|
||||
|
||||
servicesManager.registerService(HelloWorldService);
|
||||
|
||||
// In an extension
|
||||
const { HelloWorldService } = servicesManager.services;
|
||||
|
||||
if (HelloWorldService) {
|
||||
HelloWorldService.speak();
|
||||
}
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
# Measurements Package (ohif-measurements)
|
||||
# Service: Measurements
|
||||
|
||||
## Package design
|
||||
...
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Services Overview
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Kinds of Services](#kinds-of-services)
|
||||
- [Services (default)](#services-default)
|
||||
- [UI Services](#ui-services)
|
||||
- [Related Patterns](#related-patterns)
|
||||
|
||||
## Overview
|
||||
|
||||
Services are a beefier version of [commands][commands]. They provide a set of
|
||||
operations, often tied to some shared state, and are made available to
|
||||
extensions via the `ServicesManager`. Services are particularly well suited to
|
||||
address [cross-cutting concerns][cross-cutting-concerns].
|
||||
|
||||
Each service should be:
|
||||
|
||||
- self-contained
|
||||
- able to fail and/or be removed without breaking the application
|
||||
- completely interchangeable with another module implementing the same interface
|
||||
|
||||
## Kinds of Services
|
||||
|
||||
Depending on the kind of service, we follow slightly different conventions. For
|
||||
example, a UI service often receives its implementation from a React Context
|
||||
Provider. You can read more about the different kinds of services and what makes
|
||||
them different below:
|
||||
|
||||
### Services (default)
|
||||
|
||||
Services are a work in progress. As we are still in the progress of creating a
|
||||
non-ui maintained service, this usage may change.
|
||||
|
||||
[You can read more about default services: here](./default/index.md)
|
||||
|
||||
### UI Services
|
||||
|
||||
A typical web application will have components and state for common UI like
|
||||
modals, notifications, dialogs, etc. A UI service makes it possible to leverage
|
||||
these components from an extension.
|
||||
|
||||
We maintain the following UI Services:
|
||||
|
||||
- [UIDialogService](./ui/ui-dialog-service.md)
|
||||
- [UIModalService](./ui/ui-modal-service.md)
|
||||
- [UINotificationService](./ui/ui-notification-service.md)
|
||||
|
||||
You can read more about a specific service by selecting it in the above list,
|
||||
and more about [UI services in general: here](./ui/index.md)
|
||||
|
||||
## Related Patterns
|
||||
|
||||
Services are "concern-specific" code modules that can be consumed across layers.
|
||||
We try to minimize the coupling they introduce by authoring services that are
|
||||
able to fail or be removed. Related patterns that may reduce coupling include:
|
||||
|
||||
- Pub/Sub
|
||||
- Commands
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[commands]: #/
|
||||
[core-services]: https://github.com/OHIF/Viewers/tree/master/platform/core/src/services
|
||||
[services-manager]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/services/ServicesManager.js
|
||||
[cross-cutting-concerns]: https://en.wikipedia.org/wiki/Cross-cutting_concern
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,106 @@
|
||||
# UI Services
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Example](#example)
|
||||
- [Tips & Tricks](#/)
|
||||
- [Maintained Services](#/)
|
||||
|
||||
## Overview
|
||||
|
||||
A typical web application will have components and state for common UI like
|
||||
modals, notifications, dialogs, etc. A UI service makes it possible to leverage
|
||||
these components from an extension.
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/ui-services.png">
|
||||
<img src="/assets/img/ui-services.png" alt="UI Services Diagram" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>Diagram showing relationship between React Context and UI Service</i></div>
|
||||
</div>
|
||||
|
||||
In `@ohif/core`, we have a collection of service factories. We select one we
|
||||
would like our application to support, create an instance of it, and pass that
|
||||
instance to our `ServicesManager` AND to a React component (in this example,
|
||||
`ModalContext`'s provider).
|
||||
|
||||
The `ModalContext`'s provider:
|
||||
|
||||
- Exposes context values
|
||||
- Exposes methods that leverage `useCallback` hooks
|
||||
- Sets the service's implementation in a `useEffect` hook
|
||||
|
||||
The `ServicesManager` is:
|
||||
|
||||
- Passed to the `ExtensionManager`
|
||||
- The `ExtensionManager` makes the `ServicesManager` available to:
|
||||
- All of it's lifecycle hooks (`preRegistration`)
|
||||
- Each "getModuleFunction" (`getToolbarModule`, `getPanelModule`, etc.)
|
||||
|
||||
## Example
|
||||
|
||||
That's all fine and good, but it's still a little too abstract. What does this
|
||||
translate to in practice?
|
||||
|
||||
```js
|
||||
// In the application
|
||||
import UINotificationService from '@ohif/core';
|
||||
const servicesManager = new ServicesManager();
|
||||
|
||||
servicesManager.registerService(UINotificationService);
|
||||
|
||||
// UI Service Provider
|
||||
useEffect(() => {
|
||||
if (service) {
|
||||
service.setServiceImplementation({ hide, show });
|
||||
}
|
||||
}, [service, hide, show]);
|
||||
|
||||
// In an extension
|
||||
const { UINotificationService } = servicesManager.services;
|
||||
|
||||
if (UINotificationService) {
|
||||
UINotificationService.show('Hello from the other side 👋');
|
||||
}
|
||||
```
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/notification-example.gif">
|
||||
<img src="/assets/img/notification-example.gif" alt="UI Notification Service Example" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>GIF showing successful call of UINotificationService from an extension.</i></div>
|
||||
</div>
|
||||
|
||||
## Tips & Tricks
|
||||
|
||||
It's important to remember that all we're doing is making it possible to control
|
||||
bits of the application's UI from an extension. Here are a few non-obvious
|
||||
takeaways worth mentioning:
|
||||
|
||||
- Your application code should continue to use React context
|
||||
(consumers/providers) as it normally would
|
||||
- You can substitute our "out of the box" UI implementations with your own
|
||||
- You can create and register your own UI services
|
||||
- You can choose not to register a service or provide a service implementation
|
||||
- In extensions, you can provide fallback/alternative behavior if an expected
|
||||
service is not registered
|
||||
- No `UIModalService`? Use the `UINotificationService` to notify users.
|
||||
- While we don't have an examples of this, you can technically register a
|
||||
service in an extension and expose it to the core application
|
||||
|
||||
> Note: These are recommended patterns, not hard and fast rules. Following them
|
||||
> will help reduce confusion and interoperability with the larger OHIF
|
||||
> community, but they're not silver bullets. Please speak up, create an issue,
|
||||
> if you would like to discuss new services or improvements to this pattern.
|
||||
|
||||
## Maintained Services
|
||||
|
||||
Our `@ohif/viewer` project is an example of how to glue together the different
|
||||
parts and pieces of the OHIF Platform to create a polished and powerful product.
|
||||
To accomplish that, we maintain several UI Services that you can use in your own
|
||||
project, or provide alternative implementations for:
|
||||
|
||||
| Name | Docs |
|
||||
| --------------------- | ------------------------------------ |
|
||||
| UIDialogService | [Here](./ui-dialog-service.md) |
|
||||
| UIModalService | [Here](./ui-modal-service.md) |
|
||||
| UINotificationService | [Here](./ui-notification-service.md) |
|
||||
@@ -0,0 +1,49 @@
|
||||
# UI Dialog Service
|
||||
|
||||
Dialogs have similar characteristics to that of Modals, but often with a
|
||||
streamlined focus. They can be helpful when:
|
||||
|
||||
- We need to grab the user's attention
|
||||
- We need user input
|
||||
- We need to show additional information
|
||||
|
||||
If you're curious about the DOs and DON'Ts of dialogs and modals, check out this
|
||||
article: ["Best Practices for Modals / Overlays / Dialog Windows"][ux-article]
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/dialog-example.gif">
|
||||
<img src="/assets/img/dialog-example.gif" alt="UI Dialog Service Example" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>GIF showing successful call of UIDialogService from an extension.</i></div>
|
||||
</div>
|
||||
|
||||
## Interface
|
||||
|
||||
For a more detailed look on the options and return values each of these methods
|
||||
is expected to support, [check out it's interface in `@ohif/core`][interface]
|
||||
|
||||
| API Member | Description |
|
||||
| -------------- | ------------------------------------------------------ |
|
||||
| `create()` | Creates a new Dialog that is displayed until dismissed |
|
||||
| `dismiss()` | Dismisses the specified dialog |
|
||||
| `dismissAll()` | Dismisses all dialogs |
|
||||
|
||||
## Implementations
|
||||
|
||||
| Implementation | Consumer |
|
||||
| ------------------------------------ | -------------------------- |
|
||||
| [Dialog Provider][dialog-provider]\* | Baked into Dialog Provider |
|
||||
|
||||
`*` - Denotes maintained by OHIF
|
||||
|
||||
> 3rd Party implementers may be added to this table via pull requests.
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[interface]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/services/UIDialogService/index.js
|
||||
[dialog-provider]: https://github.com/OHIF/Viewers/blob/master/platform/ui/src/contextProviders/DialogProvider.js
|
||||
[ux-article]: https://uxplanet.org/best-practices-for-modals-overlays-dialog-windows-c00c66cddd8c
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,50 @@
|
||||
# UI Modal Service
|
||||
|
||||
Modals have similar characteristics to that of Dialogs, but are often larger,
|
||||
and only allow for a single instance to be viewable at once. They also tend to
|
||||
be centered, and not draggable. They're commonly used when:
|
||||
|
||||
- We need to grab the user's attention
|
||||
- We need user input
|
||||
- We need to show additional information
|
||||
|
||||
If you're curious about the DOs and DON'Ts of dialogs and modals, check out this
|
||||
article: ["Best Practices for Modals / Overlays / Dialog Windows"][ux-article]
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/modal-example.gif">
|
||||
<img src="/assets/img/modal-example.gif" alt="UI Modal Service Example" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>GIF showing successful call of UIModalService from an extension.</i></div>
|
||||
</div>
|
||||
|
||||
## Interface
|
||||
|
||||
For a more detailed look on the options and return values each of these methods
|
||||
is expected to support, [check out it's interface in `@ohif/core`][interface]
|
||||
|
||||
| API Member | Description |
|
||||
| ---------- | ------------------------------------- |
|
||||
| `hide()` | Hides the open modal |
|
||||
| `show()` | Shows the provided content in a modal |
|
||||
|
||||
## Implementations
|
||||
|
||||
| Implementation | Consumer |
|
||||
| ---------------------------------- | ----------------------------- |
|
||||
| [Modal Provider][modal-provider]\* | [OHIFModal][modal-consumer]\* |
|
||||
|
||||
`*` - Denotes maintained by OHIF
|
||||
|
||||
> 3rd Party implementers may be added to this table via pull requests.
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[interface]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/services/UIModalService/index.js
|
||||
[modal-provider]: https://github.com/OHIF/Viewers/blob/master/platform/ui/src/contextProviders/ModalProvider.js
|
||||
[modal-consumer]: https://github.com/OHIF/Viewers/tree/master/platform/ui/src/components/ohifModal
|
||||
[ux-article]: https://uxplanet.org/best-practices-for-modals-overlays-dialog-windows-c00c66cddd8c
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,51 @@
|
||||
# UI Notification Service
|
||||
|
||||
Notifications can be annoying and disruptive. They can also deliver timely
|
||||
helpful information, or expedite the user's workflow. Here is some high level
|
||||
guidance on when and how to use them:
|
||||
|
||||
- Notifications should be non-interfering (timely, relevant, important)
|
||||
- We should only show small/brief notifications
|
||||
- Notifications should be contextual to current behavior/actions
|
||||
- Notifications can serve warnings (acting as a confirmation)
|
||||
|
||||
If you're curious about the DOs and DON'Ts of notifications, check out this
|
||||
article: ["How To Design Notifications For Better UX"][ux-article]
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="/assets/img/notification-example.gif">
|
||||
<img src="/assets/img/notification-example.gif" alt="UI Notification Service Example" style="margin: 0 auto; max-width: 500px;" />
|
||||
</a>
|
||||
<div><i>GIF showing successful call of UINotificationService from an extension.</i></div>
|
||||
</div>
|
||||
|
||||
## Interface
|
||||
|
||||
For a more detailed look on the options and return values each of these methods
|
||||
is expected to support, [check out it's interface in `@ohif/core`][interface]
|
||||
|
||||
| API Member | Description |
|
||||
| ---------- | --------------------------------------- |
|
||||
| `hide()` | Hides the specified notification |
|
||||
| `show()` | Creates and displays a new notification |
|
||||
|
||||
## Implementations
|
||||
|
||||
| Implementation | Consumer |
|
||||
| ---------------------------------------- | ----------------------------------------- |
|
||||
| [Snackbar Provider][snackbar-provider]\* | [SnackbarContainer][snackbar-container]\* |
|
||||
|
||||
`*` - Denotes maintained by OHIF
|
||||
|
||||
> 3rd Party implementers may be added to this table via pull requests.
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[interface]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/services/UINotificationService/index.js
|
||||
[snackbar-provider]: https://github.com/OHIF/Viewers/blob/master/platform/ui/src/contextProviders/SnackbarProvider.js
|
||||
[snackbar-container]: https://github.com/OHIF/Viewers/blob/master/platform/ui/src/components/snackbar/SnackbarContainer.js
|
||||
[ux-article]: https://uxplanet.org/how-to-design-notifications-for-better-ux-6fb0711be54d
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,56 @@
|
||||
# Viewer: Configuration
|
||||
|
||||
We maintain a number of common viewer application configurations at [`<root>/platform/viewer/public/configs`][config-dir]. How these values are passed to the viewer depend on how it's deployed, but the two most common paths are:
|
||||
|
||||
- `index.html` looks for `https://your-website.com/app-config.js` OR
|
||||
- `index.html` passes the values to `OHIF.installViewer()`
|
||||
|
||||
```js
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
whiteLabelling: {},
|
||||
extensions: [],
|
||||
showStudyList: true,
|
||||
filterQueryParam: false,
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: 'DCM4CHEE',
|
||||
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
|
||||
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
qidoSupportsIncludeField: true,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
enableStudyLazyLoad: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Supported Keys: https://craig.is/killing/mice
|
||||
hotkeys: [
|
||||
{ commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] },
|
||||
{ commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] },
|
||||
{ commandName: 'invertViewport', label: 'Invert', keys: ['i'] },
|
||||
{
|
||||
commandName: 'flipViewportVertical',
|
||||
label: 'Flip Horizontally',
|
||||
keys: ['h'],
|
||||
},
|
||||
{
|
||||
commandName: 'flipViewportHorizontal',
|
||||
label: 'Flip Vertically',
|
||||
keys: ['v'],
|
||||
},
|
||||
],
|
||||
// Config to pass to the bundled cornerstone extension
|
||||
cornerstoneExtensionConfig: {},
|
||||
};
|
||||
```
|
||||
|
||||
<!--
|
||||
LINKS
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[config-dir]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/public/config
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -0,0 +1,23 @@
|
||||
# Environment Variables
|
||||
|
||||
There are a number of environment variables we use at build time to influence the output application's behavior.
|
||||
|
||||
```bash
|
||||
# Application
|
||||
NODE_ENV=< production | development >
|
||||
DEBUG=< true | false >
|
||||
APP_CONFIG=< relative path to application configuration file >
|
||||
PUBLIC_URL=<>
|
||||
VERSION_NUMBER=<Set by CircleCI>
|
||||
BUILD_NUM=<Set by CircleCI>
|
||||
# i18n
|
||||
USE_LOCIZE=<false>
|
||||
LOCIZE_PROJECTID=<ProjectID to pull translations for>
|
||||
LOCIZE_API_KEY=<To enable Locize live editing of translations>
|
||||
```
|
||||
|
||||
## Setting Environment Variables
|
||||
|
||||
- `npx cross-env`
|
||||
- `.env` files
|
||||
- env variables on build machine, or for terminal session
|
||||
@@ -0,0 +1,3 @@
|
||||
# Hotkeys
|
||||
|
||||
...
|
||||
@@ -0,0 +1,9 @@
|
||||
# Viewer
|
||||
|
||||
The OHIF Viewing Platform strives to be highly configurable and extensible. This
|
||||
makes it easier for our community members to keep their "secret sauce" private,
|
||||
and incentivises contributions back to the platform. The `@ohif/viewer` project
|
||||
of the platform is the lynchpin that combines everything to create our
|
||||
application.
|
||||
|
||||
- When configuration and themeing aren't enough
|
||||
@@ -1,4 +1,4 @@
|
||||
# Translating
|
||||
# Viewer: Internationalization
|
||||
|
||||
OHIF supports internationalization using [i18next](https://www.i18next.com/)
|
||||
through the npm package [@ohif/i18n](https://www.npmjs.com/package/@ohif/i18n),
|
||||
@@ -15,7 +15,7 @@ where is the main instance of i18n containing several languages and tools.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Installing
|
||||
## Installing
|
||||
|
||||
```bash
|
||||
yarn add @ohif/i18n
|
||||
@@ -25,7 +25,7 @@ yarn add @ohif/i18n
|
||||
npm install --save @ohif/i18n
|
||||
```
|
||||
|
||||
### How it works
|
||||
## How it works
|
||||
|
||||
After installing `@ohif/i18n` npm package, the translation function
|
||||
[t](https://www.i18next.com/overview/api#t) can be used [with](#with-react) or
|
||||
@@ -57,13 +57,13 @@ If the translation.json file contains a key that matches the HTML content e.g.
|
||||
|
||||
---
|
||||
|
||||
#### With React
|
||||
### With React
|
||||
|
||||
This section will introduce you to [react-i18next](https://react.i18next.com/)
|
||||
basics and show how to implement the [t](https://www.i18next.com/overview/api#t)
|
||||
function easily.
|
||||
|
||||
##### Using HOCs
|
||||
#### Using HOCs
|
||||
|
||||
In most cases we used
|
||||
[High Order Components](https://react.i18next.com/latest/withtranslation-hoc) to
|
||||
@@ -86,13 +86,13 @@ export default withTranslation('MyNameSpace')(MyComponent);
|
||||
> [I18nextProvider](#using-outside-of-ohif-viewer) section, `withTranslation`
|
||||
> HOC doesnt works without a I18nextProvider
|
||||
|
||||
##### Using Hooks
|
||||
#### Using Hooks
|
||||
|
||||
Also, it's possible to get the `t` tool using
|
||||
[React Hooks](https://react.i18next.com/latest/usetranslation-hook), but it
|
||||
requires at least React > 16.8 😉
|
||||
|
||||
#### Using outside of OHIF viewer
|
||||
### Using outside of OHIF viewer
|
||||
|
||||
OHIF Viewer already sets a main
|
||||
[I18nextProvider](https://react.i18next.com/latest/i18nextprovider) connected to
|
||||
@@ -119,7 +119,7 @@ usage.
|
||||
|
||||
---
|
||||
|
||||
#### Without React
|
||||
### Without React
|
||||
|
||||
When needed, you can also use available translations _without React_.
|
||||
|
||||
@@ -145,8 +145,8 @@ becomes a new namespace automatically.
|
||||
- CineDialog: Translations for the toll tips inside the Cine Player Dialog
|
||||
- Common: all common jargons that can be reused like `t('$t(common:image)')`
|
||||
- Header: translations related to OHIF's Header Top Bar
|
||||
- MeasurementTable - Translations for the react-viewerbase Measurement Table
|
||||
- UserPreferencesModal - Translations for the react-viewerbase Preferences Modal
|
||||
- MeasurementTable - Translations for the `@ohif/ui` Measurement Table
|
||||
- UserPreferencesModal - Translations for the `@ohif/ui` Preferences Modal
|
||||
|
||||
### How to use another NameSpace inside the current NameSpace?
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Themeing
|
||||
# Viewer: Themeing
|
||||
|
||||
Themeing is currently accomplished with color variables that are defined within
|
||||
the [`:root`](https://css-tricks.com/almanac/selectors/r/root/) selector
|
||||
(allowing them to cascade across all elements). This repository's components,
|
||||
and the ones we consume from our
|
||||
[React Viewerbase component library](https://react.ohif.org/styling-and-theming)
|
||||
[`@ohif/ui` component library](https://react.ohif.org/styling-and-theming)
|
||||
utilize them. We are interested in pursuing more robust themeing options, and
|
||||
open to pull requests and discussion issues.
|
||||
|
||||
@@ -80,12 +80,12 @@ function RadicalImagingLogo() {
|
||||
href: 'http://radicalimaging.com',
|
||||
},
|
||||
React.createElement('h5', {}, 'RADICAL IMAGING')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
props.whiteLabelling = {
|
||||
logoComponent: RadicalImagingLogo(),
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
<!--
|
||||
@@ -11,7 +11,12 @@ export default {
|
||||
* LIFECYCLE HOOKS
|
||||
*/
|
||||
|
||||
preRegistration(extensionConfiguration) {},
|
||||
preRegistration({
|
||||
servicesManager = {},
|
||||
commandsManager = {},
|
||||
appConfig = {},
|
||||
configuration = {},
|
||||
}) {},
|
||||
|
||||
/**
|
||||
* MODULE GETTERS
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.commonjs.js');
|
||||
@@ -29,9 +30,15 @@ module.exports = (env, argv) => {
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifExtensionCornerstone',
|
||||
library: 'OHIFExtCornerstone',
|
||||
libraryTarget: 'umd',
|
||||
libraryExport: 'default',
|
||||
filename: pkg.main,
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.LimitChunkCountPlugin({
|
||||
maxChunks: 1,
|
||||
}),
|
||||
],
|
||||
});
|
||||
};
|
||||
@@ -3,6 +3,291 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.1.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.1.0...@ohif/extension-cornerstone@2.1.1) (2019-12-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 add WwwcRegionTool to cornerstone tools initialization ([#1302](https://github.com/OHIF/Viewers/issues/1302)) ([d5bf728](https://github.com/OHIF/Viewers/commit/d5bf72851a32dff9fd3fc09332ea5250bc7e6114))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.0.2...@ohif/extension-cornerstone@2.1.0) (2019-12-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 DICOM SR STOW on MeasurementAPI ([#954](https://github.com/OHIF/Viewers/issues/954)) ([ebe1af8](https://github.com/OHIF/Viewers/commit/ebe1af8d4f75d2483eba869655906d7829bd9666)), closes [#758](https://github.com/OHIF/Viewers/issues/758)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.0.1...@ohif/extension-cornerstone@2.0.2) (2019-12-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.0.0...@ohif/extension-cornerstone@2.0.1) (2019-12-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.7.2...@ohif/extension-cornerstone@2.0.0) (2019-12-09)
|
||||
|
||||
|
||||
* feat!: Ability to configure cornerstone tools via extension configuration (#1229) ([55a5806](https://github.com/OHIF/Viewers/commit/55a580659ecb74ca6433461d8f9a05c2a2b69533)), closes [#1229](https://github.com/OHIF/Viewers/issues/1229)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* modifies the exposed react <App /> components props. The contract for providing configuration for the app has changed. Please reference updated documentation for guidance.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.7.1...@ohif/extension-cornerstone@1.7.2) (2019-12-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.7.0...@ohif/extension-cornerstone@1.7.1) (2019-12-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.7.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.6.0...@ohif/extension-cornerstone@1.7.0) (2019-11-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add new annotate tool using new dialog service ([#1211](https://github.com/OHIF/Viewers/issues/1211)) ([8fd3af1](https://github.com/OHIF/Viewers/commit/8fd3af1e137e793f1b482760a22591c64a072047))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.6.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.5.1...@ohif/extension-cornerstone@1.6.0) (2019-11-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* New dialog service ([#1202](https://github.com/OHIF/Viewers/issues/1202)) ([f65639c](https://github.com/OHIF/Viewers/commit/f65639c2b0dab01decd20cab2cef4263cb4fab37))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.5.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.5.0...@ohif/extension-cornerstone@1.5.1) (2019-11-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.5.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.4.1...@ohif/extension-cornerstone@1.5.0) (2019-11-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* expose UiNotifications service ([#1172](https://github.com/OHIF/Viewers/issues/1172)) ([5c04e34](https://github.com/OHIF/Viewers/commit/5c04e34c8fb2394ab7acd9eb4f2ab12afeb2f255))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.4.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.4.0...@ohif/extension-cornerstone@1.4.1) (2019-11-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add a fallback metadata provider which pulls metadata from WADO-… ([#1158](https://github.com/OHIF/Viewers/issues/1158)) ([31b1adf](https://github.com/OHIF/Viewers/commit/31b1adfa5993d6c8e3e9c8b03fa9856f2621b037))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.4.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.3.1...@ohif/extension-cornerstone@1.4.0) (2019-10-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Snapshot Download Tool ([#840](https://github.com/OHIF/Viewers/issues/840)) ([450e098](https://github.com/OHIF/Viewers/commit/450e0981a5ba054fcfcb85eeaeb18371af9088f8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.3.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.3.0...@ohif/extension-cornerstone@1.3.1) (2019-10-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 set tools bidirectional, eraser and annotate command ([#1020](https://github.com/OHIF/Viewers/issues/1020)) ([a28984e](https://github.com/OHIF/Viewers/commit/a28984e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.3.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.5...@ohif/extension-cornerstone@1.3.0) (2019-10-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Multiple fixes and implementation changes to react-cornerstone-viewport ([1cc94f3](https://github.com/OHIF/Viewers/commit/1cc94f3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.2.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.4...@ohif/extension-cornerstone@1.2.5) (2019-09-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* version bump issue ([#963](https://github.com/OHIF/Viewers/issues/963)) ([e607ed2](https://github.com/OHIF/Viewers/commit/e607ed2)), closes [#962](https://github.com/OHIF/Viewers/issues/962)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.2...@ohif/extension-cornerstone@2.0.0) (2019-09-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Add DicomLoaderService & FileLoaderService to fix SR, PDF, and SEG support in local file and WADO-RS-only use cases ([#862](https://github.com/OHIF/Viewers/issues/862)) ([e7e1a8a](https://github.com/OHIF/Viewers/commit/e7e1a8a)), closes [#838](https://github.com/OHIF/Viewers/issues/838)
|
||||
* version bump issue ([#962](https://github.com/OHIF/Viewers/issues/962)) ([c80ea17](https://github.com/OHIF/Viewers/commit/c80ea17))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* DICOM Seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.2...@ohif/extension-cornerstone@2.0.0) (2019-09-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Add DicomLoaderService & FileLoaderService to fix SR, PDF, and SEG support in local file and WADO-RS-only use cases ([#862](https://github.com/OHIF/Viewers/issues/862)) ([e7e1a8a](https://github.com/OHIF/Viewers/commit/e7e1a8a)), closes [#838](https://github.com/OHIF/Viewers/issues/838)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* DICOM Seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.2.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.1...@ohif/extension-cornerstone@1.2.2) (2019-09-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add some code splitting for PWA build ([#937](https://github.com/OHIF/Viewers/issues/937)) ([8938035](https://github.com/OHIF/Viewers/commit/8938035))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.2.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.0...@ohif/extension-cornerstone@1.2.1) (2019-09-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bump cornerstone-tools version in peerDeps ([4afc88c](https://github.com/OHIF/Viewers/commit/4afc88c))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.2.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.1.1...@ohif/extension-cornerstone@1.2.0) (2019-09-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Annotate:** Add annotate tool back to toolbar ([26be967](https://github.com/OHIF/Viewers/commit/26be967))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.1.0...@ohif/extension-cornerstone@1.1.1) (2019-09-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.1.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.0.1...@ohif/extension-cornerstone@1.1.0) (2019-09-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **BidirectionalTool:** Add BidrectionalTool to "more" menu ([#911](https://github.com/OHIF/Viewers/issues/911)) ([e40cbae](https://github.com/OHIF/Viewers/commit/e40cbae))
|
||||
* **EraserTool:** add eraserTool to @ohif/extension-cornerstone ([#912](https://github.com/OHIF/Viewers/issues/912)) ([698d274](https://github.com/OHIF/Viewers/commit/698d274))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.0.0...@ohif/extension-cornerstone@1.0.1) (2019-09-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* simplify runtime-extension usage ([ac5dbda](https://github.com/OHIF/Viewers/commit/ac5dbda))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.0.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@0.50.5...@ohif/extension-cornerstone@1.0.0) (2019-09-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 Upgraded to cornerstoneTools 4.0 ([86adb51](https://github.com/OHIF/Viewers/commit/86adb51))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* n
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@0.50.4...@ohif/extension-cornerstone@0.50.5) (2019-09-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@0.50.3...@ohif/extension-cornerstone@0.50.4) (2019-09-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
@@ -67,6 +67,24 @@ Our Viewport wraps [cornerstonejs/react-cornerstone-viewport][react-viewport]
|
||||
and is connected the redux store. This module is the most prone to change as we
|
||||
hammer out our Viewport interface.
|
||||
|
||||
## Tool Configuration
|
||||
|
||||
Tools can be configured through extension configuration using the tools key:
|
||||
|
||||
```js
|
||||
...
|
||||
cornerstoneExtensionConfig: {
|
||||
tools: {
|
||||
ArrowAnnotate: {
|
||||
configuration: {
|
||||
getTextCallback: (callback, eventDetails) => callback(prompt('Enter your custom annotation')),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
...
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
### Repositories
|
||||
|
||||