Compare commits
706 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9490a06303 | |||
| 5fb1ae0678 | |||
| 97c03e216b | |||
|
|
bab4490847 | ||
|
8e824d4afa
|
|||
|
|
777cf1a31d | ||
|
efacb2a332
|
|||
|
|
17c4e9dd22 | ||
| 503ccbb2ad | |||
|
54c40d7acc
|
|||
|
d8d5e076ba
|
|||
|
|
fd2b3fe691 | ||
| 6ae7a7dac8 | |||
|
e429a855e5
|
|||
|
|
9ed60b7cc8 | ||
|
|
175df0ce33 | ||
|
|
d5cde19250 | ||
| 2e1165d99c | |||
| a100ffa77b | |||
| 95c3608d85 | |||
| 15d91d87bf | |||
| f6ec692ebf | |||
| f41617c08e | |||
| 2bf0d82a5b | |||
| 3e61cfb939 | |||
| 21ec3a04ab | |||
| 5d6fe5572b | |||
| 0a543c7b21 | |||
| b1ba2effe3 | |||
| 626ce34dc0 | |||
| b879555e6a | |||
| ed08980df3 | |||
| 6aee2bbc60 | |||
| d4701c958c | |||
| 446d4f4171 | |||
| 1ed2a15c4c | |||
| 42b746871a | |||
| 6c20b01cc2 | |||
| 4f879252a0 | |||
|
|
11724987b0 | ||
| d90703453f | |||
|
eaea4b2e21
|
|||
|
|
68efc76e8e | ||
| 6df17c88c7 | |||
|
ec109328fb
|
|||
|
|
f4943a148b | ||
|
15e348c17b
|
|||
|
6cf5262dd5
|
|||
|
|
4b229cd7d7 | ||
| e372be192a | |||
|
ab37e88bb0
|
|||
|
|
d38a784326 | ||
| 4d18b105c8 | |||
|
492651e0f3
|
|||
|
cd678a41f6
|
|||
| 03fbc14b72 | |||
|
d86db7a66c
|
|||
|
7182f7c9f0
|
|||
|
eac23e7d1a
|
|||
|
b500fdb211
|
|||
|
180aba4fa5
|
|||
|
|
d9d7221e90 | ||
| b3fe6f8b70 | |||
| 4792720d74 | |||
| 46e86eb5f9 | |||
| 9a890f30fc | |||
| 66c44976d8 | |||
| 608caeeda2 | |||
| 55bcaaf963 | |||
|
|
ce10ea93db | ||
|
e513d87d24
|
|||
|
|
08061bc6ce | ||
| dd55a0c9df | |||
| 89f0f768e3 | |||
|
5315a05fa2
|
|||
| 57b28daf4e | |||
|
|
0ba060d78c | ||
|
|
b2077ae317 | ||
|
4cd3673d15
|
|||
|
|
771712ad9a | ||
| 1d6941ecc6 | |||
|
56d34767d7
|
|||
| 5fbd914e24 | |||
| 5f193c559f | |||
| a998483d2c | |||
|
|
a4159f0fff | ||
| 866f3a317b | |||
|
4eac05cbb7
|
|||
|
efb3292d9f
|
|||
|
6e822bd5d1
|
|||
|
d8bf174d3a
|
|||
|
2f7be7b051
|
|||
| 18bb207e4a | |||
|
c914f4a477
|
|||
|
2da1be0c6b
|
|||
|
eb00b8c19d
|
|||
|
09a9e47348
|
|||
|
156ae2315a
|
|||
|
|
cf6bedbd9b | ||
| 36aa90519e | |||
|
14c1a57331
|
|||
| d7f0630693 | |||
| 3b7149f161 | |||
| 5545e90160 | |||
| da5b38d1ea | |||
|
65928c4064
|
|||
|
|
033b61dd4f | ||
| 5725d43b11 | |||
|
a8a187a412
|
|||
|
|
f30e16b15e | ||
| bd745042df | |||
|
70878e1423
|
|||
|
937b2c367b
|
|||
| faa0a8533e | |||
|
1cb9d455db
|
|||
|
|
453c9d234c | ||
| 369127e081 | |||
|
|
563faa6c0b | ||
|
|
17163ab002 | ||
|
|
6293e9e67a | ||
|
|
a68ef32614 | ||
| 4de10614be | |||
|
|
2887e6a909 | ||
|
|
e75ffc41e5 | ||
|
|
a620c26812 | ||
|
|
f2bb57b50d | ||
| 8e0cb2105a | |||
|
|
048e80356b | ||
|
|
a47fb89143 | ||
|
|
1b8167c66e | ||
|
|
48d46eda62 | ||
|
|
36307c822e | ||
|
|
dca32db800 | ||
|
|
a153238f79 | ||
|
|
c1fa85fd1b | ||
|
|
69b380e665 | ||
|
|
afc888ab60 | ||
|
|
9a4ef08060 | ||
|
f68b7f68c8
|
|||
|
|
d8143a6b8d | ||
|
e04d36ca12
|
|||
|
|
275ec44a97 | ||
|
fff7913cd5
|
|||
|
|
23ba2efe96 | ||
|
759bbc6f60
|
|||
|
3140c07ad0
|
|||
|
b109dbdcbd
|
|||
|
c1be7c468d
|
|||
|
|
d3797115f7 | ||
|
6d04af6230
|
|||
|
7cf50641f9
|
|||
|
dd398bd96b
|
|||
|
|
63d782ade4 | ||
| e3a1f56b87 | |||
|
|
2f18948cce | ||
|
|
4786850431 | ||
|
|
7584bf661f | ||
|
|
f23b3f1821 | ||
|
|
5bb2ffd67c | ||
| c3c9e8e4e2 | |||
| b03908f93e | |||
| c2e7762df8 | |||
|
|
c83beadd45 | ||
| 46d6b1277b | |||
|
|
10a8c42319
|
||
| 9ed4165ebc | |||
|
|
8cc840adc5 | ||
|
|
79c6e2abd0 | ||
|
|
3093757454 | ||
|
028945bfca
|
|||
|
|
09556bc5df | ||
|
|
94b7f25852 | ||
|
|
2831c8a5cb | ||
|
|
1fed7adf80 | ||
|
|
a9145f6f79 | ||
|
|
ccbe07619f | ||
| 95e6096fbb | |||
|
|
65c29879ab | ||
| b794fc3b68 | |||
| df7be8d894 | |||
|
a474e7cbd4
|
|||
| 5aa83c4bf2 | |||
| 210a04c24d | |||
| 6a35b374c2 | |||
|
785d0d57ae
|
|||
| 7e376f3609 | |||
| ae233cb764 | |||
| 0b9751a97b | |||
| c6c5659b2c | |||
| e1d67df304 | |||
| 7b00f80ac9 | |||
| 92be7a0201 | |||
| 7700924d0e | |||
| 6620c44202 | |||
|
ca5c6791d3
|
|||
|
|
d80797bb17 | ||
|
|
4d9e78cd69 | ||
|
|
4980a41a44
|
||
|
|
d5047b0189 | ||
|
|
8c17a644d5 | ||
|
|
c77ce73a69 | ||
|
|
020a2f2e00 | ||
|
847270877a
|
|||
| d4dd7945cb | |||
| 4626333c74 | |||
| d5341acd28 | |||
| 3c2da99235 | |||
| 013b5fea91 | |||
| 7ea657b582 | |||
| d1e416c850 | |||
| 232c095954 | |||
|
|
f5a3920eea | ||
|
|
51cb94a2e0 | ||
|
|
e0b5522b8f | ||
|
|
19827701aa | ||
| 48dcee7d7f | |||
| 02b6b36f95 | |||
| 8f38f19dd0 | |||
| 04bde9e221 | |||
| 3d948d3ba9 | |||
| 67c23b8707 | |||
| fbe0e59175 | |||
| 1f86f950d6 | |||
| ffce84bb37 | |||
| 2308d50310 | |||
| 1f5dd53673 | |||
|
f8940c9220
|
|||
| 9566bce0bd | |||
|
|
2f9b292ee4 | ||
|
54d8c3fe09
|
|||
| ddd84b2af3 | |||
|
f8ab41bbda
|
|||
| 2f4a458964 | |||
|
|
799fbe67e5 | ||
| 33d94c5d94 | |||
|
|
beedeb836b | ||
| d4766f249b | |||
|
|
fc41c91d41 | ||
| 679ab2f945 | |||
| 13b257f7ff | |||
| bfc25a2894 | |||
| 9f112aedd8 | |||
|
|
61b4323803 | ||
|
|
271f40cdbc | ||
|
|
2bf628103c | ||
|
|
5be346e0fc | ||
|
|
d8f38c496d | ||
|
|
917058b7be | ||
|
|
1b4f4ef360 | ||
|
|
da6a1995c1 | ||
| b030e8eeb7 | |||
| 6c8bb8b95a | |||
|
|
a9c6ebc0de | ||
| b50fe38a06 | |||
|
a627b08df2
|
|||
|
b062f66cf9
|
|||
| 99c0279a1f | |||
| ba3906da71 | |||
|
|
db87ef5df1 | ||
|
|
dacc30da0d | ||
|
|
6d5a72412b | ||
|
|
748ba286ab | ||
|
|
49d50b4bb1 | ||
|
|
039df744d3 | ||
|
|
3a9c616f6b | ||
| 570a2237f1 | |||
| 50b5524c13 | |||
| b2c475101c | |||
|
|
187a5e36e3 | ||
| cde779ea00 | |||
| 8106bb9380 | |||
| df56303949 | |||
| 79238c2a8f | |||
|
|
637d22e0f0 | ||
| ac82e2c7ba | |||
| 5b429bd94f | |||
|
754477b679
|
|||
| c9bed6623c | |||
|
993e5680bb
|
|||
| cf8ec277cb | |||
|
|
9b6a3ef133 | ||
|
|
2476d9f83c | ||
|
|
e9c21c1292 | ||
|
|
c6eee07317 | ||
| aaa56271b0 | |||
| 4280431d0f | |||
|
|
e85a114a23 | ||
|
|
1d1ddf2fef | ||
|
|
0bd66f89fd | ||
|
|
e886589332 | ||
|
|
a7cb34d7ba | ||
|
|
1edf1c2e55 | ||
|
|
234cd19af7 | ||
|
|
40414db1f6 | ||
|
|
f160e341ce | ||
|
5a4ef2bd70
|
|||
|
0473f7b765
|
|||
|
|
7fb92d18c7 | ||
|
|
7054ade55d | ||
|
|
0a54ae3dcc | ||
| 6016cda9ef | |||
|
|
4257ec5598 | ||
| 009008e0d7 | |||
|
|
554bb6b184 | ||
|
b5c21bb62c
|
|||
| 3b0de79bd8 | |||
| ed916c1362 | |||
|
|
77c8b95af4 | ||
|
8482921420
|
|||
| d3d1851142 | |||
| 7a93caecb1 | |||
| 7ebaaa419f | |||
| 4850f9d4c3 | |||
| 7075cc50b9 | |||
| 2a1761e5eb | |||
| c6c4eb57a9 | |||
| 6d92b9b929 | |||
| 90a5c83ca1 | |||
| aadb8d6b50 | |||
|
90bab5ecc0
|
|||
| 0cf2b641cd | |||
| 6183d235ac | |||
| 79ae757e7d | |||
| 4782cde597 | |||
| e934101db7 | |||
| dbea593b1c | |||
| 8f0c414775 | |||
| 17181f6ca2 | |||
| 8792637774 | |||
| 506b76fc00 | |||
| edfd519b8e | |||
| 5520ab8d30 | |||
| 8f06be26ef | |||
| a627d509ac | |||
| 1fa65def25 | |||
| d805997470 | |||
| 1e1e429c9a | |||
| 9eed6af711 | |||
| a046e7d849 | |||
| db37040209 | |||
| 217fd54ec4 | |||
| 17c8c12f55 | |||
| 3ff2a0f63c | |||
| edcf95f71e | |||
| aafc0d55bf | |||
| 215409c7c8 | |||
| 59d5557bdd | |||
| 22ea4b29b8 | |||
| 59ce5b98b8 | |||
| 51fc7503b5 | |||
| 143b55634e | |||
| 3ba59a39bf | |||
| 0dbd11ed68 | |||
| f7fbc5d70d | |||
| 7e3a520dad | |||
| 9a26a258b6 | |||
| 94432247b3 | |||
| 86425a2292 | |||
| 9bd0562b47 | |||
| 1a7777acd1 | |||
| 214fb650c1 | |||
| e9b3c4adba | |||
| fa63ade2e1 | |||
| eab1b42f76 | |||
| c5b85e9ad4 | |||
| 79daa83aca | |||
| 761946660c | |||
| 723064ae52 | |||
| 7db499b1c7 | |||
| c28664b9ee | |||
| f250e8bf16 | |||
| b6818cd7fa | |||
| 3055b8d489 | |||
| 819964ec87 | |||
| 0898faec4d | |||
| 3b4ec021af | |||
| 3ddd22edd1 | |||
| cd4431db1b | |||
| b7ba8eb771 | |||
| f74aacf53b | |||
| cacff8d4df | |||
| b028e54c52 | |||
| 34774e57de | |||
| 9181b43732 | |||
| 1e12fa52aa | |||
| 7176919e94 | |||
| 5ee01e58d8 | |||
| ce495ebcb8 | |||
| b91a528108 | |||
| 333ddd0ba3 | |||
| 291c077536 | |||
| 362718dd9c | |||
| 7e12df8cc0 | |||
| c862cb172f | |||
| 6cdafc22b4 | |||
| 750d1a0803 | |||
| ff7ce98672 | |||
|
|
03eab47d23 | ||
| 1b12faa61a | |||
|
9388d3758d
|
|||
|
7f6ad2b853
|
|||
|
|
4467957b8f | ||
| cafe1204ef | |||
|
16f968657b
|
|||
|
|
8274bb982a | ||
| b3da5b2a96 | |||
|
|
b293044258 | ||
|
|
4db102157f | ||
| 16a4ccbc6b | |||
|
|
407a278e28 | ||
|
|
8134999600 | ||
|
|
f29aafe943 | ||
|
d64ee45d9e
|
|||
|
48b5da9da3
|
|||
|
|
4882fa51e1 | ||
|
|
f72107751f | ||
|
|
cb6265dcb1 | ||
|
|
92ef67a75f | ||
|
|
2e2ae7a0be | ||
| 209f668879 | |||
|
|
f3e1d98704 | ||
|
|
f8045f6dcc | ||
|
|
9a41f0a2f3 | ||
|
|
81743540d0 | ||
|
|
a332fe72a2 | ||
|
|
9bb9d855e4 | ||
|
|
16643c3460 | ||
|
|
eacaa05236 | ||
|
5476583cb2
|
|||
|
|
cb5f059661 | ||
| 23498f5b04 | |||
|
|
5e84185950 | ||
|
|
22339c6ade | ||
|
|
690ce80957 | ||
|
|
d7b373630c | ||
|
60a47b0308
|
|||
|
|
bbb3ebc97c | ||
|
|
a5b348e439 | ||
|
|
aebcfb2e1e | ||
|
904845fe0a
|
|||
|
|
94ccb3583d | ||
|
|
4ecd386f47 | ||
| d182900b02 | |||
|
|
c6f2a04b07 | ||
|
|
c75d13711a | ||
|
|
7fff70b7d5 | ||
|
|
43d36ded42 | ||
|
|
9ea31be332 | ||
|
|
6151eb86f0 | ||
|
|
bda39dea78 | ||
|
|
63294887b1 | ||
|
|
598fd5a7b0 | ||
|
|
582d0377ab | ||
|
704242e120
|
|||
| 5a3474a282 | |||
|
|
3e984d7ee2 | ||
|
|
e3a2d2a1fb | ||
| ea335bc3fb | |||
|
|
c0ac950062 | ||
| e34464782a | |||
| be1f942413 | |||
|
|
3749e2d87d | ||
| 94c8accf45 | |||
|
|
07858a5c7e | ||
| 1a0ca268ab | |||
| fe21779363 | |||
| b7a3d3a3ce | |||
| 60981b6edf | |||
| 845ea0cbc2 | |||
| 1742b99f19 | |||
| 61140b656c | |||
| a6ee8e24fd | |||
| 443bf8e9bd | |||
| a3d98f24b3 | |||
| 143f0ca988 | |||
| b4ef9d9c93 | |||
| 4dc956c9e6 | |||
| c3cc338b20 | |||
| 79f02c18b7 | |||
| 9737cb154b | |||
| 4c6a93ae60 | |||
| a48e7f2f22 | |||
| 190b227d97 | |||
| b4c8de2e09 | |||
| 0922a8fa08 | |||
|
|
ce3d0321c2 | ||
|
93c166144e
|
|||
|
|
09f11c2e4d | ||
|
b9b97205c2
|
|||
|
91e73b7904
|
|||
|
|
6501f45238 | ||
| 7894dba21a | |||
|
0586f2f7d3
|
|||
|
|
352421d5ee | ||
|
|
05f6e35d72 | ||
|
7b90371f84
|
|||
|
|
a3bb3285e1 | ||
| 1e76a29131 | |||
| f6ce5d26c3 | |||
| 295fb9c116 | |||
|
29eeb17306
|
|||
|
ebc12b9ef9
|
|||
|
|
7a4a9f4f05 | ||
| d76fd50321 | |||
|
5fb18877c4
|
|||
| 046dd4ac11 | |||
|
|
e162a8a320 | ||
| cd5a397c3a | |||
|
b2d8dec9a4
|
|||
| a4f1752e72 | |||
| ace083af9e | |||
|
|
7216ddd67b | ||
|
2e260d1184
|
|||
|
|
c222803ef1 | ||
| 05bdb97e1d | |||
| 5a6c7258a4 | |||
|
902a28932d
|
|||
|
|
3519a0df5c | ||
|
c2a99ac1ee
|
|||
|
|
550e3f153b | ||
| 0c3388cf08 | |||
| 2a074357e0 | |||
| 5402af7f8f | |||
| 9cd9518a38 | |||
|
|
704c310b83 | ||
|
|
12fe518235 | ||
|
|
03733df79d | ||
|
|
1247d4d092 | ||
| ad91a3dd23 | |||
|
|
8ad5cdb3ee | ||
|
2c6a30a4f6
|
|||
|
|
4a893d8a56 | ||
| 9ba2c73e5c | |||
|
|
8e72010740 | ||
|
|
6affdada5d | ||
| bf92311c11 | |||
| ac25329204 | |||
| 047d74723e | |||
| 3a7df65f0a | |||
|
|
e7ae2ee38a | ||
|
|
e73ac386a4 | ||
|
6e31e77f03
|
|||
| 8c7334f121 | |||
|
27df77bfeb
|
|||
|
fd76b47789
|
|||
|
|
ce01aac316 | ||
| dae8ceacd6 | |||
| 4806dd97de | |||
| d58deea636 | |||
|
|
e77895c2eb
|
||
|
|
12f215c6a0 | ||
|
f441a15f69
|
|||
|
|
8827130729 | ||
|
b2cce311b5
|
|||
|
|
a3212fa80f | ||
|
cee62b15e6
|
|||
|
|
ba481964e4 | ||
| cd72635051 | |||
|
7205dfe7ca
|
|||
|
|
8e05f95ecc | ||
|
|
4596fd750f | ||
|
|
55c798d7f7 | ||
| 124a900b44 | |||
| 90b17a59a2 | |||
| 015f24669e | |||
|
|
e439057c5b | ||
| db21ab46d4 | |||
|
d35f666664
|
|||
|
|
957d9e72a4 | ||
| d7dff3dbc3 | |||
|
|
62b09deb8d | ||
|
|
9db2ec0d64 | ||
| 3bd402937f | |||
|
1780867a89
|
|||
|
7d378a52d1
|
|||
|
5ecb1b0945
|
|||
|
|
62b1431ed8 | ||
| e48555d88e | |||
|
8d9843d467
|
|||
|
|
0e6dbda05f | ||
| e89237e493 | |||
|
f6267962b3
|
|||
|
7983d948f1
|
|||
| 5df2fba6b7 | |||
|
6e7fa4b9c7
|
|||
|
|
396699f1f1 | ||
|
|
9f776e5e01 | ||
|
|
2c0b264ebd | ||
| d230509984 | |||
|
2a3bb68e3e
|
|||
| 3593a4494d | |||
|
|
1b55c435a9 | ||
| e184e997c0 | |||
|
a37e602131
|
|||
|
|
cacc02d94f | ||
| 60c9d32114 | |||
|
|
82c43bb5f0
|
||
| c9a846b5fc | |||
| 0a104a5195 | |||
| 371a628907 | |||
|
|
4a791f8473 | ||
| 49c8eb6280 | |||
|
1d454a0413
|
|||
|
|
ff11bd34b0 | ||
| 05fec47e1d | |||
|
bb0f2bac3a
|
|||
| 842df2fdb6 | |||
| e25d5ffb5c | |||
|
4490ddf47c
|
|||
| 2cdee9deb9 | |||
|
68ef2f7b72
|
|||
|
270e5c02fc
|
|||
|
|
95bcca6626 | ||
| 202ec86739 | |||
| 7aab840067 | |||
|
|
0402785fc7 | ||
|
|
27e54a7e1d | ||
| 9b69b91199 | |||
| 786165c845 | |||
| d27cf41487 | |||
|
|
7ac255d870 | ||
| 58593aabae | |||
|
|
33c28ccb76 | ||
|
|
7517226194 | ||
| 9fdc22f99f | |||
|
|
c1a147363a | ||
|
|
43ff8c52e4 | ||
|
b2cbc4de09
|
|||
|
ebe6b70883
|
|||
| 89e750d9ea | |||
|
|
b5873e254b | ||
|
|
0e8c89a732 | ||
|
fa063a9508
|
|||
|
e66430cb32
|
|||
| e9a73e5da8 | |||
| 9dbdea3f72 | |||
|
eedcd333d0
|
|||
|
|
57d00a75bf | ||
| 98f70d2774 | |||
|
cb9d678bce
|
|||
|
18c5399625
|
|||
|
|
c4bc3d6509 | ||
| 7ce6827add | |||
|
aa6c01c5f2
|
|||
| f36d11884c | |||
|
dbef03187c
|
|||
|
0e080a70e1
|
|||
|
|
100c1d9e96 | ||
|
c4134f8b27
|
|||
|
|
72c4e824a3 | ||
| 645531287f | |||
|
fe3370f50f
|
|||
|
a6c2c949c2
|
|||
|
|
e2313efc45 | ||
| f12e90355d | |||
|
0e256e6218
|
|||
|
|
56c01cc148 | ||
|
d41c664b64
|
|||
|
|
c7af875f8e | ||
| a1773ca99d | |||
|
|
13ac803269 | ||
|
|
a464a5ac06 | ||
|
|
e69897fc94 | ||
|
|
a400bf9e0b | ||
|
|
0345568e6b | ||
| f67b0602ed | |||
| fd78702ab4 | |||
|
|
adb7853b63 | ||
| b125be1a1c | |||
|
558c4829d9
|
|||
|
|
0cc43ce6d6 | ||
|
|
6815e46775 | ||
|
|
1cbd34c102 | ||
|
|
d60345339b | ||
|
|
c482f51829 | ||
|
|
44f12a825d | ||
|
|
716f7527d0 | ||
|
|
3046ec563d | ||
|
|
a582dba95b | ||
|
4c615ddad9
|
|||
|
|
7fa65dae37 | ||
| 2d39ecfedf | |||
|
|
2f395712d5 | ||
|
|
b5531dd527 | ||
| 7cf9cab032 | |||
|
1c14274cdb
|
|||
|
|
59ac2aa3c9 | ||
|
|
b29a29a2d2 | ||
| 40c5d7559b | |||
|
41d792dc2a
|
|||
|
|
258d1c1868 | ||
|
|
10a6c109c6 | ||
|
ec87726347
|
|||
|
36e12f39cc
|
|||
|
|
c9ea587cfa | ||
| 6870e882a0 | |||
|
|
8bd0c7146f | ||
|
|
135f665881 | ||
| 77717eb32a | |||
|
712b7d2bf2
|
|||
|
cab6de560d
|
|||
|
7d348248bb
|
|||
|
92d3583e0b
|
|||
| d47359b840 | |||
|
|
8570ee37e0
|
||
|
|
39dbfa5592
|
@@ -1,38 +0,0 @@
|
||||
open Fake.Core
|
||||
open Fake.IO
|
||||
open Farmer
|
||||
open Farmer.Builders
|
||||
|
||||
open Helpers
|
||||
|
||||
initializeContext()
|
||||
|
||||
let packPath = Path.getFullName "packages"
|
||||
|
||||
Target.create "Clean" (fun _ -> Shell.cleanDir packPath)
|
||||
|
||||
Target.create "InstallClient" (fun _ ->
|
||||
run bun "install" "."
|
||||
run dotnet "tool restore" "."
|
||||
)
|
||||
|
||||
Target.create "Run" ignore
|
||||
|
||||
Target.create "Format" (fun _ ->
|
||||
run dotnet "fantomas . -r" "src"
|
||||
)
|
||||
|
||||
open Fake.Core.TargetOperators
|
||||
|
||||
let dependencies = [
|
||||
"Clean"
|
||||
==> "InstallClient"
|
||||
|
||||
"Run"
|
||||
==> "InstallClient"
|
||||
|
||||
"Format"
|
||||
]
|
||||
|
||||
[<EntryPoint>]
|
||||
let main args = runOrDefault args
|
||||
@@ -1,127 +0,0 @@
|
||||
module Helpers
|
||||
|
||||
open Fake.Core
|
||||
|
||||
let initializeContext () =
|
||||
let execContext = Context.FakeExecutionContext.Create false "build.fsx" [ ]
|
||||
Context.setExecutionContext (Context.RuntimeContext.Fake execContext)
|
||||
|
||||
module Proc =
|
||||
module Parallel =
|
||||
open System
|
||||
|
||||
let locker = obj()
|
||||
|
||||
let colors =
|
||||
[| ConsoleColor.Blue
|
||||
ConsoleColor.Yellow
|
||||
ConsoleColor.Magenta
|
||||
ConsoleColor.Cyan
|
||||
ConsoleColor.DarkBlue
|
||||
ConsoleColor.DarkYellow
|
||||
ConsoleColor.DarkMagenta
|
||||
ConsoleColor.DarkCyan |]
|
||||
|
||||
let print color (colored: string) (line: string) =
|
||||
lock locker
|
||||
(fun () ->
|
||||
let currentColor = Console.ForegroundColor
|
||||
Console.ForegroundColor <- color
|
||||
Console.Write colored
|
||||
Console.ForegroundColor <- currentColor
|
||||
Console.WriteLine line)
|
||||
|
||||
let onStdout index name (line: string) =
|
||||
let color = colors.[index % colors.Length]
|
||||
if isNull line then
|
||||
print color $"{name}: --- END ---" ""
|
||||
else if String.isNotNullOrEmpty line then
|
||||
print color $"{name}: " line
|
||||
|
||||
let onStderr name (line: string) =
|
||||
let color = ConsoleColor.Red
|
||||
if isNull line |> not then
|
||||
print color $"{name}: " line
|
||||
|
||||
let redirect (index, (name, createProcess)) =
|
||||
createProcess
|
||||
|> CreateProcess.redirectOutputIfNotRedirected
|
||||
|> CreateProcess.withOutputEvents (onStdout index name) (onStderr name)
|
||||
|
||||
let printStarting indexed =
|
||||
for (index, (name, c: CreateProcess<_>)) in indexed do
|
||||
let color = colors.[index % colors.Length]
|
||||
let wd =
|
||||
c.WorkingDirectory
|
||||
|> Option.defaultValue ""
|
||||
let exe = c.Command.Executable
|
||||
let args = c.Command.Arguments.ToStartInfo
|
||||
print color $"{name}: {wd}> {exe} {args}" ""
|
||||
|
||||
let run cs =
|
||||
cs
|
||||
|> Seq.toArray
|
||||
|> Array.indexed
|
||||
|> fun x -> printStarting x; x
|
||||
|> Array.map redirect
|
||||
|> Array.Parallel.map Proc.run
|
||||
|
||||
let createProcess exe arg dir =
|
||||
CreateProcess.fromRawCommandLine exe arg
|
||||
|> CreateProcess.withWorkingDirectory dir
|
||||
|> CreateProcess.ensureExitCode
|
||||
|
||||
let dotnet = createProcess "dotnet"
|
||||
|
||||
let fable = createProcess "fable"
|
||||
|
||||
let bun =
|
||||
let bunPath =
|
||||
match ProcessUtils.tryFindFileOnPath "bun" with
|
||||
| Some path -> path
|
||||
| None ->
|
||||
"bun was not found in path. Please install it and make sure it's available from your path. " +
|
||||
"See https://safe-stack.github.io/docs/quickstart/#install-pre-requisites for more info"
|
||||
|> failwith
|
||||
|
||||
createProcess bunPath
|
||||
|
||||
let bunx = createProcess "bunx"
|
||||
|
||||
type BundleMode =
|
||||
| Prod
|
||||
| Devel
|
||||
| Watch
|
||||
with
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| Prod -> "production"
|
||||
| Devel -> "development"
|
||||
| Watch -> "watch"
|
||||
|
||||
let viteCmd (m: BundleMode) outDir =
|
||||
match m with
|
||||
| Prod -> $"vite build -c ../../vite.config.js -m {m} --emptyOutDir --outDir {outDir}/public"
|
||||
| Devel -> $"vite build -c ../../vite.config.js -m {m} --minify false --sourcemap true --emptyOutDir --outDir {outDir}/public"
|
||||
| Watch -> "vite -c ../../vite.config.js"
|
||||
|
||||
let run proc arg dir =
|
||||
proc arg dir
|
||||
|> Proc.run
|
||||
|> ignore
|
||||
|
||||
let runParallel processes =
|
||||
processes
|
||||
|> Proc.Parallel.run
|
||||
|> ignore
|
||||
|
||||
let runOrDefault args =
|
||||
try
|
||||
match args with
|
||||
| [| target |] -> Target.runOrDefault target
|
||||
| _ ->
|
||||
Target.runOrDefault "Run"
|
||||
0
|
||||
with e ->
|
||||
printfn "%A" e
|
||||
1
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"fable": {
|
||||
"version": "4.24.0",
|
||||
"commands": [
|
||||
"fable"
|
||||
],
|
||||
"rollForward": false
|
||||
},
|
||||
"femto": {
|
||||
"version": "0.19.0",
|
||||
"commands": [
|
||||
"femto"
|
||||
],
|
||||
"rollForward": false
|
||||
},
|
||||
"fantomas": {
|
||||
"version": "7.0.0",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
],
|
||||
"rollForward": false
|
||||
},
|
||||
"dotnet-outdated-tool": {
|
||||
"version": "4.6.7",
|
||||
"commands": [
|
||||
"dotnet-outdated"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0.301
|
||||
|
||||
# Bun version
|
||||
ARG BUN_INSTALL=/usr/local
|
||||
@@ -26,4 +26,4 @@ ENV PATH="/root/.dotnet/tools:${PATH}"
|
||||
|
||||
# Copy endpoint specific user settings into container to specify
|
||||
# .NET Core should be used as the runtime.
|
||||
COPY settings.vscode.json /root/.vscode-remote/data/Machine/settings.json
|
||||
COPY settings.vscode.json /root/.vscode-remote/data/Machine/settings.json
|
||||
|
||||
@@ -9,8 +9,23 @@ insert_final_newline = false
|
||||
|
||||
[*.js]
|
||||
indent_size = 2
|
||||
max_line_length = 80
|
||||
|
||||
[*.scss]
|
||||
indent_size = 2
|
||||
max_line_length = 80
|
||||
|
||||
[*.nix]
|
||||
indent_size = 2
|
||||
max_line_length= 80
|
||||
|
||||
[*.scss]
|
||||
indent_size = 2
|
||||
max_line_length = 80
|
||||
|
||||
[*.yaml]
|
||||
indent_size = 2
|
||||
|
||||
[*.fs]
|
||||
max_line_length= 120
|
||||
|
||||
@@ -21,6 +36,7 @@ fsharp_space_before_uppercase_invocation = true
|
||||
fsharp_blank_lines_around_nested_multiline_expressions = false
|
||||
fsharp_newline_between_type_definition_and_members = false
|
||||
fsharp_multiline_bracket_style = stroustrup
|
||||
fsharp_multi_line_lambda_closing_newline = true
|
||||
|
||||
fsharp_array_or_list_multiline_formatter = character_width
|
||||
fsharp_max_array_or_list_width = 70
|
||||
|
||||
17
.envrc
17
.envrc
@@ -1 +1,16 @@
|
||||
use nix
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export NPINS_DIRECTORY="nix"
|
||||
export APP_ENV=$USER
|
||||
|
||||
# the shebang is ignored, but nice for editors
|
||||
watch_file nix/sources.json
|
||||
|
||||
# Load .env file if it exists
|
||||
dotenv_if_exists
|
||||
|
||||
# Activate development shell
|
||||
use nix
|
||||
|
||||
# HACK: Workaround for direnv bug
|
||||
unset TMP TMPDIR TEMP TEMPDIR
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -5,23 +5,31 @@
|
||||
.idea/
|
||||
.ionide/
|
||||
.certs/
|
||||
.config/
|
||||
obj/
|
||||
bin/
|
||||
packages/
|
||||
node_modules/
|
||||
release.cmd
|
||||
release.sh
|
||||
*.orig
|
||||
*.DotSettings.user
|
||||
.pre-commit-config.yaml
|
||||
deploy/
|
||||
dist/
|
||||
build/
|
||||
*.db
|
||||
.env
|
||||
build.fsx.lock
|
||||
*.sif
|
||||
result*
|
||||
result-*
|
||||
netrc
|
||||
.deps*
|
||||
*.key
|
||||
_*.yaml
|
||||
tilt/base/_manifest.yaml
|
||||
NuGet.Config
|
||||
sync.list
|
||||
packages.lock.json
|
||||
package-lock.json
|
||||
*.nupkg
|
||||
*.fable-temp*
|
||||
.env
|
||||
@@ -1,28 +1,51 @@
|
||||
# yaml-language-server: $schema=https://gitlab.com/gitlab-org/gitlab/-/raw/master/app/assets/javascripts/editor/schema/ci.json
|
||||
variables:
|
||||
SDK_VERSION: 9.0
|
||||
SKIP_TESTS: "true"
|
||||
SKIP_TESTS: "true"
|
||||
|
||||
default:
|
||||
tags:
|
||||
- nix
|
||||
|
||||
include:
|
||||
- project: oceanbox/gitlab-ci
|
||||
ref: v4.1
|
||||
file: template/Base.gitlab-ci.yml
|
||||
- local: '/src/Atlantis/.gitlab-ci.yml'
|
||||
rules:
|
||||
- changes:
|
||||
- 'src/Atlantis/**/*'
|
||||
- local: '/src/Sorcerer/.gitlab-ci.yml'
|
||||
rules:
|
||||
- changes:
|
||||
- 'src/Sorcerer/**/*'
|
||||
- local: '/src/Interfaces/.gitlab-ci.yml'
|
||||
rules:
|
||||
- changes:
|
||||
- 'src/Interfaces/**/*'
|
||||
- local: '/src/DataAgent/.gitlab-ci.yml'
|
||||
rules:
|
||||
- changes:
|
||||
- 'src/DataAgent/**/*'
|
||||
- local: '/src/ServerPack/.gitlab-ci.yml'
|
||||
rules:
|
||||
- changes:
|
||||
- 'src/ServerPack/**/*'
|
||||
- project: oceanbox/gitlab-ci
|
||||
ref: v4.5
|
||||
file: template/Base.gitlab-ci.yml
|
||||
- local: "/src/Atlantis/.gitlab-ci.yml"
|
||||
rules:
|
||||
- changes:
|
||||
- "src/Atlantis/**/*"
|
||||
- "nix/packages/atlantis.nix"
|
||||
- "nix/packages/atlantis-client.nix"
|
||||
- "nix/containers.nix"
|
||||
- local: "/src/Sorcerer/.gitlab-ci.yml"
|
||||
rules:
|
||||
- changes:
|
||||
- "src/Sorcerer/**/*"
|
||||
- "nix/packages/sorcerer.nix"
|
||||
- "nix/containers.nix"
|
||||
- local: "/src/Archivist/.gitlab-ci.yml"
|
||||
rules:
|
||||
- changes:
|
||||
- "src/Archivist/**/*"
|
||||
- "nix/packages/archivist.nix"
|
||||
- local: "/src/Interfaces/.gitlab-ci.yml"
|
||||
rules:
|
||||
- changes:
|
||||
- "src/Interfaces/**/*"
|
||||
- "nix/packages/api.nix"
|
||||
- local: "/src/DataAgent/.gitlab-ci.yml"
|
||||
rules:
|
||||
- changes:
|
||||
- "src/DataAgent/**/*"
|
||||
- "nix/packages/dataagent.nix"
|
||||
- local: "/src/ServerPack/.gitlab-ci.yml"
|
||||
rules:
|
||||
- changes:
|
||||
- "src/ServerPack/**/*"
|
||||
- "nix/packages/serverpack.nix"
|
||||
- local: "/src/Codex/.gitlab-ci.yml"
|
||||
rules:
|
||||
- changes:
|
||||
- "src/Codex/**/*"
|
||||
- "nix/packages/node-modules.nix"
|
||||
- "nix/packages/sources.nix"
|
||||
|
||||
@@ -15,7 +15,7 @@ plugins:
|
||||
- "src/Atlantis/src/**.fsproj"
|
||||
- "src/Sorcerer/src/**.fsproj"
|
||||
- "src/DataAgent/src/**.fsproj"
|
||||
- "src/ServerPack/src/*.fsproj"
|
||||
- "src/ServerPack/src/**.fsproj"
|
||||
- "src/Interfaces/**.fsproj"
|
||||
- - '@semantic-release/exec'
|
||||
- generateNotesCmd: "echo ${nextRelease.version} > VERSION"
|
||||
@@ -29,7 +29,7 @@ plugins:
|
||||
- "src/Atlantis/src/**.fsproj"
|
||||
- "src/Sorcerer/src/**.fsproj"
|
||||
- "src/DataAgent/src/**.fsproj"
|
||||
- "src/ServerPack/src/*.fsproj"
|
||||
- "src/ServerPack/src/**.fsproj"
|
||||
- "src/Interfaces/**.fsproj"
|
||||
|
||||
analyzeCommits:
|
||||
|
||||
17
Build.fsproj
17
Build.fsproj
@@ -1,17 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include=".build/Helpers.fs" />
|
||||
<Compile Include=".build/Build.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fake.Core.Target" Version="6.1.3" />
|
||||
<PackageReference Include="Fake.DotNet.Cli" Version="6.1.3" />
|
||||
<PackageReference Include="Fake.IO.FileSystem" Version="6.1.3" />
|
||||
<PackageReference Include="Farmer" Version="1.9.6" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.100" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
35
Directory.Build.props
Normal file
35
Directory.Build.props
Normal file
@@ -0,0 +1,35 @@
|
||||
<Project>
|
||||
<!-- Make F# support Central Package Management -->
|
||||
<PropertyGroup>
|
||||
<DisableImplicitSystemValueTupleReference>true</DisableImplicitSystemValueTupleReference>
|
||||
<DisableImplicitFSharpCoreReference>true</DisableImplicitFSharpCoreReference>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<!-- <DebugType Condition=" '$(DebugType)' == '' ">embedded</DebugType> -->
|
||||
<!-- <DebugType>embedded</DebugType> -->
|
||||
<!-- <Deterministic>true</Deterministic> -->
|
||||
<!-- <NetCoreTargetingPackRoot>[UNDEFINED]</NetCoreTargetingPackRoot> -->
|
||||
|
||||
<!-- Warnings and Errors -->
|
||||
<!--
|
||||
FS0025: Incomplete pattern matches on this expression.
|
||||
FS1182: Unused variables
|
||||
FS1178: Does not support structural equality
|
||||
FS3390: Malformed XML doc comment
|
||||
-->
|
||||
<!-- <WarnOn>FS3388,FS3559</WarnOn> -->
|
||||
<!-- <WarnOn>1182;3390;1178;$(WarnOn)</WarnOn> -->
|
||||
<!-- <TreatWarningsAsErrors>true</TreatWarningsAsErrors> -->
|
||||
<WarningsAsErrors>FS0025</WarningsAsErrors>
|
||||
<NoWarn>NU1603;MSB3277</NoWarn>
|
||||
|
||||
<!-- Restore with Lockfiles -->
|
||||
<!-- https://www.gresearch.co.uk/blog/article/improve-nuget-restores-with-static-graph-evaluation/ -->
|
||||
<RestoreUseStaticGraphEvaluation>true</RestoreUseStaticGraphEvaluation>
|
||||
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
|
||||
|
||||
<!-- Performance -->
|
||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||
<OtherFlags>$(OtherFlags) --test:GraphBasedChecking --test:ParallelOptimization --test:ParallelIlxGen</OtherFlags>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
109
Directory.Packages.props
Normal file
109
Directory.Packages.props
Normal file
@@ -0,0 +1,109 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Common -->
|
||||
<PackageVersion Include="FSharp.Core" Version="9.0.303" />
|
||||
<PackageVersion Include="Fargo.CmdLine" Version="1.7.5" />
|
||||
<PackageVersion Include="FSharpPlus" Version="1.7.0" />
|
||||
<PackageVersion Include="FSharp.Data" Version="6.4.1" />
|
||||
<PackageVersion Include="FsToolkit.ErrorHandling" Version="5.0.1" />
|
||||
<PackageVersion Include="Thoth.Json.Giraffe" Version="6.0.0" />
|
||||
<PackageVersion Include="Thoth.Json.Net" Version="12.0.0" />
|
||||
<PackageVersion Include="Serilog" Version="4.2.0" />
|
||||
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0"/>
|
||||
<PackageVersion Include="Drifters.Api" Version="6.22.0" />
|
||||
<!-- Client -->
|
||||
<PackageVersion Include="Fable.Browser.IndexedDB" Version="2.2.0" />
|
||||
<PackageVersion Include="Fable.Browser.ResizeObserver" Version="1.0.0" />
|
||||
<PackageVersion Include="Fable.Browser.WebGL" Version="1.3.0" />
|
||||
<PackageVersion Include="Fable.Core" Version="4.4.0"/>
|
||||
<PackageVersion Include="Fable.Elmish" Version="4.2.0" />
|
||||
<PackageVersion Include="Fable.Fetch" Version="2.7.0" />
|
||||
<PackageVersion Include="Fable.FontAwesome.Free" Version="3.0.0"/>
|
||||
<PackageVersion Include="Fable.Lit.Elmish" Version="1.6.2-oceanbox" />
|
||||
<PackageVersion Include="Fable.Lit.React" Version="1.6.2-oceanbox" />
|
||||
<PackageVersion Include="Fable.Lit" Version="1.6.2-oceanbox" />
|
||||
<PackageVersion Include="Fable.OpenLayers" Version="2.19.0" />
|
||||
<PackageVersion Include="Fable.Promise" Version="3.2.0" />
|
||||
<PackageVersion Include="Fable.React" Version="9.4.0" />
|
||||
<PackageVersion Include="Fable.Remoting.Client" Version="7.32.0" />
|
||||
<PackageVersion Include="Fable.Remoting.MsgPack" Version="1.24.0" />
|
||||
<PackageVersion Include="Fable.SignalR.Elmish" Version="2.1.0" />
|
||||
<PackageVersion Include="Fable.SimpleHttp" Version="3.6.0" />
|
||||
<PackageVersion Include="Feliz.Router" Version="4.0.0"/>
|
||||
<PackageVersion Include="Feliz" Version="2.9.0" />
|
||||
<PackageVersion Include="Feliz.UseElmish" Version="2.5.0" />
|
||||
<PackageVersion Include="Feliz.CompilerPlugins" Version="2.2.0" />
|
||||
<PackageVersion Include="Matplotlib.ColorMaps" Version="3.0.1" />
|
||||
<PackageVersion Include="Thoth.Fetch" Version="3.0.1" />
|
||||
<PackageVersion Include="Thoth.Json" Version="10.4.1"/>
|
||||
<PackageVersion Include="FS.FluentUI" Version="3.0.0"/>
|
||||
<!-- Serverpack -->
|
||||
<PackageVersion Include="OpenFga.Sdk" Version="0.7.0"/>
|
||||
<PackageVersion Include="FSharp.SystemTextJson" Version="1.3.13"/>
|
||||
<PackageVersion Include="Saturn.OpenTelemetry" Version="0.6.0-alpha"/>
|
||||
<!-- Atlantis -->
|
||||
<PackageVersion Include="Argu" Version="6.2.5" />
|
||||
<PackageVersion Include="AspNetCore.Serilog.RequestLoggingMiddleware" Version="1.0.2" />
|
||||
<PackageVersion Include="Azure.Extensions.AspNetCore.DataProtection.Blobs" Version="1.5.0" />
|
||||
<PackageVersion Include="Azure.Extensions.AspNetCore.DataProtection.Keys" Version="1.4.0" />
|
||||
<PackageVersion Include="Azure.Identity" Version="1.13.2" />
|
||||
<PackageVersion Include="Azure.Security.KeyVault.Secrets" Version="4.7.0" />
|
||||
<PackageVersion Include="Dapr.Actors" Version="1.16.0" />
|
||||
<PackageVersion Include="Dapr.Actors.AspNetCore" Version="1.16.0" />
|
||||
<PackageVersion Include="Dapr.AspNetCore" Version="1.16.0" />
|
||||
<PackageVersion Include="Dapr.Client" Version="1.16.0" />
|
||||
<PackageVersion Include="Fable.Remoting.DotnetClient" Version="3.35.0" />
|
||||
<PackageVersion Include="Fable.Remoting.Giraffe" Version="5.21.0" />
|
||||
<PackageVersion Include="Fable.Remoting.Server" Version="5.39.0" />
|
||||
<PackageVersion Include="Fable.SignalR.Saturn" Version="2.1.0" />
|
||||
<PackageVersion Include="Giraffe" Version="7.0.2" />
|
||||
<PackageVersion Include="IdentityModel.AspNetCore" Version="4.3.0" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.2" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.2" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="9.0.2" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Http.Polly" Version="9.0.2" />
|
||||
<PackageVersion Include="Oceanbox.FvcomKit" Version="5.13.0" />
|
||||
<PackageVersion Include="prometheus-net.AspNetCore" Version="8.2.1" />
|
||||
<PackageVersion Include="Saturn" Version="0.17.0" />
|
||||
<PackageVersion Include="SecurityCodeScan" Version="3.5.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageVersion>
|
||||
<PackageVersion Include="Sentry.AspNetCore" Version="5.11.0" />
|
||||
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
<PackageVersion Include="Serilog.Enrichers.CorrelationId" Version="3.0.1" />
|
||||
<PackageVersion Include="Serilog.Expressions" Version="5.0.0" />
|
||||
<PackageVersion Include="Serilog.Sinks.OpenTelemetry" Version="4.1.1" />
|
||||
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.2" />
|
||||
<!-- Sorcerer -->
|
||||
<PackageVersion Include="MessagePack" Version="3.1.3" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageVersion Include="ProjNet.FSharp" Version="5.2.0" />
|
||||
<!-- Dapperizer -->
|
||||
<PackageVersion Include="Oceanbox.SDSLite" Version="2.8.0" />
|
||||
<PackageVersion Include="Dapper.FSharp" Version="4.9.0"/>
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.2"/>
|
||||
<PackageVersion Include="NetTopologySuite" Version="2.5.0"/>
|
||||
<PackageVersion Include="Npgsql" Version="9.0.2" />
|
||||
<PackageVersion Include="Npgsql.NetTopologySuite" Version="9.0.2"/>
|
||||
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2"/>
|
||||
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite" Version="9.0.2"/>
|
||||
<!-- Entity -->
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.1"/>
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageVersion>
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageVersion>
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.1" />
|
||||
<!-- Analyzers -->
|
||||
<PackageVersion Include="G-Research.FSharp.Analyzers" Version="0.19.0" />
|
||||
<PackageVersion Include="Ionide.Analyzers" Version="0.14.9" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
21
LICENSE
21
LICENSE
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Serit Tromsø AS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -24,6 +24,10 @@
|
||||
<Project Path="src/Atlantis/src/Server/Petimeter/Petimeter.fsproj" />
|
||||
<Project Path="src/Atlantis/src/Server/Server.fsproj" />
|
||||
</Folder>
|
||||
<Folder Name="/Codex/">
|
||||
<Project Path="src\Codex\src\Client\Codex.Client.fsproj" />
|
||||
<Project Path="src\Codex\src\Server\Codex.Server.fsproj" />
|
||||
</Folder>
|
||||
<Folder Name="/DataAgent/">
|
||||
<Project Path="src/DataAgent/src/Entity/Entity.csproj" />
|
||||
</Folder>
|
||||
@@ -31,6 +35,7 @@
|
||||
<Project Path="src/DataAgent/src/DataAgent/Oceanbox.DataAgent.fsproj" />
|
||||
</Folder>
|
||||
<Folder Name="/Interfaces/">
|
||||
<Project Path="src/Interfaces/Api/Poseidon.Api.fsproj" />
|
||||
<Project Path="src/Interfaces/Archmaester/Archmaester.Api.fsproj" />
|
||||
<Project Path="src/Interfaces/Atlantis/Atlantis.Api.fsproj" />
|
||||
<Project Path="src/Interfaces/Hipster/Hipster.Api.fsproj" />
|
||||
@@ -46,7 +51,6 @@
|
||||
<File Path="global.json" />
|
||||
</Folder>
|
||||
<Folder Name="/Sorcerer/">
|
||||
<Project Path="src/Sorcerer/src/Client/Client.fsproj" />
|
||||
<Project Path="src/Sorcerer/src/Server/Sorcerer.fsproj" />
|
||||
</Folder>
|
||||
</Solution>
|
||||
106
README.md
106
README.md
@@ -1,15 +1,21 @@
|
||||
[](https://nixos.org/)
|
||||
|
||||
# Atlantis
|
||||
# Poseidon
|
||||
|
||||
Oceanbox's Single Page Application used for Visualizations and Analysis.
|
||||
Oceanbox's comprehensive platform for oceanic data visualization, analysis, and processing.
|
||||
|
||||
## Documentation
|
||||
|
||||
- **[Nix Build System](nix/README.md)** - Comprehensive guide to the Nix-based build system, packages, containers, and workflows
|
||||
- **[Scripts](scripts/README.md)** - Available utility scripts for development and deployment
|
||||
|
||||
## Bootstrapping Guide
|
||||
|
||||
To bootstrap Atlantis for development, build and run it using Tilt.
|
||||
|
||||
Some setup is required:
|
||||
|
||||
### k8s access
|
||||
### Kubernetes Access
|
||||
|
||||
To run our application on the kubernetes cluster, Tilt needs access.
|
||||
You need to authenticate with `oidc`, using your microsoft account.
|
||||
@@ -40,21 +46,21 @@ Next, configure the required contexts to use `oidc` (also in your `~/.kube/confi
|
||||
```yaml
|
||||
---
|
||||
- context:
|
||||
cluster: ekman
|
||||
namespace: sorcerer
|
||||
user: oidc
|
||||
cluster: ekman
|
||||
namespace: sorcerer
|
||||
user: oidc
|
||||
name: ekman
|
||||
- context:
|
||||
cluster: oceanbox
|
||||
user: oidc
|
||||
cluster: oceanbox
|
||||
namespace: atlantis
|
||||
user: oidc
|
||||
name: oceanbox
|
||||
---
|
||||
```
|
||||
|
||||
Finally, **you must be granted the necessary priveleges in Entra to access the clusters.**
|
||||
Verify that you have access with `kubectl`:
|
||||
|
||||
```sh
|
||||
```shell
|
||||
kubectl --context oceanbox -n default get pods
|
||||
```
|
||||
|
||||
@@ -63,26 +69,7 @@ kubectl --context oceanbox -n default get pods
|
||||
Required helm manifests are hosted in a separate repository: <https://gitlab.com/oceanbox/manifests>.
|
||||
Clone it into a directory _in the same parent directory as this repository._
|
||||
|
||||
The Bitnami respository must also be added to helm:
|
||||
|
||||
```sh
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||
```
|
||||
|
||||
### DNS
|
||||
|
||||
Some DNS masking is required.
|
||||
Add the following to your NixOS configuration:
|
||||
|
||||
```nix
|
||||
services.dnsmasq = {
|
||||
enable = true;
|
||||
settings.address = [
|
||||
"/.local/127.0.0.1"
|
||||
"/.local.oceanbox.io/127.0.0.1"
|
||||
];
|
||||
};
|
||||
```
|
||||
You'll have to run `helm dependency update` in the atlantis directory within the manifest repo to download the charts.
|
||||
|
||||
### NuGet
|
||||
|
||||
@@ -97,28 +84,45 @@ To retrieve packages from the private Oceanbox nuget registry, configure it with
|
||||
</packageSources>
|
||||
<packageSourceCredentials>
|
||||
<oceanbox>
|
||||
<add key="Username" value="oceanbox-nuget" />
|
||||
<add key="ClearTextPassword" value="<...>" />
|
||||
<add key="Username" value="<Your-GitLab-Username>" />
|
||||
<add key="ClearTextPassword" value="<Your-GitLab-PAT>" />
|
||||
</oceanbox>
|
||||
</packageSourceCredentials>
|
||||
<packageSourceMapping>
|
||||
<packageSource key="nuget.org">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
<packageSource key="oceanbox">
|
||||
<package pattern="Oceanbox.*" />
|
||||
<package pattern="ProjNet.FSharp" />
|
||||
<package pattern="Drifters.Api" />
|
||||
<package pattern="Fable.Lit" />
|
||||
<package pattern="Fable.Lit.*" />
|
||||
<package pattern="Fable.SignalR" />
|
||||
<package pattern="Fable.SignalR.*" />
|
||||
<package pattern="Fable.OpenLayers" />
|
||||
<package pattern="Matplotlib.*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
```
|
||||
|
||||
Substitute `<...>` for the corresponding secret.
|
||||
Substitute with your own gitlab username and PAT in the credentials.
|
||||
|
||||
Now, we should be able to `restore`:
|
||||
|
||||
```sh
|
||||
dotnet tool restore
|
||||
dotnet restore
|
||||
```shell
|
||||
dotnet restore Poseidon.slnx
|
||||
```
|
||||
|
||||
for `dotnet-tools` we use nix, so entering the shell using `nix-shell` or `direnv` is enough.
|
||||
|
||||
### Mkcert
|
||||
|
||||
To generate certificates correctly, vite needs the `mkcert` binary in a predefined path in our home directory.
|
||||
`mkcert` is included in our dev shell, so we can create a symlink to its location in the nix store:
|
||||
|
||||
```sh
|
||||
```fish
|
||||
which mkcert | xargs -I{} ln -s {} ~/.vite-plugin-mkcert
|
||||
```
|
||||
|
||||
@@ -127,12 +131,16 @@ which mkcert | xargs -I{} ln -s {} ~/.vite-plugin-mkcert
|
||||
### Docker Login
|
||||
|
||||
In order for Tilt to push the images it builds to the oceanbox registry, we must use `docker login` to authenticate with it.
|
||||
First, create a personal access token in your gitlab account.
|
||||
It should have the `read_registry` and `write_registry` scopes set.
|
||||
First, create a personal access token in your gitlab account. It should have the `read_registry` and `write_registry` scopes set.
|
||||
|
||||
```fish
|
||||
set -x TOKEN glpat-xxxx
|
||||
```
|
||||
|
||||
Then, supply it to `docker login`:
|
||||
|
||||
```sh
|
||||
docker login registry.gitlab.com/oceanbox
|
||||
```shell
|
||||
echo "$TOKEN" | docker login gitlab.com -u <user> --password-stdin
|
||||
```
|
||||
|
||||
When prompted, authenticate with your gitlab username and the PAT you just created.
|
||||
@@ -141,7 +149,7 @@ When prompted, authenticate with your gitlab username and the PAT you just creat
|
||||
|
||||
A namespace must be created for your tilt application to live in on the cluster.
|
||||
|
||||
```sh
|
||||
```shell
|
||||
kubectl create ns "$APP_NAMESPACE" --context oceanbox
|
||||
```
|
||||
|
||||
@@ -149,7 +157,7 @@ kubectl create ns "$APP_NAMESPACE" --context oceanbox
|
||||
|
||||
In the project root, run tilt with the following command:
|
||||
|
||||
```sh
|
||||
```shell
|
||||
tilt up --context oceanbox
|
||||
```
|
||||
|
||||
@@ -157,9 +165,21 @@ You should now be able to access the Atlantis client (with HMR) on <atlantis.loc
|
||||
|
||||
### Trust Root Certificate
|
||||
|
||||
> [!note]
|
||||
> You'll need to run `just run-client` in `src/Atlantis` to generate the certificates in `~/.vite-plugin-mkcert/certs`
|
||||
|
||||
In order for your browser to allow you to access the web application, you must add the root certificate generated by `mkcert` to the list of trusted authorities in your browser:
|
||||
|
||||
1. In firefox, navigate to settings and search for _"Certificates"._
|
||||
2. Click on _"View Certificates",_ then _"Import..."_ in the _"Authorities"_ tab.
|
||||
3. Select the root certificate; `~/.vite-plugin-mkcert/certs/rootCA.pem`.
|
||||
- Make sure to check _"This certificate can identify websites"._
|
||||
|
||||
### Add `user` to OpenFGA
|
||||
|
||||
Ask [sales](support@oceanbox.io) to add your `azure-ad-user` to OpenFGA.
|
||||
|
||||
### CORS for Sorcerer
|
||||
|
||||
Add the `url` of your instance to the CORS list of Sorcerer
|
||||
[here](https://gitlab.com/oceanbox/manifests/-/blob/main/values/sorcerer/kustomize/prod/appsettings.json?ref_type=heads#L52).
|
||||
988
RELEASE_NOTES.md
988
RELEASE_NOTES.md
@@ -1,5 +1,993 @@
|
||||
# Changelog
|
||||
|
||||
## [1.40.5](https://gitlab.com/oceanbox/Poseidon/compare/v1.40.4...v1.40.5) (2026-01-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **xtractor:** Reduce to 4 cores per task ([8e824d4](https://gitlab.com/oceanbox/Poseidon/commit/8e824d4afa0b03f59e006d3a0d50fb216e71483e))
|
||||
|
||||
## [1.40.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.40.3...v1.40.4) (2026-01-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **xtractor:** Reduce core requirement to 8 ([efacb2a](https://gitlab.com/oceanbox/Poseidon/commit/efacb2a3322de0ced45db4eec240846f4e371a75))
|
||||
|
||||
## [1.40.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.40.2...v1.40.3) (2026-01-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **inbox|xtracto:** Delete/Read msg and allow non-ascii xtractor names ([d8d5e07](https://gitlab.com/oceanbox/Poseidon/commit/d8d5e076baf8b559200f2da91237f9874678b216))
|
||||
* **multiauth:** Add clientId to redirect on signout ([54c40d7](https://gitlab.com/oceanbox/Poseidon/commit/54c40d7accc4bbc43f66dda0df647ccac482a2b0))
|
||||
|
||||
## [1.40.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.40.1...v1.40.2) (2026-01-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **xtract:** Disabled if not allowed to simulate transport ([e429a85](https://gitlab.com/oceanbox/Poseidon/commit/e429a855e5bd00493e2f99647092aebce9c99a2a))
|
||||
|
||||
## [1.40.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.40.0...v1.40.1) (2026-01-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix tilt build on net10 ([d5cde19](https://gitlab.com/oceanbox/Poseidon/commit/d5cde19250847f7b091cfa5f65eb703405c202b6))
|
||||
|
||||
# [1.40.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.39.2...v1.40.0) (2026-01-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Codex:** expose days instead of frames in arcive form ([6cf5262](https://gitlab.com/oceanbox/Poseidon/commit/6cf5262dd5c98517a3c767f410c858fe32c07bd5))
|
||||
* **Codex:** only allow inbounds time intervals on edit archive ([eaea4b2](https://gitlab.com/oceanbox/Poseidon/commit/eaea4b2e215669cec19f2a8cec122ba670a7a202))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Codex:** edit archives ([ec10932](https://gitlab.com/oceanbox/Poseidon/commit/ec109328fbf5f237a52ef77cbd44dff571deee5f))
|
||||
|
||||
## [1.39.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.39.1...v1.39.2) (2026-01-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix net10 issues ([f4943a1](https://gitlab.com/oceanbox/Poseidon/commit/f4943a148b72fb7e10a745cc3e806b9c4bdd76d8))
|
||||
|
||||
## [1.39.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.39.0...v1.39.1) (2026-01-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ci:** Remove schedule check ([ab37e88](https://gitlab.com/oceanbox/Poseidon/commit/ab37e88bb0f669a7aa94bf831f95f8c60dc28804))
|
||||
|
||||
# [1.39.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.38.5...v1.39.0) (2026-01-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Codex:** add * user in archmeister on public archives ([cd678a4](https://gitlab.com/oceanbox/Poseidon/commit/cd678a41f64a64c6f3616f32bafeaae6715c08a4))
|
||||
* **Codex:** use feliz router guid matching ([7182f7c](https://gitlab.com/oceanbox/Poseidon/commit/7182f7c9f094d65c884e8e02d4aaa89561ca5e82))
|
||||
* **Codex:** utc start_time ([492651e](https://gitlab.com/oceanbox/Poseidon/commit/492651e0f34035d8c61174aa50336222bcfd979c))
|
||||
* **DataAgent:** use files from parent attribs instead of archive_files ([eac23e7](https://gitlab.com/oceanbox/Poseidon/commit/eac23e7d1a541f2e90374a2add689846d9e7b642))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Codex:** ability to add FVCOM archives ([d86db7a](https://gitlab.com/oceanbox/Poseidon/commit/d86db7a66ca5ecb6a9ad45ce3d47be3a98d56bb8))
|
||||
|
||||
## [1.38.5](https://gitlab.com/oceanbox/Poseidon/compare/v1.38.4...v1.38.5) (2026-01-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Archmaester:** Rollback add archive if openfga fails ([46e86eb](https://gitlab.com/oceanbox/Poseidon/commit/46e86eb5f961a45fba2da1525c1472bdca79ab47))
|
||||
|
||||
## [1.38.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.38.3...v1.38.4) (2026-01-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **nix:** Bump node deps ([e513d87](https://gitlab.com/oceanbox/Poseidon/commit/e513d87d249843423f0e0a62275afe45e6c73a46))
|
||||
|
||||
## [1.38.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.38.2...v1.38.3) (2026-01-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **xtractor:** Set maxEndDate to 1 year and format ([5315a05](https://gitlab.com/oceanbox/Poseidon/commit/5315a05fa255c6164d3ef73c0f5e20cdb4c632d0))
|
||||
|
||||
## [1.38.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.38.1...v1.38.2) (2026-01-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **atlas:** Disable Snowflakes ([4cd3673](https://gitlab.com/oceanbox/Poseidon/commit/4cd3673d15783afa72ca3358e6bd8c3a8cfbfd16))
|
||||
|
||||
## [1.38.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.38.0...v1.38.1) (2026-01-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **xtractor:** Move to short partition and 16 CPU, also set max duration to 1 year ([56d3476](https://gitlab.com/oceanbox/Poseidon/commit/56d34767d7a2e0bc6aadaa5987344c6e7a58698a))
|
||||
|
||||
# [1.38.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.37.1...v1.38.0) (2026-01-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* client layout ([efb3292](https://gitlab.com/oceanbox/Poseidon/commit/efb3292d9f4a8fccf2cebbdd75b3d3ffc186fa11))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add fluent ui to codex ([d8bf174](https://gitlab.com/oceanbox/Poseidon/commit/d8bf174d3aa181169365c178b4335052e13eabc5))
|
||||
|
||||
## [1.37.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.37.0...v1.37.1) (2026-01-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **xtractor:** Avoid using union types in Dapr Actors ([14c1a57](https://gitlab.com/oceanbox/Poseidon/commit/14c1a57331f981b1e1e0793426448ea261002e6d))
|
||||
|
||||
# [1.37.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.36.0...v1.37.0) (2025-12-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add XtractActor ([a8a187a](https://gitlab.com/oceanbox/Poseidon/commit/a8a187a412c13d3e9d21cbbcfc2e1813c0e38dfe))
|
||||
|
||||
# [1.36.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.35.2...v1.36.0) (2025-12-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add Saturn.ReverseProxy middleware ([bd74504](https://gitlab.com/oceanbox/Poseidon/commit/bd745042dfa51fbbef7bf7b55d31b8b57e6ad0a4))
|
||||
|
||||
## [1.35.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.35.1...v1.35.2) (2025-12-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **drifters:** reverse toggle on postdrift analysis ([563faa6](https://gitlab.com/oceanbox/Poseidon/commit/563faa6c0bd20a7d3f184bba66ae5df340e7ef4e))
|
||||
|
||||
## [1.35.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.35.0...v1.35.1) (2025-12-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **stats:** no stats banner showing when stats are available, closing [#87](https://gitlab.com/oceanbox/Poseidon/issues/87) ([e75ffc4](https://gitlab.com/oceanbox/Poseidon/commit/e75ffc41e5d298e2ecf92c5c4d11e0f930f633ab))
|
||||
* **stats:** set priority order of depth plots, closing [#88](https://gitlab.com/oceanbox/Poseidon/issues/88) ([2887e6a](https://gitlab.com/oceanbox/Poseidon/commit/2887e6a90951f4aaa088ad14b3d2bbcb6fd25b93))
|
||||
|
||||
# [1.35.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.34.2...v1.35.0) (2025-12-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ❄️ ([a620c26](https://gitlab.com/oceanbox/Poseidon/commit/a620c26812d3ec7517c34e7931e03b411f725907))
|
||||
|
||||
## [1.34.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.34.1...v1.34.2) (2025-11-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Temporarily use vtn as only source for wind barbs ([048e803](https://gitlab.com/oceanbox/Poseidon/commit/048e80356b59cfcd408bf6784bbc2e22aebe25c6))
|
||||
|
||||
## [1.34.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.34.0...v1.34.1) (2025-11-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **stats:** find available stats archives ([48d46ed](https://gitlab.com/oceanbox/Poseidon/commit/48d46eda62160d3efe1423238a25f26a439c6b88))
|
||||
|
||||
# [1.34.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.11...v1.34.0) (2025-11-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* extract data cage interaction matrix, closing [#84](https://gitlab.com/oceanbox/Poseidon/issues/84) ([afc888a](https://gitlab.com/oceanbox/Poseidon/commit/afc888ab604f4759e3787e3feab568a322109b34))
|
||||
* reintroduce active layer selector, closes [#74](https://gitlab.com/oceanbox/Poseidon/issues/74) ([c1fa85f](https://gitlab.com/oceanbox/Poseidon/commit/c1fa85fd1b955e810bd76973e5873a7ab4cb8f18))
|
||||
* remove parameter limitations on particle sims ([69b380e](https://gitlab.com/oceanbox/Poseidon/commit/69b380e6659521c9f9ab489fa75d1221cc9b7db2))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* fly-to coordinate button, closes [#85](https://gitlab.com/oceanbox/Poseidon/issues/85) ([a153238](https://gitlab.com/oceanbox/Poseidon/commit/a153238f79e2b2c87ac3553acce00bb17c1529f4))
|
||||
|
||||
## [1.33.11](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.10...v1.33.11) (2025-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ci:** Run archivist ci on coffee ([f68b7f6](https://gitlab.com/oceanbox/Poseidon/commit/f68b7f68c8fd95d5d593702632cc2e9a7b36007a))
|
||||
|
||||
## [1.33.10](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.9...v1.33.10) (2025-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ci:** Build on Coffee ([e04d36c](https://gitlab.com/oceanbox/Poseidon/commit/e04d36ca124693b471ac973cd4d0f39f42f0fec0))
|
||||
|
||||
## [1.33.9](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.8...v1.33.9) (2025-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **nix:** Bump hash for node_modules ([fff7913](https://gitlab.com/oceanbox/Poseidon/commit/fff7913cd5280f0732bb23bc1cb6ed5282631b90))
|
||||
|
||||
## [1.33.8](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.7...v1.33.8) (2025-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ci:** Format .gitlab-ci.yml and move codex to nix runner ([3140c07](https://gitlab.com/oceanbox/Poseidon/commit/3140c07ad078d3b8b3082d2f86eaa73f4ba08969))
|
||||
* **ci:** Remove unsed var ([759bbc6](https://gitlab.com/oceanbox/Poseidon/commit/759bbc6f60e5b364dd83653193d1501ce86c9eef))
|
||||
* **ci:** Try using v4.4 ([c1be7c4](https://gitlab.com/oceanbox/Poseidon/commit/c1be7c468dd9a689eb0b1b61797841c398fadc02))
|
||||
* **ci:** Use 4.4 for check ([b109dbd](https://gitlab.com/oceanbox/Poseidon/commit/b109dbdcbdfa3315e099b2edf72eb10518732c8f))
|
||||
|
||||
## [1.33.7](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.6...v1.33.7) (2025-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ci:** Change name to codex ([6d04af6](https://gitlab.com/oceanbox/Poseidon/commit/6d04af6230b536c1cbadf9abd2b59cf13609b451))
|
||||
* **ci:** Correct tag for codex pipeline ([7cf5064](https://gitlab.com/oceanbox/Poseidon/commit/7cf50641f986ab81b030e678ff7db0de83acae98))
|
||||
* **ci:** Run Codex on Coffee ([dd398bd](https://gitlab.com/oceanbox/Poseidon/commit/dd398bd96b0d79c8585a3156edcd2158982744d9))
|
||||
|
||||
## [1.33.6](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.5...v1.33.6) (2025-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **maps:** Make FluentUI DatePicker popup inline; closes [#83](https://gitlab.com/oceanbox/Poseidon/issues/83) ([e3a1f56](https://gitlab.com/oceanbox/Poseidon/commit/e3a1f56b87c20ad9aada6108c92854b9d12671df))
|
||||
|
||||
## [1.33.5](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.4...v1.33.5) (2025-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* General fixes "stats" menu ([c3c9e8e](https://gitlab.com/oceanbox/Poseidon/commit/c3c9e8e4e2b473564d1f6434a28dd934457189e9)), closes [#79](https://gitlab.com/oceanbox/Poseidon/issues/79) [#80](https://gitlab.com/oceanbox/Poseidon/issues/80) [#81](https://gitlab.com/oceanbox/Poseidon/issues/81) [#82](https://gitlab.com/oceanbox/Poseidon/issues/82)
|
||||
* no more DateFlicker (thanks Simen) ([7584bf6](https://gitlab.com/oceanbox/Poseidon/commit/7584bf661f2fd1cbf95e473a3334efcd69c77392))
|
||||
* remove goto today in date picker ([f23b3f1](https://gitlab.com/oceanbox/Poseidon/commit/f23b3f18213682e0b41c1db13b72e3c0bb0534b6))
|
||||
* **stats:** alert banner on missing stats ([5bb2ffd](https://gitlab.com/oceanbox/Poseidon/commit/5bb2ffd67c16078854b9f86a6728958c3923626c))
|
||||
|
||||
## [1.33.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.3...v1.33.4) (2025-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **js:** Remove unused packages ([10a8c42](https://gitlab.com/oceanbox/Poseidon/commit/10a8c42319bbceebbf413d330fc72071f428e2dd))
|
||||
|
||||
## [1.33.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.2...v1.33.3) (2025-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **nix:** Pre-commit with prek ([3093757](https://gitlab.com/oceanbox/Poseidon/commit/309375745443add8347ad6fca7b2dfe86ed1b7a7))
|
||||
* **nix:** Watch correct lock file ([79c6e2a](https://gitlab.com/oceanbox/Poseidon/commit/79c6e2abd0e26d220c10e532dffe53511f5dea0a))
|
||||
|
||||
## [1.33.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.1...v1.33.2) (2025-11-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* create input display modal on demand ([1fed7ad](https://gitlab.com/oceanbox/Poseidon/commit/1fed7adf8009282184cacb4ddabf91274ee22b60))
|
||||
* **drifters:** Add datepickers for drifters sims ([785d0d5](https://gitlab.com/oceanbox/Poseidon/commit/785d0d57ae6cc53b59ad1d8708e5f513aca8dd77))
|
||||
* sim duration with restrictions ([a9145f6](https://gitlab.com/oceanbox/Poseidon/commit/a9145f6f79aa30cbe529d7a797b38dd2abe0a6cd))
|
||||
* **timeline:** display use local time in timeline ([ccbe076](https://gitlab.com/oceanbox/Poseidon/commit/ccbe07619f31c1b7511c8a8f4ca11fe3af8cbd53))
|
||||
* **timeline:** Marker uses UTC instead of CET + DST ([a474e7c](https://gitlab.com/oceanbox/Poseidon/commit/a474e7cbd4a894b9c1f5f20420dc728f93bc2e07))
|
||||
|
||||
## [1.33.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.33.0...v1.33.1) (2025-11-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add missing * in Drifters ArchiveType FromString ([7054ade](https://gitlab.com/oceanbox/Poseidon/commit/7054ade55dffd058f0d622447da08587633b815c))
|
||||
* **Atlantis:** Add wildcards in allow origin ([cde779e](https://gitlab.com/oceanbox/Poseidon/commit/cde779ea00f0666e6b548c7d711873b64cb294d9))
|
||||
|
||||
# [1.33.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.32.0...v1.33.0) (2025-11-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* properly display sim parameters, and fix clone, closing [#70](https://gitlab.com/oceanbox/Poseidon/issues/70) ([4980a41](https://gitlab.com/oceanbox/Poseidon/commit/4980a41a4456be53c8a0193f1fbc40e0238c0111))
|
||||
|
||||
# [1.32.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.31.0...v1.32.0) (2025-11-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* spell out units in plots ([020a2f2](https://gitlab.com/oceanbox/Poseidon/commit/020a2f2e000ed907ad1eb7768e47f6b053038e4e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add Density profile plot and cancelable jobs ([8472708](https://gitlab.com/oceanbox/Poseidon/commit/847270877abc3bd983a400a29a0b4bebae033b06)), closes [oceanbox/Poseidon#30](https://gitlab.com/oceanbox/Poseidon/issues/30)
|
||||
|
||||
# [1.31.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.30.1...v1.31.0) (2025-11-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **DataAgent:** offline eval function when you have a dto ([1982770](https://gitlab.com/oceanbox/Poseidon/commit/19827701aad9625d55f3bab4d48cb44122d512ae))
|
||||
|
||||
## [1.30.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.30.0...v1.30.1) (2025-11-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Remove implicit FSharp.Core, Lib and Nuget for better CPM compat ([f8ab41b](https://gitlab.com/oceanbox/Poseidon/commit/f8ab41bbda9957727de63970a80f3c69e8715098))
|
||||
|
||||
# [1.30.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.29.0...v1.30.0) (2025-11-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* don't fetch tz contour on update timeframe ([beedeb8](https://gitlab.com/oceanbox/Poseidon/commit/beedeb836b4353a5253362c11c3f772f65ad503d))
|
||||
* switch to element path and use haversine distance ([61b4323](https://gitlab.com/oceanbox/Poseidon/commit/61b432380310a9cbc5c1383854d71055034a49dd))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add Chaikin curve smoothing algorithm ([d4766f2](https://gitlab.com/oceanbox/Poseidon/commit/d4766f249b2ec1238a7df61df1a8fd3f3525f797))
|
||||
* sea distance circle, closing [#73](https://gitlab.com/oceanbox/Poseidon/issues/73) ([fc41c91](https://gitlab.com/oceanbox/Poseidon/commit/fc41c91d41ee35036ca6482e0f5128a51e175d7f))
|
||||
|
||||
# [1.29.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.28.0...v1.29.0) (2025-11-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move map type picker to the usual place ([917058b](https://gitlab.com/oceanbox/Poseidon/commit/917058b7be861a674a975f0ba939f5a227c11cf9))
|
||||
* naming ([5be346e](https://gitlab.com/oceanbox/Poseidon/commit/5be346e0fc7473640f2506a94e81f9e28a95b0c2))
|
||||
* switch to node path and use lonlat coord in api ([d8f38c4](https://gitlab.com/oceanbox/Poseidon/commit/d8f38c496d8fefb575157082ea1d6fc8f03fe806))
|
||||
* update fvcomkit ([da6a199](https://gitlab.com/oceanbox/Poseidon/commit/da6a1995c11702fe29965e77abfa7da525ff9e9c))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* calculation of sea distance, closes [#51](https://gitlab.com/oceanbox/Poseidon/issues/51) ([1b4f4ef](https://gitlab.com/oceanbox/Poseidon/commit/1b4f4ef3606354e09d5c20f8413b939291c6a78d))
|
||||
|
||||
# [1.28.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.27.2...v1.28.0) (2025-11-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Don't build Sorcerer Client ([a627b08](https://gitlab.com/oceanbox/Poseidon/commit/a627b08df2fc02e28db105068a9766be5bf6ac10))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Centralize Nuget Package Management ([b062f66](https://gitlab.com/oceanbox/Poseidon/commit/b062f66cf90639ec3cccdbcf54826a622f28bb08))
|
||||
|
||||
## [1.27.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.27.1...v1.27.2) (2025-11-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cage interaction matrix and labeling, closes [#72](https://gitlab.com/oceanbox/Poseidon/issues/72) ([6d5a724](https://gitlab.com/oceanbox/Poseidon/commit/6d5a72412ba144cb9d948ba0cfdb1d464747e41f))
|
||||
|
||||
## [1.27.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.27.0...v1.27.1) (2025-10-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** add sanity check for sim names, closes [#66](https://gitlab.com/oceanbox/Poseidon/issues/66) ([637d22e](https://gitlab.com/oceanbox/Poseidon/commit/637d22e0f094042504b50922932da5d1786f0cfe))
|
||||
* **Atlantis:** minor tweaks in ui naming and layout ([187a5e3](https://gitlab.com/oceanbox/Poseidon/commit/187a5e36e3bd28bf73dde4eaa1634df4fecb5ce1))
|
||||
* **Atlantis:** switch to chart-trend icon ([9b6a3ef](https://gitlab.com/oceanbox/Poseidon/commit/9b6a3ef1334eb0e2f74c1e398f3873a7095e5d43))
|
||||
* **Atlantis:** use Conc instead of activeLayer ([039df74](https://gitlab.com/oceanbox/Poseidon/commit/039df744d3901e3e476c53db2a39daaae0d93855))
|
||||
* **Atlantis:** use tab for statistics ([3a9c616](https://gitlab.com/oceanbox/Poseidon/commit/3a9c616f6b29df39fc679126036a79d76a4c2909))
|
||||
|
||||
# [1.27.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.26.4...v1.27.0) (2025-10-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** fix buttons on sim setup ([c6eee07](https://gitlab.com/oceanbox/Poseidon/commit/c6eee0731705254bd32b68de8ceac7b6a37a5cc6))
|
||||
* **Atlantis:** fix style in point samples section ([e85a114](https://gitlab.com/oceanbox/Poseidon/commit/e85a114a234006c7aa4456ebf383f2dfbb884b65))
|
||||
* **Atlantis:** read sample radius from string ([0bd66f8](https://gitlab.com/oceanbox/Poseidon/commit/0bd66f89fd8539a323a3fcc34aca7a6620b26370))
|
||||
* **Mapster:** Do not disable timeline when not in OceanControls ([aaa5627](https://gitlab.com/oceanbox/Poseidon/commit/aaa56271b0e97132550eb687725d39174d7446b5))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Atlantis:** add alternative unit for downwelling, closes [#47](https://gitlab.com/oceanbox/Poseidon/issues/47) ([234cd19](https://gitlab.com/oceanbox/Poseidon/commit/234cd19af7021c45cf74e6792b38784f27ca981e))
|
||||
* **Atlantis:** introduce average point values within circle ([a7cb34d](https://gitlab.com/oceanbox/Poseidon/commit/a7cb34d7bad0fcb76b67a36c6292e5d65b878448))
|
||||
* **Atlantis:** time series from point samples, closes [#29](https://gitlab.com/oceanbox/Poseidon/issues/29) ([1d1ddf2](https://gitlab.com/oceanbox/Poseidon/commit/1d1ddf2fef4d8687a1eb9652538e9d2fa2c1a40f))
|
||||
* **Hipster:** add slurm account and comment ([40414db](https://gitlab.com/oceanbox/Poseidon/commit/40414db1f6976fcfd87e55e60b57feec0189e9cf))
|
||||
|
||||
## [1.26.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.26.3...v1.26.4) (2025-10-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Create TMP directory for atlantis and add errorhandler ([0473f7b](https://gitlab.com/oceanbox/Poseidon/commit/0473f7b7656accd8bc493fd12908c2dd4a59a1b9))
|
||||
|
||||
## [1.26.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.26.2...v1.26.3) (2025-10-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlas:** Fix top nav logo offset ([c5b85e9](https://gitlab.com/oceanbox/Poseidon/commit/c5b85e9ad44d02edda765ce7a8b6f314adaea669))
|
||||
* **Atlas:** Show loading when waiting for model area archives ([9181b43](https://gitlab.com/oceanbox/Poseidon/commit/9181b43732151fae37f0a837d946458b6544103d))
|
||||
* **Mapster:** Add back stats download button ([86425a2](https://gitlab.com/oceanbox/Poseidon/commit/86425a2292ea413bc9a6b24aab2105c9e85fade1))
|
||||
* **Mapster:** Add timeseries help text on stats ([0dbd11e](https://gitlab.com/oceanbox/Poseidon/commit/0dbd11ed68991a13d94f8a3053794751b5185bc4))
|
||||
* **Mapster:** Catch potential timeout error fetching time series ([214fb65](https://gitlab.com/oceanbox/Poseidon/commit/214fb650c1c06f5fbb9e42d922fb352833f3efec))
|
||||
* **Mapster:** Choose better warn condition for missing post drift ([17181f6](https://gitlab.com/oceanbox/Poseidon/commit/17181f6ca2d5f6a23a8d5f7f8853b1a64c670324))
|
||||
* **Mapster:** Fix plotly chart not auto ranging properly ([c862cb1](https://gitlab.com/oceanbox/Poseidon/commit/c862cb172fd24dbb3cb071e0e223665804965ed3))
|
||||
* **Mapster:** Handle grid search case for sub grids/models ([a046e7d](https://gitlab.com/oceanbox/Poseidon/commit/a046e7d84957cdc31d047b397ddd9d9470fdb847))
|
||||
* **Mapster:** Handle probing errors and show toast ([db37040](https://gitlab.com/oceanbox/Poseidon/commit/db370402090fc78206c31a48347338624fdabbed))
|
||||
* **Mapster:** Make loading clearer when loading ([215409c](https://gitlab.com/oceanbox/Poseidon/commit/215409c7c880e2ca48e8df58e591cbb3f385000c))
|
||||
* **Mapster:** Make notifier list an array ([3b4ec02](https://gitlab.com/oceanbox/Poseidon/commit/3b4ec021af8f1efff3f994a8ce912d8780eb966c))
|
||||
* **Mapster:** More sane stat selection in depth plots ([fa63ade](https://gitlab.com/oceanbox/Poseidon/commit/fa63ade2e1a974cc4cbf2c40b67b999b2040a1af))
|
||||
* **Mapster:** Redirect to /signin if entering map unauthenticated ([7176919](https://gitlab.com/oceanbox/Poseidon/commit/7176919e944fab87f7081887077a25c7ec2a5f33))
|
||||
* **Mapster:** Remove Esc listener from side nav stats controls ([59ce5b9](https://gitlab.com/oceanbox/Poseidon/commit/59ce5b98b83bd53dd47e0a7666fedcaf5b8bad20))
|
||||
* **Mapster:** Show warning when non-transport sims are missing post ([9bd0562](https://gitlab.com/oceanbox/Poseidon/commit/9bd0562b47eac0a36338ca0ce479b9207f142a67))
|
||||
* **Mapster:** Sidebar styling updates ([f7fbc5d](https://gitlab.com/oceanbox/Poseidon/commit/f7fbc5d70dc277f2f9bb9df2fa020b9b49a06416))
|
||||
* **Mapster:** Update field probing data extraction view ([9eed6af](https://gitlab.com/oceanbox/Poseidon/commit/9eed6af711e570fb4b7079686a7e01a592c3f383))
|
||||
* Use custom plotly bundle in react-plotly.js ([51fc750](https://gitlab.com/oceanbox/Poseidon/commit/51fc7503b5fae6c05c233888ece06e314f0555a3))
|
||||
|
||||
## [1.26.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.26.1...v1.26.2) (2025-10-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tmp:** Add prints to debug ([b5c21bb](https://gitlab.com/oceanbox/Poseidon/commit/b5c21bb62c31c98e21da7a670eda92e1b5c9d02d))
|
||||
|
||||
## [1.26.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.26.0...v1.26.1) (2025-10-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Don't use nodejs in dev ([90bab5e](https://gitlab.com/oceanbox/Poseidon/commit/90bab5ecc0d095f494bb3c65c16c5ad5a36cc8a8)), closes [oceanbox/Poseidon#1](https://gitlab.com/oceanbox/Poseidon/issues/1)
|
||||
* Typo and build archivist with netcdf runtimeDeps ([8482921](https://gitlab.com/oceanbox/Poseidon/commit/84829214204828cbf1fed6f54f4055dc9d456561))
|
||||
|
||||
# [1.26.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.25.5...v1.26.0) (2025-10-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **fga:** Add start_time to ReadChanges ([9388d37](https://gitlab.com/oceanbox/Poseidon/commit/9388d3758dc769106c2413686e59821352e74967))
|
||||
|
||||
## [1.25.5](https://gitlab.com/oceanbox/Poseidon/compare/v1.25.4...v1.25.5) (2025-10-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **nix:** Build Archivist SIF in pipeline ([16f9686](https://gitlab.com/oceanbox/Poseidon/commit/16f968657b61cb6ce6cecb12d8016565a25919fc))
|
||||
|
||||
## [1.25.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.25.3...v1.25.4) (2025-10-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* reduce number of cpus per drifter job ([b293044](https://gitlab.com/oceanbox/Poseidon/commit/b293044258ecc9699e62205181e8963f8470d1c2))
|
||||
|
||||
## [1.25.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.25.2...v1.25.3) (2025-10-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** set limitations on simulation parameters ([407a278](https://gitlab.com/oceanbox/Poseidon/commit/407a278e283144ef2d163108c63e8b2a586b560c))
|
||||
|
||||
## [1.25.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.25.1...v1.25.2) (2025-10-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Send Drifters to Inbox instantly and Track Plumes ([48b5da9](https://gitlab.com/oceanbox/Poseidon/commit/48b5da9da3f3fcffc57592ea66f3a3d3c8828761))
|
||||
* Submit as queued if there is a queue ([d64ee45](https://gitlab.com/oceanbox/Poseidon/commit/d64ee45d9e82da86c6ca348d36169dbbdb363edd))
|
||||
|
||||
## [1.25.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.25.0...v1.25.1) (2025-10-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Cleanup ([f721077](https://gitlab.com/oceanbox/Poseidon/commit/f72107751f0e81c1685a7b07ef5c22d512e5c031))
|
||||
* Release ([cb6265d](https://gitlab.com/oceanbox/Poseidon/commit/cb6265dcb1c2458eb69098be61df77afdd85ef32))
|
||||
|
||||
# [1.25.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.24.5...v1.25.0) (2025-10-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** avoid positive release depth, closes [#42](https://gitlab.com/oceanbox/Poseidon/issues/42) ([16643c3](https://gitlab.com/oceanbox/Poseidon/commit/16643c346033b6d3e134152a2bf6f79bbfd45ca3))
|
||||
* **Atlantis:** clear point samples on deselect ([8174354](https://gitlab.com/oceanbox/Poseidon/commit/81743540d053dbc789cda41fdbc9b716decda53e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Atlantis:** add point samples to any sim type, closes [#54](https://gitlab.com/oceanbox/Poseidon/issues/54) ([9a41f0a](https://gitlab.com/oceanbox/Poseidon/commit/9a41f0a2f3c804d5d6728c1d28020c51e61d060f))
|
||||
* **Atlantis:** add toggle button for showing releases, closes [#53](https://gitlab.com/oceanbox/Poseidon/issues/53) ([f8045f6](https://gitlab.com/oceanbox/Poseidon/commit/f8045f6dcc46a1ba0de33e9092db87f798fb6255))
|
||||
* **Atlantis:** copy release sites, closes [#56](https://gitlab.com/oceanbox/Poseidon/issues/56) ([9bb9d85](https://gitlab.com/oceanbox/Poseidon/commit/9bb9d855e4f93f07e634b1f7e499feb7136643f1))
|
||||
* **Atlantis:** fetch time series data from plot, closes [#55](https://gitlab.com/oceanbox/Poseidon/issues/55) ([a332fe7](https://gitlab.com/oceanbox/Poseidon/commit/a332fe72a2c745ffe8ed45598c6a9ab8f3391cb0))
|
||||
|
||||
## [1.24.5](https://gitlab.com/oceanbox/Poseidon/compare/v1.24.4...v1.24.5) (2025-10-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mapster:** Set static artifact for plume downloads ([5476583](https://gitlab.com/oceanbox/Poseidon/commit/5476583cb2fde0beed37b6235144532c6234432c))
|
||||
|
||||
## [1.24.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.24.3...v1.24.4) (2025-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* broken vite version ([5e84185](https://gitlab.com/oceanbox/Poseidon/commit/5e8418595046d7685eb405c36953f7b888650aea))
|
||||
* update drifters.api version ([22339c6](https://gitlab.com/oceanbox/Poseidon/commit/22339c6adebe584254b6c1a5c52804ce970435d5))
|
||||
|
||||
## [1.24.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.24.2...v1.24.3) (2025-10-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Remove client from archivist cli and use correct path ([60a47b0](https://gitlab.com/oceanbox/Poseidon/commit/60a47b030801c6fc36f3d7599455624058e9c075))
|
||||
|
||||
## [1.24.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.24.1...v1.24.2) (2025-10-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove tz contours on deselect ([a5b348e](https://gitlab.com/oceanbox/Poseidon/commit/a5b348e439c33ff7367ae299f8e5afed87b2be8c))
|
||||
|
||||
## [1.24.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.24.0...v1.24.1) (2025-10-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update lockfiles ([904845f](https://gitlab.com/oceanbox/Poseidon/commit/904845fe0aeb1b1daaa75f785205ad4242eb4f05))
|
||||
|
||||
# [1.24.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.23.3...v1.24.0) (2025-10-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** sync import of sp-picker ([6151eb8](https://gitlab.com/oceanbox/Poseidon/commit/6151eb86f0ce9bcc013fa5f12c3713035e39cc7d))
|
||||
* Build Archivist with correct archmaester interface ([d182900](https://gitlab.com/oceanbox/Poseidon/commit/d182900b028549fcf443c841ba8aad0adec57a19))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Atlantis:** add multiple transition zone contours, closes [#34](https://gitlab.com/oceanbox/Poseidon/issues/34) ([c75d137](https://gitlab.com/oceanbox/Poseidon/commit/c75d13711ae681b428cf177e7463888ac9a997f3))
|
||||
* **Atlantis:** first take on cage interaction matrix, closes [#33](https://gitlab.com/oceanbox/Poseidon/issues/33) ([9ea31be](https://gitlab.com/oceanbox/Poseidon/commit/9ea31be3329afca6f29d869c95251c64e61bb6b4))
|
||||
* **Atlantis:** point values section to sedimentation fields, closes [#43](https://gitlab.com/oceanbox/Poseidon/issues/43) ([7fff70b](https://gitlab.com/oceanbox/Poseidon/commit/7fff70b7d5e9f01303d6036f0e299ce92d44950a))
|
||||
* **Atlantis:** separate groups in accumulate, closes [#44](https://gitlab.com/oceanbox/Poseidon/issues/44) ([bda39de](https://gitlab.com/oceanbox/Poseidon/commit/bda39dea78edc85f273ab471a12ae24d2b6c9485))
|
||||
* **Sorcerer:** add api for field2d contours ([598fd5a](https://gitlab.com/oceanbox/Poseidon/commit/598fd5a7b05fc169b14ead197c51e00385c01f06))
|
||||
|
||||
## [1.23.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.23.2...v1.23.3) (2025-09-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** Go back to how secrets were fetched ([ea335bc](https://gitlab.com/oceanbox/Poseidon/commit/ea335bc3fb1ca68ef2e23247ec17baac362fee4f))
|
||||
|
||||
## [1.23.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.23.1...v1.23.2) (2025-09-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** Ensure dapr is healthy before running ([e344647](https://gitlab.com/oceanbox/Poseidon/commit/e34464782ab95613f786c24a139be0ecbf97a043))
|
||||
* **Atlantis:** Use correct DI settings type in FgaActor ([be1f942](https://gitlab.com/oceanbox/Poseidon/commit/be1f942413b78f288fe26a042fa53ac1d482eda9))
|
||||
|
||||
## [1.23.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.23.0...v1.23.1) (2025-09-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** Overwrite slurm token with value from secrets ([94c8acc](https://gitlab.com/oceanbox/Poseidon/commit/94c8accf45b44bf9840c8165a2668d3ba948c696))
|
||||
|
||||
# [1.23.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.8...v1.23.0) (2025-09-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add slurm-access-token stub to tilt ([190b227](https://gitlab.com/oceanbox/Poseidon/commit/190b227d97880f310e14d6459b6e9b0e18f3715a))
|
||||
* change slurm secret token key to SLURM_JWT ([b4c8de2](https://gitlab.com/oceanbox/Poseidon/commit/b4c8de2e09b7a6676f96dbeee520496c13d8059a))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* move slurmrestd from basic auth to jwt ([0922a8f](https://gitlab.com/oceanbox/Poseidon/commit/0922a8fa08c81e967edf03fdedb9dfba77b2ee8a))
|
||||
|
||||
## [1.22.8](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.7...v1.22.8) (2025-09-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dataagent:** Add privateassets and bump api to match version ([93c1661](https://gitlab.com/oceanbox/Poseidon/commit/93c166144eb0b411aa147dc4e935aa560de2badd))
|
||||
|
||||
## [1.22.7](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.6...v1.22.7) (2025-09-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dataagent:** Actual bump in version ([b9b9720](https://gitlab.com/oceanbox/Poseidon/commit/b9b97205c27c1d9a9d1f50f1c7c7d86b2d9e4eba))
|
||||
|
||||
## [1.22.6](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.5...v1.22.6) (2025-09-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dataagent:** Add back weird Targets ([0586f2f](https://gitlab.com/oceanbox/Poseidon/commit/0586f2f7d3c5dec1c3b8b8d7039f8214690238c2))
|
||||
|
||||
## [1.22.5](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.4...v1.22.5) (2025-09-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mapster:** Add authorization for plume usage ([7b90371](https://gitlab.com/oceanbox/Poseidon/commit/7b90371f849f92260d84bfd03f581799a7e86fb5))
|
||||
|
||||
## [1.22.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.3...v1.22.4) (2025-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add archivist binary to shell and allow dirs in add ([ebc12b9](https://gitlab.com/oceanbox/Poseidon/commit/ebc12b9ef9cfc483cdb4c0319ce08f761930a9f6))
|
||||
* **Atlantis:** Remove heuristic caching tags instead of cache control ([f6ce5d2](https://gitlab.com/oceanbox/Poseidon/commit/f6ce5d26c383027b5363ab7804d766a057e60b28))
|
||||
* Don't validate files in parser ([29eeb17](https://gitlab.com/oceanbox/Poseidon/commit/29eeb17306ab6b44e3aea6136601f259f98ab123))
|
||||
|
||||
## [1.22.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.2...v1.22.3) (2025-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Load agenix secrets in direnv ([b2d8dec](https://gitlab.com/oceanbox/Poseidon/commit/b2d8dec9a4be788f7c38dd26369ddd37f32fcd22))
|
||||
|
||||
## [1.22.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.1...v1.22.2) (2025-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Umami:** Add some initial event tracking ([ace083a](https://gitlab.com/oceanbox/Poseidon/commit/ace083af9e7318a0eece2f7c88fd728607b3395e))
|
||||
|
||||
## [1.22.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.22.0...v1.22.1) (2025-09-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Typo rename URL -> WEB_ID ([2e260d1](https://gitlab.com/oceanbox/Poseidon/commit/2e260d118445f86b733bbe5068fd9d9adc7df207))
|
||||
|
||||
# [1.22.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.11...v1.22.0) (2025-09-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Atlantis:** Add user id to umami payload as unique id ([5a6c725](https://gitlab.com/oceanbox/Poseidon/commit/5a6c7258a49bbd91e8ddc9b0ccce715d34afed58))
|
||||
|
||||
## [1.21.11](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.10...v1.21.11) (2025-09-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Change from plausible to umami ([c2a99ac](https://gitlab.com/oceanbox/Poseidon/commit/c2a99ac1eed9dbdafac52f163dc49a384ee7399a))
|
||||
|
||||
## [1.21.10](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.9...v1.21.10) (2025-09-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** Configure static files manually ([5402af7](https://gitlab.com/oceanbox/Poseidon/commit/5402af7f8f3f588131862b2c9a95d7469ed68561))
|
||||
* **Atlantis:** Use correct barentswatch secret ([9cd9518](https://gitlab.com/oceanbox/Poseidon/commit/9cd9518a38912b2b50fd4e01ead348e92a7e1a40))
|
||||
|
||||
## [1.21.9](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.8...v1.21.9) (2025-09-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add no-cache header to served content ([1247d4d](https://gitlab.com/oceanbox/Poseidon/commit/1247d4d0923b2cce16c278012abdeb16b6e8e913))
|
||||
* **Slurm:** Catch decode errors in handleSlurmEvents ([ad91a3d](https://gitlab.com/oceanbox/Poseidon/commit/ad91a3dd2339d9e9252eeb0ca82e1a37e205d5b4))
|
||||
|
||||
## [1.21.8](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.7...v1.21.8) (2025-09-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add closing bracket vite atlantis ([2c6a30a](https://gitlab.com/oceanbox/Poseidon/commit/2c6a30a4f6d5adad548443e4558e3fee1fda5545))
|
||||
|
||||
## [1.21.7](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.6...v1.21.7) (2025-09-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add hash to vite output artifacts ([8e72010](https://gitlab.com/oceanbox/Poseidon/commit/8e72010740d20bfb99ac7b635a5f679546d407ba))
|
||||
|
||||
## [1.21.6](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.5...v1.21.6) (2025-09-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** convert release span from sec to hr ([e7ae2ee](https://gitlab.com/oceanbox/Poseidon/commit/e7ae2ee38aa49fd5bfe4a3404aed7c8aeab7139e))
|
||||
* **Mapster:** Redirect to Atlas if no archive is chosen ([047d747](https://gitlab.com/oceanbox/Poseidon/commit/047d74723ec7ec2710cbf4e219a80d7dcbd7926e))
|
||||
* **Mapster:** Test session storage on loading map ([3a7df65](https://gitlab.com/oceanbox/Poseidon/commit/3a7df65f0a94440ec2fae401730cc2fa0bcd8937))
|
||||
|
||||
## [1.21.5](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.4...v1.21.5) (2025-09-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Clean up package.json ([27df77b](https://gitlab.com/oceanbox/Poseidon/commit/27df77bfebcaa2efdd22f5057d5b811c209d9a53))
|
||||
* Ignore buildkit builder ([6e31e77](https://gitlab.com/oceanbox/Poseidon/commit/6e31e77f0347c6b3a3953d043b0e0842f057ad8a))
|
||||
|
||||
## [1.21.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.3...v1.21.4) (2025-09-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Mapster:** Fix aquaculture locations not showing ([4806dd9](https://gitlab.com/oceanbox/Poseidon/commit/4806dd97de3ffbe2d683e8318d16a53db217e171))
|
||||
|
||||
## [1.21.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.2...v1.21.3) (2025-08-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Default to Debug and rename to env ([f441a15](https://gitlab.com/oceanbox/Poseidon/commit/f441a15f693c9beb0f01c17634a9bbc1a8addc9d))
|
||||
|
||||
## [1.21.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.1...v1.21.2) (2025-08-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add Error propagation and diagnosticlogging ([b2cce31](https://gitlab.com/oceanbox/Poseidon/commit/b2cce311b5a2cea329e95a755d1db71d24876b76))
|
||||
|
||||
## [1.21.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.21.0...v1.21.1) (2025-08-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 4GB maxRequestBodySize in prod and update fsi file ([cee62b1](https://gitlab.com/oceanbox/Poseidon/commit/cee62b15e6b2e15fd86fd5f9f5e05aaa6a92d136))
|
||||
|
||||
# [1.21.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.20.2...v1.21.0) (2025-08-27)
|
||||
|
||||
## [1.20.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.20.1...v1.20.2) (2025-08-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Mapster:** Fix ArchiveDialog table squeeze ([90b17a5](https://gitlab.com/oceanbox/Poseidon/commit/90b17a59a24aa5be03cf5fc168a63bf131f05bce))
|
||||
* **Mapster:** Fix InboxDialog table squeeze ([124a900](https://gitlab.com/oceanbox/Poseidon/commit/124a900b4413a3526692d6d736feb0aab423f126))
|
||||
|
||||
## [1.20.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.20.0...v1.20.1) (2025-08-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Downgrade vite plugin for correct js bundle ([d35f666](https://gitlab.com/oceanbox/Poseidon/commit/d35f666664c740e7778a889d2a7be1f8f9f776ac))
|
||||
|
||||
# [1.20.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.19.4...v1.20.0) (2025-08-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add custom depth separator in conc analysis ([62b09de](https://gitlab.com/oceanbox/Poseidon/commit/62b09deb8d64feeae3a242c39314c28b16842cc3))
|
||||
|
||||
## [1.19.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.19.3...v1.19.4) (2025-08-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Don't run linter ([1780867](https://gitlab.com/oceanbox/Poseidon/commit/1780867a89244bbd7b6c095e477acbabb3fd4cc7))
|
||||
* **nix:** Format, lint and remove dead code ([7d378a5](https://gitlab.com/oceanbox/Poseidon/commit/7d378a52d1e6f2293d6f3bcae9b0a97b23fb4d74))
|
||||
|
||||
## [1.19.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.19.2...v1.19.3) (2025-08-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add fable temp files to gitignore ([8d9843d](https://gitlab.com/oceanbox/Poseidon/commit/8d9843d4679198c88bee8261e8cf5091f45280a1))
|
||||
|
||||
## [1.19.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.19.1...v1.19.2) (2025-08-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add libnetcdf as runtime dependency for containers ([6e7fa4b](https://gitlab.com/oceanbox/Poseidon/commit/6e7fa4b9c702e1e7bb694443163693397293f27f))
|
||||
* Add memorysize ([f626796](https://gitlab.com/oceanbox/Poseidon/commit/f6267962b34920288e3b625ea637890cd2e9a289))
|
||||
* Include nix files for CI ([7983d94](https://gitlab.com/oceanbox/Poseidon/commit/7983d948f10e11461be91dc6a9259a3eb2749953))
|
||||
|
||||
## [1.19.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.19.0...v1.19.1) (2025-08-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlas:** Fix squashed archive table in modal ([3593a44](https://gitlab.com/oceanbox/Poseidon/commit/3593a4494d332ae042c13e345fd0a0d59b46984e))
|
||||
|
||||
# [1.19.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.18.3...v1.19.0) (2025-08-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add OpenLayer FullScreen Controls ([2a3bb68](https://gitlab.com/oceanbox/Poseidon/commit/2a3bb68e3e1ffe57772c961c27b904d9023a5294))
|
||||
|
||||
## [1.18.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.18.2...v1.18.3) (2025-08-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add .env to gitignore and generate server docs ([a37e602](https://gitlab.com/oceanbox/Poseidon/commit/a37e6021312f431fd33c435981ddfcafd47b890c))
|
||||
|
||||
## [1.18.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.18.1...v1.18.2) (2025-08-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **nix:** Add `debug` as argstr and match version with fsproj's ([82c43bb](https://gitlab.com/oceanbox/Poseidon/commit/82c43bb5f0db0e8e442cab97f049f1a0568ab2db))
|
||||
|
||||
## [1.18.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.18.0...v1.18.1) (2025-08-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Encrypt netrc with agenix and add to git ([4490ddf](https://gitlab.com/oceanbox/Poseidon/commit/4490ddf47c6f53de34317fcf6e0c97603785931c))
|
||||
* Encrypt netrc with agenix and add to git ([68ef2f7](https://gitlab.com/oceanbox/Poseidon/commit/68ef2f7b7272af094376a8e3438f294812c4ca69))
|
||||
* Encrypt netrc with agenix and add to git ([270e5c0](https://gitlab.com/oceanbox/Poseidon/commit/270e5c02fc3dfc904195a0c318c0453594d0d93f))
|
||||
* fix loading of ssh keys ([842df2f](https://gitlab.com/oceanbox/Poseidon/commit/842df2fdb672c000b3f21ca2045a60329e9c2a61))
|
||||
|
||||
# [1.18.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.17.1...v1.18.0) (2025-08-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Cleanup ([786165c](https://gitlab.com/oceanbox/Poseidon/commit/786165c8452564944f743084cf0d1b23dda1b9cf))
|
||||
* Drop netrc and add nupkg build ([d27cf41](https://gitlab.com/oceanbox/Poseidon/commit/d27cf4148758ea6db4d4697018f6c20a33608c6f))
|
||||
* Revert tilt instances and add additional docs ([0402785](https://gitlab.com/oceanbox/Poseidon/commit/0402785fc7078e11f298635cf9a0e0cba47ecad1))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Build with Nix ([ebe6b70](https://gitlab.com/oceanbox/Poseidon/commit/ebe6b7088310340587708811be18f211165b6d96))
|
||||
* migrate to nix-actions and modernize build infrastructure ([27e54a7](https://gitlab.com/oceanbox/Poseidon/commit/27e54a7e1da571315b02bfa028461bfd82d144bc))
|
||||
|
||||
## [1.17.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.17.0...v1.17.1) (2025-08-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Sorcerer:** remove duplicate release sites in transition zone ([33c28cc](https://gitlab.com/oceanbox/Poseidon/commit/33c28ccb7647cc13f6a2d29fb2508741796b12e9))
|
||||
|
||||
# [1.17.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.16.4...v1.17.0) (2025-08-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Atlantis:** send correct aid for aze contour download ([43ff8c5](https://gitlab.com/oceanbox/Poseidon/commit/43ff8c52e4c93ddaba6ef83dd0dfda3ee12997ee))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Rewrite Archivist CLI with Fargo ([fa063a9](https://gitlab.com/oceanbox/Poseidon/commit/fa063a9508f70421f53da0b028f0d107b1b2b841))
|
||||
|
||||
## [1.16.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.16.3...v1.16.4) (2025-07-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Don't restore ([cb9d678](https://gitlab.com/oceanbox/Poseidon/commit/cb9d678bce9fe95b9f709682470abf12564e9b4d))
|
||||
* Remove compiler check ([18c5399](https://gitlab.com/oceanbox/Poseidon/commit/18c5399625d47867fc2f265e514fcc66c74cb676))
|
||||
|
||||
## [1.16.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.16.2...v1.16.3) (2025-07-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Check for fable compiler in Dapr.Actor interfaces ([aa6c01c](https://gitlab.com/oceanbox/Poseidon/commit/aa6c01c5f27c7aa9c764c930426cb92c8f31b9f2))
|
||||
* Plume cleanup ([0e080a7](https://gitlab.com/oceanbox/Poseidon/commit/0e080a70e194e3b54cc2179396e0662067db9cef))
|
||||
* Use Ordinal StringComparison for fgaToken ([dbef031](https://gitlab.com/oceanbox/Poseidon/commit/dbef03187c7977666d40997828430a386868c1c6))
|
||||
|
||||
## [1.16.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.16.1...v1.16.2) (2025-07-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Don't restore before Release build ([c4134f8](https://gitlab.com/oceanbox/Poseidon/commit/c4134f8b2755ccfaebd33499b81e6ffb6af1093f))
|
||||
|
||||
## [1.16.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.16.0...v1.16.1) (2025-07-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make inboxTypeFromString case insensitive ([fe3370f](https://gitlab.com/oceanbox/Poseidon/commit/fe3370f50f58c4b05a4b5016ba3a6a4a50bb6d1e))
|
||||
* Remove unused code and bump slurmrestd ([a6c2c94](https://gitlab.com/oceanbox/Poseidon/commit/a6c2c949c2bbfec923aec551f180c88ead7fc071))
|
||||
|
||||
# [1.16.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.15.3...v1.16.0) (2025-07-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add working parts of plume ([0e256e6](https://gitlab.com/oceanbox/Poseidon/commit/0e256e621894244f43f9bf4ba8cb78d2905d8815))
|
||||
|
||||
## [1.15.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.15.2...v1.15.3) (2025-07-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **atlantis:** disable probing on no stats ([a464a5a](https://gitlab.com/oceanbox/Poseidon/commit/a464a5ac06ea9420c963409f562a40b3da04b500))
|
||||
* **plume:** adjust plume stop when changing start or duration ([13ac803](https://gitlab.com/oceanbox/Poseidon/commit/13ac8032690809dbd93b36b5a1e93a6eccd9d236))
|
||||
* **plume:** allow cancel plume when running ([a400bf9](https://gitlab.com/oceanbox/Poseidon/commit/a400bf9e0bb8703f109bbc809dbabf08bec172c4))
|
||||
* **plume:** notify on fail ([e69897f](https://gitlab.com/oceanbox/Poseidon/commit/e69897fc94d1011ecb4391c69f499f9856a8941a))
|
||||
|
||||
## [1.15.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.15.1...v1.15.2) (2025-07-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* misc wonk to fix pipeline build ([fd78702](https://gitlab.com/oceanbox/Poseidon/commit/fd78702ab49016726723dfdb2a144f180c6e4c10))
|
||||
|
||||
## [1.15.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.15.0...v1.15.1) (2025-07-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Disable spinner after job is completed ([558c482](https://gitlab.com/oceanbox/Poseidon/commit/558c4829d903798e682233b07951f0ca8b78e9a2))
|
||||
|
||||
# [1.15.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.14.5...v1.15.0) (2025-07-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing fetch fields button for downwelling ([44f12a8](https://gitlab.com/oceanbox/Poseidon/commit/44f12a825d0f6d3bb7a6da4e661b84c2669a6d02))
|
||||
* **atlantis:** show color bar on stats properties ([3046ec5](https://gitlab.com/oceanbox/Poseidon/commit/3046ec563d5456e46090673a4f91d5b51da83a92))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add Initial Plume UI ([1c14274](https://gitlab.com/oceanbox/Poseidon/commit/1c14274cdbdd9dbe940742d5116be5b1e32e9dff))
|
||||
* add traits input for plume ([d603453](https://gitlab.com/oceanbox/Poseidon/commit/d60345339b871655836fa6254265d957371d1dc2))
|
||||
* **plume:** add download button for plume result ([1cbd34c](https://gitlab.com/oceanbox/Poseidon/commit/1cbd34c1022db5f1a9b4233f88266f1b55262f74))
|
||||
|
||||
## [1.14.5](https://gitlab.com/oceanbox/Poseidon/compare/v1.14.4...v1.14.5) (2025-07-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing fetch fields button for downwelling ([2f39571](https://gitlab.com/oceanbox/Poseidon/commit/2f395712d5fd85d5769c4af3d0cf5855fb556ae6))
|
||||
|
||||
## [1.14.4](https://gitlab.com/oceanbox/Poseidon/compare/v1.14.3...v1.14.4) (2025-07-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **atlantis:** show color bar on stats properties ([59ac2aa](https://gitlab.com/oceanbox/Poseidon/commit/59ac2aa3c922d89fedb4133db98461e353b007e4))
|
||||
|
||||
## [1.14.3](https://gitlab.com/oceanbox/Poseidon/compare/v1.14.2...v1.14.3) (2025-06-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sorcerer:** Only run sorcerer on c-x nodes ([41d792d](https://gitlab.com/oceanbox/Poseidon/commit/41d792dc2adafe7faa710bb1d6a271e415b03b84))
|
||||
|
||||
## [1.14.2](https://gitlab.com/oceanbox/Poseidon/compare/v1.14.1...v1.14.2) (2025-06-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **atlantis:** Replace plotly with plotly-basic-dist-min ([36e12f3](https://gitlab.com/oceanbox/Poseidon/commit/36e12f39cc9475f6cb8ab55f66522e9dce41bde7))
|
||||
* **atlantis:** Switch to custom bundle ([ec87726](https://gitlab.com/oceanbox/Poseidon/commit/ec87726347552a009f89fd1d948a82e08280077a))
|
||||
|
||||
## [1.14.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.14.0...v1.14.1) (2025-06-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **atlantis:** multiple select archive management ([8bd0c71](https://gitlab.com/oceanbox/Poseidon/commit/8bd0c7146f609f26293692d6b2c9b9d80e8695a9))
|
||||
|
||||
# [1.14.0](https://gitlab.com/oceanbox/Poseidon/compare/v1.13.1...v1.14.0) (2025-06-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Allow sentry in tilt and prod ([cab6de5](https://gitlab.com/oceanbox/Poseidon/commit/cab6de560d1850e1344e85fbda6d548f47f8cbff))
|
||||
* Build Catalog and Archivist Client ([7d34824](https://gitlab.com/oceanbox/Poseidon/commit/7d348248bb456446a63d54d9f4958f527dea4fb1))
|
||||
* **sentry:** Only run in Prod/Staging ([712b7d2](https://gitlab.com/oceanbox/Poseidon/commit/712b7d2bf2db280a5403d4f790401933c5585b87))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **atlantis:** Add Sentry to Client and Server ([39dbfa5](https://gitlab.com/oceanbox/Poseidon/commit/39dbfa5592ebf628b4318c65d0ab7673419c6bec))
|
||||
* **atlantis:** Instrument server with sentry ([d47359b](https://gitlab.com/oceanbox/Poseidon/commit/d47359b84085eb10a843a288037ef3f97327e3ab))
|
||||
* **sorcerer:** Instrument sorcerer server ([92d3583](https://gitlab.com/oceanbox/Poseidon/commit/92d3583e0b576a0ec3bfe43dd868920a5d5526bc))
|
||||
|
||||
## [1.13.1](https://gitlab.com/oceanbox/Poseidon/compare/v1.13.0...v1.13.1) (2025-06-22)
|
||||
|
||||
|
||||
|
||||
@@ -5,29 +5,22 @@ Stage: build
|
||||
%files
|
||||
. /build
|
||||
|
||||
# Install apt packages
|
||||
%post
|
||||
# Add keys and sources lists
|
||||
apt-get update && apt-get install -y ca-certificates gnupg
|
||||
mkdir -p /etc/apt/keyrings
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||
NODE_MAJOR=20
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
||||
|
||||
# Install node, 7zip, yarn, git, process tools
|
||||
apt update \
|
||||
&& apt install -y nodejs p7zip-full git procps ssh-client
|
||||
&& apt install -y p7zip-full git procps ssh-client
|
||||
|
||||
# Clean up
|
||||
apt autoremove -y \
|
||||
&& apt clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install dotnet tools
|
||||
dotnet tool install fable -g
|
||||
|
||||
# Build application
|
||||
%post
|
||||
cd /build/src/Archivist
|
||||
dotnet restore --force-evaluate
|
||||
dotnet run bundle
|
||||
|
||||
|
||||
Bootstrap: docker
|
||||
From: mcr.microsoft.com/dotnet/runtime:9.0
|
||||
Stage: runtime
|
||||
@@ -39,7 +32,6 @@ Stage: runtime
|
||||
apt update \
|
||||
&& apt install -y libnetcdf-dev
|
||||
|
||||
# Clean up
|
||||
apt autoremove -y \
|
||||
&& apt clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
@@ -52,4 +44,4 @@ Stage: runtime
|
||||
export ARCHMAESTER_AUTH="admin:en-to-tre-fire"
|
||||
|
||||
%runscript
|
||||
exec /app/Archivist "$@"
|
||||
exec /app/archivist "$@"
|
||||
69
default.nix
Normal file
69
default.nix
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
sources ? import ./nix,
|
||||
system ? builtins.currentSystem,
|
||||
pkgs ? import sources.nixpkgs {
|
||||
inherit system;
|
||||
config = { };
|
||||
overlays = [ ];
|
||||
},
|
||||
env ? "Debug",
|
||||
nix-utils ? import sources.nix-utils { },
|
||||
}:
|
||||
let
|
||||
version =
|
||||
let
|
||||
clean = str: str |> (pkgs.lib.removeSuffix "\n");
|
||||
version = builtins.readFile ./VERSION;
|
||||
in
|
||||
clean version;
|
||||
|
||||
dotnet-sdk = pkgs.dotnetCorePackages.sdk_10_0;
|
||||
dotnet-runtime = pkgs.dotnetCorePackages.aspnetcore_10_0;
|
||||
deps = nix-utils.output.lib.nuget.deps;
|
||||
|
||||
# Usage: export NETRC="$(agenix -d netrc.age)" in `./nix/secrets`
|
||||
netrcConfig = builtins.getEnv "NETRC";
|
||||
|
||||
scripts = import ./scripts { inherit pkgs; };
|
||||
|
||||
packages = import ./nix/packages {
|
||||
inherit
|
||||
env
|
||||
deps
|
||||
pkgs
|
||||
version
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
;
|
||||
inherit netrcConfig;
|
||||
};
|
||||
|
||||
containers = pkgs.callPackage ./nix/containers.nix {
|
||||
inherit (packages)
|
||||
atlantis
|
||||
sorcerer
|
||||
atlantis-client
|
||||
archivist
|
||||
;
|
||||
inherit
|
||||
version
|
||||
env
|
||||
;
|
||||
codex = packages.codex;
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit packages;
|
||||
|
||||
inherit scripts;
|
||||
|
||||
# Expose atlantis as default packages
|
||||
default = packages.atlantis;
|
||||
|
||||
# Docker and Singurlarity images
|
||||
containers = containers;
|
||||
|
||||
checks = {
|
||||
pre-commit = import ./nix/pre-commit.nix;
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "9.0.0",
|
||||
"version": "10.0.100",
|
||||
"rollForward": "latestMinor"
|
||||
}
|
||||
}
|
||||
42
justfile
Normal file
42
justfile
Normal file
@@ -0,0 +1,42 @@
|
||||
# Poseidon build commands
|
||||
# Install just: https://github.com/casey/just
|
||||
#
|
||||
# Sub-projects with justfiles:
|
||||
# - Atlantis (src/Atlantis) - Server + Client application with Fable/Vite
|
||||
# - ServerPack (src/ServerPack) - Server package library
|
||||
# - DataAgent (src/DataAgent) - Data agent library
|
||||
# - Interfaces (src/Interfaces) - API interfaces library
|
||||
# - Archivist (src/Archivist) - CLI tool with client
|
||||
# - Sorcerer (src/Sorcerer) - Server application with client
|
||||
#
|
||||
# Run 'just <project>' to see available commands for each project (e.g., 'just atlantis')
|
||||
|
||||
set dotenv-load
|
||||
|
||||
# Default recipe - show available commands
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# Show available commands for Atlantis (src/Atlantis)
|
||||
atlantis:
|
||||
@just src/Atlantis/
|
||||
|
||||
# Show available commands for ServerPack (src/ServerPack)
|
||||
serverpack:
|
||||
@just src/ServerPack/
|
||||
|
||||
# Show available commands for DataAgent (src/DataAgent)
|
||||
dataagent:
|
||||
@just src/DataAgent/
|
||||
|
||||
# Show available commands for Interfaces (src/Interfaces)
|
||||
interfaces:
|
||||
@just src/Interfaces/
|
||||
|
||||
# Show available commands for Archivist (src/Archivist)
|
||||
archivist:
|
||||
@just src/Archivist/
|
||||
|
||||
# Show available commands for Sorcerer (src/Sorcerer)
|
||||
sorcerer:
|
||||
@just src/Sorcerer/
|
||||
109
nix/README.md
Normal file
109
nix/README.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Nix
|
||||
|
||||
This directory contains Nix expressions defining the packages, and containers used to run/build Poseidon.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
nix/
|
||||
├── packages/ # Individual Poseidon service packages
|
||||
│ ├── default.nix # Entry point - builds all packages with dependencies
|
||||
│ ├── serverpack.nix
|
||||
│ ├── dataagent.nix
|
||||
│ ├── atlantis.nix
|
||||
│ ├── atlantis-client.nix
|
||||
│ ├── atlantis-client.json # Client dependencies metadata
|
||||
│ ├── atlantis-deps.json # Atlantis backend dependencies metadata
|
||||
│ ├── sorcerer.nix
|
||||
│ └── archivist.nix
|
||||
├── secrets/ # Age encrypted files
|
||||
│ ├── secrets.nix
|
||||
│ └── *.age
|
||||
├── containers.nix # Docker & Singularity container definitions
|
||||
│ ├── atlantis
|
||||
│ ├── sorcerer
|
||||
│ └── archivist
|
||||
└── pre-commit.nix # Pre-commit hooks for code quality
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Note: `nix-build` can be switched for `nom-build` for a pretty-printed output (using [Nix Output Monitor](https://github.com/maralorn/nix-output-monitor))
|
||||
|
||||
### Secrets
|
||||
|
||||
```bash
|
||||
# To run nix-build
|
||||
$ set -x NETRC $(agenix -d netrc.age)
|
||||
```
|
||||
|
||||
Secrets used for development and production are stored as `*.age` files and decrypted/encrypted using agenix via ssh-keys.
|
||||
|
||||
```bash
|
||||
# To encrypt
|
||||
$ agenix -e name.age # And add to secrets.nix
|
||||
|
||||
# To decrypt
|
||||
$ agenix -d name.age
|
||||
```
|
||||
|
||||
In case a new key is added to the `secrets.nix` file we need to re-key the age files with:
|
||||
```bash
|
||||
$ agenix -r
|
||||
```
|
||||
|
||||
### Building Individual Packages
|
||||
```bash
|
||||
# Build a specific service
|
||||
$ nix-build -A packages.atlantis
|
||||
$ nix-build -A packages.sorcerer
|
||||
|
||||
# Build all packages
|
||||
$ nix-build -A packages
|
||||
```
|
||||
|
||||
### Building Container Images
|
||||
```bash
|
||||
# Build Docker containers
|
||||
$ nix-build -A containers.atlantis
|
||||
$ nix-build -A containers.sorcerer
|
||||
|
||||
# Build Singularity container for HPC
|
||||
$ nix-build -A containers.archivist
|
||||
```
|
||||
|
||||
### Development Shell
|
||||
```bash
|
||||
# Enter development environment
|
||||
$ nix-shell
|
||||
|
||||
# Or use a specific package's shell
|
||||
$ nix-shell -A packages.atlantis
|
||||
```
|
||||
|
||||
### Running Services
|
||||
```bash
|
||||
# Run Atlantis server
|
||||
$ ./result/bin/atlantis
|
||||
|
||||
# Run Sorcerer API
|
||||
$ ./result/bin/sorcerer
|
||||
```
|
||||
|
||||
### Update dependencies
|
||||
|
||||
When updating the `npm` dependencies, the `outputHash` in `atlantis-client.nix` needs to be updated. Simply run
|
||||
|
||||
```bash
|
||||
nix-build -A packages.atlantis-client # in the root
|
||||
```
|
||||
|
||||
It will then fail on the wrong hash and provide the correct one.
|
||||
|
||||
#### Deterministic builds, vendor hashes, and lock files
|
||||
|
||||
Nix aims for deterministic (reproducible) builds. A key part of this is **fixed-output derivations (FODs)** such as `fetchurl`, `buildDotnetModule`’s vendor step, `fetchgit`, etc. For any FOD, Nix requires a **content hash** up front. After the build/fetch runs, Nix verifies that the resulting output’s hash exactly matches what was declared; if it doesn’t, the build fails with a “hash mismatch in fixed-output derivation” error. This protects you from drifting dependencies and ensures that CI and local builds use the exact same inputs.
|
||||
|
||||
#### Why vendor hashes need to be pinned
|
||||
|
||||
Language ecosystems resolve and download a lot of upstream content (Go modules, npm/yarn, cargo crates, vendored tarballs…). To make those fetches deterministic, Nix needs the **expected content hash**. For example, with `makeDerivation`, you must set `outputHash` so Nix knows what the fully-resolved module tree should hash to. If you bump a version or change dependencies, the **content changes** and the old hash becomes invalid—Nix will (correctly) refuse the build until you update the pinned hash.
|
||||
102
nix/containers.nix
Normal file
102
nix/containers.nix
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
env,
|
||||
pkgs,
|
||||
version,
|
||||
atlantis,
|
||||
atlantis-client,
|
||||
sorcerer,
|
||||
archivist,
|
||||
codex,
|
||||
}:
|
||||
let
|
||||
# Entrypoints
|
||||
startArchivist = pkgs.writeScriptBin "entrypoint" ''
|
||||
#!${pkgs.runtimeShell}
|
||||
set -euo pipefail
|
||||
exec archivist "$@"
|
||||
'';
|
||||
in
|
||||
{
|
||||
atlantis = pkgs.dockerTools.buildLayeredImage {
|
||||
name = "Atlantis";
|
||||
tag = version;
|
||||
created = "now";
|
||||
contents = [
|
||||
atlantis
|
||||
pkgs.dockerTools.caCertificates
|
||||
]
|
||||
++ pkgs.lib.optionals (env == "Debug") [
|
||||
pkgs.busybox
|
||||
pkgs.dockerTools.binSh
|
||||
];
|
||||
|
||||
extraCommands = ''
|
||||
mkdir -m 0777 tmp
|
||||
mkdir -p ./app
|
||||
cp -r ${atlantis}/lib/Atlantis/* ./app/
|
||||
cp -r ${atlantis-client}/public ./app/
|
||||
'';
|
||||
|
||||
config = {
|
||||
cmd = [ "Server" ];
|
||||
workingDir = "/app";
|
||||
env = [
|
||||
"SERVER_CONTENT_ROOT=/app/public"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
sorcerer = pkgs.dockerTools.buildLayeredImage {
|
||||
name = "Sorcerer";
|
||||
tag = version;
|
||||
created = "now";
|
||||
contents = [
|
||||
sorcerer
|
||||
pkgs.dockerTools.caCertificates
|
||||
]
|
||||
++ pkgs.lib.optionals (env == "Debug") [
|
||||
pkgs.busybox
|
||||
pkgs.dockerTools.binSh
|
||||
];
|
||||
extraCommands = ''
|
||||
mkdir -p ./app
|
||||
cp -r ${sorcerer}/lib/Sorcerer/* ./app/
|
||||
'';
|
||||
config = {
|
||||
cmd = [ "Sorcerer" ];
|
||||
workingDir = "/app";
|
||||
};
|
||||
};
|
||||
|
||||
archivist = pkgs.dockerTools.buildLayeredImage {
|
||||
name = "archivist";
|
||||
tag = archivist.version;
|
||||
created = "now";
|
||||
|
||||
contents = [
|
||||
archivist
|
||||
]
|
||||
++ pkgs.lib.optionals (env == "Debug") [
|
||||
pkgs.busybox
|
||||
pkgs.dockerTools.binSh
|
||||
];
|
||||
|
||||
compressor = "none";
|
||||
|
||||
extraCommands = ''
|
||||
mkdir -p ./app
|
||||
cp -r ${archivist}/lib/Archivist/* ./app/
|
||||
'';
|
||||
|
||||
config = {
|
||||
entrypoint = [ "${startArchivist}/bin/entrypoint" ];
|
||||
workingDir = "/app";
|
||||
env = [
|
||||
"ARCHMAESTER_URL=https://maps.oceanbox.io"
|
||||
"ARCHMAESTER_AUTH=admin:en-to-tre-fire"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
codex = pkgs.callPackage ../src/Codex/container.nix { server = codex; };
|
||||
}
|
||||
249
nix/default.nix
Normal file
249
nix/default.nix
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
This file is provided under the MIT licence:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
# Generated by npins. Do not modify; will be overwritten regularly
|
||||
let
|
||||
# Backwards-compatibly make something that previously didn't take any arguments take some
|
||||
# The function must return an attrset, and will unfortunately be eagerly evaluated
|
||||
# Same thing, but it catches eval errors on the default argument so that one may still call it with other arguments
|
||||
mkFunctor =
|
||||
fn:
|
||||
let
|
||||
e = builtins.tryEval (fn { });
|
||||
in
|
||||
(if e.success then e.value else { error = fn { }; }) // { __functor = _self: fn; };
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
|
||||
range =
|
||||
first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1);
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
|
||||
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
|
||||
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
|
||||
concatStrings = builtins.concatStringsSep "";
|
||||
|
||||
# If the environment variable NPINS_OVERRIDE_${name} is set, then use
|
||||
# the path directly as opposed to the fetched source.
|
||||
# (Taken from Niv for compatibility)
|
||||
mayOverride =
|
||||
name: path:
|
||||
let
|
||||
envVarName = "NPINS_OVERRIDE_${saneName}";
|
||||
saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name;
|
||||
ersatz = builtins.getEnv envVarName;
|
||||
in
|
||||
if ersatz == "" then
|
||||
path
|
||||
else
|
||||
# this turns the string into an actual Nix path (for both absolute and
|
||||
# relative paths)
|
||||
builtins.trace "Overriding path of \"${name}\" with \"${ersatz}\" due to set \"${envVarName}\"" (
|
||||
if builtins.substring 0 1 ersatz == "/" then
|
||||
/. + ersatz
|
||||
else
|
||||
/. + builtins.getEnv "PWD" + "/${ersatz}"
|
||||
);
|
||||
|
||||
mkSource =
|
||||
name: spec:
|
||||
{
|
||||
pkgs ? null,
|
||||
}:
|
||||
assert spec ? type;
|
||||
let
|
||||
# Unify across builtin and pkgs fetchers.
|
||||
# `fetchGit` requires a wrapper because of slight API differences.
|
||||
fetchers =
|
||||
if pkgs == null then
|
||||
{
|
||||
inherit (builtins) fetchTarball fetchurl;
|
||||
# For some fucking reason, fetchGit has a different signature than the other builtin fetchers …
|
||||
fetchGit = args: (builtins.fetchGit args).outPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
fetchTarball =
|
||||
{
|
||||
url,
|
||||
sha256,
|
||||
}:
|
||||
pkgs.fetchzip {
|
||||
inherit url sha256;
|
||||
extension = "tar";
|
||||
};
|
||||
inherit (pkgs) fetchurl;
|
||||
fetchGit =
|
||||
{
|
||||
url,
|
||||
submodules,
|
||||
rev,
|
||||
name,
|
||||
narHash,
|
||||
}:
|
||||
pkgs.fetchgit {
|
||||
inherit url rev name;
|
||||
fetchSubmodules = submodules;
|
||||
hash = narHash;
|
||||
};
|
||||
};
|
||||
|
||||
# Dispatch to the correct code path based on the type
|
||||
path =
|
||||
if spec.type == "Git" then
|
||||
mkGitSource fetchers spec
|
||||
else if spec.type == "GitRelease" then
|
||||
mkGitSource fetchers spec
|
||||
else if spec.type == "PyPi" then
|
||||
mkPyPiSource fetchers spec
|
||||
else if spec.type == "Channel" then
|
||||
mkChannelSource fetchers spec
|
||||
else if spec.type == "Tarball" then
|
||||
mkTarballSource fetchers spec
|
||||
else if spec.type == "Container" then
|
||||
mkContainerSource pkgs spec
|
||||
else
|
||||
builtins.throw "Unknown source type ${spec.type}";
|
||||
in
|
||||
spec // { outPath = mayOverride name path; };
|
||||
|
||||
mkGitSource =
|
||||
{
|
||||
fetchTarball,
|
||||
fetchGit,
|
||||
...
|
||||
}:
|
||||
{
|
||||
repository,
|
||||
revision,
|
||||
url ? null,
|
||||
submodules,
|
||||
hash,
|
||||
...
|
||||
}:
|
||||
assert repository ? type;
|
||||
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
|
||||
# In the latter case, there we will always be an url to the tarball
|
||||
if url != null && !submodules then
|
||||
fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
}
|
||||
else
|
||||
let
|
||||
url =
|
||||
if repository.type == "Git" then
|
||||
repository.url
|
||||
else if repository.type == "GitHub" then
|
||||
"https://github.com/${repository.owner}/${repository.repo}.git"
|
||||
else if repository.type == "GitLab" then
|
||||
"${repository.server}/${repository.repo_path}.git"
|
||||
else if repository.type == "Forgejo" then
|
||||
"${repository.server}/${repository.owner}/${repository.repo}.git"
|
||||
else
|
||||
throw "Unrecognized repository type ${repository.type}";
|
||||
urlToName =
|
||||
url: rev:
|
||||
let
|
||||
matched = builtins.match "^.*/([^/]*)(\\.git)?$" url;
|
||||
|
||||
short = builtins.substring 0 7 rev;
|
||||
|
||||
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
|
||||
in
|
||||
"${if matched == null then "source" else builtins.head matched}${appendShort}";
|
||||
name = urlToName url revision;
|
||||
in
|
||||
fetchGit {
|
||||
rev = revision;
|
||||
narHash = hash;
|
||||
|
||||
inherit name submodules url;
|
||||
};
|
||||
|
||||
mkPyPiSource =
|
||||
{ fetchurl, ... }:
|
||||
{
|
||||
url,
|
||||
hash,
|
||||
...
|
||||
}:
|
||||
fetchurl {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkChannelSource =
|
||||
{ fetchTarball, ... }:
|
||||
{
|
||||
url,
|
||||
hash,
|
||||
...
|
||||
}:
|
||||
fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkTarballSource =
|
||||
{ fetchTarball, ... }:
|
||||
{
|
||||
url,
|
||||
locked_url ? url,
|
||||
hash,
|
||||
...
|
||||
}:
|
||||
fetchTarball {
|
||||
url = locked_url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkContainerSource =
|
||||
pkgs:
|
||||
{
|
||||
image_name,
|
||||
image_tag,
|
||||
image_digest,
|
||||
...
|
||||
}:
|
||||
if pkgs == null then
|
||||
builtins.throw "container sources require passing in a Nixpkgs value: https://github.com/andir/npins/blob/master/README.md#using-the-nixpkgs-fetchers"
|
||||
else
|
||||
pkgs.dockerTools.pullImage {
|
||||
imageName = image_name;
|
||||
imageDigest = image_digest;
|
||||
finalImageTag = image_tag;
|
||||
};
|
||||
in
|
||||
mkFunctor (
|
||||
{
|
||||
input ? ./sources.json,
|
||||
}:
|
||||
let
|
||||
data =
|
||||
if builtins.isPath input then
|
||||
# while `readFile` will throw an error anyways if the path doesn't exist,
|
||||
# we still need to check beforehand because *our* error can be caught but not the one from the builtin
|
||||
# *piegames sighs*
|
||||
if builtins.pathExists input then
|
||||
builtins.fromJSON (builtins.readFile input)
|
||||
else
|
||||
throw "Input path ${toString input} does not exist"
|
||||
else if builtins.isAttrs input then
|
||||
input
|
||||
else
|
||||
throw "Unsupported input type ${builtins.typeOf input}, must be a path or an attrset";
|
||||
version = data.version;
|
||||
in
|
||||
if version == 7 then
|
||||
builtins.mapAttrs (name: spec: mkFunctor (mkSource name spec)) data.pins
|
||||
else
|
||||
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
|
||||
)
|
||||
47
nix/packages/api.nix
Normal file
47
nix/packages/api.nix
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
env,
|
||||
deps,
|
||||
pkgs,
|
||||
netrcConfig,
|
||||
nix-gitignore,
|
||||
packageSources,
|
||||
dotnet-sdk,
|
||||
dotnet-runtime,
|
||||
buildDotnetModule,
|
||||
}:
|
||||
let
|
||||
src = nix-gitignore.gitignoreSource [ ] ../../.;
|
||||
projectFile = "src/Interfaces/Api/Poseidon.Api.fsproj";
|
||||
versionMatch = builtins.match ".*<Version>([^<]+)</Version>.*" (
|
||||
builtins.readFile (../../. + "/${projectFile}")
|
||||
);
|
||||
version = builtins.head versionMatch;
|
||||
in
|
||||
buildDotnetModule rec {
|
||||
inherit
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
version
|
||||
src
|
||||
projectFile
|
||||
;
|
||||
name = "Poseidon.Api";
|
||||
pname = "Poseidon.Api";
|
||||
nugetDeps = deps {
|
||||
inherit
|
||||
name
|
||||
pkgs
|
||||
netrcConfig
|
||||
packageSources
|
||||
;
|
||||
lockfiles = [
|
||||
../../src/Interfaces/Api/packages.lock.json
|
||||
];
|
||||
};
|
||||
doCheck = false;
|
||||
buildType = env;
|
||||
# packNupkg = true;
|
||||
# NOTE(mrtz): Can't package nuget without it
|
||||
# [ref](https://github.com/dotnet/fsharp/issues/12320)
|
||||
# dotnetFlags = "--property:TargetsForTfmSpecificContentInPackage=";
|
||||
}
|
||||
46
nix/packages/archivist.nix
Normal file
46
nix/packages/archivist.nix
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
env,
|
||||
pkgs,
|
||||
deps,
|
||||
netrcConfig,
|
||||
nix-gitignore,
|
||||
packageSources,
|
||||
dotnet-sdk,
|
||||
buildDotnetModule,
|
||||
}:
|
||||
let
|
||||
src = nix-gitignore.gitignoreSource [ ] ../../.;
|
||||
projectFile = "src/Archivist/src/Cli/Archivist.fsproj";
|
||||
versionMatch = builtins.match ".*<Version>([^<]+)</Version>.*" (
|
||||
builtins.readFile (../../. + "/${projectFile}")
|
||||
);
|
||||
version = builtins.head versionMatch;
|
||||
in
|
||||
buildDotnetModule rec {
|
||||
inherit
|
||||
dotnet-sdk
|
||||
version
|
||||
src
|
||||
projectFile
|
||||
;
|
||||
name = "Archivist";
|
||||
pname = name;
|
||||
dotnet-runtime = pkgs.dotnetCorePackages.runtime_10_0;
|
||||
dotnetRestoreFlags = "--force-evaluate";
|
||||
nugetDeps = deps {
|
||||
inherit
|
||||
name
|
||||
pkgs
|
||||
netrcConfig
|
||||
packageSources
|
||||
;
|
||||
lockfiles = [
|
||||
../../src/Archivist/src/Cli/packages.lock.json
|
||||
];
|
||||
};
|
||||
runtimeDeps = [
|
||||
pkgs.netcdf
|
||||
];
|
||||
buildType = env;
|
||||
doCheck = false;
|
||||
}
|
||||
89
nix/packages/atlantis-client.nix
Normal file
89
nix/packages/atlantis-client.nix
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
lib,
|
||||
bun,
|
||||
pkgs,
|
||||
deps,
|
||||
fable,
|
||||
version,
|
||||
dotnet-sdk,
|
||||
netrcConfig,
|
||||
nodeModules,
|
||||
nix-gitignore,
|
||||
packageSources,
|
||||
dotnet-runtime,
|
||||
buildDotnetModule,
|
||||
}:
|
||||
let
|
||||
root = ../../.;
|
||||
|
||||
src = nix-gitignore.gitignoreSource [ ] root;
|
||||
# src = lib.cleanSource root;
|
||||
|
||||
pname = "Atlantis";
|
||||
|
||||
in
|
||||
buildDotnetModule {
|
||||
inherit dotnet-sdk dotnet-runtime;
|
||||
inherit src version;
|
||||
pname = "${pname}-Client";
|
||||
|
||||
projectFile = "src/Atlantis/src/Client/Client.fsproj";
|
||||
dotnetRestoreFlags = "--force-evaluate";
|
||||
# nugetDeps = ./atlantis-client.json; # nix-build -A packages.atlantis-client.fetch-deps && ./result src/Atlantis/nix/atlantis-client.json
|
||||
nugetDeps = deps {
|
||||
inherit
|
||||
pkgs
|
||||
netrcConfig
|
||||
packageSources
|
||||
;
|
||||
name = "${pname}-Client";
|
||||
lockfiles = [
|
||||
../../src/Atlantis/src/Client/packages.lock.json
|
||||
];
|
||||
};
|
||||
|
||||
# Skip the default dotnet build since we're using Fable
|
||||
dontDotnetBuild = true;
|
||||
|
||||
buildInputs = [
|
||||
fable
|
||||
bun
|
||||
];
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
export HOME=$TMPDIR
|
||||
|
||||
cp -r ${nodeModules}/node_modules ./.
|
||||
chmod -R u+rw node_modules
|
||||
|
||||
chmod -R u+x node_modules/.bin
|
||||
patchShebangs node_modules/.bin
|
||||
export PATH="./node_modules/.bin:$PATH"
|
||||
|
||||
cd src/Atlantis/src/Client
|
||||
|
||||
# NOTE(mrtz): Uses fable from nixpkgs instead of dotnet (Could be out of sync). --MSBuildCracker
|
||||
${lib.getExe fable} -e .jsx -o build
|
||||
|
||||
# Run vite from the Atlantis directory with proper config, always bundle for prod
|
||||
${lib.getExe bun} ../../../../node_modules/.bin/vite build -c ../../vite.config.js --outDir dist/public --mode Production
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
# Copy output (*.js, *.css and *.html) to `/public`.
|
||||
mkdir -p $out/public
|
||||
cp -r dist/public/* $out/public/
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
dontFixup = true;
|
||||
dontPatchELF = true;
|
||||
dontStrip = true;
|
||||
}
|
||||
49
nix/packages/atlantis.nix
Normal file
49
nix/packages/atlantis.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
env,
|
||||
pkgs,
|
||||
deps,
|
||||
version,
|
||||
netrcConfig,
|
||||
nix-gitignore,
|
||||
packageSources,
|
||||
dotnet-sdk,
|
||||
dotnet-runtime,
|
||||
buildDotnetModule,
|
||||
}:
|
||||
buildDotnetModule rec {
|
||||
inherit
|
||||
version
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
;
|
||||
name = "Atlantis";
|
||||
pname = "Atlantis";
|
||||
# NOTE(mrtz): Ensures reproducibility and reduces closure size,
|
||||
# by filtering out irrelevant files and `.git` which changes between commits.
|
||||
src = nix-gitignore.gitignoreSource [ ] ../..;
|
||||
projectFile = "src/Atlantis/src/Server/Server.fsproj";
|
||||
dotnetRestoreFlags = "--force-evaluate";
|
||||
nugetDeps = deps {
|
||||
inherit
|
||||
name
|
||||
pkgs
|
||||
netrcConfig
|
||||
packageSources
|
||||
;
|
||||
lockfiles = [
|
||||
../../src/Atlantis/src/Server/packages.lock.json
|
||||
../../src/DataAgent/src/Entity/packages.lock.json
|
||||
];
|
||||
};
|
||||
runtimeDeps = [
|
||||
pkgs.netcdf
|
||||
];
|
||||
# NOTE: Add back when we have tests
|
||||
doCheck = false;
|
||||
buildType = env;
|
||||
# Copy `appsettings` for local build
|
||||
postBuild = ''
|
||||
mkdir -p $out/bin
|
||||
cp src/Atlantis/src/Server/appsettings.json $out/bin/
|
||||
'';
|
||||
}
|
||||
49
nix/packages/dataagent.nix
Normal file
49
nix/packages/dataagent.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
pkgs,
|
||||
deps,
|
||||
netrcConfig,
|
||||
nix-gitignore,
|
||||
packageSources,
|
||||
dotnet-sdk,
|
||||
dotnet-runtime,
|
||||
buildDotnetModule,
|
||||
}:
|
||||
let
|
||||
src = nix-gitignore.gitignoreSource [ ] ../../.;
|
||||
projectFile = "src/DataAgent/src/DataAgent/Oceanbox.DataAgent.fsproj";
|
||||
versionMatch = builtins.match ".*<Version>([^<]+)</Version>.*" (
|
||||
builtins.readFile (../../. + "/${projectFile}")
|
||||
);
|
||||
version = builtins.head versionMatch;
|
||||
runtimeId = "linux-x64";
|
||||
in
|
||||
buildDotnetModule rec {
|
||||
inherit
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
version
|
||||
src
|
||||
projectFile
|
||||
runtimeId
|
||||
;
|
||||
name = "Oceanbox.DataAgent";
|
||||
pname = "Oceanbox.DataAgent";
|
||||
dotnetRestoreFlags = "--force-evaluate";
|
||||
# NOTE(mrtz): Can't package nuget without it
|
||||
# [ref](https://github.com/dotnet/fsharp/issues/12320)
|
||||
nugetDeps = deps {
|
||||
inherit
|
||||
name
|
||||
pkgs
|
||||
netrcConfig
|
||||
packageSources
|
||||
;
|
||||
lockfiles = [
|
||||
../../src/DataAgent/src/Entity/packages.lock.json
|
||||
../../src/DataAgent/src/DataAgent/packages.lock.json
|
||||
];
|
||||
};
|
||||
doCheck = false;
|
||||
# packNupkg = true;
|
||||
# dotnetFlags = [ "--property:TargetsForTfmSpecificContentInPackage="];
|
||||
}
|
||||
113
nix/packages/default.nix
Normal file
113
nix/packages/default.nix
Normal file
@@ -0,0 +1,113 @@
|
||||
{
|
||||
env,
|
||||
deps,
|
||||
pkgs,
|
||||
version,
|
||||
dotnet-sdk,
|
||||
dotnet-runtime,
|
||||
netrcConfig ? null,
|
||||
}:
|
||||
let
|
||||
# NOTE(mrtz): Gitlab Nuget Registry does not support groupwide fetches :/
|
||||
packageSources = import ./sources.nix;
|
||||
|
||||
nodeModules = pkgs.callPackage ./node-modules.nix {};
|
||||
|
||||
codex-client = pkgs.callPackage ../../src/Codex/src/Client {
|
||||
inherit
|
||||
deps
|
||||
dotnet-sdk
|
||||
netrcConfig
|
||||
nodeModules
|
||||
packageSources
|
||||
;
|
||||
};
|
||||
in
|
||||
{
|
||||
serverpack = pkgs.callPackage ./serverpack.nix {
|
||||
inherit
|
||||
deps
|
||||
netrcConfig
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
packageSources
|
||||
;
|
||||
};
|
||||
|
||||
# NOTE(mrtz): It's acutally Oceanbox.DataAgent
|
||||
archmaester = pkgs.callPackage ./dataagent.nix {
|
||||
inherit
|
||||
deps
|
||||
netrcConfig
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
packageSources
|
||||
;
|
||||
};
|
||||
|
||||
# NOTE(mrtz): It's acutally Poseidon.Api
|
||||
interfaces = pkgs.callPackage ./api.nix {
|
||||
inherit
|
||||
env
|
||||
deps
|
||||
netrcConfig
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
packageSources
|
||||
;
|
||||
};
|
||||
|
||||
atlantis = pkgs.callPackage ./atlantis.nix {
|
||||
inherit
|
||||
env
|
||||
deps
|
||||
netrcConfig
|
||||
version
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
packageSources
|
||||
;
|
||||
};
|
||||
|
||||
sorcerer = pkgs.callPackage ./sorcerer.nix {
|
||||
inherit
|
||||
env
|
||||
deps
|
||||
netrcConfig
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
packageSources
|
||||
;
|
||||
};
|
||||
archivist = pkgs.callPackage ./archivist.nix {
|
||||
inherit
|
||||
env
|
||||
deps
|
||||
netrcConfig
|
||||
dotnet-sdk
|
||||
packageSources
|
||||
;
|
||||
};
|
||||
atlantis-client = pkgs.callPackage ./atlantis-client.nix {
|
||||
inherit
|
||||
deps
|
||||
version
|
||||
dotnet-sdk
|
||||
netrcConfig
|
||||
nodeModules
|
||||
dotnet-runtime
|
||||
packageSources
|
||||
;
|
||||
};
|
||||
|
||||
codex = pkgs.callPackage ../../src/Codex/src/Server {
|
||||
inherit
|
||||
deps
|
||||
dotnet-sdk
|
||||
netrcConfig
|
||||
dotnet-runtime
|
||||
packageSources
|
||||
;
|
||||
client = codex-client;
|
||||
};
|
||||
}
|
||||
52
nix/packages/node-modules.nix
Normal file
52
nix/packages/node-modules.nix
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
bun,
|
||||
stdenvNoCC,
|
||||
nix-gitignore,
|
||||
writableTmpDirAsHomeHook,
|
||||
}:
|
||||
stdenvNoCC.mkDerivation {
|
||||
name = "node-modules";
|
||||
|
||||
nativeBuildInputs = [
|
||||
bun
|
||||
writableTmpDirAsHomeHook
|
||||
];
|
||||
|
||||
src = nix-gitignore.gitignoreSource [ ] ../../.;
|
||||
|
||||
dontConfigure = true;
|
||||
|
||||
# Required else we get errors that our fixed-output derivation references store paths
|
||||
dontFixup = true;
|
||||
|
||||
# Only install dependencies, don't build
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
export BUN_INSTALL_CACHE_DIR=$(mktemp -d)
|
||||
|
||||
# Disable post-install scripts to avoid shebang issues
|
||||
bun install \
|
||||
--frozen-lockfile \
|
||||
--ignore-scripts \
|
||||
--backend copyfile \
|
||||
--no-progress \
|
||||
--force
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out
|
||||
cp -r node_modules $out/
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
outputHashMode = "recursive";
|
||||
outputHashAlgo = "sha256";
|
||||
# NOTE: Empty this when a new dependency is added
|
||||
outputHash = "sha256-bbCaGoZRE7vRuAS3eRyP8yHANYXBJVaHmuL99BAovjY=";
|
||||
}
|
||||
44
nix/packages/serverpack.nix
Normal file
44
nix/packages/serverpack.nix
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
pkgs,
|
||||
deps,
|
||||
netrcConfig,
|
||||
nix-gitignore,
|
||||
packageSources,
|
||||
dotnet-sdk,
|
||||
dotnet-runtime,
|
||||
buildDotnetModule,
|
||||
}:
|
||||
let
|
||||
src = nix-gitignore.gitignoreSource [ ] ../../.;
|
||||
projectFile = "src/ServerPack/src/Oceanbox.ServerPack.fsproj";
|
||||
versionMatch = builtins.match ".*<Version>([^<]+)</Version>.*" (
|
||||
builtins.readFile (../../. + "/${projectFile}")
|
||||
);
|
||||
version = builtins.head versionMatch;
|
||||
in
|
||||
buildDotnetModule rec {
|
||||
inherit
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
version
|
||||
src
|
||||
projectFile
|
||||
;
|
||||
name = "Oceanbox.ServerPack";
|
||||
pname = "Oceanbox.ServerPack";
|
||||
nugetDeps = deps {
|
||||
inherit
|
||||
name
|
||||
pkgs
|
||||
netrcConfig
|
||||
packageSources
|
||||
;
|
||||
lockfiles = [
|
||||
../../src/ServerPack/src/packages.lock.json
|
||||
];
|
||||
};
|
||||
packNupkg = true;
|
||||
# NOTE(mrtz): Can't package nuget without it
|
||||
# [ref](https://github.com/dotnet/fsharp/issues/12320)
|
||||
dotnetFlags = "--property:TargetsForTfmSpecificContentInPackage=";
|
||||
}
|
||||
50
nix/packages/sorcerer.nix
Normal file
50
nix/packages/sorcerer.nix
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
env,
|
||||
deps,
|
||||
pkgs,
|
||||
netrcConfig,
|
||||
nix-gitignore,
|
||||
packageSources,
|
||||
dotnet-sdk,
|
||||
dotnet-runtime,
|
||||
buildDotnetModule,
|
||||
}:
|
||||
let
|
||||
src = nix-gitignore.gitignoreSource [ ] ../../.;
|
||||
projectFile = "src/Sorcerer/src/Server/Sorcerer.fsproj";
|
||||
# NOTE(mrtz): Extra the version attribute from the fsharp project (XML)
|
||||
versionMatch = builtins.match ".*<Version>([^<]+)</Version>.*" (
|
||||
builtins.readFile (../../. + "/${projectFile}")
|
||||
);
|
||||
version = builtins.head versionMatch;
|
||||
in
|
||||
buildDotnetModule rec {
|
||||
inherit
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
version
|
||||
src
|
||||
projectFile
|
||||
;
|
||||
name = "Sorcerer";
|
||||
pname = name;
|
||||
dotnetRestoreFlags = "--force-evaluate";
|
||||
nugetDeps = deps {
|
||||
inherit
|
||||
name
|
||||
pkgs
|
||||
netrcConfig
|
||||
packageSources
|
||||
;
|
||||
lockfiles = [
|
||||
../../src/Sorcerer/src/Server/packages.lock.json
|
||||
../../src/DataAgent/src/Entity/packages.lock.json
|
||||
];
|
||||
};
|
||||
runtimeDeps = [
|
||||
pkgs.netcdf
|
||||
];
|
||||
# TODO: Add back when we have tests
|
||||
doCheck = false;
|
||||
buildType = env;
|
||||
}
|
||||
19
nix/packages/sources.nix
Normal file
19
nix/packages/sources.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Drifters.Api" = "https://gitlab.com/api/v4/projects/37086336/packages/nuget/download";
|
||||
"Fable.Lit" = "https://gitlab.com/api/v4/projects/61744837/packages/nuget/download";
|
||||
"Fable.Lit.Elmish" = "https://gitlab.com/api/v4/projects/61744837/packages/nuget/download";
|
||||
"Fable.Lit.React" = "https://gitlab.com/api/v4/projects/61744837/packages/nuget/download";
|
||||
"Fable.OpenLayers" = "https://gitlab.com/api/v4/projects/36202053/packages/nuget/download";
|
||||
"Fable.SignalR" = "https://gitlab.com/api/v4/projects/40255650/packages/nuget/download";
|
||||
"Fable.SignalR.AspNetCore" = "https://gitlab.com/api/v4/projects/40255650/packages/nuget/download";
|
||||
"Fable.SignalR.Elmish" = "https://gitlab.com/api/v4/projects/40255650/packages/nuget/download";
|
||||
"Fable.SignalR.Saturn" = "https://gitlab.com/api/v4/projects/40255650/packages/nuget/download";
|
||||
"Fable.SignalR.Shared" = "https://gitlab.com/api/v4/projects/40255650/packages/nuget/download";
|
||||
"Matplotlib.ColorMaps" = "https://gitlab.com/api/v4/projects/36675671/packages/nuget/download";
|
||||
"Oceanbox.DataAgent" = "https://gitlab.com/api/v4/projects/37541600/packages/nuget/download";
|
||||
"Oceanbox.FvcomKit" = "https://gitlab.com/api/v4/projects/35569541/packages/nuget/download";
|
||||
"Oceanbox.ServerPack" = "https://gitlab.com/api/v4/projects/67427353/packages/nuget/download";
|
||||
"ProjNet.FSharp" = "https://gitlab.com/api/v4/projects/35009572/packages/nuget/download";
|
||||
"Oceanbox.SDSLite" = "https://gitlab.com/api/v4/projects/34025102/packages/nuget/download";
|
||||
}
|
||||
|
||||
36
nix/pre-commit.nix
Normal file
36
nix/pre-commit.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
let
|
||||
sources = import ./default.nix;
|
||||
pkgs = import sources.nixpkgs { };
|
||||
pre-commit = import sources.pre-commit;
|
||||
in
|
||||
pre-commit.run {
|
||||
src = ./.;
|
||||
# NOTE: Do not run at pre-commit time
|
||||
default_stages = [
|
||||
"pre-push"
|
||||
];
|
||||
package = pkgs.prek;
|
||||
hooks = {
|
||||
nixfmt-rfc-style = {
|
||||
enable = true;
|
||||
package = pkgs.nixfmt-rfc-style;
|
||||
};
|
||||
deadnix = {
|
||||
enable = true;
|
||||
package = pkgs.deadnix;
|
||||
};
|
||||
# NOTE(mrtz): Does not work with |>
|
||||
# statix = {
|
||||
# enable = true;
|
||||
# package = pkgs.statix;
|
||||
# settings.ignore = [ "../nix/default.nix" ];
|
||||
# };
|
||||
# TODO(mrtz): Format manually for now
|
||||
# fantomas = {
|
||||
# enable = true;
|
||||
# name = "fantomas";
|
||||
# entry = "${pkgs.fantomas}/bin/fantomas src";
|
||||
# files = "(\\.fs$)|(\\.fsx$)|(\\.fsi$)";
|
||||
# };
|
||||
};
|
||||
}
|
||||
34
nix/secrets/netrc.age
Normal file
34
nix/secrets/netrc.age
Normal file
@@ -0,0 +1,34 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 7bzzBw +aTkCV7hy4aJfDYbuHWFLP/1fSit2IFavOB0g2U/7EA
|
||||
w5Eu3FiX/4USe2HOXtbebv9tArwrgIvM60+N8vVFJOA
|
||||
-> ssh-ed25519 NV/uBA ynrvtm8t5Nlgpg/fJKF6svts4CcwzQxubMWzin8LHlo
|
||||
nDLJpmUsy2FX6lGWgf5p3cTQ0lMIoAOQkOIyzLhNOsA
|
||||
-> ssh-ed25519 7au5uA uq0WLcauhAx55gBHewUrVHLoZ5l1wqqNLIyc5pijgSw
|
||||
lQtu0SGM5gg+uSQkT2uVFenisKBZxYAuKkOjxodluNw
|
||||
-> ssh-rsa mafBQw
|
||||
lKWdqgtpUd8UUQYG2z+mFejTZKd3tjNnXuQX7A88oZbuwK0OS+e2Q60AEezH9/+z
|
||||
za6huPKwJWBo1YP3nnREBINmRH0rSYvSSvhW+X01Mupb2xoBf5ba4FAevDEMXlZh
|
||||
SfdduBF3X71dLEtrsZnwUmpNwcSKFzYHin1JugsWKiYfmiMJ0ZdIUHmneyimUgGx
|
||||
BpRlTaQyf4n6joDgNX4XhhmPafSJ6FpEmQTEy9XLUNjWPlhKLIgswS97Xm0NHab8
|
||||
wY6/ZsL1Um8008dcMeq+KjT6P7jGjifhwY97m4f8C/Pc5NZewNPPVo8l+X2F/uSd
|
||||
5cHKZCLcwwIbFfhWaJD51E2o1mf7ZvS+CgdVkO09lqb4tVABQOvWVHxzj+nh7sP6
|
||||
/LXCdzkVbopPI3XxNzn0PDIlx/mcCiv30rUqMR/9q3NS2p51YOF8FvniHesNusHE
|
||||
Kkr5rTkfUqN/MOJ0an9o+wNL7g6HPvNR3BRcyuSc5qJJ+4ZDZcPyfngNP/YVe0BN
|
||||
|
||||
-> ssh-ed25519 m/eJnA JzmTs9RX/dF9p49AEKvS2e9xCSHPOWn2r7CHZ61Cd1s
|
||||
X4/Hbazgs9H9kc25HFFxFVKMU3FKAr6hj30+SoA7gHU
|
||||
-> ssh-rsa HJx+NA
|
||||
L7otgs2FGW0/vMg+QoC/xK3wnD/l98cF6TVASE5NAHGwmm6CurtftoMnsQ7I6XUN
|
||||
OP3gDYWPvSnDvGkhQC39KKtGZWpCeDepicrXabySfbjJb0qEKkwekh2D9SJCCNPQ
|
||||
N3b0rL0IRuTEBkUCRyOxwIZ4jbBrfMF0TTIL6mdfg/PRIshvwb/fp3+1AFZqOxt5
|
||||
pqHTku5vVHcNzfv4CdNkeksME10W1HccK/Jwyk41Cny4xoOSnlFEsP1bJAB6h5LX
|
||||
MLmTkXMd0dwHTvLjSNbHsoOKh/a2m+LIAc70Bp4mgzv9x0gUUQcVObpJ6HZJTUvc
|
||||
JqOSzcGukUdt7zZPWDA4Ty6w422JGpq5ZTX8kCV0wTBtsT4Ne1GeMOUVFYPaoFof
|
||||
I4bQZeWnOnvqabN6mhLDx+aXSnHX07nHcvQS2c6vTH9qKIU7Ujopox2EqHClkyD6
|
||||
d2qHwem9PvWHzFKfUq3u51MTeJvQSHkK+61fIUZdjMEEQhvd/ixTavzLjmi84X0X
|
||||
XLgbJ46NEMwAWG03fys4Te9IEbXkW/gGJEC1gq4Ui9BTerfhC5F+2B51neVLm+xp
|
||||
U6K4LtjKJStrCjZL/ZJ8AJHgBgeRzMfB69OanEGJsXDP5OOz21x7ToYx2FrDxLTi
|
||||
4L0dY1WjiaI7yTeE99C08YaopjQRsGGiFfQ25ibc1kQ
|
||||
--- 84bJaUdMhO93N0qltdsWhEhKZbCma9hK7sJpUUH1N+c
|
||||
|Ðß3Å]„ÍKôsdð-<2D>Qwð•%K´D”öµj{Øá*Ç
|
||||
Š=4VÍb3·^mÙcl˜'›¼ÏøúýŒÈ¶07èƒ&AÒ·é)ZµÕÿ/ÝõoYˆ6{c¡&ø¼®ž)*¥
|
||||
28
nix/secrets/secrets.nix
Normal file
28
nix/secrets/secrets.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
# Agenix secrets configuration
|
||||
#
|
||||
# This file defines which SSH public keys can decrypt secrets.
|
||||
# To encrypt a secret:
|
||||
# agenix -e netrc.age
|
||||
#
|
||||
# To decrypt a secret (for testing):
|
||||
# agenix -d netrc.age
|
||||
|
||||
let
|
||||
user-keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII77Aa2MFZMTha8PdkNg32UR8y6Hwb4R0aR9Ad9qifNq" # Moritz
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBksFS1H6QZNQsrmWSnWuvVVaOcjvPZ0CLisWCDDDtU/" # Moritz 2
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKiAS30ZO+wgfAqDE9Y7VhRunn2QszPHA5voUwo+fGOf" # Jonas
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDULdlLC8ZLu9qBZUYsjhpr6kv5RH4yPkekXQdD7prkqapyoptUkO1nOTDwy7ZsKDxmp9Zc6OtdhgoJbowhGW3VIZPmooWO8twcaYDpkxEBLUehY/n8SlAwBtiHJ4mTLLcynJMVrjmTQLF3FeWVof0Aqy6UtZceFpLp1eNkiHTCM3anwtb9+gfr91dX1YsAOqxqv7ooRDu5rCRUvOi4OvRowepyuBcCjeWpTkJHkC9WGxuESvDV3CySWkGC2fF2LHkAu6SFsFE39UA5ZHo0b1TK+AFqRFiBAb7ULmtuno1yxhpBxbozf8+Yyc7yLfMNCyBpL1ci7WnjKkghQv7yM1xN2XMJLpF56v0slSKMoAs7ThoIlmkRm/6o3NCChgu0pkpNg/YP6A3HfYiEDgChvA6rAHX6+to50L9xF3ajqk4BUzWd/sCk7Q5Op2lzj31L53Ryg8vMP8hjDjYcgEcCCsGOcjUVgcsmfC9LupwRIEz3aF14AWg66+3zAxVho8ozjes=" # Jonas 2
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKfgY468dPNpdXZCkD9jw1p2qA0+z56Wi/c1VYE+riki" # Stig
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC2tox0uyFGfU1zPNU6yAVSoGOUkeU959aiTMrqu1U9MCCOP2o4IhZIlRpZ08XVnUU/AhycCUF4HgGqdcco8oIVX0P0Cn83KJoD/DOqAiz+1VwIUUV1ylrRdNqCgf4wnmLni3sUPHJdQnuq57+pzDDjHMr9CcBL2KzOHD/QanfR+jZmv9K3OS5oDcWquSCziXkpbkWQURPactmtyzGK2FRRxONZgYrB8gRTDstlWQg/t6GHNVelzuJ7SEf+t8pk/S2e/XAvfZyRJhrVJ35iZKpmxkIn5v0g1Z+z0yX/KRSAPRtNg9uM44cmto77MFx7iFs0CuleL3zHvRvZYW1ZnsKAiP07UkEK87luMpkTzFr9CSHJGpgk1RZYA3qidQti44n6NU9YRNhzO4v+KQE6XDqO80gZCJboSXr3fnYn/QHpPXzK5JcZNWmClyMURYj10qv9So3Fh0o3LV5GThA6JgN874vUywUZanPEdn8ePBcAsjLRzA4YBGEuvJCc6FELSuY2s+/pFba8NXQvrOdJKSRC0g5USQFfaWDln4Q4zZ1G5z76p1u6GtRWxvakkUQ0fze9KAW7msxeKaw+B7uMtyvCL8V2zEE8WKFP1sNyYEe7Sgp3RVfym2VPMNTZVhEImfM/3D+WbzfoJztnJvFKXeeMCcne4G8swyef3o1s3b+CvQ==" # Simen
|
||||
];
|
||||
|
||||
# TODO(mrtz): Add key for ekman & rossby
|
||||
system-keys = [
|
||||
];
|
||||
|
||||
all-keys = user-keys ++ system-keys;
|
||||
in
|
||||
{
|
||||
"netrc.age".publicKeys = all-keys;
|
||||
}
|
||||
49
nix/sources.json
Normal file
49
nix/sources.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"pins": {
|
||||
"agenix": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "GitHub",
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix"
|
||||
},
|
||||
"branch": "main",
|
||||
"submodules": false,
|
||||
"revision": "fcdea223397448d35d9b31f798479227e80183f6",
|
||||
"url": "https://github.com/ryantm/agenix/archive/fcdea223397448d35d9b31f798479227e80183f6.tar.gz",
|
||||
"hash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ="
|
||||
},
|
||||
"nix-utils": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "Git",
|
||||
"url": "https://git.sr.ht/~mrtz/nix-utils"
|
||||
},
|
||||
"branch": "trunk",
|
||||
"submodules": false,
|
||||
"revision": "098f594425d2b9dde0657becad0f6498d074f8b3",
|
||||
"url": null,
|
||||
"hash": "sha256-y++BijM+FRkKDhVrL7YXZQiJ0DNVMiRN7yHf6QIXBUI="
|
||||
},
|
||||
"nixpkgs": {
|
||||
"type": "Channel",
|
||||
"name": "nixpkgs-unstable",
|
||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre930822.ed142ab1b3a0/nixexprs.tar.xz",
|
||||
"hash": "sha256-XH6awru9NnBc/m+2YhRNT8r1PAKEiPGF3gs//F3ods0="
|
||||
},
|
||||
"pre-commit": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "GitHub",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix"
|
||||
},
|
||||
"branch": "master",
|
||||
"submodules": false,
|
||||
"revision": "a1ef738813b15cf8ec759bdff5761b027e3e1d23",
|
||||
"url": "https://github.com/cachix/git-hooks.nix/archive/a1ef738813b15cf8ec759bdff5761b027e3e1d23.tar.gz",
|
||||
"hash": "sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W+xc49RL/U="
|
||||
}
|
||||
},
|
||||
"version": 7
|
||||
}
|
||||
111
package.json
111
package.json
@@ -1,74 +1,79 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite src/Client",
|
||||
"build": "vite build -p",
|
||||
"test": "vite test/Client"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/exec": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@semantic-release/gitlab": "^13.2.6",
|
||||
"@vitejs/plugin-react": "^4.5.2",
|
||||
"@semantic-release/gitlab": "^13.2.8",
|
||||
"@sentry/vite-plugin": "^4.3.0",
|
||||
"@vitejs/plugin-react": "^5.0.4",
|
||||
"rollup-plugin-scss": "^4.0.1",
|
||||
"sass": "^1.89.2",
|
||||
"semantic-release": "^24.2.5",
|
||||
"sass": "^1.93.0",
|
||||
"semantic-release": "^24.2.9",
|
||||
"semantic-release-dotnet": "^1.0.0",
|
||||
"vite": "^6.3.5",
|
||||
"vite": "^7.1.9",
|
||||
"vite-plugin-mkcert": "^1.17.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluentui/react-components": "^9.72.9",
|
||||
"@fluentui/react-datepicker-compat": "^0.6.20",
|
||||
"@fluentui/react-calendar-compat": "^0.3.15",
|
||||
"@fluentui/react-timepicker-compat": "^0.4.26",
|
||||
"@fluentui-contrib/react-data-grid-react-window": "^1.4.2",
|
||||
"@fluentui/react-icons": "^2.0.316",
|
||||
"react-window": "^2.2.3",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@lit-labs/motion": "^1.0.8",
|
||||
"@lit/context": "^1.1.5",
|
||||
"@microsoft/signalr": "^8.0.7",
|
||||
"@sentry/browser": "^8.55.0",
|
||||
"@lit/context": "^1.1.6",
|
||||
"@microsoft/signalr": "^8.0.17",
|
||||
"@sentry/browser": "^9.46.0",
|
||||
"@shoelace-style/shoelace": "^2.20.1",
|
||||
"@spectrum-web-components/accordion": "^1.7.0",
|
||||
"@spectrum-web-components/action-button": "^1.6.0",
|
||||
"@spectrum-web-components/action-group": "^1.7.0",
|
||||
"@spectrum-web-components/action-menu": "^1.7.0",
|
||||
"@spectrum-web-components/button": "^1.6.0",
|
||||
"@spectrum-web-components/card": "^1.7.0",
|
||||
"@spectrum-web-components/checkbox": "^1.6.0",
|
||||
"@spectrum-web-components/color-slider": "^1.7.0",
|
||||
"@spectrum-web-components/dialog": "^1.7.0",
|
||||
"@spectrum-web-components/divider": "^1.6.0",
|
||||
"@spectrum-web-components/field-group": "^1.6.0",
|
||||
"@spectrum-web-components/field-label": "^1.6.0",
|
||||
"@spectrum-web-components/icon": "^1.6.0",
|
||||
"@spectrum-web-components/menu": "^1.6.0",
|
||||
"@spectrum-web-components/number-field": "^1.6.0",
|
||||
"@spectrum-web-components/overlay": "^1.6.0",
|
||||
"@spectrum-web-components/popover": "^1.6.0",
|
||||
"@spectrum-web-components/progress-bar": "^1.7.0",
|
||||
"@spectrum-web-components/progress-circle": "^1.6.0",
|
||||
"@spectrum-web-components/radio": "^1.7.0",
|
||||
"@spectrum-web-components/slider": "^1.7.0",
|
||||
"@spectrum-web-components/split-view": "^1.7.0",
|
||||
"@spectrum-web-components/status-light": "^1.7.0",
|
||||
"@spectrum-web-components/styles": "^1.6.0",
|
||||
"@spectrum-web-components/switch": "^1.7.0",
|
||||
"@spectrum-web-components/table": "^1.7.0",
|
||||
"@spectrum-web-components/tabs": "^1.6.0",
|
||||
"@spectrum-web-components/theme": "^1.6.0",
|
||||
"@spectrum-web-components/toast": "^1.7.0",
|
||||
"@spectrum-web-components/tooltip": "^1.6.0",
|
||||
"@spectrum-web-components/top-nav": "^1.7.0",
|
||||
"@spectrum-web-components/underlay": "^1.6.0",
|
||||
"@spectrum-web-components/accordion": "^1.8.0",
|
||||
"@spectrum-web-components/action-button": "^1.8.0",
|
||||
"@spectrum-web-components/action-group": "^1.8.0",
|
||||
"@spectrum-web-components/action-menu": "^1.8.0",
|
||||
"@spectrum-web-components/alert-banner": "^1.8.0",
|
||||
"@spectrum-web-components/button": "^1.8.0",
|
||||
"@spectrum-web-components/card": "^1.8.0",
|
||||
"@spectrum-web-components/checkbox": "^1.8.0",
|
||||
"@spectrum-web-components/color-slider": "^1.8.0",
|
||||
"@spectrum-web-components/combobox": "^1.8.0",
|
||||
"@spectrum-web-components/contextual-help": "^1.8.0",
|
||||
"@spectrum-web-components/dialog": "^1.8.0",
|
||||
"@spectrum-web-components/divider": "^1.8.0",
|
||||
"@spectrum-web-components/field-group": "^1.8.0",
|
||||
"@spectrum-web-components/field-label": "^1.8.0",
|
||||
"@spectrum-web-components/icon": "^1.8.0",
|
||||
"@spectrum-web-components/menu": "^1.8.0",
|
||||
"@spectrum-web-components/number-field": "^1.8.0",
|
||||
"@spectrum-web-components/overlay": "^1.8.0",
|
||||
"@spectrum-web-components/popover": "^1.8.0",
|
||||
"@spectrum-web-components/progress-bar": "^1.8.0",
|
||||
"@spectrum-web-components/progress-circle": "^1.8.0",
|
||||
"@spectrum-web-components/radio": "^1.8.0",
|
||||
"@spectrum-web-components/slider": "^1.8.0",
|
||||
"@spectrum-web-components/split-view": "^1.8.0",
|
||||
"@spectrum-web-components/status-light": "^1.8.0",
|
||||
"@spectrum-web-components/styles": "^1.8.0",
|
||||
"@spectrum-web-components/switch": "^1.8.0",
|
||||
"@spectrum-web-components/table": "^1.8.0",
|
||||
"@spectrum-web-components/tabs": "^1.8.0",
|
||||
"@spectrum-web-components/theme": "^1.8.0",
|
||||
"@spectrum-web-components/toast": "^1.8.0",
|
||||
"@spectrum-web-components/tooltip": "^1.8.0",
|
||||
"@spectrum-web-components/top-nav": "^1.8.0",
|
||||
"@spectrum-web-components/underlay": "^1.8.0",
|
||||
"@turf/bezier-spline": "^7.2.0",
|
||||
"@vaadin/login": "^24.8.0",
|
||||
"lit": "^3.3.0",
|
||||
"lit-html": "^3.3.0",
|
||||
"ol": "^10.6.0",
|
||||
"lit": "^3.3.1",
|
||||
"lit-html": "^3.3.1",
|
||||
"ol": "^10.6.1",
|
||||
"plotly.js": "^2.35.3",
|
||||
"proj4": "^2.17.0",
|
||||
"proj4": "^2.19.10",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-plotly.js": "^2.6.0",
|
||||
"vis-timeline": "^7.7.4"
|
||||
"vis-timeline": "^8.4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
20
scripts/README.md
Normal file
20
scripts/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Scripts
|
||||
|
||||
Development helper scripts.
|
||||
|
||||
```shell
|
||||
├── update-deps.sh
|
||||
│ └─ Updates dependencies for the Poseidon project, including both .NET and npm.
|
||||
├── configure-manifests.sh
|
||||
│ └─ Configures Kubernetes manifests by replacing placeholders and applying them to a namespace.
|
||||
├── get-barentswatch-token.sh
|
||||
│ └─ Retrieves an authentication token from the Barentswatch API using client credentials.
|
||||
├── init-namespace.sh
|
||||
│ └─ Creates a Kubernetes namespace if it doesn't already exist.
|
||||
├── run_lgtm.sh
|
||||
│ └─ Runs the LGTM (Loki, Grafana, Tempo, Mimir) observability stack in Docker.
|
||||
├── start-postgres.sh
|
||||
│ └─ Starts a PostgreSQL development server using Docker with persistent volume.
|
||||
└── trackFga.sh
|
||||
└─ Toggles Fine-Grained Authorization tracking in the Archmaester service.
|
||||
```
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
top="$(cd "$(dirname "$BASH_SOURCE[0]")" >/dev/null 2>&1 && pwd)"
|
||||
top="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
||||
|
||||
if [ $# = 1 -o $# = 2 ]; then
|
||||
if [ $# = 1 ] || [ $# = 2 ]; then
|
||||
env=$1
|
||||
ns=${2:-atlantis}
|
||||
else
|
||||
@@ -10,10 +10,10 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$top/init-namespace.sh $ns
|
||||
"$top/init-namespace.sh" "$ns"
|
||||
|
||||
if [ -d $top/../manifests ]; then
|
||||
for i in $top/../manifests/*.yaml; do
|
||||
sed "s/<x>-/$env-/g" $i | kubectl apply -n $ns -f -
|
||||
if [ -d "$top/../manifests" ]; then
|
||||
for i in "$top"/../manifests/*.yaml; do
|
||||
sed "s/<x>-/$env-/g" "$i" | kubectl apply -n "$ns" -f -
|
||||
done
|
||||
fi
|
||||
56
scripts/default.nix
Normal file
56
scripts/default.nix
Normal file
@@ -0,0 +1,56 @@
|
||||
{ pkgs }:
|
||||
let
|
||||
inherit (pkgs.lib) mapAttrs;
|
||||
|
||||
inherit (pkgs)
|
||||
writeShellApplication
|
||||
jaq
|
||||
fd
|
||||
ripgrep
|
||||
coreutils
|
||||
kubectl
|
||||
curl
|
||||
gnused
|
||||
;
|
||||
|
||||
scripts = {
|
||||
update-deps = [
|
||||
jaq
|
||||
coreutils
|
||||
fd
|
||||
ripgrep
|
||||
];
|
||||
configure-manifests = [
|
||||
coreutils
|
||||
kubectl
|
||||
gnused
|
||||
];
|
||||
get-barentswatch-token = [
|
||||
curl
|
||||
];
|
||||
init-namespace = [
|
||||
kubectl
|
||||
coreutils
|
||||
];
|
||||
run_lgtm = [
|
||||
ripgrep
|
||||
coreutils
|
||||
];
|
||||
start-postgres = [
|
||||
coreutils
|
||||
];
|
||||
trackFga = [
|
||||
curl
|
||||
];
|
||||
};
|
||||
|
||||
self = mapAttrs (
|
||||
name: runtimeInputs:
|
||||
writeShellApplication {
|
||||
inherit name runtimeInputs;
|
||||
|
||||
text = builtins.readFile ./${name}.sh;
|
||||
}
|
||||
) scripts;
|
||||
in
|
||||
self
|
||||
@@ -3,7 +3,7 @@
|
||||
ns=${1:-oceanbox}
|
||||
|
||||
init_namespace() {
|
||||
kubectl create ns $ns
|
||||
kubectl create ns "$ns"
|
||||
}
|
||||
|
||||
kubectl get ns $ns > /dev/null 2>&1 || init_namespace
|
||||
kubectl get ns "$ns" > /dev/null 2>&1 || init_namespace
|
||||
@@ -1,8 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
docker ps 2>&1 | grep -q zipkin
|
||||
|
||||
if [ $? = 0 ]; then
|
||||
if docker ps 2>&1 | grep -q zipkin; then
|
||||
echo "Please stop the running Zipkin Docker instance and try again"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
echo "Starting postgresql server with docker"
|
||||
|
||||
docker volume inspect archmaester_dev > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
if ! docker volume inspect archmaester_dev > /dev/null 2>&1; then
|
||||
echo -n "Creating separate dev volume"
|
||||
docker volume create archmaester_dev
|
||||
fi
|
||||
|
||||
@@ -8,4 +8,4 @@ esac
|
||||
curl \
|
||||
-H "Authorization: bearer $ARCHMAESTER_AUTH" \
|
||||
-d "$toggle" \
|
||||
https://$USER-atlantis.dev.oceanbox.io/internal/trackFga
|
||||
"https://${USER}-atlantis.dev.oceanbox.io/internal/trackFga"
|
||||
258
scripts/update-deps.sh
Executable file
258
scripts/update-deps.sh
Executable file
@@ -0,0 +1,258 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
shopt -s lastpipe
|
||||
|
||||
# Determine project root - handle both direct execution and nix result execution
|
||||
if [[ "${BASH_SOURCE[0]}" == */result/bin/* ]]; then
|
||||
# Running from nix result, find project root by looking for default.nix
|
||||
PROJECT_ROOT="$(pwd)"
|
||||
while [[ "$PROJECT_ROOT" != "/" && ! -f "$PROJECT_ROOT/default.nix" ]]; do
|
||||
PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
|
||||
done
|
||||
if [[ ! -f "$PROJECT_ROOT/default.nix" ]]; then
|
||||
echo "Error: Could not find project root with default.nix" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Running directly from scripts directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
fi
|
||||
PACKAGES_DIR="$PROJECT_ROOT/nix/packages"
|
||||
|
||||
info() {
|
||||
echo -e "\033[36m[INFO]\033[0m $*"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "\033[32m[SUCCESS]\033[0m $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "\033[31m[ERROR]\033[0m $*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "\033[33m[WARN]\033[0m $*"
|
||||
}
|
||||
|
||||
declare -A PRIVATE_DEPS=(
|
||||
["Drifters.Api"]="https://gitlab.com/api/v4/projects/37086336/packages/nuget/download/drifters.api"
|
||||
["Fable.SignalR.AspNetCore"]="https://gitlab.com/api/v4/projects/40255650/packages/nuget/download/fable.signalr.aspnetcore"
|
||||
["Fable.SignalR.Saturn"]="https://gitlab.com/api/v4/projects/40255650/packages/nuget/download/fable.signalr.saturn"
|
||||
["Fable.SignalR.Shared"]="https://gitlab.com/api/v4/projects/40255650/packages/nuget/download/fable.signalr.shared"
|
||||
["Fable.SignalR"]="https://gitlab.com/api/v4/projects/40255650/packages/nuget/download/fable.signalr"
|
||||
["Fable.SignalR.Elmish"]="https://gitlab.com/api/v4/projects/40255650/packages/nuget/download/fable.signalr.elmish"
|
||||
["Fable.Lit"]="https://gitlab.com/api/v4/projects/61744837/packages/nuget/download/fable.lit"
|
||||
["Fable.Lit.Elmish"]="https://gitlab.com/api/v4/projects/61744837/packages/nuget/download/fable.lit.elmish"
|
||||
["Fable.Lit.React"]="https://gitlab.com/api/v4/projects/61744837/packages/nuget/download/fable.lit.react"
|
||||
["Fable.OpenLayers"]="https://gitlab.com/api/v4/projects/36202053/packages/nuget/download/fable.openlayers"
|
||||
["Oceanbox.FvcomKit"]="https://gitlab.com/api/v4/projects/35569541/packages/nuget/download/oceanbox.fvcomkit"
|
||||
["ProjNet.FSharp"]="https://gitlab.com/api/v4/projects/35009572/packages/nuget/download/projnet.fsharp"
|
||||
["SDSLite.Oceanbox"]="https://gitlab.com/api/v4/projects/34025102/packages/nuget/download/sdslite.oceanbox"
|
||||
["Matplotlib.ColorMaps"]="https://gitlab.com/api/v4/projects/36675671/packages/nuget/download/matplotlib.colormaps"
|
||||
)
|
||||
|
||||
# Function to add private URLs to a .NET deps JSON file
|
||||
add_private_urls() {
|
||||
local json_file="$1"
|
||||
local temp_file="${json_file}.tmp"
|
||||
|
||||
info "Processing private URLs for $json_file"
|
||||
|
||||
# NOTE: Thanks in large to Claude :) for this monstrosity
|
||||
# shellcheck disable=SC2016
|
||||
local jaq_filter='map(if $private_deps[.pname] then . + {"url": ($url_map[.pname] + "/" + (.version | ascii_downcase) + "/" + (.pname | ascii_downcase) + "." + (.version | ascii_downcase) + ".nupkg")} else . end)'
|
||||
|
||||
jaq --argjson private_deps "$(printf '%s\n' "${!PRIVATE_DEPS[@]}" | jaq -R . | jaq -s 'map({key: ., value: 1}) | from_entries')" \
|
||||
--argjson url_map "$(for pkg in "${!PRIVATE_DEPS[@]}"; do
|
||||
echo "{\"$pkg\": \"${PRIVATE_DEPS[$pkg]}\"}"
|
||||
done | jaq -s 'add')" \
|
||||
"$jaq_filter" "$json_file" > "$temp_file"
|
||||
|
||||
if [[ -s "$temp_file" ]]; then
|
||||
mv "$temp_file" "$json_file"
|
||||
success "Updated private URLs in $json_file"
|
||||
else
|
||||
error "Failed to update $json_file"
|
||||
rm -f "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to update .NET dependencies
|
||||
update_dotnet_deps() {
|
||||
local package_name="$1"
|
||||
local json_file="$2"
|
||||
|
||||
info "Updating .NET dependencies for $package_name"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Run nix-build to generate new dependencies
|
||||
if nix-build -A "packages.$package_name.fetch-deps" --no-out-link > /dev/null 2>&1; then
|
||||
local result_path
|
||||
result_path=$(nix-build -A "packages.$package_name.fetch-deps" --no-out-link)
|
||||
|
||||
# Run the result to update the JSON file
|
||||
if "$result_path" "$json_file"; then
|
||||
success "Generated new dependencies for $package_name"
|
||||
|
||||
# Add private URLs if this JSON file has any
|
||||
if [[ -f "$json_file" ]]; then
|
||||
add_private_urls "$json_file"
|
||||
fi
|
||||
else
|
||||
error "Failed to generate dependencies for $package_name"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
error "Failed to build fetch-deps for $package_name"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to backup files
|
||||
backup_files() {
|
||||
local timestamp
|
||||
timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local backup_dir="$PROJECT_ROOT/.deps_backup_$timestamp"
|
||||
|
||||
info "Creating backup in $backup_dir"
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
cp "$PACKAGES_DIR/atlantis-deps.json" "$backup_dir/" 2>/dev/null || true
|
||||
cp "$PACKAGES_DIR/atlantis-client.json" "$backup_dir/" 2>/dev/null || true
|
||||
|
||||
success "Backup created in $backup_dir"
|
||||
}
|
||||
|
||||
# Function to show usage
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $0 [OPTIONS]
|
||||
|
||||
Update Poseidon project dependencies including .NET packages
|
||||
|
||||
OPTIONS:
|
||||
-h, --help Show this help message
|
||||
-b, --backup Create backup before updating (default: true)
|
||||
--no-backup Skip creating backup
|
||||
--atlantis-only Update only atlantis dependencies
|
||||
--client-only Update only atlantis-client dependencies
|
||||
--dry-run Show what would be updated without making changes
|
||||
|
||||
EXAMPLES:
|
||||
$0 Update all dependencies
|
||||
$0 --atlantis-only Update only atlantis server dependencies
|
||||
$0 --dry-run Preview changes without applying them
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
local create_backup=true
|
||||
local update_atlantis=true
|
||||
local update_client=true
|
||||
local dry_run=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-b|--backup)
|
||||
create_backup=true
|
||||
shift
|
||||
;;
|
||||
--no-backup)
|
||||
create_backup=false
|
||||
shift
|
||||
;;
|
||||
--atlantis-only)
|
||||
update_client=false
|
||||
shift
|
||||
;;
|
||||
--client-only)
|
||||
update_atlantis=false
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
dry_run=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
info "Starting dependency update process"
|
||||
|
||||
if [[ "$dry_run" == "true" ]]; then
|
||||
warn "DRY RUN MODE - No files will be modified"
|
||||
if [[ "$update_atlantis" == "true" ]]; then
|
||||
info "Would update: atlantis-deps.json"
|
||||
fi
|
||||
if [[ "$update_client" == "true" ]]; then
|
||||
info "Would update: atlantis-client.json"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Verify we're in the right directory
|
||||
if [[ ! -f "$PROJECT_ROOT/default.nix" ]] || [[ ! -d "$PACKAGES_DIR" ]]; then
|
||||
error "This script must be run from the Poseidon project root or scripts directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check dependencies
|
||||
if ! command -v jaq &> /dev/null; then
|
||||
error "jaq not found in PATH. Please install jaq."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v nix-build &> /dev/null; then
|
||||
error "nix-build not found in PATH. Please install Nix."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create backup if requested
|
||||
if [[ "$create_backup" == "true" ]]; then
|
||||
backup_files
|
||||
fi
|
||||
|
||||
# Update dependencies
|
||||
local exit_code=0
|
||||
|
||||
if [[ "$update_atlantis" == "true" ]]; then
|
||||
if ! update_dotnet_deps "atlantis" "$PACKAGES_DIR/atlantis-deps.json"; then
|
||||
exit_code=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$update_client" == "true" ]]; then
|
||||
if ! update_dotnet_deps "atlantis-client" "$PACKAGES_DIR/atlantis-client.json"; then
|
||||
exit_code=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
success "All dependency updates completed successfully!"
|
||||
info "You may want to commit these changes:"
|
||||
info " git add nix/packages/"
|
||||
info " git commit -m 'chore: update dependencies'"
|
||||
else
|
||||
error "Some dependency updates failed. Check the output above."
|
||||
fi
|
||||
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
main "$@"
|
||||
101
scripts/update-rider.sh
Executable file
101
scripts/update-rider.sh
Executable file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#! nix-shell -i bash --pure
|
||||
#! nix-shell -p bash which xmlstarlet
|
||||
|
||||
if [[ ! $# -eq 1 ]]; then
|
||||
echo "Usage: $0 <dotnet-path>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dotnet_path=$1
|
||||
|
||||
function stderr() {
|
||||
echo "$@" 1>&2;
|
||||
}
|
||||
|
||||
function create_settings_file() {
|
||||
cat << EOF
|
||||
<?xml version="1.0"?>
|
||||
<wpf:ResourceDictionary
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:ss="urn:schemas-jetbrains-com:settings-storage-xaml"
|
||||
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/DotNetCliExePath/@EntryValue">${1}</s:String>
|
||||
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue">${2}</s:String>
|
||||
</wpf:ResourceDictionary>
|
||||
EOF
|
||||
}
|
||||
|
||||
# HACK: Configure Rider to use the correct .NET paths from an ambient .NET
|
||||
function use_rider_dotnet() {
|
||||
local solution_file=$(find . -maxdepth 1 -type f -name '*.slnx' | cut -d'.' -f2 | cut -d'/' -f2)
|
||||
local settings_file=$(find . -maxdepth 1 -type f -name '*.sln.DotSettings.user')
|
||||
# Get paths
|
||||
local cli_path=$(realpath "$dotnet_path")
|
||||
local dir=$(dirname $cli_path)
|
||||
local msbuild_path=$(find "$dir" -maxdepth 3 -type f -name MSBuild.dll)
|
||||
|
||||
# stderr "dotnet path is $dir"
|
||||
# stderr "Found msbuild: $msbuild_path"
|
||||
|
||||
if [ -f "$settings_file" ] ; then
|
||||
# stderr "Updating rider settings file: $settings_file"
|
||||
# stderr "Setting DotNetCliExePath to $cli_path"
|
||||
|
||||
# NOTE: check if dotnet binary in share folder settings exists
|
||||
xml sel -t -v "wpf:ResourceDictionary/s:String[@x:Key='/Default/Environment/Hierarchy/Build/BuildTool/DotNetCliExePath/@EntryValue']" "$settings_file"
|
||||
if [[ $? -eq 0 ]]; then
|
||||
xml ed --inplace \
|
||||
-N wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" \
|
||||
-N x="http://schemas.microsoft.com/winfx/2006/xaml" \
|
||||
-N s="clr-namespace:System;assembly=mscorlib" \
|
||||
-N ss="urn:schemas-jetbrains-com:settings-storage-xaml" \
|
||||
--update "//s:String[@x:Key='/Default/Environment/Hierarchy/Build/BuildTool/DotNetCliExePath/@EntryValue']" \
|
||||
--value "$cli_path" \
|
||||
"$settings_file"
|
||||
else
|
||||
xml ed --inplace \
|
||||
-N wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" \
|
||||
-N x="http://schemas.microsoft.com/winfx/2006/xaml" \
|
||||
-N s="clr-namespace:System;assembly=mscorlib" \
|
||||
-N ss="urn:schemas-jetbrains-com:settings-storage-xaml" \
|
||||
-s /wpf:ResourceDictionary -t elem -n s:String -v "$cli_path" \
|
||||
--var new_node '$prev' \
|
||||
-i '$new_node' -t attr -n "x:Key" -v "/Default/Environment/Hierarchy/Build/BuildTool/DotNetCliExePath/@EntryValue" \
|
||||
"$settings_file"
|
||||
fi
|
||||
|
||||
xml sel -t -v "wpf:ResourceDictionary/s:String[@x:Key='/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue']" "$settings_file"
|
||||
if [[ $? -eq 0 ]]; then
|
||||
xmlstarlet ed --inplace \
|
||||
-N wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" \
|
||||
-N x="http://schemas.microsoft.com/winfx/2006/xaml" \
|
||||
-N s="clr-namespace:System;assembly=mscorlib" \
|
||||
-N ss="urn:schemas-jetbrains-com:settings-storage-xaml" \
|
||||
--update "//s:String[@x:Key='/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue']" \
|
||||
--value "$msbuild_path" \
|
||||
"$settings_file"
|
||||
else
|
||||
xml ed --inplace \
|
||||
-N wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" \
|
||||
-N x="http://schemas.microsoft.com/winfx/2006/xaml" \
|
||||
-N s="clr-namespace:System;assembly=mscorlib" \
|
||||
-N ss="urn:schemas-jetbrains-com:settings-storage-xaml" \
|
||||
-s /wpf:ResourceDictionary -t elem -n s:String -v "$cli_path" \
|
||||
--var new_node '$prev' \
|
||||
-i '$new_node' -t attr -n "x:Key" -v "/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue" \
|
||||
"$settings_file"
|
||||
fi
|
||||
else
|
||||
create_settings_file $cli_path $msbuild_path > "$solution_file.sln.DotSettings.user"
|
||||
fi
|
||||
}
|
||||
|
||||
function main() {
|
||||
use_rider_dotnet
|
||||
}
|
||||
|
||||
main
|
||||
81
shell.nix
81
shell.nix
@@ -1,10 +1,81 @@
|
||||
with import <nixpkgs> { };
|
||||
mkShell {
|
||||
{
|
||||
sources ? import ./nix,
|
||||
pkgs ? import sources.nixpkgs { },
|
||||
pre-commit ? import ./nix/pre-commit.nix,
|
||||
}:
|
||||
let
|
||||
dotnet-sdk = pkgs.dotnetCorePackages.sdk_10_0;
|
||||
agenix = pkgs.callPackage "${sources.agenix}/pkgs/agenix.nix" { };
|
||||
fable = pkgs.buildDotnetGlobalTool {
|
||||
pname = "fable";
|
||||
version = "4.24.0";
|
||||
nugetHash = "sha256-ERewWqfEyyZKpHFFALpMGJT0fDWywBYY5buU/wTZZTg=";
|
||||
};
|
||||
in
|
||||
pkgs.mkShellNoCC {
|
||||
buildInputs = [ dotnet-sdk ];
|
||||
|
||||
packages = [
|
||||
bun
|
||||
# F#
|
||||
fable
|
||||
pkgs.dotnet-outdated
|
||||
pkgs.fantomas
|
||||
pkgs.fsautocomplete
|
||||
|
||||
# JavaScript
|
||||
pkgs.bun
|
||||
pkgs.nodejs_25
|
||||
|
||||
# Devlopment tools
|
||||
pkgs.npins
|
||||
pkgs.mkcert
|
||||
pkgs.dive
|
||||
pkgs.nix-output-monitor
|
||||
pkgs.just
|
||||
pkgs.skopeo
|
||||
|
||||
# Secret management with agenix
|
||||
agenix
|
||||
|
||||
# Kubernetes tools
|
||||
pkgs.tilt
|
||||
pkgs.dapr-cli
|
||||
pkgs.kustomize
|
||||
pkgs.kubernetes-helm
|
||||
];
|
||||
|
||||
# Environment variables
|
||||
DOTNET_ROOT = "${dotnet-sdk}/share/dotnet";
|
||||
LOG_LEVEL = "verbose";
|
||||
|
||||
shellHook = '' '';
|
||||
}
|
||||
shellHook = ''
|
||||
scripts/update-rider.sh ${dotnet-sdk}/bin/dotnet
|
||||
'';
|
||||
|
||||
# Alternative shells
|
||||
passthru = pkgs.lib.mapAttrs (name: value: pkgs.mkShellNoCC (value // { inherit name; })) {
|
||||
pre-commit.shellHook = pre-commit.shellHook;
|
||||
ci-shell = {
|
||||
packages = [
|
||||
pkgs.npins
|
||||
];
|
||||
shellHook = ''
|
||||
export NPINS_DIRECTORY="nix"
|
||||
'';
|
||||
};
|
||||
agenix-gen = {
|
||||
packages = [ agenix ];
|
||||
shellHook = ''
|
||||
if [ -z "$NETRC" ] && [ -e ~/.ssh/id_ed25519 ]; then
|
||||
pushd ./nix/secrets
|
||||
export NETRC=$(agenix -d netrc.age -i ~/.ssh/id_ed25519)
|
||||
popd
|
||||
elif [ -z "$NETRC" ] && [ -e ~/.ssh/rsa ]; then
|
||||
pushd ./nix/secrets
|
||||
export NETRC=$(agenix -d netrc.age -i ~/.ssh/id_rsa)
|
||||
popd
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
open Fake.Core
|
||||
open Fake.IO
|
||||
open Farmer
|
||||
open Farmer.Builders
|
||||
|
||||
open Helpers
|
||||
|
||||
initializeContext()
|
||||
|
||||
let clientPath = Path.getFullName "src/Client"
|
||||
let cliPath = Path.getFullName "src/Cli"
|
||||
let testPath = Path.getFullName "tests"
|
||||
|
||||
let distPath = Path.getFullName "dist"
|
||||
|
||||
let vite = $"bunx --bun vite -c ../../vite.config.js"
|
||||
let viteBundle = $"{vite} build --outDir {distPath}/public"
|
||||
|
||||
Target.create "Clean" (fun _ -> Shell.cleanDir distPath)
|
||||
|
||||
// Target.create "Bundle" (fun _ ->
|
||||
// let vite = $"{viteBundle} -m production"
|
||||
// run dotnet $"publish -c Release -o \"{distPath}\"" serverPath
|
||||
// run dotnet $"fable -o build/client --run {vite}" clientPath
|
||||
// )
|
||||
|
||||
// Target.create "BundleDebug" (fun _ ->
|
||||
// let vite = $"{viteBundle} -m development --minify false"
|
||||
// run dotnet $"publish -c Debug -o \"{distPath}\"" serverPath
|
||||
// run dotnet $"fable -o build/client --run {vite}" clientPath
|
||||
// )
|
||||
|
||||
Target.create "Bundle" (fun _ ->
|
||||
run dotnet $"publish -c Release -o \"{distPath}\"" cliPath
|
||||
)
|
||||
|
||||
Target.create "BundleDebug" (fun _ ->
|
||||
run dotnet $"publish -c Debug -o \"{distPath}\"" cliPath
|
||||
)
|
||||
|
||||
Target.create "Format" (fun _ ->
|
||||
run dotnet "fantomas . -r" "src"
|
||||
)
|
||||
|
||||
Target.create "Test" (fun _ ->
|
||||
if System.IO.Directory.Exists testPath then
|
||||
run dotnet "run" testPath
|
||||
else ()
|
||||
)
|
||||
|
||||
Target.create "Run" (fun _ -> Target.runOrDefault "Bundle")
|
||||
|
||||
open Fake.Core.TargetOperators
|
||||
|
||||
let dependencies = [
|
||||
"Clean"
|
||||
==> "Bundle"
|
||||
|
||||
"Clean"
|
||||
==> "BundleDebug"
|
||||
|
||||
"Clean"
|
||||
==> "Test"
|
||||
]
|
||||
|
||||
[<EntryPoint>]
|
||||
let main args = runOrDefault args
|
||||
@@ -1,127 +0,0 @@
|
||||
module Helpers
|
||||
|
||||
open Fake.Core
|
||||
|
||||
let initializeContext () =
|
||||
let execContext = Context.FakeExecutionContext.Create false "build.fsx" [ ]
|
||||
Context.setExecutionContext (Context.RuntimeContext.Fake execContext)
|
||||
|
||||
module Proc =
|
||||
module Parallel =
|
||||
open System
|
||||
|
||||
let locker = obj()
|
||||
|
||||
let colors =
|
||||
[| ConsoleColor.Blue
|
||||
ConsoleColor.Yellow
|
||||
ConsoleColor.Magenta
|
||||
ConsoleColor.Cyan
|
||||
ConsoleColor.DarkBlue
|
||||
ConsoleColor.DarkYellow
|
||||
ConsoleColor.DarkMagenta
|
||||
ConsoleColor.DarkCyan |]
|
||||
|
||||
let print color (colored: string) (line: string) =
|
||||
lock locker
|
||||
(fun () ->
|
||||
let currentColor = Console.ForegroundColor
|
||||
Console.ForegroundColor <- color
|
||||
Console.Write colored
|
||||
Console.ForegroundColor <- currentColor
|
||||
Console.WriteLine line)
|
||||
|
||||
let onStdout index name (line: string) =
|
||||
let color = colors.[index % colors.Length]
|
||||
if isNull line then
|
||||
print color $"{name}: --- END ---" ""
|
||||
else if String.isNotNullOrEmpty line then
|
||||
print color $"{name}: " line
|
||||
|
||||
let onStderr name (line: string) =
|
||||
let color = ConsoleColor.Red
|
||||
if isNull line |> not then
|
||||
print color $"{name}: " line
|
||||
|
||||
let redirect (index, (name, createProcess)) =
|
||||
createProcess
|
||||
|> CreateProcess.redirectOutputIfNotRedirected
|
||||
|> CreateProcess.withOutputEvents (onStdout index name) (onStderr name)
|
||||
|
||||
let printStarting indexed =
|
||||
for (index, (name, c: CreateProcess<_>)) in indexed do
|
||||
let color = colors.[index % colors.Length]
|
||||
let wd =
|
||||
c.WorkingDirectory
|
||||
|> Option.defaultValue ""
|
||||
let exe = c.Command.Executable
|
||||
let args = c.Command.Arguments.ToStartInfo
|
||||
print color $"{name}: {wd}> {exe} {args}" ""
|
||||
|
||||
let run cs =
|
||||
cs
|
||||
|> Seq.toArray
|
||||
|> Array.indexed
|
||||
|> fun x -> printStarting x; x
|
||||
|> Array.map redirect
|
||||
|> Array.Parallel.map Proc.run
|
||||
|
||||
let createProcess exe arg dir =
|
||||
CreateProcess.fromRawCommandLine exe arg
|
||||
|> CreateProcess.withWorkingDirectory dir
|
||||
|> CreateProcess.ensureExitCode
|
||||
|
||||
let dotnet = createProcess "dotnet"
|
||||
|
||||
let fable = createProcess "fable"
|
||||
|
||||
let bun =
|
||||
let bunPath =
|
||||
match ProcessUtils.tryFindFileOnPath "bun" with
|
||||
| Some path -> path
|
||||
| None ->
|
||||
"bun was not found in path. Please install it and make sure it's available from your path. " +
|
||||
"See https://safe-stack.github.io/docs/quickstart/#install-pre-requisites for more info"
|
||||
|> failwith
|
||||
|
||||
createProcess bunPath
|
||||
|
||||
let bunx = createProcess "bunx"
|
||||
|
||||
type BundleMode =
|
||||
| Prod
|
||||
| Devel
|
||||
| Watch
|
||||
with
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| Prod -> "production"
|
||||
| Devel -> "development"
|
||||
| Watch -> "watch"
|
||||
|
||||
let viteCmd (m: BundleMode) outDir =
|
||||
match m with
|
||||
| Prod -> $"vite build -c ../../vite.config.js -m {m} --emptyOutDir --outDir {outDir}/public"
|
||||
| Devel -> $"vite build -c ../../vite.config.js -m {m} --minify false --sourcemap true --emptyOutDir --outDir {outDir}/public"
|
||||
| Watch -> "vite -c ../../vite.config.js"
|
||||
|
||||
let run proc arg dir =
|
||||
proc arg dir
|
||||
|> Proc.run
|
||||
|> ignore
|
||||
|
||||
let runParallel processes =
|
||||
processes
|
||||
|> Proc.Parallel.run
|
||||
|> ignore
|
||||
|
||||
let runOrDefault args =
|
||||
try
|
||||
match args with
|
||||
| [| target |] -> Target.runOrDefault target
|
||||
| _ ->
|
||||
Target.runOrDefault "Run"
|
||||
0
|
||||
with e ->
|
||||
printfn "%A" e
|
||||
1
|
||||
@@ -1 +1,6 @@
|
||||
use nix
|
||||
#!/usr/bin/env bash
|
||||
# the shebang is ignored, but nice for editors
|
||||
use nix
|
||||
|
||||
# HACK: Workaround for direnv bug
|
||||
unset TMP TMPDIR TEMP TEMPDIR
|
||||
15
src/Archivist/.gitlab-ci.yml
Normal file
15
src/Archivist/.gitlab-ci.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
# yaml-language-server: $schema=https://gitlab.com/gitlab-org/gitlab/-/raw/master/app/assets/javascripts/editor/schema/ci.json
|
||||
variables:
|
||||
SKIP_TESTS: "true"
|
||||
|
||||
include:
|
||||
- project: oceanbox/gitlab-ci
|
||||
ref: v4.5
|
||||
file: DotnetDeployment.gitlab-ci.yml
|
||||
inputs:
|
||||
project-name: archivist
|
||||
project-dir: src/Cli
|
||||
|
||||
dockerize-archivist:
|
||||
tags:
|
||||
- nix
|
||||
@@ -1,17 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include=".build/Helpers.fs" />
|
||||
<Compile Include=".build/Build.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fake.Core.Target" Version="6.1.3" />
|
||||
<PackageReference Include="Fake.DotNet.Cli" Version="6.1.3" />
|
||||
<PackageReference Include="Fake.IO.FileSystem" Version="6.1.3" />
|
||||
<PackageReference Include="Farmer" Version="1.9.10" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
40
src/Archivist/justfile
Normal file
40
src/Archivist/justfile
Normal file
@@ -0,0 +1,40 @@
|
||||
# Archivist build commands
|
||||
# Install just: https://github.com/casey/just
|
||||
|
||||
set dotenv-load
|
||||
|
||||
src_path := "src"
|
||||
client_path := "src/Client"
|
||||
cli_path := "src/Cli"
|
||||
test_path := "tests"
|
||||
dist_path := "dist"
|
||||
|
||||
# Default recipe - show available commands
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
rm -rf {{dist_path}}
|
||||
|
||||
# Build production bundle
|
||||
bundle: clean
|
||||
dotnet publish -c Release -o {{dist_path}} {{cli_path}}
|
||||
|
||||
# Build debug bundle
|
||||
bundle-debug: clean
|
||||
dotnet publish -c Debug -o {{dist_path}} {{cli_path}}
|
||||
|
||||
# Format code with Fantomas
|
||||
format:
|
||||
fantomas {{src_path}} -r
|
||||
|
||||
# Run tests
|
||||
test: clean
|
||||
#!/usr/bin/env bash
|
||||
if [ -d "{{test_path}}" ]; then
|
||||
dotnet run {{test_path}}
|
||||
fi
|
||||
|
||||
# Run (builds bundle)
|
||||
run: bundle
|
||||
@@ -1,22 +1,20 @@
|
||||
with import <nixpkgs> { };
|
||||
{
|
||||
sources ? import ./../../nix,
|
||||
pkgs ? import sources.nixpkgs { },
|
||||
}:
|
||||
let
|
||||
port = 9000;
|
||||
baseShell = import ./../../shell.nix { inherit pkgs; };
|
||||
in
|
||||
mkShell {
|
||||
packages = [
|
||||
tilt
|
||||
dapr-cli
|
||||
kustomize
|
||||
bun
|
||||
mkcert
|
||||
];
|
||||
pkgs.mkShellNoCC {
|
||||
inputsFrom = [ baseShell ];
|
||||
|
||||
buildInputs = [
|
||||
netcdf
|
||||
pkgs.netcdf
|
||||
];
|
||||
|
||||
LOG_LEVEL = "verbose";
|
||||
LD_LIBRARY_PATH = lib.makeLibraryPath [ netcdf ];
|
||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.netcdf ];
|
||||
|
||||
DB_HOST = "localhost";
|
||||
DB_PORT = 5432;
|
||||
@@ -31,7 +29,10 @@ mkShell {
|
||||
SERVER_PORT = port + 85;
|
||||
TILT_PORT = port + 50;
|
||||
|
||||
DOTNET_ROOT = "${pkgs.dotnetCorePackages.sdk_10_0}/share/dotnet";
|
||||
|
||||
shellHook = ''
|
||||
export PATH="$PWD/src/Cli/bin/Release/net9.0/linux-x64/:$PATH"
|
||||
export ARCHMAESTER_URL="https://$USER-atlantis.dev.oceanbox.io"
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
module AclCli
|
||||
|
||||
open Argu
|
||||
open Args
|
||||
open FSharpPlus
|
||||
open Serilog
|
||||
|
||||
open ArchiveIndex
|
||||
open Oceanbox.DataAgent
|
||||
|
||||
@@ -16,14 +16,14 @@ let inline private execAsync job =
|
||||
|
||||
type private Handler = string[] -> Async<Result<unit, string>>
|
||||
|
||||
let addOwners (args: ParseResults<Prinicipal>) =
|
||||
let owners = args.GetResult Prinicipal.Ids |> Array.ofList
|
||||
let addOwners (args: PrincipalArgs) =
|
||||
let owners = args.Ids |> Array.ofList
|
||||
|
||||
if args.Contains Prinicipal.Archive then
|
||||
let aid = args.GetResult Prinicipal.Archive
|
||||
if args.Archive.IsSome then
|
||||
let aid = args.Archive |> Option.get
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.aclApi ()
|
||||
|
||||
async {
|
||||
@@ -31,7 +31,7 @@ let addOwners (args: ParseResults<Prinicipal>) =
|
||||
match! aclApi.addOwners (aid, owners) with
|
||||
| Ok _ ->
|
||||
Log.Information $"Added owners %A{owners} to archive {aid}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -39,20 +39,20 @@ let addOwners (args: ParseResults<Prinicipal>) =
|
||||
return Error exn.Message
|
||||
})
|
||||
else
|
||||
async { return Ok() }
|
||||
async { return Ok () }
|
||||
|> Async.RunSynchronously
|
||||
|> function
|
||||
| Ok _ -> ()
|
||||
| Error e -> Log.Error e
|
||||
|
||||
let addUsers (args: ParseResults<Prinicipal>) =
|
||||
let users = args.GetResult Prinicipal.Ids |> Array.ofList
|
||||
let addUsers (args: PrincipalArgs) =
|
||||
let users = args.Ids |> Array.ofList
|
||||
|
||||
if args.Contains Prinicipal.Archive then
|
||||
let aid = args.GetResult Prinicipal.Archive
|
||||
if args.Archive.IsSome then
|
||||
let aid = args.Archive |> Option.get
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.aclApi ()
|
||||
|
||||
async {
|
||||
@@ -60,7 +60,7 @@ let addUsers (args: ParseResults<Prinicipal>) =
|
||||
match! aclApi.addUsers (aid, users) with
|
||||
| Ok _ ->
|
||||
Log.Information $"Added users %A{users} to archive {aid}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -69,15 +69,19 @@ let addUsers (args: ParseResults<Prinicipal>) =
|
||||
})
|
||||
else
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.adminApi ()
|
||||
|
||||
async {
|
||||
try
|
||||
match! aclApi.addUsers (users) with
|
||||
let req : Archmaester.AddUsersRequest = {
|
||||
group = ""
|
||||
users = users
|
||||
}
|
||||
match! aclApi.addUsers req with
|
||||
| Ok _ ->
|
||||
Log.Information $"Added users %A{users}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -89,14 +93,14 @@ let addUsers (args: ParseResults<Prinicipal>) =
|
||||
| Ok _ -> ()
|
||||
| Error e -> Log.Error e
|
||||
|
||||
let addGroups (args: ParseResults<Prinicipal>) =
|
||||
let groups = args.GetResult Prinicipal.Ids |> Array.ofList
|
||||
let addGroups (args: PrincipalArgs) =
|
||||
let groups = args.Ids |> Array.ofList
|
||||
|
||||
if args.Contains Prinicipal.Archive then
|
||||
let aid = args.GetResult Prinicipal.Archive
|
||||
if args.Archive.IsSome then
|
||||
let aid = args.Archive |> Option.get
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.aclApi ()
|
||||
|
||||
async {
|
||||
@@ -104,7 +108,7 @@ let addGroups (args: ParseResults<Prinicipal>) =
|
||||
match! aclApi.addGroups (aid, groups) with
|
||||
| Ok _ ->
|
||||
Log.Information $"Added groups %A{groups} to archive {aid}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -113,15 +117,15 @@ let addGroups (args: ParseResults<Prinicipal>) =
|
||||
})
|
||||
else
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.adminApi ()
|
||||
|
||||
async {
|
||||
try
|
||||
match! aclApi.addGroups (groups) with
|
||||
match! aclApi.addGroups groups with
|
||||
| Ok _ ->
|
||||
Log.Information $"Added groups %A{groups}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -133,14 +137,14 @@ let addGroups (args: ParseResults<Prinicipal>) =
|
||||
| Ok _ -> ()
|
||||
| Error e -> Log.Error e
|
||||
|
||||
let deleteOwners (args: ParseResults<Prinicipal>) =
|
||||
let owners = args.GetResult Prinicipal.Ids |> Array.ofList
|
||||
let deleteOwners (args: PrincipalArgs) =
|
||||
let owners = args.Ids |> Array.ofList
|
||||
|
||||
if args.Contains Prinicipal.Archive then
|
||||
let aid = args.GetResult Prinicipal.Archive
|
||||
if args.Archive.IsSome then
|
||||
let aid = args.Archive |> Option.get
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.aclApi ()
|
||||
|
||||
async {
|
||||
@@ -148,7 +152,7 @@ let deleteOwners (args: ParseResults<Prinicipal>) =
|
||||
match! aclApi.removeOwners (aid, owners) with
|
||||
| Ok _ ->
|
||||
Log.Information $"Removed owners %A{owners} from archive {aid}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -156,20 +160,20 @@ let deleteOwners (args: ParseResults<Prinicipal>) =
|
||||
return Error exn.Message
|
||||
})
|
||||
else
|
||||
async { return Ok() }
|
||||
async { return Ok () }
|
||||
|> Async.RunSynchronously
|
||||
|> function
|
||||
| Ok _ -> ()
|
||||
| Error e -> Log.Error e
|
||||
|
||||
let deleteUsers (args: ParseResults<Prinicipal>) =
|
||||
let users = args.GetResult Prinicipal.Ids |> Array.ofList
|
||||
let deleteUsers (args: PrincipalArgs) =
|
||||
let users = args.Ids |> Array.ofList
|
||||
|
||||
if args.Contains Prinicipal.Archive then
|
||||
let aid = args.GetResult Prinicipal.Archive
|
||||
if args.Archive.IsSome then
|
||||
let aid = args.Archive.Value
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.aclApi ()
|
||||
|
||||
async {
|
||||
@@ -177,7 +181,7 @@ let deleteUsers (args: ParseResults<Prinicipal>) =
|
||||
match! aclApi.removeUsers (aid, users) with
|
||||
| Ok _ ->
|
||||
Log.Information $"Removed users %A{users} from archive {aid}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -186,15 +190,15 @@ let deleteUsers (args: ParseResults<Prinicipal>) =
|
||||
})
|
||||
else
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.adminApi ()
|
||||
|
||||
async {
|
||||
try
|
||||
match! aclApi.removeUsers (users) with
|
||||
match! aclApi.removeUsers users with
|
||||
| Ok _ ->
|
||||
Log.Information $"Removed users %A{users}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -206,14 +210,14 @@ let deleteUsers (args: ParseResults<Prinicipal>) =
|
||||
| Ok _ -> ()
|
||||
| Error e -> Log.Error e
|
||||
|
||||
let deleteGroups (args: ParseResults<Prinicipal>) =
|
||||
let groups = args.GetResult Prinicipal.Ids |> Array.ofList
|
||||
let deleteGroups (args: PrincipalArgs) =
|
||||
let groups = args.Ids |> Array.ofList
|
||||
|
||||
if args.Contains Prinicipal.Archive then
|
||||
let aid = args.GetResult Prinicipal.Archive
|
||||
if args.Archive.IsSome then
|
||||
let aid = args.Archive |> Option.get
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.aclApi ()
|
||||
|
||||
async {
|
||||
@@ -221,7 +225,7 @@ let deleteGroups (args: ParseResults<Prinicipal>) =
|
||||
match! aclApi.removeGroups (aid, groups) with
|
||||
| Ok _ ->
|
||||
Log.Information $"Removed groups %A{groups} from archive {aid}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -230,15 +234,15 @@ let deleteGroups (args: ParseResults<Prinicipal>) =
|
||||
})
|
||||
else
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let aclApi = api.adminApi ()
|
||||
|
||||
async {
|
||||
try
|
||||
match! aclApi.removeGroups (groups) with
|
||||
match! aclApi.removeGroups groups with
|
||||
| Ok _ ->
|
||||
Log.Information $"Removed groups %A{groups}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module ArchiveCli
|
||||
|
||||
open FSharpPlus
|
||||
open Serilog
|
||||
open System
|
||||
open System.IO
|
||||
open Argu
|
||||
open Serilog
|
||||
open FSharpPlus
|
||||
|
||||
open Args
|
||||
open ArchiveIndex
|
||||
open Archmaester.Dto
|
||||
@@ -17,20 +17,20 @@ let inline private execAsync job =
|
||||
| Ok _ -> ()
|
||||
| Error e -> Log.Error e
|
||||
|
||||
let getArchiveId (args: ParseResults<AddArchive>) (idx: ArchiveIndex.ArchiveIndex) =
|
||||
match args.TryGetResult AddArchive.Id with
|
||||
let getArchiveId (args: AddArchiveArgs) (idx: ArchiveIndex.ArchiveIndex) =
|
||||
match args.Id with
|
||||
| Some id -> id
|
||||
| None -> idx.archiveId
|
||||
|
||||
let getArchiveBasePath (args: ParseResults<AddArchive>) =
|
||||
let getArchiveBasePath (args: AddArchiveArgs) =
|
||||
let e = "neither index.json or base path specified"
|
||||
let fs = args.GetResult AddArchive.Files
|
||||
let fs = args.Files
|
||||
|
||||
match args.TryGetResult AddArchive.Index with
|
||||
match args.Index with
|
||||
| Some f -> getBasePath f
|
||||
| None ->
|
||||
if fs.Length = 1 then
|
||||
// TODO: Handle exn
|
||||
// TODO: Handle exn :/
|
||||
if isDir fs[0] then
|
||||
Path.GetFullPath fs[0]
|
||||
else
|
||||
@@ -42,25 +42,25 @@ let getArchiveBasePath (args: ParseResults<AddArchive>) =
|
||||
|
||||
let getModelAreaArchives modelId =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let cli = api.inventoryApi ()
|
||||
cli.getModelAreaArchives (modelId, ArchiveType.FromString "*:*:*"))
|
||||
|
||||
let getArchive archiveId =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let cli = api.adminApi ()
|
||||
cli.getArchiveDto archiveId)
|
||||
|
||||
let getFiles archiveId =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let cli = api.adminApi ()
|
||||
cli.getFiles archiveId)
|
||||
|
||||
let getAllFiles archiveId =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let cli = api.adminApi ()
|
||||
cli.getAllFiles archiveId)
|
||||
|
||||
@@ -78,7 +78,7 @@ let postArchive (idx, modelArea, basePath, files, reverse, json, published) =
|
||||
let args = idx, modelArea, basePath, files, reverse, json, published
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let adminApi = api.adminApi ()
|
||||
|
||||
instantiateArchiveDto args
|
||||
@@ -103,7 +103,7 @@ let postArchive (idx, modelArea, basePath, files, reverse, json, published) =
|
||||
/// <param name="force">TODO: Whether to overwrite the archive when we find a conflicting ID</param>
|
||||
let postSubArchive (force: bool) (dto: SubArchiveDef) =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let cli = api.archiveApi ()
|
||||
cli.addSubArchive dto)
|
||||
|
||||
@@ -113,11 +113,14 @@ let postSubArchive (force: bool) (dto: SubArchiveDef) =
|
||||
/// <param name="idx">Content of the archive's index file</param>
|
||||
let postArchiveUpdate (idx: ArchiveIndex) =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let archiveApi = api.archiveApi ()
|
||||
|
||||
async {
|
||||
match! archiveApi.getArchive idx.archiveId with
|
||||
| Error err ->
|
||||
failwith err
|
||||
return Error err
|
||||
| Ok _ ->
|
||||
let form: Archmaester.Forms.ArchiveForm = {
|
||||
name = idx.name
|
||||
@@ -129,28 +132,28 @@ let postArchiveUpdate (idx: ArchiveIndex) =
|
||||
}
|
||||
|
||||
return! archiveApi.updateArchive (idx.archiveId, form)
|
||||
| Error err ->
|
||||
failwith err
|
||||
return Error err
|
||||
})
|
||||
|
||||
let modifyArchive (args: ParseResults<ModifyArchive>) =
|
||||
let aid = args.GetResult ModifyArchive.ArchiveId
|
||||
let modifyArchive (args: ModifyArchiveArgs) =
|
||||
let aid = args.ArchiveId
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let archiveApi = api.archiveApi ()
|
||||
let expiry = args.TryGetResult ModifyArchive.Expires |> Option.map DateTime.Parse
|
||||
let points = args.TryGetResult ModifyArchive.Fence |> Option.map List.toArray
|
||||
let expiry = args.Expires |> Option.map DateTime.Parse
|
||||
let points = args.Fence |> Option.map List.toArray
|
||||
|
||||
async {
|
||||
try
|
||||
match! archiveApi.getArchive aid with
|
||||
| Error e ->
|
||||
Log.Error $"{e}"
|
||||
return Error e
|
||||
| Ok a ->
|
||||
let form: Archmaester.Forms.ArchiveForm = {
|
||||
name = args.GetResult(ModifyArchive.Name, a.name)
|
||||
isPublished = args.GetResult(ModifyArchive.Published, a.isPublished)
|
||||
isPublic = args.GetResult(ModifyArchive.Public, a.isPublic)
|
||||
name = args.Name |> Option.defaultValue a.name
|
||||
isPublished = args.Published |> Option.defaultValue a.isPublished
|
||||
isPublic = args.Public |> Option.defaultValue a.isPublic
|
||||
expires = expiry
|
||||
json = if a.json = "" then None else Some a.json
|
||||
geometry =
|
||||
@@ -167,60 +170,57 @@ let modifyArchive (args: ParseResults<ModifyArchive>) =
|
||||
|> fun y ->
|
||||
Log.Debug $"%A{y}"
|
||||
y
|
||||
else a.polygon
|
||||
else
|
||||
a.polygon
|
||||
}
|
||||
|
||||
return! archiveApi.updateArchive (aid, form)
|
||||
| Error e ->
|
||||
Log.Error $"{e}"
|
||||
return Error e
|
||||
with exn ->
|
||||
return Error exn.Message
|
||||
})
|
||||
|> execAsync
|
||||
|
||||
let modifyArchiveAttribs (args: ParseResults<ModifyArchiveAttribs>) =
|
||||
let aid = args.GetResult ModifyArchiveAttribs.ArchiveId
|
||||
let modifyArchiveAttribs (args: ModifyArchiveAttribsArgs) =
|
||||
let aid = args.ArchiveId
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let adminApi = api.adminApi ()
|
||||
|
||||
async {
|
||||
try
|
||||
if args.Contains ModifyArchiveAttribs.Add_Related then
|
||||
let related = args.GetResult ModifyArchiveAttribs.Add_Related
|
||||
if args.AddRelated.IsSome then
|
||||
let related = args.AddRelated |> Option.get
|
||||
let! _ = adminApi.addAssociation (aid, related)
|
||||
()
|
||||
|
||||
if args.Contains ModifyArchiveAttribs.Remove_Related then
|
||||
let related = args.GetResult ModifyArchiveAttribs.Remove_Related
|
||||
if args.RemoveRelated.IsSome then
|
||||
let related = args.RemoveRelated |> Option.get
|
||||
let! _ = adminApi.removeAssociation (aid, related)
|
||||
()
|
||||
|
||||
match! adminApi.getArchiveDto aid with
|
||||
| Error e ->
|
||||
Log.Error $"{e}"
|
||||
return Error e
|
||||
| Ok a ->
|
||||
let form: Archmaester.Forms.ArchiveAttribsForm = {
|
||||
description = args.GetResult(ModifyArchiveAttribs.Description, a.props.description)
|
||||
basePath = args.GetResult(ModifyArchiveAttribs.Base_Path, a.files.basePath)
|
||||
modelArea = args.GetResult(ModifyArchiveAttribs.Model_Area, a.props.modelArea)
|
||||
focalpoint = args.GetResult(ModifyArchiveAttribs.Focal, a.props.focalPoint)
|
||||
defaultZoom = args.GetResult(ModifyArchiveAttribs.Zoom, a.props.defaultZoom)
|
||||
description = args.Description |> Option.defaultValue a.props.description
|
||||
basePath = args.BasePath |> Option.defaultValue a.files.basePath
|
||||
modelArea = args.ModelArea |> Option.defaultValue a.props.modelArea
|
||||
focalpoint = args.Focal |> Option.defaultValue a.props.focalPoint
|
||||
defaultZoom = args.Zoom |> Option.defaultValue a.props.defaultZoom
|
||||
json = if a.json = "" then None else Some a.json
|
||||
geometry = if a.polygon = [||] then None else Some a.polygon
|
||||
}
|
||||
|
||||
return! adminApi.updateArchiveAttribs (aid, form)
|
||||
| Error e ->
|
||||
Log.Error $"{e}"
|
||||
return Error e
|
||||
with exn ->
|
||||
return Error exn.Message
|
||||
})
|
||||
|> execAsync
|
||||
|
||||
let deleteArchives (args: ParseResults<Delete>) =
|
||||
args.GetResult Delete.Archive |> retireArchive |> ignore
|
||||
let deleteArchives (archive: string) = archive |> retireArchive |> ignore
|
||||
|
||||
let readDriftersInputJson file =
|
||||
if File.Exists file then
|
||||
@@ -229,23 +229,23 @@ let readDriftersInputJson file =
|
||||
Log.Error $"Drifters input not found: {file}"
|
||||
""
|
||||
|
||||
let rec addArchive (args: ParseResults<AddArchive>) =
|
||||
let rec addArchive (args: AddArchiveArgs) =
|
||||
let basePath = getArchiveBasePath args
|
||||
Log.Information $"BasePath: %s{basePath}"
|
||||
|
||||
let idx =
|
||||
match args.TryGetResult AddArchive.Index with
|
||||
match args.Index with
|
||||
| Some ix -> ix
|
||||
| None -> $"{basePath}/index.json"
|
||||
|> readArchiveIdx
|
||||
|
||||
let files =
|
||||
getArchiveFiles idx.archiveType basePath (args.GetResult AddArchive.Files |> Array.ofList)
|
||||
let files = getArchiveFiles idx.archiveType basePath (args.Files |> Array.ofList)
|
||||
|
||||
let modelArea = initiateModelArea idx basePath
|
||||
|
||||
let json, reverse =
|
||||
match idx.archiveType with
|
||||
| Drifters(_, DriftersFormat.Particle) ->
|
||||
| Drifters (_, DriftersFormat.Particle) ->
|
||||
let s = readDriftersInputJson (Path.Join [| basePath; "input.json" |])
|
||||
|
||||
let r =
|
||||
@@ -258,8 +258,8 @@ let rec addArchive (args: ParseResults<AddArchive>) =
|
||||
match r with
|
||||
| Ok x -> s, x
|
||||
| Error e -> failwith e
|
||||
| Drifters(_, DriftersFormat.Field2D)
|
||||
| Drifters(_, DriftersFormat.Field3D) ->
|
||||
| Drifters (_, DriftersFormat.Field2D)
|
||||
| Drifters (_, DriftersFormat.Field3D) ->
|
||||
let s = readDriftersInputJson (Path.Join [| basePath; "input.json" |])
|
||||
|
||||
let r =
|
||||
@@ -274,29 +274,29 @@ let rec addArchive (args: ParseResults<AddArchive>) =
|
||||
| Error e -> failwith e
|
||||
| _ -> "", false
|
||||
|
||||
let published = args.GetResult(AddArchive.Published, defaultValue = true)
|
||||
let published = args.Published |> Option.defaultValue true
|
||||
|
||||
let saveRes =
|
||||
try
|
||||
postArchive (idx, modelArea, basePath, files, reverse, json, published)
|
||||
|> Async.RunSynchronously
|
||||
with e ->
|
||||
Log.Error(e, "Archivist.addArchive {ArchmaesterUrl}", Settings.archmaesterUrl)
|
||||
Log.Error (e, "Archivist.addArchive {ArchmaesterUrl}", Settings.archmaesterUrl)
|
||||
Error "Could not add archive"
|
||||
|
||||
match saveRes with
|
||||
| Ok() -> Log.Information $"Successfully added archive %s{idx.name}"
|
||||
| Ok () -> Log.Information $"Successfully added archive %s{idx.name}"
|
||||
| Error err -> Log.Error $"Error: {err}"
|
||||
|
||||
let createSubArchive (args: ParseResults<SubArchive>) =
|
||||
let createSubArchive (args: SubArchiveArgs) =
|
||||
let fetchRefArchive = getArchive >> Async.RunSynchronously
|
||||
|
||||
let createSubArchive refArchive = {
|
||||
uuid = Guid.NewGuid()
|
||||
uuid = Guid.NewGuid ()
|
||||
reference = refArchive.props.archiveId
|
||||
name = args.GetResult SubArchive.Name
|
||||
startFile = args.GetResult SubArchive.From
|
||||
endFile = args.GetResult(SubArchive.To, defaultValue = Int32.MaxValue)
|
||||
name = args.Name
|
||||
startFile = args.From
|
||||
endFile = args.To |> Option.defaultValue Int32.MaxValue
|
||||
acl = {
|
||||
owners = [||]
|
||||
groups = [||]
|
||||
@@ -306,12 +306,12 @@ let createSubArchive (args: ParseResults<SubArchive>) =
|
||||
polygon = [||]
|
||||
json = ""
|
||||
isPublic = false
|
||||
isPublished = args.GetResult(SubArchive.Published, defaultValue = true)
|
||||
isPublished = args.Published |> Option.defaultValue true
|
||||
}
|
||||
|
||||
let postSubArchive = postSubArchive false >> Async.RunSynchronously
|
||||
|
||||
fetchRefArchive (args.GetResult SubArchive.Ref)
|
||||
fetchRefArchive args.Ref
|
||||
|> Result.map createSubArchive
|
||||
|> Result.bind postSubArchive
|
||||
|> function
|
||||
@@ -320,7 +320,7 @@ let createSubArchive (args: ParseResults<SubArchive>) =
|
||||
|
||||
let getAcl archiveId =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let cli = api.aclApi ()
|
||||
cli.getAcl archiveId)
|
||||
|
||||
@@ -336,17 +336,17 @@ let printAcl acl =
|
||||
acl.users |> formatAcl "users" |> (fun s -> printf $"{s}")
|
||||
acl.groups |> formatAcl "groups" |> (fun s -> printf $"{s}")
|
||||
|
||||
let showArchive (args: ParseResults<ShowArchive>) =
|
||||
let archiveId = args.GetResult ShowArchive.Archive
|
||||
let showArchive (args: ShowArchiveArgs) =
|
||||
let archiveId = args.ArchiveId
|
||||
let fmt = "yyyy-MM-dd HH:mm"
|
||||
|
||||
async {
|
||||
match! getArchive archiveId with
|
||||
| Ok a ->
|
||||
let! files =
|
||||
if args.Contains ShowArchive.All then getAllFiles archiveId
|
||||
elif args.Contains ShowArchive.Files then getFiles archiveId
|
||||
else async.Return({ basePath = ""; series = [||] } |> Ok)
|
||||
if args.All then getAllFiles archiveId
|
||||
elif args.Files then getFiles archiveId
|
||||
else async.Return ({ basePath = ""; series = [||] } |> Ok)
|
||||
|
||||
let! acl = getAcl archiveId
|
||||
|
||||
@@ -360,20 +360,20 @@ let showArchive (args: ParseResults<ShowArchive>) =
|
||||
|
||||
f.series
|
||||
|> Array.iteri (fun n x ->
|
||||
let name = String.truncate 32 x.name |> fun y -> y.PadRight(32, ' ')
|
||||
printfn $" %-3d{n}: {name} | {x.startTime.ToString(fmt)} - {x.endTime.ToString(fmt)}")
|
||||
let name = String.truncate 32 x.name |> fun y -> y.PadRight (32, ' ')
|
||||
printfn $" %-3d{n}: {name} | {x.startTime.ToString (fmt)} - {x.endTime.ToString (fmt)}")
|
||||
| Error e -> Log.Error e
|
||||
| Error e -> Log.Error e
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
let showRelatedArchives (args: ParseResults<ShowArchive>) =
|
||||
let archiveId = args.GetResult ShowArchive.Archive
|
||||
let showRelatedArchives (args: ShowArchiveArgs) =
|
||||
let archiveId = args.ArchiveId
|
||||
|
||||
async {
|
||||
let! r =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let cli = api.inventoryApi ()
|
||||
cli.getAssociated (archiveId, ArchiveType.Any))
|
||||
// cli.getRelated(archiveId, Atmo(AtmoVariant.Any, AtmoFormat.Any)))
|
||||
@@ -383,12 +383,12 @@ let showRelatedArchives (args: ParseResults<ShowArchive>) =
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
let augmentArchive (args: ParseResults<Augment>) =
|
||||
let aid = args.GetResult Augment.Archive
|
||||
let fnames = args.GetResult Augment.Files |> List.map Path.GetFullPath
|
||||
let augmentArchive (args: AugmentArgs) =
|
||||
let aid = args.Archive
|
||||
let fnames = args.Files |> List.map Path.GetFullPath
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let archmaester = api.adminApi ()
|
||||
|
||||
async {
|
||||
@@ -402,7 +402,7 @@ let augmentArchive (args: ParseResults<Augment>) =
|
||||
|> traverse (readDataSet a)
|
||||
|> Result.bind (fun files ->
|
||||
let _, _, t = List.head files
|
||||
let startUtc = t.ToUniversalTime()
|
||||
let startUtc = t.ToUniversalTime ()
|
||||
let f = Array.ofList files
|
||||
ensureContiguous startUtc archive.props.freq f |> Result.map fst)
|
||||
|
||||
@@ -414,8 +414,8 @@ let augmentArchive (args: ParseResults<Augment>) =
|
||||
name = stripBasePath archive.files.basePath name
|
||||
frames = frames
|
||||
ordering = 0
|
||||
startTime = t.ToUniversalTime()
|
||||
endTime = t.AddSeconds(archive.props.freq * frames |> float)
|
||||
startTime = t.ToUniversalTime ()
|
||||
endTime = t.AddSeconds (archive.props.freq * frames |> float)
|
||||
reverse = reverse
|
||||
})
|
||||
|
||||
@@ -428,27 +428,27 @@ let augmentArchive (args: ParseResults<Augment>) =
|
||||
})
|
||||
|> execAsync
|
||||
|
||||
let resizeArchive (args: ParseResults<Resize>) =
|
||||
let aid = args.GetResult Resize.Archive
|
||||
let first = args.GetResult(Resize.From, Int32.MinValue)
|
||||
let last = args.GetResult(Resize.To, Int32.MaxValue)
|
||||
let resizeArchive (args: ResizeArgs) =
|
||||
let aid = args.Archive
|
||||
let first = args.From
|
||||
let last = args.To |> Option.defaultValue Int32.MaxValue
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let archmaester = api.archiveApi ()
|
||||
async { return! archmaester.resizeArchive (aid, first, last) })
|
||||
|> execAsync
|
||||
|
||||
let addType (t: string) =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let adminApi = api.adminApi ()
|
||||
async { return! adminApi.addType t })
|
||||
|> execAsync
|
||||
|
||||
let deleteType (t: string) =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let adminApi = api.adminApi ()
|
||||
async { return! adminApi.removeType t })
|
||||
|> execAsync
|
||||
@@ -1,15 +1,16 @@
|
||||
module ArchiveIndex
|
||||
|
||||
open FSharpPlus
|
||||
open Microsoft.Research.Science.Data
|
||||
open ProjNet.FSharp
|
||||
open Serilog
|
||||
open System
|
||||
open System.IO
|
||||
open Thoth.Json.Net
|
||||
|
||||
open Archmaester.Dto
|
||||
open Oceanbox.DataAgent
|
||||
open Oceanbox.DataAgent.DatasetAgent
|
||||
open FSharpPlus
|
||||
open ProjNet.FSharp
|
||||
|
||||
type ModelAreaIndex = {
|
||||
modelAreaId: ModelAreaId
|
||||
@@ -116,7 +117,9 @@ let inline withCliAuth f =
|
||||
| None ->
|
||||
Log.Fatal "You must provide ARCHMAESTER_AUTH"
|
||||
Error "You are not logged in" |> async.Return
|
||||
| Some auth -> f auth
|
||||
| Some auth ->
|
||||
Log.Debug "You are logged in"
|
||||
f auth
|
||||
|
||||
let private (|NumSeq|_|) x =
|
||||
let rex = Text.RegularExpressions.Regex @".+[-_]([0-9]+)\..+$"
|
||||
@@ -298,7 +301,7 @@ let FvStatsArchive =
|
||||
member x.getNumFrames ds = 12 // year
|
||||
}
|
||||
|
||||
let getArchiveFiles format basePath (files: string[]) =
|
||||
let getArchiveFiles format basePath (files: string array) =
|
||||
let fs =
|
||||
if files.Length = 1 then
|
||||
Directory.GetFiles(basePath, "*.nc", SearchOption.AllDirectories)
|
||||
@@ -462,32 +465,34 @@ let initiateModelArea (idx: ArchiveIndex) (basePath: string) =
|
||||
|
||||
let getParentModelAreaId rid =
|
||||
async {
|
||||
let! parent = adminApi.getArchiveDto rid
|
||||
|
||||
match parent with
|
||||
| Ok p -> return Ok p.props.modelArea
|
||||
| Error e -> return failwith $"Could not get model area id: {e}"
|
||||
try
|
||||
let! parent = adminApi.getArchiveDto rid
|
||||
match parent with
|
||||
| Ok p ->
|
||||
return Ok p.props.modelArea
|
||||
| Error e -> return failwith $"Could not get model area id: {e}"
|
||||
with e -> return failwith $"Failed to get parent archive: %A{rid} with %A{e.Message}"
|
||||
}
|
||||
|
||||
let checkModelArea () =
|
||||
let failBadly () =
|
||||
Log.Error "Either modelArea or reference must be specified!"
|
||||
Environment.Exit 1
|
||||
failwith "Missing modelArea or reference."
|
||||
let failBadly () =
|
||||
Log.Error "Either modelArea or reference must be specified!"
|
||||
Environment.Exit 1
|
||||
failwith "Missing modelArea or reference."
|
||||
|
||||
match idx.modelArea with
|
||||
| None ->
|
||||
if idx.reference.IsSome then
|
||||
async {
|
||||
match! inventoryApi.getArchive idx.reference.Value with
|
||||
| Ok ref -> return! modelAreaApi.getModelArea ref.modelArea
|
||||
| Error e ->
|
||||
Log.Error $"{e}"
|
||||
return None
|
||||
}
|
||||
else
|
||||
failBadly ()
|
||||
| Some mid -> modelAreaApi.getModelArea mid
|
||||
match idx.modelArea with
|
||||
| None ->
|
||||
if idx.reference.IsSome then
|
||||
async {
|
||||
match! inventoryApi.getArchive idx.reference.Value with
|
||||
| Ok ref -> return! modelAreaApi.getModelArea ref.modelArea
|
||||
| Error e ->
|
||||
Log.Error $"{e}"
|
||||
return None
|
||||
}
|
||||
else
|
||||
failBadly ()
|
||||
| Some mid -> modelAreaApi.getModelArea mid
|
||||
// match model with
|
||||
// | ModelAreaId mid -> modelAreaApi.getModelArea mid
|
||||
// | ModelArea m -> tryAddModelArea m basePath
|
||||
@@ -497,7 +502,6 @@ let initiateModelArea (idx: ArchiveIndex) (basePath: string) =
|
||||
// | Ok m -> return! tryAddModelArea m basePath
|
||||
// | Error e -> return Error e
|
||||
// }
|
||||
|
||||
match idx.archiveType with
|
||||
| FvStats _
|
||||
| Atmo _ ->
|
||||
@@ -515,14 +519,11 @@ let initiateModelArea (idx: ArchiveIndex) (basePath: string) =
|
||||
| Fvcom _ ->
|
||||
async {
|
||||
let! model = modelAreaApi.getModelAreaId idx.name
|
||||
|
||||
match model with
|
||||
| Ok m ->
|
||||
Log.Debug $"Existing model area: %A{model}"
|
||||
return Ok m
|
||||
| Error _ ->
|
||||
Log.Debug "Make new model area"
|
||||
|
||||
match! checkModelArea () with
|
||||
| Some ma ->
|
||||
Log.Debug $"New model area: %A{ma}"
|
||||
@@ -630,7 +631,6 @@ let instantiateArchiveDto (idx, modelArea, basePath, files, reverse, json, publi
|
||||
}
|
||||
|
||||
let retireArchive (archive: string) =
|
||||
// TODO: retire all dependent archies
|
||||
let aid =
|
||||
try
|
||||
Guid.Parse archive
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||
<AssemblyName>archivist</AssemblyName>
|
||||
<Version>7.1.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
@@ -16,27 +19,26 @@
|
||||
<Compile Include="Main.fs"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Argu" Version="6.2.5"/>
|
||||
<PackageReference Include="FSharp.Data" Version="6.4.1"/>
|
||||
<PackageReference Include="FSharpPlus" Version="1.7.0"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.1">
|
||||
<PackageReference Include="Fargo.CmdLine" />
|
||||
<PackageReference Include="FSharp.Data" />
|
||||
<PackageReference Include="FSharpPlus" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" >
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.1">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" >
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Oceanbox.FvcomKit" Version="5.6.0"/>
|
||||
<PackageReference Include="Serilog" Version="4.2.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0"/>
|
||||
<PackageReference Include="Thoth.Json.Net" Version="12.0.0"/>
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201"/>
|
||||
<PackageReference Include="Serilog" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" />
|
||||
<PackageReference Include="Thoth.Json.Net" />
|
||||
<PackageReference Include="FSharp.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\DataAgent\src\DataAgent\Oceanbox.DataAgent.fsproj"/>
|
||||
<ProjectReference Include="..\..\..\DataAgent\src\Entity\Entity.csproj"/>
|
||||
<ProjectReference Include="..\..\..\Interfaces\Archmaester\Archmaester.Api.fsproj" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -2,319 +2,582 @@ module Args
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open Argu
|
||||
|
||||
open Fargo
|
||||
open Fargo.Operators
|
||||
open Serilog
|
||||
|
||||
open Archmaester.Dto
|
||||
|
||||
let colorizer =
|
||||
function
|
||||
| ErrorCode.HelpText -> None
|
||||
| _ -> Some ConsoleColor.Red
|
||||
|
||||
let errorHandler = ProcessExiter(colorizer = colorizer)
|
||||
|
||||
let showVersion () =
|
||||
let assembly = System.Reflection.Assembly.GetExecutingAssembly()
|
||||
let assembly = System.Reflection.Assembly.GetExecutingAssembly ()
|
||||
let version = System.Diagnostics.FileVersionInfo.GetVersionInfo assembly.Location
|
||||
printfn $"{version.FileVersion}"
|
||||
|
||||
type ListArchive =
|
||||
| All
|
||||
| Retired
|
||||
| Refs
|
||||
| Type of string
|
||||
| Owner of string
|
||||
| User of string
|
||||
| Group of string
|
||||
| Archive_Name of string: string
|
||||
| Model_Name of string: string
|
||||
| [<AltCommandLine("-V")>] Verbose
|
||||
| Json
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| All -> "List all archives"
|
||||
| Refs -> "List referencing archives"
|
||||
| Retired -> "List retired archives"
|
||||
| Type _ -> "List archives of the given type"
|
||||
| Owner _ -> "List archives owned by user"
|
||||
| User _ -> "List archives for user"
|
||||
| Group _ -> "Remove archives for group"
|
||||
| Archive_Name _ -> "List archives matching pattern"
|
||||
| Model_Name _ -> "List archives matching model area"
|
||||
| Verbose -> "Detailed listing"
|
||||
| Json -> "Json output"
|
||||
type CmdType =
|
||||
| ListCmd
|
||||
| ShowCmd
|
||||
| AddCmd
|
||||
| DeleteCmd
|
||||
| ModifyCmd
|
||||
| AugmentCmd
|
||||
| ResizeCmd
|
||||
|
||||
type ListModel =
|
||||
| Model_Name of regex: string
|
||||
| Verbose
|
||||
| Json
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Model_Name _ -> "List models matching regex"
|
||||
| Verbose -> "Detailed listing"
|
||||
| Json -> "Json output"
|
||||
type ListType =
|
||||
| Archives
|
||||
| Models
|
||||
| Types
|
||||
|
||||
type List =
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("a")>] Archives of ParseResults<ListArchive>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("m")>] Models of ParseResults<ListModel>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("t")>] Types
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Archives _ -> "List archives"
|
||||
| Models _ -> "List models"
|
||||
| Types -> "List types"
|
||||
type ShowType =
|
||||
| Archive
|
||||
| Model
|
||||
|
||||
type ShowArchive =
|
||||
| All
|
||||
| Refs
|
||||
| Related
|
||||
| Files
|
||||
| Json
|
||||
| [<MainCommand; Last>] Archive of id: ArchiveId
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Json -> "Json output"
|
||||
| Refs -> "List archives referencing archive"
|
||||
| Related -> "List related archives"
|
||||
| Files -> "List file names"
|
||||
| All -> "List all available files (for resize)"
|
||||
| Archive _ -> "Archive id"
|
||||
type AddType =
|
||||
| Archive
|
||||
| Sub
|
||||
| Model
|
||||
| Owner
|
||||
| User
|
||||
| Group
|
||||
| Type
|
||||
|
||||
type ShowModel =
|
||||
| Verbose
|
||||
| Json
|
||||
| [<MainCommand; Last>] Model of id: ModelAreaId
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Model _ -> "Model id"
|
||||
| Verbose -> "Detailed listing"
|
||||
| Json -> "Json output"
|
||||
type DeleteType =
|
||||
| Archive
|
||||
| Model
|
||||
| Owner
|
||||
| User
|
||||
| Group
|
||||
| Type
|
||||
|
||||
type Show =
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("a")>] Archive of ParseResults<ShowArchive>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("m")>] Model of ParseResults<ShowModel>
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Archive _ -> "List archive"
|
||||
| Model _ -> "List model"
|
||||
type ModifyType =
|
||||
| Archive
|
||||
| ArchiveAttribs
|
||||
| Model
|
||||
|
||||
type AddArchive =
|
||||
| Index of index: string
|
||||
| No_sort
|
||||
| Id of guid: ArchiveId
|
||||
| Force
|
||||
| Published of bool
|
||||
| [<MainCommand; Last>] Files of files: string list
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| No_sort -> "No sorting of files"
|
||||
| Index _ -> "index.json"
|
||||
| Id _ -> "Archive id to update"
|
||||
| Files _ -> "Files to add"
|
||||
| Force -> "Forcefully add or update"
|
||||
| Published _ -> "Publish archive (default: true)"
|
||||
type ListArchiveArgs = {
|
||||
All: bool
|
||||
Retired: bool
|
||||
Refs: bool
|
||||
Type: string option
|
||||
Owner: string option
|
||||
User: string option
|
||||
Group: string option
|
||||
ArchiveName: string option
|
||||
ModelName: string option
|
||||
Verbose: bool
|
||||
Json: bool
|
||||
}
|
||||
|
||||
type SubArchive =
|
||||
| [<Mandatory>] Ref of guid: ArchiveId
|
||||
| [<Mandatory>] From of first: int
|
||||
| To of last: int
|
||||
| Published of bool
|
||||
| [<MainCommand; Last>] Name of name: string
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Ref _ -> "Reference archive"
|
||||
| From _ -> "Index of first file to include"
|
||||
| To _ -> "Index of last file to include"
|
||||
| Published _ -> "Publish archive (default: true)"
|
||||
| Name _ -> "Name of the new archive"
|
||||
type ListModelArgs = { ModelName: string option; Verbose: bool; Json: bool }
|
||||
|
||||
type AddModel =
|
||||
| [<MainCommand; Last>] File of json: string
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| File _ -> "model.json"
|
||||
type ShowArchiveArgs = {
|
||||
All: bool
|
||||
Refs: bool
|
||||
Related: bool
|
||||
Files: bool
|
||||
Json: bool
|
||||
ArchiveId: ArchiveId
|
||||
}
|
||||
|
||||
type Prinicipal =
|
||||
| Archive of id: ArchiveId
|
||||
| [<MainCommand; Last>] Ids of name: string list
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Archive _ -> "Apply to archive"
|
||||
| Ids _ -> "Identies"
|
||||
type ShowModelArgs = { Verbose: bool; Json: bool; ModelId: ModelAreaId }
|
||||
|
||||
type Add =
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("a")>] Archive of ParseResults<AddArchive>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("s")>] Sub of ParseResults<SubArchive>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("m")>] Model of ParseResults<AddModel>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("o")>] Owner of ParseResults<Prinicipal>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("u")>] User of ParseResults<Prinicipal>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("g")>] Group of ParseResults<Prinicipal>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("t")>] Type of string
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Archive _ -> "Add archive"
|
||||
| Sub _ -> "Add sub-archive"
|
||||
| Model _ -> "Add model"
|
||||
| Owner _ -> "Add owner"
|
||||
| User _ -> "Add user"
|
||||
| Group _ -> "Add group"
|
||||
| Type _ -> "Add type"
|
||||
type AddArchiveArgs = {
|
||||
Index: string option
|
||||
NoSort: bool
|
||||
Id: ArchiveId option
|
||||
Force: bool
|
||||
Published: bool option
|
||||
Files: string list
|
||||
}
|
||||
|
||||
type DeleteModel =
|
||||
| Force
|
||||
| [<MainCommand; Last>] Model of id: ModelAreaId
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Force -> "Force delete"
|
||||
| Model _ -> "Model id"
|
||||
type SubArchiveArgs = {
|
||||
Ref: ArchiveId
|
||||
From: int
|
||||
To: int option
|
||||
Published: bool option
|
||||
Name: string
|
||||
}
|
||||
|
||||
type Delete =
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("a")>] Archive of id: string
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("m")>] Model of ParseResults<DeleteModel>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("o")>] Owner of ParseResults<Prinicipal>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("u")>] User of ParseResults<Prinicipal>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("g")>] Group of ParseResults<Prinicipal>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("t")>] Type of string
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Archive _ -> "Delete archive"
|
||||
| Model _ -> "Delete model"
|
||||
| Owner _ -> "Delete owner"
|
||||
| User _ -> "Delete user"
|
||||
| Group _ -> "Delete group"
|
||||
| Type _ -> "Delete type"
|
||||
type AddModelArgs = { File: string }
|
||||
|
||||
type ModifyArchiveAttribs =
|
||||
| Base_Path of string
|
||||
| Projection of string
|
||||
| Description of string
|
||||
| Focal of single * single
|
||||
| Zoom of single
|
||||
| Retired of bool
|
||||
| Polygon of file: string
|
||||
| Model_Area of id: ModelAreaId
|
||||
| Json of json: string
|
||||
| Add_Related of ArchiveId
|
||||
| Remove_Related of ArchiveId
|
||||
| [<MainCommand; Last>] ArchiveId of id: ModelAreaId
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Base_Path _ -> ""
|
||||
| Projection _ -> ""
|
||||
| Description _ -> ""
|
||||
| Focal _ -> ""
|
||||
| Zoom _ -> ""
|
||||
| Retired _ -> ""
|
||||
| Polygon _ -> ""
|
||||
| Model_Area _ -> "'"
|
||||
| Json _ -> "'"
|
||||
| Add_Related _ -> ""
|
||||
| Remove_Related _ -> ""
|
||||
| ArchiveId _ -> ""
|
||||
type PrincipalArgs = { Archive: ArchiveId option; Ids: string list }
|
||||
|
||||
type ModifyArchive =
|
||||
| Name of string
|
||||
| Published of bool
|
||||
| Public of bool
|
||||
| Expires of datetime: string
|
||||
| Json of file: string
|
||||
| Fence of string list
|
||||
| End
|
||||
| [<MainCommand; Last>] ArchiveId of id: ArchiveId
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Name _ -> "Name of archive"
|
||||
| Published _ -> "Publish archive"
|
||||
| Public _ -> "Make archive public (careful!)"
|
||||
| Expires _ -> "Set expiry"
|
||||
| Json _ -> "Any json you fancy"
|
||||
| Fence _ -> "Geofence points given as 'lng,lat',..."
|
||||
| End -> "End fence list (sic)"
|
||||
| ArchiveId _ -> "Archive to modify"
|
||||
type DeleteModelArgs = { Force: bool; ModelId: ModelAreaId }
|
||||
|
||||
type ModifyModel =
|
||||
| Name of string
|
||||
| Description of string
|
||||
| Focal of single * single
|
||||
| Zoom of single
|
||||
| Polygon of file: string
|
||||
| Projection of string
|
||||
| [<MainCommand; Last>] ModelId of id: ModelAreaId
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Name _ -> ""
|
||||
| Description _ -> ""
|
||||
| Focal _ -> ""
|
||||
| Zoom _ -> ""
|
||||
| Polygon _ -> "Bounding polygon file"
|
||||
| Projection _ -> "Projection of bounding polygon"
|
||||
| ModelId _ -> ""
|
||||
type ModifyArchiveArgs = {
|
||||
Name: string option
|
||||
Published: bool option
|
||||
Public: bool option
|
||||
Expires: string option
|
||||
Json: string option
|
||||
Fence: string list option
|
||||
End: bool
|
||||
ArchiveId: ArchiveId
|
||||
}
|
||||
|
||||
type Modify =
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("a")>] Archive of ParseResults<ModifyArchive>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("t")>] ArchiveAttribs of ParseResults<ModifyArchiveAttribs>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine("m")>] Model of ParseResults<ModifyModel>
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Archive _ -> "Modify archive"
|
||||
| ArchiveAttribs _ -> "Modify archive attribs"
|
||||
| Model _ -> "Modify model"
|
||||
type ModifyArchiveAttribsArgs = {
|
||||
BasePath: string option
|
||||
Projection: string option
|
||||
Description: string option
|
||||
Focal: (single * single) option
|
||||
Zoom: single option
|
||||
Retired: bool option
|
||||
Polygon: string option
|
||||
ModelArea: ModelAreaId option
|
||||
Json: string option
|
||||
AddRelated: ArchiveId option
|
||||
RemoveRelated: ArchiveId option
|
||||
ArchiveId: ModelAreaId
|
||||
}
|
||||
|
||||
type Augment =
|
||||
| [<Mandatory>] Archive of guid: ArchiveId
|
||||
| [<MainCommand; Last>] Files of name: string list
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| Archive _ -> "Archive id to augment"
|
||||
| Files _ -> "Files to add"
|
||||
type ModifyModelArgs = {
|
||||
Name: string option
|
||||
Description: string option
|
||||
Focal: (single * single) option
|
||||
Zoom: single option
|
||||
Polygon: string option
|
||||
Projection: string option
|
||||
ModelId: ModelAreaId
|
||||
}
|
||||
|
||||
type Resize =
|
||||
| [<Mandatory>] From of first: int
|
||||
| To of last: int
|
||||
| [<MainCommand; Last>] Archive of id: ArchiveId
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| From _ -> "Index of first file to include"
|
||||
| To _ -> "Index of last file to include"
|
||||
| Archive _ -> "Archive to resize"
|
||||
type AugmentArgs = { Archive: ArchiveId; Files: string list }
|
||||
|
||||
type Verbs =
|
||||
| [<CliPrefix(CliPrefix.None)>] Add of ParseResults<Add>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine([| "ls" |])>] List of ParseResults<List>
|
||||
| [<CliPrefix(CliPrefix.None)>] Show of ParseResults<Show>
|
||||
| [<CliPrefix(CliPrefix.None); AltCommandLine([| "rm" |])>] Delete of ParseResults<Delete>
|
||||
| [<CliPrefix(CliPrefix.None)>] Modify of ParseResults<Modify>
|
||||
| [<CliPrefix(CliPrefix.None)>] Augment of ParseResults<Augment>
|
||||
| [<CliPrefix(CliPrefix.None)>] Resize of ParseResults<Resize>
|
||||
| Log_Level of level: int
|
||||
| [<AltCommandLine("-v")>] Version
|
||||
interface IArgParserTemplate with
|
||||
member this.Usage =
|
||||
match this with
|
||||
| List _ -> "List entities"
|
||||
| Show _ -> "Show entities"
|
||||
| Add _ -> "Add entities"
|
||||
| Modify _ -> "Modify entities"
|
||||
| Delete _ -> "Delete entities"
|
||||
| Augment _ -> "Augment archive"
|
||||
| Resize _ -> "Resize archive"
|
||||
| Log_Level _ -> "0=Error, 1=Warning, 2=Info, 3=Debug, 4=Verbose"
|
||||
| Version -> "Show the current version"
|
||||
type ResizeArgs = { From: int; To: int option; Archive: ArchiveId }
|
||||
|
||||
type Command =
|
||||
| ListArchives of ListArchiveArgs
|
||||
| ListModels of ListModelArgs
|
||||
| ListTypes of int
|
||||
| ShowArchive of ShowArchiveArgs
|
||||
| ShowModel of ShowModelArgs
|
||||
| AddArchive of AddArchiveArgs
|
||||
| AddSub of SubArchiveArgs
|
||||
| AddModel of AddModelArgs
|
||||
| AddOwner of PrincipalArgs
|
||||
| AddUser of PrincipalArgs
|
||||
| AddGroup of PrincipalArgs
|
||||
| AddType of string
|
||||
| DeleteArchive of string
|
||||
| DeleteModel of DeleteModelArgs
|
||||
| DeleteOwner of PrincipalArgs
|
||||
| DeleteUser of PrincipalArgs
|
||||
| DeleteGroup of PrincipalArgs
|
||||
| DeleteType of string
|
||||
| ModifyArchive of ModifyArchiveArgs
|
||||
| ModifyArchiveAttribs of ModifyArchiveAttribsArgs
|
||||
| ModifyModel of ModifyModelArgs
|
||||
| Augment of AugmentArgs
|
||||
| Resize of ResizeArgs
|
||||
| Version of int
|
||||
|
||||
let parseArchiveId (s: string) =
|
||||
match ArchiveId.TryParse s with
|
||||
| true, g -> Ok g
|
||||
| false, _ -> Error "Invalid archive ID format"
|
||||
|
||||
let parseModelAreaId (s: string) =
|
||||
match ModelAreaId.TryParse s with
|
||||
| true, g -> Ok g
|
||||
| false, _ -> Error "Invalid model area ID format"
|
||||
|
||||
let parseFocal (s: string) =
|
||||
let parts = s.Split ','
|
||||
if parts.Length = 2 then
|
||||
match Single.TryParse parts.[0], Single.TryParse parts.[1] with
|
||||
| (true, x), (true, y) -> Ok (x, y)
|
||||
| _ -> Error "Invalid focal point format (should be 'x,y')"
|
||||
else
|
||||
Error "Invalid focal point format (should be 'x,y')"
|
||||
|
||||
let argParser: Arg<Command * int> =
|
||||
fargo {
|
||||
let! logLevel =
|
||||
opt "log-level" null "level" "Log level (0=Error, 1=Warning, 2=Info, 3=Debug, 4=Verbose)"
|
||||
|> optParse (fun s ->
|
||||
match Int32.TryParse s with
|
||||
| true, v when v >= 0 && v <= 4 -> Ok v
|
||||
| true, _ -> Error "Log level must be between 0 and 4"
|
||||
| false, _ -> Error "Invalid log level value"
|
||||
)
|
||||
|> defaultValue 2
|
||||
|
||||
let! version = flag "version" "v" "Show version"
|
||||
|
||||
if version then
|
||||
return Version logLevel, logLevel
|
||||
else
|
||||
match!
|
||||
cmd "list" "ls" "List entities" |>> CmdType.ListCmd
|
||||
<|> (cmd "show" "s" "Show entity details" |>> CmdType.ShowCmd)
|
||||
<|> (cmd "add" "a" "Add entities" |>> CmdType.AddCmd)
|
||||
<|> (cmd "delete" "rm" "Delete entities" |>> CmdType.DeleteCmd)
|
||||
<|> (cmd "modify" "m" "Modify entities" |>> CmdType.ModifyCmd)
|
||||
<|> (cmd "augment" "au" "Augment archive" |>> CmdType.AugmentCmd)
|
||||
<|> (cmd "resize" "r" "Resize archive" |>> CmdType.ResizeCmd)
|
||||
with
|
||||
| CmdType.ListCmd ->
|
||||
match!
|
||||
cmd "archives" "a" "List archives" |>> ListType.Archives
|
||||
<|> (cmd "models" "m" "List models" |>> ListType.Models)
|
||||
<|> (cmd "types" "t" "List types" |>> ListType.Types)
|
||||
with
|
||||
| ListType.Archives ->
|
||||
let! all = flag "all" null "List all archives"
|
||||
and! retired = flag "retired" null "List retired archives"
|
||||
and! refs = flag "refs" null "List referencing archives"
|
||||
and! archType = opt "type" null "type" "List archives of the given type"
|
||||
and! owner = opt "owner" null "user" "List archives owned by user"
|
||||
and! user = opt "user" null "user" "List archives for user"
|
||||
and! group = opt "group" null "group" "List archives for group"
|
||||
and! archiveName = opt "archive-name" null "pattern" "List archives matching pattern"
|
||||
and! modelName = opt "model-name" null "pattern" "List archives matching model area"
|
||||
and! verbose = flag "verbose" "V" "Detailed listing"
|
||||
and! json = flag "json" null "Json output"
|
||||
return
|
||||
ListArchives {
|
||||
All = all
|
||||
Retired = retired
|
||||
Refs = refs
|
||||
Type = archType
|
||||
Owner = owner
|
||||
User = user
|
||||
Group = group
|
||||
ArchiveName = archiveName
|
||||
ModelName = modelName
|
||||
Verbose = verbose
|
||||
Json = json
|
||||
},
|
||||
logLevel
|
||||
|
||||
| ListType.Models ->
|
||||
let! modelName = opt "model-name" null "regex" "List models matching regex"
|
||||
and! verbose = flag "verbose" null "Detailed listing"
|
||||
and! json = flag "json" null "Json output"
|
||||
return ListModels { ModelName = modelName; Verbose = verbose; Json = json }, logLevel
|
||||
|
||||
| ListType.Types -> return ListTypes logLevel, logLevel
|
||||
| CmdType.ShowCmd ->
|
||||
match!
|
||||
cmd "archive" "a" "Show archive details" |>> ShowType.Archive
|
||||
<|> (cmd "model" "m" "Show model details" |>> ShowType.Model)
|
||||
with
|
||||
| ShowType.Archive ->
|
||||
let! all = flag "all" null "List all available files (for resize)"
|
||||
and! refs = flag "refs" null "List archives referencing archive"
|
||||
and! related = flag "related" null "List related archives"
|
||||
and! files = flag "files" null "List file names"
|
||||
and! json = flag "json" null "Json output"
|
||||
and! archiveId = arg "archive-id" "Archive ID" |> reqArg |> parse parseArchiveId
|
||||
return
|
||||
ShowArchive {
|
||||
All = all
|
||||
Refs = refs
|
||||
Related = related
|
||||
Files = files
|
||||
Json = json
|
||||
ArchiveId = archiveId
|
||||
},
|
||||
logLevel
|
||||
|
||||
| ShowType.Model ->
|
||||
let! verbose = flag "verbose" null "Detailed listing"
|
||||
and! json = flag "json" null "Json output"
|
||||
and! modelId = arg "model-id" "Model ID" |> reqArg |> parse parseModelAreaId
|
||||
return ShowModel { Verbose = verbose; Json = json; ModelId = modelId }, logLevel
|
||||
|
||||
| CmdType.AddCmd ->
|
||||
match!
|
||||
cmd "archive" "a" "Add archive" |>> AddType.Archive
|
||||
<|> (cmd "sub" "s" "Add sub-archive" |>> AddType.Sub)
|
||||
<|> (cmd "model" "m" "Add model" |>> AddType.Model)
|
||||
<|> (cmd "owner" "o" "Add owner" |>> AddType.Owner)
|
||||
<|> (cmd "user" "u" "Add user" |>> AddType.User)
|
||||
<|> (cmd "group" "g" "Add group" |>> AddType.Group)
|
||||
<|> (cmd "type" "t" "Add type" |>> AddType.Type)
|
||||
with
|
||||
| AddType.Archive ->
|
||||
let! index = opt "index" null "file" "index.json"
|
||||
and! noSort = flag "no-sort" null "No sorting of files"
|
||||
and! id = opt "id" null "guid" "Archive id to update" |> optParse parseArchiveId
|
||||
and! force = flag "force" null "Forcefully add or update"
|
||||
and! published =
|
||||
opt "published" null "bool" "Publish archive (default: true)"
|
||||
|> optParse (fun s ->
|
||||
match Boolean.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid boolean value"
|
||||
)
|
||||
and! files =
|
||||
arg "files" "Files to add"
|
||||
|> Pipe.orStdIn
|
||||
// |> nonEmpty "No files to add"
|
||||
|> listParse Ok
|
||||
return
|
||||
AddArchive {
|
||||
Index = index
|
||||
NoSort = noSort
|
||||
Id = id
|
||||
Force = force
|
||||
Published = published
|
||||
Files = files
|
||||
},
|
||||
logLevel
|
||||
| AddType.Sub ->
|
||||
let! refId = opt "ref" null "guid" "Reference archive" |> optParse parseArchiveId |> reqOpt
|
||||
and! from =
|
||||
opt "from" null "int" "Index of first file to include"
|
||||
|> optParse (fun s ->
|
||||
match Int32.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid integer value"
|
||||
)
|
||||
|> reqOpt
|
||||
and! to' =
|
||||
opt "to" null "int" "Index of last file to include"
|
||||
|> optParse (fun s ->
|
||||
match Int32.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid integer value"
|
||||
)
|
||||
and! published =
|
||||
opt "published" null "bool" "Publish archive (default: true)"
|
||||
|> optParse (fun s ->
|
||||
match Boolean.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid boolean value"
|
||||
)
|
||||
and! name = arg "name" "Name of the new archive" |> reqArg
|
||||
return
|
||||
AddSub {
|
||||
Ref = refId
|
||||
From = from
|
||||
To = to'
|
||||
Published = published
|
||||
Name = name
|
||||
},
|
||||
logLevel
|
||||
| AddType.Model ->
|
||||
let! file = arg "file" "model.json" |> reqArg
|
||||
return AddModel { File = file }, logLevel
|
||||
| AddType.Owner ->
|
||||
let! archive = opt "archive" null "id" "Apply to archive" |> optParse parseArchiveId
|
||||
and! ids =
|
||||
arg "ids" "Identities"
|
||||
|> Pipe.orStdIn
|
||||
|> nonEmpty "No ids to add"
|
||||
|> listParse Ok
|
||||
return AddOwner { Archive = archive; Ids = ids }, logLevel
|
||||
| AddType.User ->
|
||||
let! archive = opt "archive" null "id" "Apply to archive" |> optParse parseArchiveId
|
||||
and! ids =
|
||||
arg "ids" "Identities"
|
||||
|> Pipe.orStdIn
|
||||
|> nonEmpty "No ids to add"
|
||||
|> listParse Ok
|
||||
return AddUser { Archive = archive; Ids = ids }, logLevel
|
||||
| AddType.Group ->
|
||||
let! archive = opt "archive" null "id" "Apply to archive" |> optParse parseArchiveId
|
||||
and! ids =
|
||||
arg "ids" "Identities"
|
||||
|> Pipe.orStdIn
|
||||
|> nonEmpty "No ids to add"
|
||||
|> listParse Ok
|
||||
return AddGroup { Archive = archive; Ids = ids }, logLevel
|
||||
|
||||
| AddType.Type ->
|
||||
let! typeName = arg "type" "Type name" |> reqArg
|
||||
return AddType typeName, logLevel
|
||||
|
||||
| CmdType.DeleteCmd ->
|
||||
match!
|
||||
cmd "archive" "a" "Delete archive" |>> DeleteType.Archive
|
||||
<|> (cmd "model" "m" "Delete model" |>> DeleteType.Model)
|
||||
<|> (cmd "owner" "o" "Delete owner" |>> DeleteType.Owner)
|
||||
<|> (cmd "user" "u" "Delete user" |>> DeleteType.User)
|
||||
<|> (cmd "group" "g" "Delete group" |>> DeleteType.Group)
|
||||
<|> (cmd "type" "t" "Delete type" |>> DeleteType.Type)
|
||||
with
|
||||
| DeleteType.Archive ->
|
||||
let! id = arg "id" "Archive ID" |> reqArg
|
||||
return DeleteArchive id, logLevel
|
||||
|
||||
| DeleteType.Model ->
|
||||
let! force = flag "force" null "Force delete"
|
||||
and! modelId = arg "model-id" "Model ID" |> reqArg |> parse parseModelAreaId
|
||||
return DeleteModel { Force = force; ModelId = modelId }, logLevel
|
||||
|
||||
| DeleteType.Owner ->
|
||||
let! archive = opt "archive" null "id" "Apply to archive" |> optParse parseArchiveId
|
||||
and! ids =
|
||||
arg "ids" "Identities"
|
||||
|> Pipe.orStdIn
|
||||
|> nonEmpty "No ids to add"
|
||||
|> listParse Ok
|
||||
return DeleteOwner { Archive = archive; Ids = ids }, logLevel
|
||||
|
||||
| DeleteType.User ->
|
||||
let! archive = opt "archive" null "id" "Apply to archive" |> optParse parseArchiveId
|
||||
and! ids =
|
||||
arg "ids" "Identities"
|
||||
|> Pipe.orStdIn
|
||||
|> nonEmpty "No ids to add"
|
||||
|> listParse Ok
|
||||
return DeleteUser { Archive = archive; Ids = ids }, logLevel
|
||||
|
||||
| DeleteType.Group ->
|
||||
let! archive = opt "archive" null "id" "Apply to archive" |> optParse parseArchiveId
|
||||
and! ids =
|
||||
arg "ids" "Identities"
|
||||
|> Pipe.orStdIn
|
||||
|> nonEmpty "No ids to add"
|
||||
|> listParse Ok
|
||||
return DeleteGroup { Archive = archive; Ids = ids }, logLevel
|
||||
|
||||
| DeleteType.Type ->
|
||||
let! typeName = arg "type" "Type name" |> reqArg
|
||||
return DeleteType typeName, logLevel
|
||||
|
||||
| CmdType.ModifyCmd ->
|
||||
match!
|
||||
cmd "archive" "a" "Modify archive" |>> ModifyType.Archive
|
||||
<|> (cmd "archive-attribs" "t" "Modify archive attributes"
|
||||
|>> ModifyType.ArchiveAttribs)
|
||||
<|> (cmd "model" "m" "Modify model" |>> ModifyType.Model)
|
||||
with
|
||||
| ModifyType.Archive ->
|
||||
let! name = opt "name" null "name" "Name of archive"
|
||||
and! published =
|
||||
opt "published" null "bool" "Publish archive"
|
||||
|> optParse (fun s ->
|
||||
match Boolean.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid boolean value"
|
||||
)
|
||||
and! public' =
|
||||
opt "public" null "bool" "Make archive public (careful!)"
|
||||
|> optParse (fun s ->
|
||||
match Boolean.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid boolean value"
|
||||
)
|
||||
and! expires = opt "expires" null "datetime" "Set expiry"
|
||||
and! json = opt "json" null "file" "Any json you fancy"
|
||||
and! fence =
|
||||
opt "fence" null "points" "Geofence points given as 'lng,lat',...'"
|
||||
|> optParse (fun s -> Ok (s.Split (',') |> Array.toList))
|
||||
and! endFlag = flag "end" null "End fence list (sic)"
|
||||
and! archiveId = arg "archive-id" "Archive to modify" |> reqArg |> parse parseArchiveId
|
||||
return
|
||||
ModifyArchive {
|
||||
Name = name
|
||||
Published = published
|
||||
Public = public'
|
||||
Expires = expires
|
||||
Json = json
|
||||
Fence = fence
|
||||
End = endFlag
|
||||
ArchiveId = archiveId
|
||||
},
|
||||
logLevel
|
||||
|
||||
| ModifyType.ArchiveAttribs ->
|
||||
let! basePath = opt "base-path" null "path" "Base path"
|
||||
and! projection = opt "projection" null "proj" "Projection"
|
||||
and! description = opt "description" null "desc" "Description"
|
||||
and! focal = opt "focal" null "x,y" "Focal point" |> optParse parseFocal
|
||||
and! zoom =
|
||||
opt "zoom" null "level" "Zoom level"
|
||||
|> optParse (fun s ->
|
||||
match Single.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid float value"
|
||||
)
|
||||
and! retired =
|
||||
opt "retired" null "bool" "Retired status"
|
||||
|> optParse (fun s ->
|
||||
match Boolean.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid boolean value"
|
||||
)
|
||||
and! polygon = opt "polygon" null "file" "Polygon file"
|
||||
and! modelArea = opt "model-area" null "id" "Model area ID" |> optParse parseModelAreaId
|
||||
and! json = opt "json" null "json" "JSON data"
|
||||
and! addRelated = opt "add-related" null "id" "Add related archive" |> optParse parseArchiveId
|
||||
and! removeRelated =
|
||||
opt "remove-related" null "id" "Remove related archive"
|
||||
|> optParse parseArchiveId
|
||||
and! archiveId = arg "archive-id" "Archive ID" |> reqArg |> parse parseModelAreaId
|
||||
return
|
||||
ModifyArchiveAttribs {
|
||||
BasePath = basePath
|
||||
Projection = projection
|
||||
Description = description
|
||||
Focal = focal
|
||||
Zoom = zoom
|
||||
Retired = retired
|
||||
Polygon = polygon
|
||||
ModelArea = modelArea
|
||||
Json = json
|
||||
AddRelated = addRelated
|
||||
RemoveRelated = removeRelated
|
||||
ArchiveId = archiveId
|
||||
},
|
||||
logLevel
|
||||
|
||||
| ModifyType.Model ->
|
||||
let! name = opt "name" null "name" "Model name"
|
||||
and! description = opt "description" null "desc" "Description"
|
||||
and! focal = opt "focal" null "x,y" "Focal point" |> optParse parseFocal
|
||||
and! zoom =
|
||||
opt "zoom" null "level" "Zoom level"
|
||||
|> optParse (fun s ->
|
||||
match Single.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid float value"
|
||||
)
|
||||
and! polygon = opt "polygon" null "file" "Bounding polygon file"
|
||||
and! projection = opt "projection" null "proj" "Projection of bounding polygon"
|
||||
and! modelId = arg "model-id" "Model ID" |> reqArg |> parse parseModelAreaId
|
||||
return
|
||||
ModifyModel {
|
||||
Name = name
|
||||
Description = description
|
||||
Focal = focal
|
||||
Zoom = zoom
|
||||
Polygon = polygon
|
||||
Projection = projection
|
||||
ModelId = modelId
|
||||
},
|
||||
logLevel
|
||||
|
||||
| CmdType.AugmentCmd ->
|
||||
let! archive =
|
||||
opt "archive" null "guid" "Archive id to augment"
|
||||
|> optParse parseArchiveId
|
||||
|> reqOpt
|
||||
and! files =
|
||||
arg "files" "Files to add"
|
||||
|> Pipe.orStdIn
|
||||
|> nonEmpty "No files to add"
|
||||
|> listParse Ok
|
||||
return Augment { Archive = archive; Files = files }, logLevel
|
||||
|
||||
| CmdType.ResizeCmd ->
|
||||
let! from =
|
||||
opt "from" null "int" "Index of first file to include"
|
||||
|> optParse (fun s ->
|
||||
match Int32.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid integer value"
|
||||
)
|
||||
|> reqOpt
|
||||
and! to' =
|
||||
opt "to" null "int" "Index of last file to include"
|
||||
|> optParse (fun s ->
|
||||
match Int32.TryParse s with
|
||||
| true, v -> Ok v
|
||||
| false, _ -> Error "Invalid integer value"
|
||||
)
|
||||
and! archive = arg "archive" "Archive to resize" |> reqArg |> parse parseArchiveId
|
||||
return Resize { From = from; To = to'; Archive = archive }, logLevel
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
module Listing
|
||||
|
||||
open System.Text.RegularExpressions
|
||||
open Archmaester.Dto
|
||||
open Argu
|
||||
open FSharpPlus
|
||||
open Serilog
|
||||
open Args
|
||||
open Oceanbox.DataAgent
|
||||
open System.Text.RegularExpressions
|
||||
|
||||
open Args
|
||||
open Archmaester.Dto
|
||||
open Oceanbox.DataAgent
|
||||
|
||||
let getArchives archiveIds =
|
||||
archiveIds
|
||||
@@ -21,8 +20,10 @@ let listModels verbose (filterM: ModelArea -> bool) (filterA: ArchiveProps -> bo
|
||||
|> Result.map (
|
||||
Array.filter filterM
|
||||
>> Array.iter (fun m ->
|
||||
let archives = ArchiveCli.getModelAreaArchives m.modelAreaId |> Async.RunSynchronously
|
||||
let archives =
|
||||
ArchiveCli.getModelAreaArchives m.modelAreaId |> Async.RunSynchronously
|
||||
match archives with
|
||||
| Error e -> Log.Error e
|
||||
| Ok arch ->
|
||||
let ax = arch |> Array.filter filterA
|
||||
|
||||
@@ -32,67 +33,64 @@ let listModels verbose (filterM: ModelArea -> bool) (filterA: ArchiveProps -> bo
|
||||
else
|
||||
Utils.printModelTerse m
|
||||
Utils.printArchivesTerse ax
|
||||
|
||||
printfn ""
|
||||
| Error e -> Log.Error e)
|
||||
printfn "")
|
||||
)
|
||||
|> Result.defaultWith (fun e -> Log.Error("Listing.listModels error fetching model areas {Error}", e))
|
||||
|> Result.defaultWith (fun e -> Log.Error ("Listing.listModels error fetching model areas {Error}", e))
|
||||
|
||||
let listArchives (args: ParseResults<ListArchive>) =
|
||||
let verbose = args.Contains ListArchive.Verbose
|
||||
let retired = args.Contains ListArchive.Retired
|
||||
let listArchives (args: ListArchiveArgs) =
|
||||
let verbose = args.Verbose
|
||||
let retired = args.Retired
|
||||
|
||||
let matchO (a: ArchiveDto) =
|
||||
if args.Contains ListArchive.Owner then
|
||||
let pat = args.GetResult ListArchive.Owner
|
||||
a.acl.owners |> Array.exists (fun y -> Regex.IsMatch(y, pat))
|
||||
else
|
||||
true
|
||||
match args.Owner with
|
||||
| None -> true
|
||||
| Some owner ->
|
||||
let pat = owner
|
||||
a.acl.owners |> Array.exists (fun y -> Regex.IsMatch (y, pat))
|
||||
|
||||
let matchU (a: ArchiveDto) =
|
||||
if args.Contains ListArchive.User then
|
||||
let pat = args.GetResult ListArchive.User
|
||||
|
||||
a.acl.users |> Array.exists (fun y -> Regex.IsMatch(y, pat))
|
||||
|| a.acl.owners |> Array.exists (fun y -> Regex.IsMatch(y, pat))
|
||||
else
|
||||
true
|
||||
match args.User with
|
||||
| None -> true
|
||||
| Some user ->
|
||||
let pat = user
|
||||
a.acl.users |> Array.exists (fun y -> Regex.IsMatch (y, pat))
|
||||
|| a.acl.owners |> Array.exists (fun y -> Regex.IsMatch (y, pat))
|
||||
|
||||
let matchG (a: ArchiveDto) =
|
||||
if args.Contains ListArchive.Group then
|
||||
let pat = args.GetResult ListArchive.Group
|
||||
a.acl.groups |> Array.exists (fun y -> Regex.IsMatch(y, pat))
|
||||
else
|
||||
true
|
||||
match args.Group with
|
||||
| None -> true
|
||||
| Some group ->
|
||||
let pat = group
|
||||
a.acl.groups |> Array.exists (fun y -> Regex.IsMatch (y, pat))
|
||||
|
||||
let matchM (m: ModelArea) =
|
||||
if args.Contains ListArchive.Model_Name then
|
||||
let pat = args.GetResult ListArchive.Model_Name
|
||||
Regex.IsMatch(m.name, pat)
|
||||
else
|
||||
true
|
||||
match args.ModelName with
|
||||
| None -> true
|
||||
| Some modelName ->
|
||||
let pat = modelName
|
||||
Regex.IsMatch (m.name, pat)
|
||||
|
||||
let matchA (a: ArchiveProps) =
|
||||
if args.Contains Archive_Name then
|
||||
let pat = args.GetResult Archive_Name
|
||||
printfn "List Archives pattern %s" pat
|
||||
Regex.IsMatch(a.name, pat)
|
||||
else
|
||||
true
|
||||
match args.ArchiveName with
|
||||
| None -> true
|
||||
| Some archiveName ->
|
||||
let pat = archiveName
|
||||
printfn $"List Archives pattern %s{pat}"
|
||||
Regex.IsMatch (a.name, pat)
|
||||
|
||||
let matchBox (a: ArchiveProps) =
|
||||
matchA a //&& matchO a && matchU a && matchG a
|
||||
// NOTE: Only checks for archive props
|
||||
let matchBox (a: ArchiveProps) = matchA a //&& matchO a && matchU a && matchG a
|
||||
|
||||
if args.Contains ListArchive.All then
|
||||
if args.All then
|
||||
listModels verbose matchM matchA
|
||||
elif args.Contains ListArchive.Type then
|
||||
elif args.Type.IsSome then
|
||||
let t =
|
||||
let spec = args.GetResult ListArchive.Type
|
||||
let spec = args.Type |> Option.get
|
||||
|
||||
try
|
||||
ArchiveType.FromString spec
|
||||
with _ ->
|
||||
Log.Warning $"Unknown archive type: {spec}"
|
||||
Log.Warning $"Unknown archive type: %s{spec}"
|
||||
ArchiveType.Any
|
||||
|
||||
let archiveF (a: ArchiveProps) = a.archiveType = t && matchBox a
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
module Archivist
|
||||
|
||||
open Fargo
|
||||
open Serilog
|
||||
open Serilog.Events
|
||||
open Argu
|
||||
|
||||
open Args
|
||||
|
||||
let configureSerilog level =
|
||||
@@ -17,103 +18,96 @@ let configureSerilog level =
|
||||
LoggerConfiguration()
|
||||
.MinimumLevel.Is(n)
|
||||
.WriteTo.Console(theme = Serilog.Sinks.SystemConsole.Themes.ConsoleTheme.None)
|
||||
.CreateLogger()
|
||||
.CreateLogger ()
|
||||
|
||||
let addHandler (args: ParseResults<Add>) =
|
||||
if args.Contains Add.Archive then
|
||||
ArchiveCli.addArchive (args.GetResult Add.Archive)
|
||||
elif args.Contains Add.Sub then
|
||||
ArchiveCli.createSubArchive (args.GetResult Add.Sub)
|
||||
elif args.Contains Add.Model then
|
||||
ModelAreaCli.addModel (args.GetResult Add.Model)
|
||||
elif args.Contains Add.Owner then
|
||||
AclCli.addOwners (args.GetResult Add.Owner)
|
||||
elif args.Contains Add.User then
|
||||
AclCli.addUsers (args.GetResult Add.User)
|
||||
elif args.Contains Add.Group then
|
||||
AclCli.addGroups (args.GetResult Add.Group)
|
||||
elif args.Contains Add.Type then
|
||||
ArchiveCli.addType (args.GetResult Add.Type)
|
||||
else
|
||||
printfn $"{args.Parser.PrintUsage()}"
|
||||
let executeCommand (ct: System.Threading.CancellationToken) (cmd: Command * int) =
|
||||
task {
|
||||
let logLevel = snd cmd
|
||||
|
||||
let listHandler (args: ParseResults<List>) =
|
||||
if args.Contains List.Archives then
|
||||
Listing.listArchives (args.GetResult List.Archives)
|
||||
elif args.Contains List.Models then
|
||||
ModelAreaCli.listModels (args.GetResult List.Models)
|
||||
else
|
||||
eprintfn "No list subcommand listed"
|
||||
eprintfn "%s" (args.Parser.PrintUsage())
|
||||
()
|
||||
Log.Logger <- configureSerilog logLevel
|
||||
|
||||
let showHandler (args: ParseResults<Show>) =
|
||||
if args.Contains Show.Archive then
|
||||
let show = args.GetResult Show.Archive
|
||||
printfn $"Archivist connection string: %s{Settings.archmaesterUrl}"
|
||||
|
||||
if show.Contains Related then
|
||||
ArchiveCli.showRelatedArchives show
|
||||
else
|
||||
ArchiveCli.showArchive show
|
||||
elif args.Contains Show.Model then
|
||||
ModelAreaCli.showModel (args.GetResult Show.Model)
|
||||
else
|
||||
args.Parser.PrintUsage() |> printfn "%s"
|
||||
|
||||
let deleteHandler (args: ParseResults<Delete>) =
|
||||
if args.Contains Delete.Archive then
|
||||
ArchiveCli.deleteArchives args
|
||||
elif args.Contains Delete.Model then
|
||||
ModelAreaCli.deleteModel (args.GetResult Delete.Model)
|
||||
elif args.Contains Delete.Owner then
|
||||
AclCli.deleteOwners (args.GetResult Delete.Owner)
|
||||
elif args.Contains Delete.User then
|
||||
AclCli.deleteUsers (args.GetResult Delete.User)
|
||||
elif args.Contains Delete.Group then
|
||||
AclCli.deleteGroups (args.GetResult Delete.Group)
|
||||
elif args.Contains Delete.Type then
|
||||
ArchiveCli.deleteType (args.GetResult Delete.Type)
|
||||
else
|
||||
()
|
||||
|
||||
let modifyHandler (args: ParseResults<Modify>) =
|
||||
if args.Contains Modify.Archive then
|
||||
ArchiveCli.modifyArchive (args.GetResult Modify.Archive)
|
||||
elif args.Contains Modify.ArchiveAttribs then
|
||||
ArchiveCli.modifyArchiveAttribs (args.GetResult Modify.ArchiveAttribs)
|
||||
elif args.Contains Modify.Model then
|
||||
ModelAreaCli.modifyModel (args.GetResult Modify.Model)
|
||||
else
|
||||
()
|
||||
match fst cmd with
|
||||
| ModifyArchive args ->
|
||||
ArchiveCli.modifyArchive args
|
||||
return 0
|
||||
| ModifyArchiveAttribs args ->
|
||||
ArchiveCli.modifyArchiveAttribs args
|
||||
return 0
|
||||
| ModifyModel args ->
|
||||
ModelAreaCli.modifyModel args
|
||||
return 0
|
||||
| ShowArchive args ->
|
||||
if args.Related then
|
||||
ArchiveCli.showRelatedArchives args
|
||||
return 0
|
||||
else
|
||||
ArchiveCli.showArchive args
|
||||
return 0
|
||||
| ShowModel args ->
|
||||
ModelAreaCli.showModel args
|
||||
return 0
|
||||
| ListArchives args ->
|
||||
Listing.listArchives args
|
||||
return 0
|
||||
| ListModels args ->
|
||||
ModelAreaCli.listModels args
|
||||
return 0
|
||||
| ListTypes args ->
|
||||
// NOTE: Not yet defined
|
||||
// ArchiveCli.c args
|
||||
return 0
|
||||
| AddArchive args ->
|
||||
ArchiveCli.addArchive args
|
||||
return 0
|
||||
| AddSub args ->
|
||||
ArchiveCli.createSubArchive args
|
||||
return 0
|
||||
| AddModel args ->
|
||||
ModelAreaCli.addModel args
|
||||
return 0
|
||||
| AddOwner args ->
|
||||
AclCli.addOwners args
|
||||
return 0
|
||||
| AddGroup args ->
|
||||
AclCli.addGroups args
|
||||
return 0
|
||||
| AddUser args ->
|
||||
AclCli.addUsers args
|
||||
return 0
|
||||
| AddType args ->
|
||||
ArchiveCli.addType args
|
||||
return 0
|
||||
| DeleteArchive args ->
|
||||
ArchiveCli.deleteArchives args
|
||||
return 0
|
||||
| DeleteModel args ->
|
||||
ModelAreaCli.deleteModel args
|
||||
return 0
|
||||
| DeleteOwner args ->
|
||||
AclCli.deleteOwners args
|
||||
return 0
|
||||
| DeleteGroup args ->
|
||||
AclCli.deleteGroups args
|
||||
return 0
|
||||
| DeleteUser args ->
|
||||
AclCli.deleteUsers args
|
||||
return 0
|
||||
| DeleteType args ->
|
||||
ArchiveCli.deleteType args
|
||||
return 0
|
||||
| Augment args ->
|
||||
ArchiveCli.augmentArchive args
|
||||
return 0
|
||||
| Resize args ->
|
||||
ArchiveCli.resizeArchive args
|
||||
return 0
|
||||
| Version _ ->
|
||||
showVersion ()
|
||||
return 0
|
||||
}
|
||||
|
||||
[<EntryPoint>]
|
||||
let main argv =
|
||||
let parser =
|
||||
ArgumentParser.Create<Verbs>(programName = "Archivist", errorHandler = errorHandler)
|
||||
|
||||
let args = parser.Parse argv
|
||||
|
||||
Log.Logger <- configureSerilog (args.GetResult(Log_Level, defaultValue = 3))
|
||||
|
||||
printfn $"Archivist connection string: {Settings.archmaesterUrl}"
|
||||
|
||||
if args.Contains Add then
|
||||
addHandler (args.GetResult Add)
|
||||
elif args.Contains List then
|
||||
listHandler (args.GetResult List)
|
||||
elif args.Contains Show then
|
||||
showHandler (args.GetResult Show)
|
||||
elif args.Contains Delete then
|
||||
deleteHandler (args.GetResult Delete)
|
||||
elif args.Contains Modify then
|
||||
modifyHandler (args.GetResult Modify)
|
||||
elif args.Contains Augment then
|
||||
ArchiveCli.augmentArchive (args.GetResult Augment)
|
||||
elif args.Contains Resize then
|
||||
ArchiveCli.resizeArchive (args.GetResult Resize)
|
||||
elif args.Contains Version then
|
||||
showVersion ()
|
||||
else
|
||||
parser.PrintUsage() |> printfn "%s"
|
||||
|
||||
0
|
||||
run "archivist" argParser argv executeCommand
|
||||
@@ -1,15 +1,15 @@
|
||||
module ModelAreaCli
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open Archmaester
|
||||
open Argu
|
||||
open Args
|
||||
open FSharpPlus
|
||||
open Serilog
|
||||
open System
|
||||
open System.IO
|
||||
|
||||
open Args
|
||||
open ArchiveIndex
|
||||
open Oceanbox.DataAgent
|
||||
open Archmaester
|
||||
open Archmaester.Dto
|
||||
open Oceanbox.DataAgent
|
||||
|
||||
let inline private execAsync job =
|
||||
job
|
||||
@@ -24,25 +24,25 @@ let inline private execAsync job =
|
||||
/// <param name="modelArea">The model area</param>
|
||||
let postModelArea modelArea =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let manage = api.adminApi ()
|
||||
async { return! manage.addModelArea modelArea })
|
||||
|
||||
let findModelAreaId (name: string) : Async<Result<ModelAreaId, string>> =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let archmaester = api.adminApi ()
|
||||
archmaester.queryModelAreaId name)
|
||||
|
||||
let listModelArchives modelAreaId =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let inventory = api.modelAreaApi ()
|
||||
|
||||
async {
|
||||
try
|
||||
let! m = inventory.getModelArea modelAreaId
|
||||
return m |> Option.toResultWith "error"
|
||||
let! m = inventory.getModelArea modelAreaId
|
||||
return m |> Option.toResultWith "error"
|
||||
with exn ->
|
||||
Log.Error exn.Message
|
||||
return Error exn.Message
|
||||
@@ -50,7 +50,7 @@ let listModelArchives modelAreaId =
|
||||
|
||||
let listModelArchivesAdmin (mid, filter: ArchiveFilter) =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let archmaester = api.archiveApi ()
|
||||
|
||||
let tp =
|
||||
@@ -67,16 +67,16 @@ let listModelArchivesAdmin (mid, filter: ArchiveFilter) =
|
||||
|
||||
let getModelArea modelId =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let archmaester = api.modelAreaApi ()
|
||||
async {
|
||||
let! m = archmaester.getModelArea modelId
|
||||
return m |> Option.toResultWith "error"
|
||||
let! m = archmaester.getModelArea modelId
|
||||
return m |> Option.toResultWith "error"
|
||||
})
|
||||
|
||||
let getBaseModelArea () =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let archmaester = api.modelAreaApi ()
|
||||
|
||||
async {
|
||||
@@ -90,14 +90,13 @@ let getBaseModelArea () =
|
||||
let getBaseModelAreas (helloWorld: Guid) : Result<ModelArea[], string> =
|
||||
Log.Information $"Fetching model area {helloWorld} model areas:"
|
||||
withCliAuth (fun auth ->
|
||||
let intra = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = intra.modelAreaApi()
|
||||
api.getSubModelAreas helloWorld
|
||||
|> Async.map Ok)
|
||||
let intra = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let api = intra.modelAreaApi ()
|
||||
api.getSubModelAreas helloWorld |> Async.map Ok)
|
||||
|> Async.RunSynchronously
|
||||
|
||||
let addModel (args: ParseResults<AddModel>) =
|
||||
let file = args.GetResult AddModel.File |> Path.GetFullPath
|
||||
let addModel (args: AddModelArgs) =
|
||||
let file = args.File |> Path.GetFullPath
|
||||
let basePath = Path.GetDirectoryName file
|
||||
|
||||
match readModelAreaFile file with
|
||||
@@ -122,7 +121,7 @@ let addModel (args: ParseResults<AddModel>) =
|
||||
Log.Debug $"{mdl}"
|
||||
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let adminApi = api.adminApi ()
|
||||
|
||||
async {
|
||||
@@ -130,7 +129,7 @@ let addModel (args: ParseResults<AddModel>) =
|
||||
match! adminApi.addModelArea mdl with
|
||||
| Ok mid ->
|
||||
Log.Information $"Added model {mid}"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -140,29 +139,29 @@ let addModel (args: ParseResults<AddModel>) =
|
||||
|> execAsync
|
||||
| Error e -> Log.Error $"Error: {e}"
|
||||
|
||||
let listModels (args: ParseResults<ListModel>) =
|
||||
let listModels (args: ListModelArgs) =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let inventory = api.modelAreaApi ()
|
||||
|
||||
async {
|
||||
try
|
||||
let! models =inventory.getSubModelAreas Guid.Empty
|
||||
let! models = inventory.getSubModelAreas Guid.Empty
|
||||
models |> Array.iter (fun m -> printfn $"{m.name}: {m.modelAreaId}")
|
||||
return Ok()
|
||||
return Ok ()
|
||||
with exn ->
|
||||
return Error exn.Message
|
||||
})
|
||||
|> execAsync
|
||||
|
||||
let showModel (args: ParseResults<ShowModel>) =
|
||||
let showModel (args: ShowModelArgs) =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let inventory = api.modelAreaApi ()
|
||||
|
||||
async {
|
||||
try
|
||||
match! inventory.getModelArea (args.GetResult ShowModel.Model) with
|
||||
match! inventory.getModelArea (args.ModelId) with
|
||||
| Some m ->
|
||||
printfn $"{m.name}: {{{m.modelAreaId}}}"
|
||||
printfn $" Desc.: {m.description}"
|
||||
@@ -174,7 +173,7 @@ let showModel (args: ParseResults<ShowModel>) =
|
||||
if m.parent.IsSome then
|
||||
printfn $" Parent: {m.parent.Value}"
|
||||
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| None ->
|
||||
Log.Error $"error"
|
||||
return Error "error"
|
||||
@@ -183,36 +182,34 @@ let showModel (args: ParseResults<ShowModel>) =
|
||||
})
|
||||
|> execAsync
|
||||
|
||||
let modifyModel (args: ParseResults<ModifyModel>) =
|
||||
let modifyModel (args: ModifyModelArgs) =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let modelApi = api.modelAreaApi ()
|
||||
let adminApi = api.adminApi ()
|
||||
|
||||
let poly (m: ModelArea) =
|
||||
let proj = args.TryGetResult ModifyModel.Projection
|
||||
let proj = args.Projection
|
||||
|
||||
if args.Contains ModifyModel.Polygon then
|
||||
readBoundingPolygon proj (args.GetResult ModifyModel.Polygon) |> Option.ofResult
|
||||
elif m.polygon = [||] then
|
||||
None
|
||||
else
|
||||
Some m.polygon
|
||||
match args.Polygon with
|
||||
| None -> Some m.polygon
|
||||
| Some poly when m.polygon = [||] -> None
|
||||
| Some poly -> readBoundingPolygon proj poly |> Option.ofResult
|
||||
|
||||
async {
|
||||
try
|
||||
match! modelApi.getModelArea (args.GetResult ModifyModel.ModelId) with
|
||||
match! modelApi.getModelArea args.ModelId with
|
||||
| Some m ->
|
||||
let form: Forms.ModelAreaForm = {
|
||||
name = args.GetResult(ModifyModel.Name, m.name)
|
||||
description = args.GetResult(ModifyModel.Description, m.description)
|
||||
focalPoint = args.GetResult(ModifyModel.Focal, m.focalPoint)
|
||||
defaultZoom = args.GetResult(ModifyModel.Zoom, m.defaultZoom)
|
||||
name = args.Name |> Option.defaultValue m.name
|
||||
description = args.Description |> Option.defaultValue m.description
|
||||
focalPoint = args.Focal |> Option.defaultValue m.focalPoint
|
||||
defaultZoom = args.Zoom |> Option.defaultValue m.defaultZoom
|
||||
json = if m.json = "" then None else Some m.json
|
||||
geometry = poly m
|
||||
}
|
||||
|
||||
return! adminApi.updateModelArea (args.GetResult ModifyModel.ModelId, form)
|
||||
return! adminApi.updateModelArea (args.ModelId, form)
|
||||
| None ->
|
||||
Log.Error $"error"
|
||||
return Error "error"
|
||||
@@ -221,13 +218,13 @@ let modifyModel (args: ParseResults<ModifyModel>) =
|
||||
})
|
||||
|> execAsync
|
||||
|
||||
let deleteModel (args: ParseResults<DeleteModel>) =
|
||||
let mid = args.GetResult DeleteModel.Model
|
||||
let force = args.Contains DeleteModel.Force
|
||||
let deleteModel (args: DeleteModelArgs) =
|
||||
let mid = args.ModelId
|
||||
let force = args.Force
|
||||
|
||||
let action () =
|
||||
withCliAuth (fun auth ->
|
||||
let api = Remoting.v1.InternalApi(Settings.archmaesterUrl, auth)
|
||||
let api = Remoting.v1.InternalApi (Settings.archmaesterUrl, auth)
|
||||
let adminApi = api.adminApi ()
|
||||
|
||||
async {
|
||||
@@ -235,7 +232,7 @@ let deleteModel (args: ParseResults<DeleteModel>) =
|
||||
match! adminApi.deleteModelArea mid with
|
||||
| Ok _ ->
|
||||
Log.Information $"Deleted model {mid} and all dependent archives"
|
||||
return Ok()
|
||||
return Ok ()
|
||||
| Error e ->
|
||||
Log.Error $"Error: {e}"
|
||||
return Error e
|
||||
@@ -250,7 +247,7 @@ let deleteModel (args: ParseResults<DeleteModel>) =
|
||||
printfn "WARNING: This will remove the modeal area and ALL dependent archives!"
|
||||
printfn "Do you want to continue YES/[no]?"
|
||||
|
||||
if Console.ReadLine() = "YES" then
|
||||
if Console.ReadLine () = "YES" then
|
||||
action ()
|
||||
else
|
||||
Environment.Exit 0
|
||||
@@ -3,7 +3,7 @@ module Settings
|
||||
open System
|
||||
|
||||
let base64enc (s: string) =
|
||||
Text.ASCIIEncoding.UTF8.GetBytes(s) |> Convert.ToBase64String
|
||||
Text.ASCIIEncoding.UTF8.GetBytes s |> Convert.ToBase64String
|
||||
|
||||
let tryGetEnv =
|
||||
Environment.GetEnvironmentVariable
|
||||
@@ -17,5 +17,4 @@ let archmaesterUrl =
|
||||
|
||||
let cliAuth = tryGetEnv "ARCHMAESTER_AUTH" |> Option.map base64enc
|
||||
|
||||
|
||||
let julianStart = DateTime.Parse("1858-11-17 00:00:00Z").ToUniversalTime()
|
||||
let julianStart = DateTime.Parse("1858-11-17 00:00:00Z").ToUniversalTime ()
|
||||
859
src/Archivist/src/Cli/packages.lock.json
Normal file
859
src/Archivist/src/Cli/packages.lock.json
Normal file
@@ -0,0 +1,859 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dependencies": {
|
||||
"net10.0": {
|
||||
"Fargo.CmdLine": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.7.5, )",
|
||||
"resolved": "1.7.5",
|
||||
"contentHash": "u2fPQAmwJSAfCJRUDoN1NEg1ZmkZw5NsbvgLHhkCjLCkefEiRS/2EVu0W5BcxgkehkgI0Wx6E2qn7rnpPR2YKQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "8.0.100"
|
||||
}
|
||||
},
|
||||
"FSharp.Core": {
|
||||
"type": "Direct",
|
||||
"requested": "[9.0.303, )",
|
||||
"resolved": "9.0.303",
|
||||
"contentHash": "6JlV8aD8qQvcmfoe/PMOxCHXc0uX4lR23u0fAyQtnVQxYULLoTZgwgZHSnRcuUHOvS3wULFWcwdnP1iwslH60g=="
|
||||
},
|
||||
"FSharp.Data": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.4.1, )",
|
||||
"resolved": "6.4.1",
|
||||
"contentHash": "P/ShAsNsuKrV9cpK7Mb/fSJ/kpinjOnVGRDXDzi/dYECS/lmlDrAvNVlodPbqCo5hIXvMMkKMc5C4f8ULLW7JQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.1",
|
||||
"FSharp.Data.Csv.Core": "6.4.1",
|
||||
"FSharp.Data.Html.Core": "6.4.1",
|
||||
"FSharp.Data.Http": "6.4.1",
|
||||
"FSharp.Data.Json.Core": "6.4.1",
|
||||
"FSharp.Data.Runtime.Utilities": "6.4.1",
|
||||
"FSharp.Data.WorldBank.Core": "6.4.1",
|
||||
"FSharp.Data.Xml.Core": "6.4.1"
|
||||
}
|
||||
},
|
||||
"FSharpPlus": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.7.0, )",
|
||||
"resolved": "1.7.0",
|
||||
"contentHash": "9+PXT3nG7K5bzgYOzxgwZu5ij25BH7OtMkMJUrWkf+HcfbvsEGCvIf3InF8MCvJ5lO02NfGb9fC8slLEytqw0Q==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.6"
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore": {
|
||||
"type": "Direct",
|
||||
"requested": "[9.0.1, )",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "E25w4XugXNykTr5Y/sLDGaQ4lf67n9aXVPvsdGsIZjtuLmbvb9AoYP8D50CDejY8Ro4D9GK2kNHz5lWHqSK+wg==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore.Abstractions": "9.0.1",
|
||||
"Microsoft.EntityFrameworkCore.Analyzers": "9.0.1",
|
||||
"Microsoft.Extensions.Caching.Memory": "9.0.1",
|
||||
"Microsoft.Extensions.Logging": "9.0.1"
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Design": {
|
||||
"type": "Direct",
|
||||
"requested": "[9.0.1, )",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "/pchcadGU57ChRYH0/bvLTeU/n1mpWO+0pVK7pUzzuwRu5SIQb8dVMZVPhzvEI2VO5rP1yricSQBBnOmDqQhvg==",
|
||||
"dependencies": {
|
||||
"Humanizer.Core": "2.14.1",
|
||||
"Microsoft.Build.Framework": "17.8.3",
|
||||
"Microsoft.Build.Locator": "1.7.8",
|
||||
"Microsoft.CodeAnalysis.CSharp": "4.8.0",
|
||||
"Microsoft.CodeAnalysis.CSharp.Workspaces": "4.8.0",
|
||||
"Microsoft.CodeAnalysis.Workspaces.MSBuild": "4.8.0",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "9.0.1",
|
||||
"Microsoft.Extensions.Caching.Memory": "9.0.1",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyModel": "9.0.1",
|
||||
"Microsoft.Extensions.Logging": "9.0.1",
|
||||
"Mono.TextTemplating": "3.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Tools": {
|
||||
"type": "Direct",
|
||||
"requested": "[9.0.1, )",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "Yu0+5OInULF5PJX/ILZFWNT4ODBv4CSbS1TCXhkZYI6FxC7WguanhmCY9DL6U1R1YQ1tC38RspbxklmBBuk1SA==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore.Design": "9.0.1"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.2.0, )",
|
||||
"resolved": "4.2.0",
|
||||
"contentHash": "gmoWVOvKgbME8TYR+gwMf7osROiWAURterc6Rt2dQyX7wtjZYpqFiA/pY6ztjGQKKV62GGCyOcmtP1UKMHgSmA=="
|
||||
},
|
||||
"Serilog.Sinks.Console": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.0.0, )",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "fQGWqVMClCP2yEyTXPIinSr5c+CBGUvBybPxjAGcf7ctDhadFhrQw03Mv8rJ07/wR5PDfFjewf2LimvXCDzpbA==",
|
||||
"dependencies": {
|
||||
"Serilog": "4.0.0"
|
||||
}
|
||||
},
|
||||
"Thoth.Json.Net": {
|
||||
"type": "Direct",
|
||||
"requested": "[12.0.0, )",
|
||||
"resolved": "12.0.0",
|
||||
"contentHash": "n2YyONYdWCFS4Pu7wrqgV/l5tPuN+t3gxEfs/2RwqCiQkRnbgKs9dK61zHeZS5YganAoFbxLSwbaNL7SvSrS9g==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Core": "3.1.6",
|
||||
"Newtonsoft.Json": "13.0.1"
|
||||
}
|
||||
},
|
||||
"Dapper": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.35",
|
||||
"contentHash": "YKRwjVfrG7GYOovlGyQoMvr1/IJdn+7QzNXJxyMh0YfFF5yvDmTYaJOVYWsckreNjGsGSEtrMTpnzxTUq/tZQw=="
|
||||
},
|
||||
"Dapr.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.16.0",
|
||||
"contentHash": "6JyPI8LxNXSjSpO9vTdbfJh78zOiiC0sgeaXuY8O6SJQh2epaRdEPw0UpamNnld3CkDjp69/VCphox7pU/lh1Q==",
|
||||
"dependencies": {
|
||||
"Dapr.Protos": "1.16.0",
|
||||
"Google.Api.CommonProtos": "2.17.0",
|
||||
"Google.Protobuf": "3.32.0",
|
||||
"Grpc.Net.Client": "2.71.0",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Dapr.Protos": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.16.0",
|
||||
"contentHash": "4k4iKjyRCsFwX7KY5tDcBWDe6JPkhnvN1nqd8zRhDw3YcajF/Br3SU072YdEQKUQ/MJNvqafvzCNPbqSbK3nqg==",
|
||||
"dependencies": {
|
||||
"Google.Api.CommonProtos": "2.17.0",
|
||||
"Google.Protobuf": "3.32.0",
|
||||
"Grpc.Net.Client": "2.71.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"DynamicInterop": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.9.1",
|
||||
"contentHash": "n21+Hd+tceX8lgaOosPV+Pne+YqnZUd5RLW3OhnsVxWRzYXiAIAKmKweHIePYeY+fmcn3N5tjkJyQUccFuL3bg=="
|
||||
},
|
||||
"Fable.Remoting.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.25.0",
|
||||
"contentHash": "ycmxT5L7jUKLkSJ4uti+WiX1OU50UYhLLiFQwJpQzwPWpNbSXowPjUtGycl8G5429edzeIHGW/77hUlIAufiAg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.0",
|
||||
"Newtonsoft.Json": "13.0.3"
|
||||
}
|
||||
},
|
||||
"FSharp.Data.Csv.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.4.1",
|
||||
"contentHash": "/RmEq3HSafm4RPAPATDsDTY0aAkJ8ioDDJ0Qf/NuJW7c7/CC3xeU0XC3sHmDkp9v98aeQOSJdTa+NJrMTHzT7g==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.1",
|
||||
"FSharp.Data.Runtime.Utilities": "6.4.1"
|
||||
}
|
||||
},
|
||||
"FSharp.Data.Html.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.4.1",
|
||||
"contentHash": "/T7k5FkR8nRJ3fZ8Bfaf/c9eda2ru0xCIbM+i2Qt/PgtHp2d1ZmDvQIWbYfDLWVcKjRVu/YpRYOw/2fX0RT8ew==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.1",
|
||||
"FSharp.Data.Csv.Core": "6.4.1",
|
||||
"FSharp.Data.Runtime.Utilities": "6.4.1"
|
||||
}
|
||||
},
|
||||
"FSharp.Data.Http": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.4.1",
|
||||
"contentHash": "7KxlBNwnSIiR1nsPal2ofmgU4Rag8dyDJ+cziW1L9Z+iA55aXeXO/RapQDnyVIwl/Fbm1scGAuSTWP36JNpQFg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.1"
|
||||
}
|
||||
},
|
||||
"FSharp.Data.Json.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.4.1",
|
||||
"contentHash": "mUyqLZiI0XPEiE9FIJLJ3Ndof4hEc2paW049Cw224knmp/b0brMwznLaOqtlmCr49QCELj0tcT0ZCKfb2cFS0g==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.1",
|
||||
"FSharp.Data.Http": "6.4.1",
|
||||
"FSharp.Data.Runtime.Utilities": "6.4.1"
|
||||
}
|
||||
},
|
||||
"FSharp.Data.Runtime.Utilities": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.4.1",
|
||||
"contentHash": "pG4X3QWilYMF3qjZWpod6QgO38uiYUM3/bkEsEyT69E3zAlFQFO9uUy0tqEhDznHvNx4QtZaScUM+06r94HHnQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.1",
|
||||
"FSharp.Data.Http": "6.4.1"
|
||||
}
|
||||
},
|
||||
"FSharp.Data.WorldBank.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.4.1",
|
||||
"contentHash": "opXr3YMArDQCiA1nkEnhSf1s6E0QsotO0VZ5nvQcMXmDuDU4IA1i1DlYp4QVmCXRKj5EHPKMwZkTVNeQDuZ5Bg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.1",
|
||||
"FSharp.Data.Http": "6.4.1",
|
||||
"FSharp.Data.Json.Core": "6.4.1",
|
||||
"FSharp.Data.Runtime.Utilities": "6.4.1"
|
||||
}
|
||||
},
|
||||
"FSharp.Data.Xml.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.4.1",
|
||||
"contentHash": "TprbqQu+DdrR6Kl5biNCAsM8yeQs+pgqRpQYDorbbFIroGw1LBMoX+1iiigJcK89TwJAtiEzVrZCQzHvCDrCbA==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.1",
|
||||
"FSharp.Data.Http": "6.4.1",
|
||||
"FSharp.Data.Json.Core": "6.4.1",
|
||||
"FSharp.Data.Runtime.Utilities": "6.4.1"
|
||||
}
|
||||
},
|
||||
"FsPickler": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.3.2",
|
||||
"contentHash": "LFtxXpQNor8az1ez3rN9oz2cqf/06i9yTrPyJ9R83qLEpFAU7Of0WL2hoSXzLHer4lh+6mO1NV4VQFiBzNRtjw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.3.2"
|
||||
}
|
||||
},
|
||||
"Google.Api.CommonProtos": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.17.0",
|
||||
"contentHash": "elfQPknFr495hm7vdy6ZlgyQh6yzZq9TU7sS35L/Fj/fqjM/mUGau9gVJLhvQEtUlPjtR80hpn/m9HvBMyCXIw==",
|
||||
"dependencies": {
|
||||
"Google.Protobuf": "[3.31.1, 4.0.0]"
|
||||
}
|
||||
},
|
||||
"Google.Protobuf": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.32.0",
|
||||
"contentHash": "fsKxV5bhcvXmZi+cUo5+IxzRMBHwHeFO8G5utNa9f+Mu37kmfy8JcUVvWPt4cX7EuQWAjjHUjZqVl7nGSTRHRg=="
|
||||
},
|
||||
"Grpc.Core.Api": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.71.0",
|
||||
"contentHash": "QquqUC37yxsDzd1QaDRsH2+uuznWPTS8CVE2Yzwl3CvU4geTNkolQXoVN812M2IwT6zpv3jsZRc9ExJFNFslTg=="
|
||||
},
|
||||
"Grpc.Net.Client": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.71.0",
|
||||
"contentHash": "U1vr20r5ngoT9nlb7wejF28EKN+taMhJsV9XtK9MkiepTZwnKxxiarriiMfCHuDAfPUm9XUjFMn/RIuJ4YY61w==",
|
||||
"dependencies": {
|
||||
"Grpc.Net.Common": "2.71.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Grpc.Net.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.71.0",
|
||||
"contentHash": "v0c8R97TwRYwNXlC8GyRXwYTCNufpDfUtj9la+wUrZFzVWkFJuNAltU+c0yI3zu0jl54k7en6u2WKgZgd57r2Q==",
|
||||
"dependencies": {
|
||||
"Grpc.Core.Api": "2.71.0"
|
||||
}
|
||||
},
|
||||
"Humanizer.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.14.1",
|
||||
"contentHash": "lQKvtaTDOXnoVJ20ibTuSIOf2i0uO0MPbDhd1jm238I+U/2ZnRENj0cktKZhtchBMtCUSRQ5v4xBCUbKNmyVMw=="
|
||||
},
|
||||
"KdTree": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.4.1",
|
||||
"contentHash": "yWbb35v/V9y88SLLMUPTlAN3pQEoPhDfZf9PApFnlU4kLtwVQ75U9vW5mW4/alQnLBuLKWBKcy4W5xK95mYsuA=="
|
||||
},
|
||||
"MathNet.Numerics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "pg1W2VwaEQMAiTpGK840hZgzavnqjlCMTVSbtVCXVyT+7AX4mc1o89SPv4TBlAjhgCOo9c1Y+jZ5m3ti2YgGgA=="
|
||||
},
|
||||
"MathNet.Numerics.FSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "lKYhd68fReW5odX/q+Uzxw3357Duq3zmvkYvnZVqqcc2r/EmrYGDoOdUGuHnhfr8yj9V34js5gQH/7IWcxZJxg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.2",
|
||||
"MathNet.Numerics": "5.0.0"
|
||||
}
|
||||
},
|
||||
"MessagePack.Annotations": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.3",
|
||||
"contentHash": "XTy4njgTAf6UVBKFj7c7ad5R0WVKbvAgkbYZy4f00kplzX2T3VOQ34AUke/Vn/QgQZ7ETdd34/IDWS3KBInSGA=="
|
||||
},
|
||||
"MessagePackAnalyzer": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.3",
|
||||
"contentHash": "19u1oVNv2brCs5F/jma8O8CnsKMMpYwNqD0CAEDEzvqwDTAhqC9r7xHZP4stPb3APs/ryO/zVn7LvjoEHfvs7Q=="
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "3aeMZ1N0lJoSyzqiP03hqemtb1BijhsJADdobn/4nsMJ8V1H+CrpuduUe4hlRdx+ikBQju1VGjMD1GJ3Sk05Eg=="
|
||||
},
|
||||
"Microsoft.Build.Framework": {
|
||||
"type": "Transitive",
|
||||
"resolved": "17.8.3",
|
||||
"contentHash": "NrQZJW8TlKVPx72yltGb8SVz3P5mNRk9fNiD/ao8jRSk48WqIIdCn99q4IjlVmPcruuQ+yLdjNQLL8Rb4c916g=="
|
||||
},
|
||||
"Microsoft.Build.Locator": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.7.8",
|
||||
"contentHash": "sPy10x527Ph16S2u0yGME4S6ohBKJ69WfjeGG/bvELYeZVmJdKjxgnlL8cJJJLGV/cZIRqSfB12UDB8ICakOog=="
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Analyzers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.3.4",
|
||||
"contentHash": "AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g=="
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.8.0",
|
||||
"contentHash": "/jR+e/9aT+BApoQJABlVCKnnggGQbvGh7BKq2/wI1LamxC+LbzhcLj4Vj7gXCofl1n4E521YfF9w0WcASGg/KA==",
|
||||
"dependencies": {
|
||||
"Microsoft.CodeAnalysis.Analyzers": "3.3.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.CSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.8.0",
|
||||
"contentHash": "+3+qfdb/aaGD8PZRCrsdobbzGs1m9u119SkkJt8e/mk3xLJz/udLtS2T6nY27OTXxBBw10HzAbC8Z9w08VyP/g==",
|
||||
"dependencies": {
|
||||
"Microsoft.CodeAnalysis.Common": "[4.8.0]"
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.CSharp.Workspaces": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.8.0",
|
||||
"contentHash": "3amm4tq4Lo8/BGvg9p3BJh3S9nKq2wqCXfS7138i69TUpo/bD+XvD0hNurpEBtcNZhi1FyutiomKJqVF39ugYA==",
|
||||
"dependencies": {
|
||||
"Humanizer.Core": "2.14.1",
|
||||
"Microsoft.CodeAnalysis.CSharp": "[4.8.0]",
|
||||
"Microsoft.CodeAnalysis.Common": "[4.8.0]",
|
||||
"Microsoft.CodeAnalysis.Workspaces.Common": "[4.8.0]"
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Workspaces.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.8.0",
|
||||
"contentHash": "LXyV+MJKsKRu3FGJA3OmSk40OUIa/dQCFLOnm5X8MNcujx7hzGu8o+zjXlb/cy5xUdZK2UKYb9YaQ2E8m9QehQ==",
|
||||
"dependencies": {
|
||||
"Humanizer.Core": "2.14.1",
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"Microsoft.CodeAnalysis.Common": "[4.8.0]",
|
||||
"System.Composition": "7.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Workspaces.MSBuild": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.8.0",
|
||||
"contentHash": "IEYreI82QZKklp54yPHxZNG9EKSK6nHEkeuf+0Asie9llgS1gp0V1hw7ODG+QyoB7MuAnNQHmeV1Per/ECpv6A==",
|
||||
"dependencies": {
|
||||
"Microsoft.Build.Framework": "16.10.0",
|
||||
"Microsoft.CodeAnalysis.Common": "[4.8.0]",
|
||||
"Microsoft.CodeAnalysis.Workspaces.Common": "[4.8.0]"
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "qy+taGVLUs82zeWfc32hgGL8Z02ZqAneYvqZiiXbxF4g4PBUcPRuxHM9K20USmpeJbn4/fz40GkCbyyCy5ojOA=="
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Analyzers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "c6ZZJZhPKrXFkE2z/81PmuT69HBL6Y68Cl0xJ5SRrDjJyq5Aabkq15yCqPg9RQ3R0aFLVaJok2DA8R3TKpejDQ=="
|
||||
},
|
||||
"Microsoft.Extensions.Caching.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "Eghsg9SyIvq0c8x6cUpe71BbQoOmsytXxqw2+ZNiTnP8a8SBLKgEor1zZeWhC0588IbS2M0PP4gXGAd9qF862Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "9.0.1"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Caching.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "JeC+PP0BCKMwwLezPGDaciJSTfcFG4KjsG8rX4XZ6RSvzdxofrFmcnmW2L4+cWUcZSBTQ+Dd7H5Gs9XZz/OlCA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Caching.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Options": "9.0.1",
|
||||
"Microsoft.Extensions.Primitives": "9.0.1"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "6m+8Xgmf8UWL0p/oGqBM+0KbHE5/ePXbV1hKXgC59zEv0aa0DW5oiiyxDbK5kH5j4gIvyD5uWL0+HadKBJngvQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "yNou2KM35RvzOh4vUFtl2l33rWPvOCoba+nzEDJ+BgD8aOL/jew4WPCibQvntRfOJ2pJU8ARygSMD+pdjvDHuA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "0vK9DnYrYChdiH3yRZWkkp4x4LbrfkWEdBc5HOsQ8t/0CLOWKXKkkhOE8A1shlex0hGydbGrhObeypxz/QTm+w==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "JJjI2Fa+QtZcUyuNjbKn04OjIUX5IgFGFu/Xc+qvzh1rXdZHLcnqqVXhR4093bGirTwacRlHiVg1XYI9xum6QQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "xY3lTjj4+ZYmiKIkyWitddrp1uL5uYiweQjqo4BKBw01ZC4HhcfgLghDpPZcUlppgWAFqFy9SgkiYWOMx365pw=="
|
||||
},
|
||||
"Microsoft.Extensions.DependencyModel": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "FHPy9cbb0y09riEpsrU5XYpOgf4nTfHj7a0m1wLC5DosGtjJn9g03gGg1GTJmEdRFBQrJwbwTnHqLCdNLsoYgA=="
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "BKkLCFXzJvNmdngeYBf72VXoZqTJSb1orvjdzDLaGobicoGFBPW8ug2ru1nnEewMEwJzMgnsjHQY8EaKWmVhKg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "UDY7blv4DCyIJ/8CkNrQKLaAZFypXQavRZ2DWf/2zi1mxYYKKw2t8AOCBWxNntyPZHPGhtEmL3snFM98ADZqTw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Http": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "jDj+4aDByk47oESlDDTtk6LWzlXlmoCsjCn6ihd+i9OntN885aPLszUII5+w0B/7wYSZcS3KdjqLAIhKLSiBXQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "Z/7ze+0iheT7FJeZPqJKARYvyC2bmwu3whbm/48BJjdlGVvgDguoCqJIkI/67NkroTYobd5geai1WheNQvWrgA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "pYnAffJL7ARD/HCnnPvnFKSIHnTSmWz84WIlT9tPeQ4lHNiu0Az7N/8itihWvcF8sT+VVD5lq8V+ckMzu4SbOw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "OmTaQ0v4gxGQkehpwWIqPoEiwsPuG/u4HUsbOFoWGx4DKET2AXzopnFe/fE608FIhzc/kcg2p8JdyMRCCUzitQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "eW2s6n06x0w6w4nsX+SvpgsFYkl+Y0CttYAt6DKUXeqprX+hzNqjSfOh637fwNJBg7wRBrOIRHe49gKiTgJxzQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "tizSIOEsIgSNSSh+hKeUVPK7xmTIjR8s+mJWOu1KXV3htvNQiPMFRMO17OdI1y/4ZApdBVk49u/08QGC9yvLug=="
|
||||
},
|
||||
"Microsoft.NET.StringTools": {
|
||||
"type": "Transitive",
|
||||
"resolved": "17.11.4",
|
||||
"contentHash": "mudqUHhNpeqIdJoUx2YDWZO/I9uEDYVowan89R6wsomfnUJQk6HteoQTlNjZDixhT2B4IXMkMtgZtoceIjLRmA=="
|
||||
},
|
||||
"Mono.TextTemplating": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.0",
|
||||
"contentHash": "YqueG52R/Xej4VVbKuRIodjiAhV0HR/XVbLbNrJhCZnzjnSjgMJ/dCdV0akQQxavX6hp/LC6rqLGLcXeQYU7XA==",
|
||||
"dependencies": {
|
||||
"System.CodeDom": "6.0.0"
|
||||
}
|
||||
},
|
||||
"NetTopologySuite.IO.PostGis": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.0",
|
||||
"contentHash": "3W8XTFz8iP6GQ5jDXK1/LANHiU+988k1kmmuPWNKcJLpmSg6CvFpbTpz+s4+LBzkAp64wHGOldSlkSuzYfrIKA==",
|
||||
"dependencies": {
|
||||
"NetTopologySuite": "[2.0.0, 3.0.0-A)"
|
||||
}
|
||||
},
|
||||
"ProjNET": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.0.0",
|
||||
"contentHash": "iMJG8qpGJ8SjFrB044O8wgo0raAWCdG1Bvly0mmVcjzsrexDHhC+dUct6Wb1YwQtupMBjSTWq7Fn00YeNErprA=="
|
||||
},
|
||||
"Serilog.Sinks.File": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "lxjg89Y8gJMmFxVkbZ+qDgjl+T4yC5F7WSLTvA+5q0R04tfKVLRL/EHpYoJ/MEQd2EeCKDuylBIVnAYMotmh2A==",
|
||||
"dependencies": {
|
||||
"Serilog": "4.0.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Seq": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.0",
|
||||
"contentHash": "aNU8A0K322q7+voPNmp1/qNPH+9QK8xvM1p72sMmCG0wGlshFzmtDW9QnVSoSYCj0MgQKcMOlgooovtBhRlNHw==",
|
||||
"dependencies": {
|
||||
"Serilog": "4.2.0",
|
||||
"Serilog.Sinks.File": "6.0.0"
|
||||
}
|
||||
},
|
||||
"System.CodeDom": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA=="
|
||||
},
|
||||
"System.Composition": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "tRwgcAkDd85O8Aq6zHDANzQaq380cek9lbMg5Qma46u5BZXq/G+XvIYmu+UI+BIIZ9zssXLYrkTykEqxxvhcmg==",
|
||||
"dependencies": {
|
||||
"System.Composition.AttributedModel": "7.0.0",
|
||||
"System.Composition.Convention": "7.0.0",
|
||||
"System.Composition.Hosting": "7.0.0",
|
||||
"System.Composition.Runtime": "7.0.0",
|
||||
"System.Composition.TypedParts": "7.0.0"
|
||||
}
|
||||
},
|
||||
"System.Composition.AttributedModel": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "2QzClqjElKxgI1jK1Jztnq44/8DmSuTSGGahXqQ4TdEV0h9s2KikQZIgcEqVzR7OuWDFPGLHIprBJGQEPr8fAQ=="
|
||||
},
|
||||
"System.Composition.Convention": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "IMhTlpCs4HmlD8B+J8/kWfwX7vrBBOs6xyjSTzBlYSs7W4OET4tlkR/Sg9NG8jkdJH9Mymq0qGdYS1VPqRTBnQ==",
|
||||
"dependencies": {
|
||||
"System.Composition.AttributedModel": "7.0.0"
|
||||
}
|
||||
},
|
||||
"System.Composition.Hosting": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "eB6gwN9S+54jCTBJ5bpwMOVerKeUfGGTYCzz3QgDr1P55Gg/Wb27ShfPIhLMjmZ3MoAKu8uUSv6fcCdYJTN7Bg==",
|
||||
"dependencies": {
|
||||
"System.Composition.Runtime": "7.0.0"
|
||||
}
|
||||
},
|
||||
"System.Composition.Runtime": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "aZJ1Zr5Txe925rbo4742XifEyW0MIni1eiUebmcrP3HwLXZ3IbXUj4MFMUH/RmnJOAQiS401leg/2Sz1MkApDw=="
|
||||
},
|
||||
"System.Composition.TypedParts": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "ZK0KNPfbtxVceTwh+oHNGUOYV2WNOHReX2AXipuvkURC7s/jPwoWfsu3SnDBDgofqbiWr96geofdQ2erm/KTHg==",
|
||||
"dependencies": {
|
||||
"System.Composition.AttributedModel": "7.0.0",
|
||||
"System.Composition.Hosting": "7.0.0",
|
||||
"System.Composition.Runtime": "7.0.0"
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore": "[9.0.1, )",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "[9.0.1, )",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "[9.0.2, )",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite": "[9.0.2, )"
|
||||
}
|
||||
},
|
||||
"oceanbox.dataagent": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Dapper.FSharp": "[4.9.0, )",
|
||||
"Dapr.Actors": "[1.16.0, )",
|
||||
"Entity": "[1.0.0, )",
|
||||
"FSharp.Core": "[9.0.303, )",
|
||||
"FSharp.Data": "[6.4.1, )",
|
||||
"FSharpPlus": "[1.7.0, )",
|
||||
"Fable.Remoting.DotnetClient": "[3.35.0, )",
|
||||
"Microsoft.EntityFrameworkCore": "[9.0.1, )",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "[9.0.1, )",
|
||||
"NetTopologySuite": "[2.5.0, )",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "[9.0.2, )",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite": "[9.0.2, )",
|
||||
"Npgsql.NetTopologySuite": "[9.0.2, )",
|
||||
"Oceanbox.FvcomKit": "[5.13.0, )",
|
||||
"Oceanbox.SDSLite": "[2.8.0, )",
|
||||
"Serilog.Sinks.Console": "[6.0.0, )",
|
||||
"Thoth.Json.Net": "[12.0.0, )"
|
||||
}
|
||||
},
|
||||
"Oceanbox.DataAgent.Api": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "[9.0.303, )"
|
||||
}
|
||||
},
|
||||
"Dapper.FSharp": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[4.9.0, )",
|
||||
"resolved": "4.9.0",
|
||||
"contentHash": "wqMi/wHSQV9v79/u8OELxO+lmUOxk3J5CAUuAmWbltbIYH0A64CV1z1RG+9EVpyAAD9bovKYAnQ2wNwDoPxTxA==",
|
||||
"dependencies": {
|
||||
"Dapper": "2.1.35",
|
||||
"FSharp.Core": "8.0.200"
|
||||
}
|
||||
},
|
||||
"Dapr.Actors": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.16.0, )",
|
||||
"resolved": "1.16.0",
|
||||
"contentHash": "s9v6VofXXYoRqZJQlQbvNYYSlGhkL+Z+bpqrx1TRo06kLhANeDmXA9yeVaD+1KwJIO1chUFj5O4iKuTxIkg1sA==",
|
||||
"dependencies": {
|
||||
"Dapr.Client": "1.16.0",
|
||||
"Dapr.Common": "1.16.0",
|
||||
"Google.Api.CommonProtos": "2.17.0",
|
||||
"Google.Protobuf": "3.32.0",
|
||||
"Grpc.Net.Client": "2.71.0",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Dapr.Client": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.16.0, )",
|
||||
"resolved": "1.16.0",
|
||||
"contentHash": "dFDKol+mtQrk1lIKlEyCx3k6W0Pf+0wC6xcsaDqa0Bg+XCWDc4juROuDcSb0/L1Y+Ev6LSLDMC/FgzNWMw9YtQ==",
|
||||
"dependencies": {
|
||||
"Dapr.Common": "1.16.0",
|
||||
"Dapr.Protos": "1.16.0",
|
||||
"Google.Api.CommonProtos": "2.17.0",
|
||||
"Google.Protobuf": "3.32.0",
|
||||
"Grpc.Net.Client": "2.71.0",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Fable.Core": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[4.4.0, )",
|
||||
"resolved": "3.1.6",
|
||||
"contentHash": "w6M1F0zoLk4kTFc1Lx6x1Ft6BD3QwRe0eaLiinAqbjVkcF+iK+NiXGJO+a6q9RAF9NCg0vI48Xku7aNeqG4JVw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.1"
|
||||
}
|
||||
},
|
||||
"Fable.Remoting.DotnetClient": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.35.0, )",
|
||||
"resolved": "3.35.0",
|
||||
"contentHash": "xaxt9nKfqIWh30+cOrG9GNl06+7yTy5htrcF5eXsZ7QJLLy7T5ZD3xeGpAb0xbh+TZTVQGluSQzxh/opIZm2PQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.0",
|
||||
"Fable.Remoting.Json": "2.25.0",
|
||||
"Fable.Remoting.MsgPack": "1.24.0"
|
||||
}
|
||||
},
|
||||
"Fable.Remoting.MsgPack": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.24.0, )",
|
||||
"resolved": "1.24.0",
|
||||
"contentHash": "Bn3nzoZbib6lPk70bIJumEu2wFMxciB4o8k0Zw6tRfAOpNKvUsi79OOll2nW3FU1P6MVBepT43m+R8JvfYnNiw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2"
|
||||
}
|
||||
},
|
||||
"MessagePack": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.1.3, )",
|
||||
"resolved": "3.1.3",
|
||||
"contentHash": "UiNv3fknvPzh5W+S0VV96R17RBZQQU71qgmsMnjjRZU2rtQM/XcTnOB+klT2dA6T1mxjnNKYrEm164AoXvGmYg==",
|
||||
"dependencies": {
|
||||
"MessagePack.Annotations": "3.1.3",
|
||||
"MessagePackAnalyzer": "3.1.3",
|
||||
"Microsoft.NET.StringTools": "17.11.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.Relational": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[9.0.1, )",
|
||||
"resolved": "9.0.1",
|
||||
"contentHash": "7Iu0h4oevRvH4IwPzmxuIJGYRt55TapoREGlluk75KCO7lenN0+QnzCl6cQDY48uDoxAUpJbpK2xW7o8Ix69dw==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore": "9.0.1",
|
||||
"Microsoft.Extensions.Caching.Memory": "9.0.1",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging": "9.0.1"
|
||||
}
|
||||
},
|
||||
"NetTopologySuite": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.5.0, )",
|
||||
"resolved": "2.5.0",
|
||||
"contentHash": "5/+2O2ADomEdUn09mlSigACdqvAf0m/pVPGtIPEPQWnyrVykYY0NlfXLIdkMgi41kvH9kNrPqYaFBTZtHYH7Xw=="
|
||||
},
|
||||
"Newtonsoft.Json": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[13.0.3, )",
|
||||
"resolved": "13.0.3",
|
||||
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
|
||||
},
|
||||
"Npgsql": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[9.0.2, )",
|
||||
"resolved": "9.0.2",
|
||||
"contentHash": "hCbO8box7i/XXiTFqCJ3GoowyLqx3JXxyrbOJ6om7dr+eAknvBNhhUHeJVGAQo44sySZTfdVffp4BrtPeLZOAA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
|
||||
}
|
||||
},
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[9.0.2, )",
|
||||
"resolved": "9.0.2",
|
||||
"contentHash": "cYdOGplIvr9KgsG8nJ8xnzBTImeircbgetlzS1OmepS5dAQW6PuGpVrLOKBNEwEvGYZPsV8037X5vZ/Dmpwz7Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.EntityFrameworkCore": "[9.0.0, 10.0.0)",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "[9.0.0, 10.0.0)",
|
||||
"Npgsql": "9.0.2"
|
||||
}
|
||||
},
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[9.0.2, )",
|
||||
"resolved": "9.0.2",
|
||||
"contentHash": "D38a3+CF8dO7nPiwt/NtQ/sLbrzZpX910jaaGiETdeS18KI0yMYEFvWWO5I/JBjVXLVnruodsukIUupdoD4fRA==",
|
||||
"dependencies": {
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "9.0.2",
|
||||
"Npgsql.NetTopologySuite": "9.0.2"
|
||||
}
|
||||
},
|
||||
"Npgsql.NetTopologySuite": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[9.0.2, )",
|
||||
"resolved": "9.0.2",
|
||||
"contentHash": "DCwN+IVl3yWfOftPe0UBUUDOqa877ca+z+xSDQVi5ShDnOIAipaaYZlzDYm8Nga8hcxx6UrIQuImFnXv8fDpwg==",
|
||||
"dependencies": {
|
||||
"NetTopologySuite": "2.5.0",
|
||||
"NetTopologySuite.IO.PostGIS": "2.1.0",
|
||||
"Npgsql": "9.0.2"
|
||||
}
|
||||
},
|
||||
"Oceanbox.FvcomKit": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[5.13.0, )",
|
||||
"resolved": "5.13.0",
|
||||
"contentHash": "6uVL3fLhRf4OU1hWygGpVex4pI5YB+GaWrKZUgoL/LkGmdFv0qU8Y7v+meHNM3E9bjR7xKinCVfrw5SXsF6C8g==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "9.0.201",
|
||||
"FSharp.Data": "6.4.1",
|
||||
"FSharpPlus": "1.7.0",
|
||||
"FsPickler": "5.3.2",
|
||||
"KDTree": "1.4.1",
|
||||
"MathNet.Numerics.FSharp": "5.0.0",
|
||||
"MessagePack": "3.1.3",
|
||||
"Oceanbox.SDSLite": "2.8.0",
|
||||
"ProjNet.FSharp": "5.2.0",
|
||||
"Serilog": "4.2.0",
|
||||
"Serilog.Sinks.Console": "6.0.0",
|
||||
"Serilog.Sinks.Seq": "9.0.0",
|
||||
"Thoth.Json.Net": "12.0.0"
|
||||
}
|
||||
},
|
||||
"Oceanbox.SDSLite": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.8.0, )",
|
||||
"resolved": "2.8.0",
|
||||
"contentHash": "DzMcnywHhtmLVDZSVCZq6Mqq+SIm4snGRYgquho9xZSyEq5RhBkLdSa5k59m7o24FGZyt75DGpElN9p+dezU7Q==",
|
||||
"dependencies": {
|
||||
"DynamicInterop": "0.9.1"
|
||||
}
|
||||
},
|
||||
"ProjNet.FSharp": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[5.2.0, )",
|
||||
"resolved": "5.2.0",
|
||||
"contentHash": "sYSePg/0sVo16Fk3r7okVSga6i9GAN0kkjt1haEXVw25SF8A4S3Gcpf5+6lgknBGdYiZBmJ+3S6v5g1WSSCp2g==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "8.0.100",
|
||||
"FSharp.Data": "6.3.0",
|
||||
"FSharpPlus": "1.5.0",
|
||||
"ProjNet": "2.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/linux-x64": {}
|
||||
}
|
||||
}
|
||||
@@ -23,22 +23,22 @@ let fetchArchives modelAreaId callback =
|
||||
|
||||
let fetchModelAreas callback =
|
||||
async {
|
||||
let! res = archmaester.getModelArea HelloWorld
|
||||
let! res = archmaester.getModelAreaArchives (HelloWorld, ArchiveType.FromString "*:*:*")
|
||||
|
||||
match res with
|
||||
| Error err -> console.error $"Fetch model areas error: {err}"
|
||||
| Ok modelAreas -> Some [| modelAreas |] |> callback
|
||||
| Ok modelAreas -> Some modelAreas |> callback
|
||||
}
|
||||
|
||||
[<LitElement("archive-listing")>]
|
||||
let ArchiveListing () =
|
||||
let _, _ = LitElement.init (fun init -> init.useShadowDom <- false)
|
||||
|
||||
let (modelAreas: ModelArea[] option), setModelAreas = Hook.useState None
|
||||
let (modelAreas: ArchiveProps[] option), setModelAreas = Hook.useState None
|
||||
|
||||
Hook.useEffectOnce (fun _ -> fetchModelAreas setModelAreas |> Async.StartImmediate)
|
||||
|
||||
let archiveId (a: ArchiveProps) = a.archiveId.ToString()
|
||||
let archiveId (a: ArchiveProps) = a.archiveId.ToString ()
|
||||
|
||||
let archiveFiles files =
|
||||
let fileEntry (fileName, _) = html $"""<li>{fileName}</li>"""
|
||||
@@ -119,7 +119,7 @@ let ArchiveListing () =
|
||||
{item.name}
|
||||
<div class="badge badge-secondary">{item.archiveType}</div>
|
||||
</h2>
|
||||
<h3>Start date: {item.startTime.ToShortDateString()} {item.startTime.ToShortTimeString()}</h3>
|
||||
<h3>Start date: {item.startTime.ToShortDateString ()} {item.startTime.ToShortTimeString ()}</h3>
|
||||
<span>Projection: {item.projection}</span>
|
||||
{{archiveOwners item.acl}}
|
||||
{{archiveUsers item.acl}}
|
||||
@@ -136,8 +136,8 @@ let ArchiveListing () =
|
||||
<p>{archiveName}</p>
|
||||
"""
|
||||
|
||||
let modelAreaItem (item: ModelArea) =
|
||||
let archiveList = Array.map archiveName item.archives
|
||||
let modelAreaItem (item: ArchiveProps) =
|
||||
// let archiveList = Array.map archiveName item.archives
|
||||
|
||||
html
|
||||
$"""
|
||||
@@ -146,7 +146,7 @@ let ArchiveListing () =
|
||||
<h2 class="card-title">
|
||||
{item.name}
|
||||
</h2>
|
||||
{archiveList}
|
||||
{item}
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Version>7.1.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
@@ -9,9 +9,9 @@
|
||||
<Compile Include="App.fs"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fable.Lit" Version="1.4.2"/>
|
||||
<PackageReference Include="Fable.Remoting.Client" Version="7.32.0"/>
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201"/>
|
||||
<PackageReference Include="Fable.Lit" />
|
||||
<PackageReference Include="Fable.Remoting.Client" />
|
||||
<PackageReference Include="FSharp.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../Interfaces/Archmaester/Archmaester.Api.fsproj"/>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Version>7.1.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
@@ -11,23 +11,23 @@
|
||||
<Compile Include="Main.fs"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Argu" Version="6.2.5"/>
|
||||
<PackageReference Include="Dapper.FSharp" Version="4.9.0"/>
|
||||
<PackageReference Include="FSharp.Data" Version="6.4.1"/>
|
||||
<PackageReference Include="FSharpPlus" Version="1.7.0"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.2">
|
||||
<PackageReference Include="Argu" />
|
||||
<PackageReference Include="Dapper.FSharp" />
|
||||
<PackageReference Include="FSharp.Data" />
|
||||
<PackageReference Include="FSharpPlus" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" >
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.2"/>
|
||||
<PackageReference Include="Npgsql.NetTopologySuite" Version="9.0.2"/>
|
||||
<PackageReference Include="Serilog" Version="4.2.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0"/>
|
||||
<PackageReference Include="Thoth.Json.Net" Version="12.0.0"/>
|
||||
<PackageReference Include="NetTopologySuite" Version="2.5.0"/>
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2"/>
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite" Version="9.0.2"/>
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
||||
<PackageReference Include="Npgsql.NetTopologySuite" />
|
||||
<PackageReference Include="Serilog" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" />
|
||||
<PackageReference Include="Thoth.Json.Net" />
|
||||
<PackageReference Include="NetTopologySuite" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite" />
|
||||
<PackageReference Update="FSharp.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Interfaces\Archmaester\Archmaester.Api.fsproj"/>
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
open Fake.Core
|
||||
open Fake.IO
|
||||
open Farmer
|
||||
open Farmer.Builders
|
||||
|
||||
open Helpers
|
||||
|
||||
initializeContext()
|
||||
|
||||
let serverPath = Path.getFullName "src/Server"
|
||||
let clientPath = Path.getFullName "src/Client"
|
||||
let testPath = Path.getFullName "test"
|
||||
let libPath = Path.getFullName "src/Interfaces" |> Some
|
||||
|
||||
let distPath = Path.getFullName "dist"
|
||||
let packPath = Path.getFullName "packages"
|
||||
let versionFile = Path.getFullName ".version"
|
||||
|
||||
let vite = """bunx --bun vite -c ../../vite.config.js"""
|
||||
|
||||
let fable opts =
|
||||
$"fable -e .jsx -o build --run {vite} build --emptyOutDir --outDir {distPath}/public {opts}"
|
||||
|
||||
let fableWatch = $"fable watch -e .jsx -o build --run {vite}"
|
||||
|
||||
Target.create "Clean" (fun _ -> Shell.cleanDir distPath)
|
||||
|
||||
Target.create "Bundle" (fun _ ->
|
||||
[ "server", dotnet $"publish -c Release -o {distPath}" serverPath
|
||||
"client", dotnet (fable "-m production") clientPath ]
|
||||
|> runParallel
|
||||
)
|
||||
|
||||
Target.create "BundleDebug" (fun _ ->
|
||||
[ "server", dotnet $"publish -c Debug -o {distPath}" serverPath
|
||||
"client", dotnet (fable "-m development --minify false --sourcemap true") clientPath ]
|
||||
|> runParallel
|
||||
)
|
||||
|
||||
Target.create "Pack" (fun _ ->
|
||||
match libPath with
|
||||
| Some p -> run dotnet $"pack -c Release -o \"{packPath}\"" p
|
||||
| None -> ()
|
||||
)
|
||||
|
||||
Target.create "Run" (fun _ ->
|
||||
[ "server", dotnet "watch run" serverPath
|
||||
"client", dotnet fableWatch clientPath ]
|
||||
|> runParallel
|
||||
)
|
||||
|
||||
Target.create "Client" (fun _ ->
|
||||
run dotnet fableWatch clientPath
|
||||
)
|
||||
|
||||
Target.create "Format" (fun _ ->
|
||||
run dotnet "fantomas . -r" "src"
|
||||
)
|
||||
|
||||
Target.create "Test" (fun _ ->
|
||||
if System.IO.Directory.Exists testPath then
|
||||
[ "server", dotnet "run" (testPath + "/Server")
|
||||
"client", dotnet $"fable -e .jsx -o build --run {vite}" (testPath + "/Client") ]
|
||||
|> runParallel
|
||||
else ()
|
||||
)
|
||||
|
||||
open Fake.Core.TargetOperators
|
||||
|
||||
let dependencies = [
|
||||
"Clean"
|
||||
==> "Bundle"
|
||||
|
||||
"Clean"
|
||||
==> "BundleDebug"
|
||||
|
||||
"Clean"
|
||||
==> "Test"
|
||||
|
||||
"Clean"
|
||||
==> "Run"
|
||||
|
||||
"Clean"
|
||||
==> "Pack"
|
||||
|
||||
"Client"
|
||||
]
|
||||
|
||||
[<EntryPoint>]
|
||||
let main args = runOrDefault args
|
||||
@@ -1 +1,6 @@
|
||||
use nix
|
||||
#!/usr/bin/env bash
|
||||
# the shebang is ignored, but nice for editors
|
||||
use nix
|
||||
|
||||
# HACK: Workaround for direnv bug
|
||||
unset TMP TMPDIR TEMP TEMPDIR
|
||||
@@ -1,15 +1,15 @@
|
||||
# yaml-language-server: $schema=https://gitlab.com/gitlab-org/gitlab/-/raw/master/app/assets/javascripts/editor/schema/ci.json
|
||||
variables:
|
||||
SKIP_TESTS: "true"
|
||||
NODE_OPTIONS: "--max-old-space-size=16384"
|
||||
SKIP_TESTS: "true"
|
||||
|
||||
include:
|
||||
- project: oceanbox/gitlab-ci
|
||||
ref: v4.1
|
||||
file: DotnetDeployment.gitlab-ci.yml
|
||||
inputs:
|
||||
project-name: atlantis
|
||||
project-dir: src/Atlantis
|
||||
- project: oceanbox/gitlab-ci
|
||||
ref: v4.5
|
||||
file: DotnetDeployment.gitlab-ci.yml
|
||||
inputs:
|
||||
project-name: atlantis
|
||||
project-dir: src/Atlantis
|
||||
|
||||
dotnet-build-atlantis:
|
||||
dockerize-atlantis:
|
||||
tags:
|
||||
- saas-linux-large-amd64
|
||||
- nix
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="../../.build/Helpers.fs" />
|
||||
<Compile Include=".build/Build.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fake.Core.Target" Version="6.1.3" />
|
||||
<PackageReference Include="Fake.DotNet.Cli" Version="6.1.3" />
|
||||
<PackageReference Include="Fake.IO.FileSystem" Version="6.1.3" />
|
||||
<PackageReference Include="Farmer" Version="1.9.6" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,4 +1,5 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y gcc-multilib libnetcdf19 libnetcdf-dev
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ allow_k8s_contexts(cluster)
|
||||
|
||||
load('ext://restart_process', 'docker_build_with_restart')
|
||||
load('ext://namespace', 'namespace_inject')
|
||||
load('ext://nix', 'build_nix_image')
|
||||
|
||||
clientPort=os.getenv('CLIENT_PORT')
|
||||
if not clientPort:
|
||||
@@ -33,10 +34,13 @@ docker_build_with_restart(
|
||||
live_update=[sync('./dist', '/app')]
|
||||
)
|
||||
|
||||
redis=str(local(
|
||||
'helm template -f ./tilt/tilt/redis.yaml --namespace {namespace} {env}-{name}-redis bitnami/redis'
|
||||
.format(namespace=namespace, env=env, name=name), echo_off=False, quiet=True)).replace('<x>',"{env}".format(env=env))
|
||||
k8s_yaml(blob(redis))
|
||||
# NOTE(mrtz): Kept for nix testing
|
||||
# build_nix_image(
|
||||
# '{repository}:latest'.format(repository=repository),
|
||||
# "../../default.nix",
|
||||
# "containers.atlantis --argstr debug 'Debug' --show-trace",
|
||||
# "../../default.nix",
|
||||
# )
|
||||
|
||||
manifest=helm(
|
||||
'../../../manifests/charts/{name}'.format(name=name),
|
||||
@@ -56,13 +60,13 @@ k8s_yaml(namespace_inject(blob(kustomizations), namespace))
|
||||
|
||||
local_resource(
|
||||
'create-bundle',
|
||||
cmd='dotnet run bundledebug',
|
||||
cmd='just bundle-debug',
|
||||
trigger_mode=TRIGGER_MODE_MANUAL
|
||||
)
|
||||
|
||||
local_resource(
|
||||
'build-server',
|
||||
cmd='dotnet publish -o ./dist src/Server',
|
||||
cmd='just bundle-debug-server',
|
||||
deps=[
|
||||
'./src/Server',
|
||||
'./src/Shared'
|
||||
@@ -70,6 +74,10 @@ local_resource(
|
||||
ignore=[
|
||||
'src/Server/bin',
|
||||
'src/Server/obj',
|
||||
'src/Server/Archmaester/obj',
|
||||
'src/Server/Hipster/obj',
|
||||
'src/Server/Petimeter/obj',
|
||||
'src/Server/Common/obj',
|
||||
'src/Shared/bin',
|
||||
'src/Shared/obj',
|
||||
],
|
||||
@@ -80,7 +88,7 @@ local_resource(
|
||||
|
||||
local_resource(
|
||||
'run-client',
|
||||
serve_cmd='dotnet fable watch -e .jsx -o build --run vite -c ../../vite.config.js',
|
||||
serve_cmd='just run-client',
|
||||
serve_dir='./src/Client',
|
||||
links=['https://{name}.local.oceanbox.io:{port}'.format(name=name, port=clientPort)],
|
||||
resource_deps=['build-server'],
|
||||
|
||||
86
src/Atlantis/justfile
Normal file
86
src/Atlantis/justfile
Normal file
@@ -0,0 +1,86 @@
|
||||
# Atlantis build commands
|
||||
# Install just: https://github.com/casey/just
|
||||
|
||||
set dotenv-load
|
||||
|
||||
src_path := "src"
|
||||
server_path := "src/Server"
|
||||
client_path := "src/Client"
|
||||
test_path := "test"
|
||||
lib_path := "src/Interfaces"
|
||||
|
||||
dist_path := "../../dist"
|
||||
pack_path := "../../packages"
|
||||
|
||||
vite_prod := "bunx --bun vite build -c ../../vite.config.js -m production --emptyOutDir --outDir " + "../../dist/public"
|
||||
vite_dev := "bunx --bun vite build -c ../../vite.config.js -m development --minify false --sourcemap true --emptyOutDir --outDir " + "../../dist/public"
|
||||
vite := "bunx vite -c ../../vite.config.js -m development "
|
||||
|
||||
# Default recipe - show available commands
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
rm -rf {{dist_path}}
|
||||
|
||||
# Build production bundle (server + client)
|
||||
[parallel]
|
||||
bundle: clean bundle-server bundle-client
|
||||
|
||||
[working-directory: 'src/Server']
|
||||
bundle-server:
|
||||
dotnet build -tl -c Release -o {{dist_path}}
|
||||
|
||||
[working-directory: 'src/Client']
|
||||
install-client:
|
||||
bun install --frozen-lockfile
|
||||
|
||||
[working-directory: 'src/Client']
|
||||
bundle-client: install-client
|
||||
|
||||
# Build debug bundle (server + client)
|
||||
[parallel]
|
||||
bundle-debug: clean bundle-debug-server bundle-debug-client
|
||||
|
||||
[working-directory: 'src/Server']
|
||||
bundle-debug-server:
|
||||
dotnet build -tl -c Debug -o {{dist_path}}
|
||||
|
||||
[working-directory: 'src/Client']
|
||||
bundle-debug-client:
|
||||
fable -e .jsx -o build --test:MSBuildCracker --run {{vite_dev}}
|
||||
|
||||
# Create NuGet package
|
||||
[working-directory: 'src/Server']
|
||||
pack: clean
|
||||
dotnet pack -c Release -o "{{pack_path}}" {{lib_path}}
|
||||
|
||||
# Run development server (watch mode)
|
||||
[parallel]
|
||||
run: clean run-server run-client
|
||||
|
||||
[working-directory: 'src/Server']
|
||||
run-server:
|
||||
dotnet watch run
|
||||
|
||||
# Run client only in watch mode
|
||||
[working-directory: 'src/Client']
|
||||
run-client: install-client
|
||||
fable watch -e .jsx -o build --test:MSBuildCracker --run {{vite}}
|
||||
|
||||
# Format code with Fantomas
|
||||
format:
|
||||
fantomas {{src_path}} -r
|
||||
|
||||
# Run tests
|
||||
[parallel]
|
||||
test: clean test-server test-client
|
||||
|
||||
[working-directory: 'src']
|
||||
test-server:
|
||||
dotnet run {{test_path}}/Server
|
||||
|
||||
[working-directory: 'src/Client']
|
||||
test-client: install-client
|
||||
fable -e .jsx -o build --run {{vite}}
|
||||
17
src/Atlantis/plotly-bundle.js
Normal file
17
src/Atlantis/plotly-bundle.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Custom distribution bundle for Plotly
|
||||
// We only import and register the components we use
|
||||
// For more info: https://github.com/plotly/plotly.js#modules
|
||||
//
|
||||
// In vite.config.js we add an alias to redirect imports
|
||||
// The original plotly can be accessed as 'plotly-dist'
|
||||
import Plotly from 'plotly-dist/lib/core';
|
||||
import scatter from 'plotly-dist/lib/scatter';
|
||||
import contour from 'plotly-dist/lib/contour';
|
||||
import heatmap from 'plotly-dist/lib/heatmap';
|
||||
import box from 'plotly-dist/lib/box';
|
||||
import bar from 'plotly-dist/lib/bar';
|
||||
import barpolar from 'plotly-dist/lib/barpolar';
|
||||
|
||||
Plotly.register([scatter, contour, heatmap, box, bar, barpolar]);
|
||||
|
||||
export default Plotly;
|
||||
@@ -1,15 +1,13 @@
|
||||
with import <nixpkgs> { };
|
||||
{
|
||||
sources ? import ./../../nix,
|
||||
pkgs ? import sources.nixpkgs { },
|
||||
}:
|
||||
let
|
||||
port = 8000;
|
||||
baseShell = import ./../../shell.nix { inherit pkgs; };
|
||||
in
|
||||
mkShell {
|
||||
packages = [
|
||||
tilt
|
||||
dapr-cli
|
||||
kustomize
|
||||
bun
|
||||
mkcert
|
||||
];
|
||||
pkgs.mkShellNoCC {
|
||||
inputsFrom = [ baseShell ];
|
||||
|
||||
LOG_LEVEL = "verbose";
|
||||
REDIS = "localhost:6379";
|
||||
@@ -21,9 +19,14 @@ mkShell {
|
||||
DAPR_API_TOKEN = "anVzdCBmb3IgbG9jYWwgdXNlCg==";
|
||||
ARCHMAESTER_AUTH = "YWRtaW46ZW4tdG8tdHJlLWZpcmU=";
|
||||
|
||||
# NOTE: Fixes docker error `Build Failed: failed to dial gRPC: unable to upgrade to h2c`
|
||||
DOCKER_BUILDKIT = 0;
|
||||
# NOTE(mrtz): Needed for tilt podman compat.
|
||||
# DOCKER_HOST = "unix:///run/user/1000/podman/podman.sock";
|
||||
|
||||
shellHook = ''
|
||||
export APP_ENV=$USER
|
||||
export APP_NAME=atlantis
|
||||
export APP_NAMESPACE=$USER-atlantis
|
||||
'';
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,12 @@ open Fable.Core.JsInterop
|
||||
open Lit
|
||||
open Remoting
|
||||
|
||||
let initSentry = Sentry.hostTargets |> Array.contains window.location.hostname
|
||||
|
||||
if initSentry then
|
||||
console.debug "Pushing to Sentry"
|
||||
Sentry.init ()
|
||||
|
||||
[<LitElement("init-app")>]
|
||||
let InitApp () =
|
||||
let _ = LitElement.init (fun cfg -> cfg.useShadowDom <- false)
|
||||
@@ -12,8 +18,9 @@ let InitApp () =
|
||||
Hook.useEffectOnce (fun () ->
|
||||
async {
|
||||
let! authenticated = authApi.IsAuthenticated()
|
||||
do! Auth.setId ()
|
||||
if authenticated.IsSome && not (isNullOrUndefined sessionStorage["archive_id"]) then
|
||||
do! Utils.initAtlantisSessionUrls ()
|
||||
do! Auth.initSessionUrls ()
|
||||
window.location.href <- "/map.html"
|
||||
else
|
||||
sessionStorage.removeItem "archive_id"
|
||||
@@ -21,4 +28,5 @@ let InitApp () =
|
||||
return ()
|
||||
} |> Async.StartImmediate
|
||||
)
|
||||
|
||||
Lit.nothing
|
||||
@@ -1,21 +1,22 @@
|
||||
module Atlas
|
||||
|
||||
open System
|
||||
|
||||
open Browser
|
||||
open Fable.Core
|
||||
open Fable.Core.JsInterop
|
||||
open Fable.OpenLayers
|
||||
open Fable.OpenLayers.Event
|
||||
open Feliz.prop
|
||||
open Lit
|
||||
open Lit.Elmish
|
||||
open Remoting
|
||||
|
||||
open Archmaester.Dto
|
||||
open Atlantis.Types
|
||||
open Maps
|
||||
open Remoting
|
||||
|
||||
importSideEffects "../public/style.scss"
|
||||
|
||||
importSideEffects "@spectrum-web-components/action-button/sp-action-button.js"
|
||||
importSideEffects "@spectrum-web-components/action-group/sp-action-group.js"
|
||||
importSideEffects "@spectrum-web-components/action-menu/sp-action-menu.js"
|
||||
@@ -53,12 +54,8 @@ importSideEffects "@spectrum-web-components/table/sp-table-row.js"
|
||||
importSideEffects "@spectrum-web-components/dialog/sp-dialog.js"
|
||||
importSideEffects "@spectrum-web-components/underlay/sp-underlay.js"
|
||||
|
||||
importSideEffects "@shoelace-style/shoelace/dist/components/dialog/dialog.js"
|
||||
|
||||
let register () = ()
|
||||
|
||||
let private hmr = HMR.createToken ()
|
||||
|
||||
let polygonStyle (feature: Feature) =
|
||||
let name = feature.get "name" :?> string
|
||||
let models = feature.get "models" :?> int
|
||||
@@ -96,7 +93,8 @@ let private createSelectInteraction () =
|
||||
|
||||
type private Model = {
|
||||
activeTab: Tab
|
||||
archives: Map<ModelAreaId, ArchiveProps[]>
|
||||
// TODO: Save this in localstorage or IndexedDB
|
||||
archives: Map<ModelAreaId, ArchiveProps array>
|
||||
helloWorld: ModelArea option
|
||||
map: OlMap
|
||||
mapKind: MapKind
|
||||
@@ -237,6 +235,7 @@ let createMapWithLayers center (layers: Layer.Layer[]) : OlMap =
|
||||
let private init () =
|
||||
let map = createMapWithLayers theCenter [| baseMapLayer |]
|
||||
map.addControl (ScaleLine.scaleLine [ scaleLine.bar false; scaleLine.minWidth 75 ])
|
||||
map.addControl (FullScreen.fullScreen [ ])
|
||||
let model = { Model.empty with map = map }
|
||||
model, Elmish.Cmd.none
|
||||
|
||||
@@ -253,11 +252,21 @@ let emptyModel = {
|
||||
json = ""
|
||||
}
|
||||
|
||||
let private hmr = HMR.createToken ()
|
||||
|
||||
[<HookComponent>]
|
||||
let private archivePopup (m: ModelArea option) =
|
||||
Hook.useHmr hmr
|
||||
|
||||
let modelArea, setModelArea =
|
||||
Hook.useState<ModelArea> (fun () -> m |> Option.defaultValue emptyModel)
|
||||
Hook.useEffectOnChange (m, Option.iter setModelArea)
|
||||
|
||||
Hook.useEffectOnChange (
|
||||
m,
|
||||
function
|
||||
| Some modelArea -> setModelArea modelArea
|
||||
| None -> ()
|
||||
)
|
||||
|
||||
let archives =
|
||||
if modelArea.archives > 0 then
|
||||
@@ -268,7 +277,8 @@ let private archivePopup (m: ModelArea option) =
|
||||
let areas =
|
||||
if modelArea.models > 0 then
|
||||
html $""" Available areas: {modelArea.models} """
|
||||
else Lit.nothing
|
||||
else
|
||||
Lit.nothing
|
||||
|
||||
html
|
||||
$"""
|
||||
@@ -299,20 +309,23 @@ let private archivePopup (m: ModelArea option) =
|
||||
"
|
||||
>
|
||||
{modelArea.name}
|
||||
<sp-divider> </sp-divider>
|
||||
<sp-divider size="s"></sp-divider>
|
||||
</div>
|
||||
<div>
|
||||
<span>{archives}</span>
|
||||
<span>{areas}</span>
|
||||
</div>
|
||||
<p>
|
||||
{archives}
|
||||
{areas}
|
||||
</p>
|
||||
</sp-popover>
|
||||
</div>
|
||||
"""
|
||||
|
||||
[<HookComponent>]
|
||||
let private topNav (dispatch: Msg -> unit) (model: Model) =
|
||||
Hook.useHmr hmr
|
||||
|
||||
let icon =
|
||||
match model.activeTab with
|
||||
| Tab.Select -> html $"""<img src="ob.png" height="35px"/>"""
|
||||
| Tab.Select -> html $"""<img src="ob.png" />"""
|
||||
| _ -> html $"""<sp-icon-undo></sp-icon-undo>"""
|
||||
|
||||
let handleActionMenu (ev: Types.Event) =
|
||||
@@ -320,87 +333,100 @@ let private topNav (dispatch: Msg -> unit) (model: Model) =
|
||||
| "logout" -> window.location.href <- "/signout"
|
||||
| _ -> ()
|
||||
|
||||
let menu =
|
||||
html
|
||||
$"""
|
||||
<sp-top-nav-item href="#about">Oceanbox</sp-top-nav-item>
|
||||
<sp-action-menu label="Account" placement="bottom-end" @change={Ev (handleActionMenu)} style="margin-inline-start: auto;">
|
||||
// NOTE: The img sizing is a bit weird, which the height is explicit
|
||||
html
|
||||
$"""
|
||||
<div class="atlas-top-nav">
|
||||
<div class="atlas-top-nav-start">
|
||||
<a href="/" style="height: 32px;">{icon}</a>
|
||||
<a href="#about">Oceanbox</a>
|
||||
</div>
|
||||
|
||||
<sp-action-menu
|
||||
label="Account"
|
||||
placement="bottom-end"
|
||||
@change={Ev handleActionMenu}
|
||||
>
|
||||
<sp-menu-item disabled>Settings</sp-menu-item>
|
||||
<sp-menu-item disabled>Profile</sp-menu-item>
|
||||
<sp-menu-divider></sp-menu-divider>
|
||||
<sp-menu-item disabled>Help</sp-menu-item>
|
||||
<sp-menu-item value="logout">Logout</sp-menu-item>
|
||||
</sp-action-menu>
|
||||
"""
|
||||
let menuButton =
|
||||
match model.activeTab with
|
||||
| Tab.Select -> menu
|
||||
| _ -> menu
|
||||
|
||||
html
|
||||
$"""
|
||||
<sp-top-nav size="s">
|
||||
<sp-top-nav-item @click={Ev (fun _ -> window.location.reload ())}>
|
||||
{icon}
|
||||
</sp-top-nav-item>
|
||||
{menuButton}
|
||||
</sp-top-nav>
|
||||
</div>
|
||||
"""
|
||||
|
||||
[<HookComponent>]
|
||||
let archiveSelectModal (modelAreaOpt: ModelArea option) (archives: ArchiveProps array) onClose =
|
||||
let private archiveSelectModal (modelAreaOpt: ModelArea option) (archives: ArchiveProps array) onClose =
|
||||
Hook.useHmr hmr
|
||||
|
||||
let modelAreaName = modelAreaOpt |> Option.map (fun model -> $"{model.name} archives") |> Option.defaultValue "N/A"
|
||||
let archiveRow (archive: ArchiveProps) =
|
||||
let selectArchive (archive: ArchiveProps) =
|
||||
do Lib.Umami.track("atlas-select-archive", {| id = archive.archiveId; name = archive.name |})
|
||||
sessionStorage["archive_id"] <- string archive.archiveId
|
||||
window.location.href <- "/map.html"
|
||||
|
||||
let startTimeStr = archive.startTime.ToString "dd/MM/yyyy"
|
||||
let daysLong = archive.endTime - archive.startTime
|
||||
|
||||
html
|
||||
$"""
|
||||
html $"""
|
||||
<sp-table-row @click={Ev (fun _ -> selectArchive archive)}>
|
||||
<sp-table-cell>{archive.name}</sp-table-cell>
|
||||
<sp-table-cell>{startTimeStr}</sp-table-cell>
|
||||
<sp-table-cell>{daysLong.Days}</sp-table-cell>
|
||||
</sp-table-row>
|
||||
"""
|
||||
|
||||
let archiveRows =
|
||||
match modelAreaOpt with
|
||||
| None -> html $"""No model area selected"""
|
||||
| Some modelArea -> archives |> Lit.mapUnique (fun a -> a.archiveId.ToString ()) archiveRow
|
||||
| Some modelArea ->
|
||||
archives
|
||||
|> Array.sortByDescending _.startTime
|
||||
|> Lit.mapUnique (fun a -> a.archiveId.ToString ()) archiveRow
|
||||
|
||||
let content () =
|
||||
if Array.isEmpty archives then
|
||||
html
|
||||
$"""
|
||||
<div class="full-box flex-center">
|
||||
<sp-progress-circle label="Loading archives" size="l" indeterminate></sp-progress-circle>
|
||||
</div>
|
||||
"""
|
||||
else
|
||||
html
|
||||
$"""
|
||||
<sp-table
|
||||
size="s"
|
||||
scroller="true"
|
||||
style="width: 100%%;"
|
||||
>
|
||||
<sp-table-head>
|
||||
<sp-table-head-cell>Name</sp-table-head-cell>
|
||||
<sp-table-head-cell>Start</sp-table-head-cell>
|
||||
<sp-table-head-cell>Days</sp-table-head-cell>
|
||||
</sp-table-head>
|
||||
<sp-table-body>
|
||||
{archiveRows}
|
||||
</sp-table-body>
|
||||
</sp-table>
|
||||
"""
|
||||
|
||||
html
|
||||
$"""
|
||||
<sp-underlay ?open={modelAreaOpt.IsSome} @click={fun _ -> onClose ()}></sp-underlay>
|
||||
|
||||
<sp-dialog size="l" dismissable @close={Ev (fun _ -> onClose ())}>
|
||||
<h2 slot="heading"> {modelAreaOpt
|
||||
|> Option.map _.name
|
||||
|> Option.defaultValue "N/A"}</h2>
|
||||
<h4>Archives</h4>
|
||||
<sp-table
|
||||
size="s"
|
||||
scroller="true"
|
||||
>
|
||||
<sp-table-head>
|
||||
<sp-table-head-cell>Name</sp-table-head-cell>
|
||||
<sp-table-head-cell>Start</sp-table-head-cell>
|
||||
<sp-table-head-cell>Days</sp-table-head-cell>
|
||||
</sp-table-head>
|
||||
<sp-table-body>
|
||||
{archiveRows}
|
||||
</sp-table-body>
|
||||
</sp-table>
|
||||
<h2 slot="heading">{modelAreaName}</h2>
|
||||
{content ()}
|
||||
</sp-dialog>
|
||||
"""
|
||||
"""
|
||||
|
||||
let selectStyle name =
|
||||
let stroke' =
|
||||
Style.stroke [ stroke.color "rgba(50, 50, 50, 0.9)"; stroke.width 1.3 ]
|
||||
let fill' = Style.fill [ fill.color "rgba(255, 255, 255, 0.5)" ]
|
||||
Fable.OpenLayers.Style.style [
|
||||
|
||||
Style.style [
|
||||
style.fill fill'
|
||||
style.stroke stroke'
|
||||
style.text (
|
||||
@@ -414,9 +440,8 @@ let selectStyle name =
|
||||
|
||||
[<HookComponent>]
|
||||
let userAccessModal isRegistered isActive =
|
||||
// let showModal, setModal = Hook.useState (isActive || isRegistered)
|
||||
Hook.useHmr hmr
|
||||
|
||||
console.debug $"user registered={isRegistered} active={isActive}"
|
||||
let accessNotifier =
|
||||
if not isRegistered then
|
||||
html
|
||||
@@ -445,9 +470,8 @@ let userAccessModal isRegistered isActive =
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
[<LitElement("atlas-app")>]
|
||||
let SelectApp () =
|
||||
let AtlasApp () =
|
||||
Hook.useHmr hmr
|
||||
LitElement.init (fun cfg -> cfg.useShadowDom <- false) |> ignore
|
||||
|
||||
@@ -474,7 +498,9 @@ let SelectApp () =
|
||||
Hook.useEffectOnce (fun () ->
|
||||
async {
|
||||
do! Auth.establishAuthentication ()
|
||||
do! Auth.setId ()
|
||||
// do! Auth.startTokenRefreshLoopOrLogin ()
|
||||
do! Lib.Umami.init ()
|
||||
|
||||
do! Atlantis.IDB.tryResetOutdatedIDB () |> Async.AwaitPromise
|
||||
|
||||
@@ -492,7 +518,7 @@ let SelectApp () =
|
||||
// // TODO: Refresh in expiry time?
|
||||
// sessionStorage["barentswatch_token"] <- token.AccessToken
|
||||
|
||||
do! Utils.initAtlantisSessionUrls ()
|
||||
do! Auth.initSessionUrls ()
|
||||
|
||||
// let drifters = driftersJobApi ()
|
||||
// let! fenceRadius = drifters.getFenceRadius()
|
||||
@@ -536,7 +562,6 @@ let SelectApp () =
|
||||
"click",
|
||||
fun (event: MapBrowserEvent) ->
|
||||
let features = model.map.getFeaturesAtPixel event.pixel
|
||||
console.debug ("Features:", features)
|
||||
features
|
||||
|> Array.tryHead
|
||||
|> Option.iter (fun feature ->
|
||||
@@ -562,12 +587,10 @@ let SelectApp () =
|
||||
|
||||
let selectedModelAreaArchives =
|
||||
model.selectedModelArea
|
||||
|> Option.map (fun modelArea ->
|
||||
if Map.containsKey modelArea.modelAreaId model.archives then
|
||||
model.archives[modelArea.modelAreaId]
|
||||
else
|
||||
[||]
|
||||
)
|
||||
|> Option.bind (fun modelArea ->
|
||||
model.archives
|
||||
|> Map.tryFind modelArea.modelAreaId
|
||||
)
|
||||
|> Option.defaultValue [||]
|
||||
|
||||
html
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<DefineConstants>FABLE_COMPILER</DefineConstants>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<Version>2.87.0</Version>
|
||||
@@ -11,27 +11,27 @@
|
||||
<Compile Include="Atlas.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fable.Browser.IndexedDB" Version="2.2.0" />
|
||||
<PackageReference Include="Fable.Browser.WebGL" Version="1.3.0" />
|
||||
<PackageReference Include="Fable.Core" Version="4.4.0" />
|
||||
<PackageReference Include="Fable.Elmish" Version="4.2.0" />
|
||||
<PackageReference Include="Fable.Fetch" Version="2.7.0" />
|
||||
<PackageReference Include="Fable.Lit" Version="1.6.2-oceanbox" />
|
||||
<PackageReference Include="Fable.Lit.React" Version="1.6.2-oceanbox" />
|
||||
<PackageReference Include="Fable.Lit.Elmish" Version="1.6.2-oceanbox" />
|
||||
<PackageReference Include="Fable.Promise" Version="3.2.0" />
|
||||
<PackageReference Include="Fable.React" Version="9.4.0" />
|
||||
<PackageReference Include="Fable.Remoting.Client" Version="7.32.0" />
|
||||
<PackageReference Include="Fable.Remoting.MsgPack" Version="1.24.0" />
|
||||
<PackageReference Include="Fable.OpenLayers" Version="2.18.0" />
|
||||
<PackageReference Include="Fable.SignalR.Elmish" Version="2.1.0" />
|
||||
<PackageReference Include="Fable.SimpleHttp" Version="3.6.0" />
|
||||
<PackageReference Include="Feliz" Version="2.9.0" />
|
||||
<PackageReference Include="Feliz.CompilerPlugins" Version="2.2.0" />
|
||||
<PackageReference Include="Thoth.Fetch" Version="3.0.1" />
|
||||
<PackageReference Include="Thoth.Json" Version="10.4.1" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201" />
|
||||
<PackageReference Include="Matplotlib.ColorMaps" Version="3.0.1" />
|
||||
<PackageReference Include="Fable.Browser.IndexedDB" />
|
||||
<PackageReference Include="Fable.Browser.WebGL" />
|
||||
<PackageReference Include="Fable.Core" />
|
||||
<PackageReference Include="Fable.Elmish" />
|
||||
<PackageReference Include="Fable.Fetch" />
|
||||
<PackageReference Include="Fable.Lit" />
|
||||
<PackageReference Include="Fable.Lit.React" />
|
||||
<PackageReference Include="Fable.Lit.Elmish" />
|
||||
<PackageReference Include="Fable.Promise" />
|
||||
<PackageReference Include="Fable.React" />
|
||||
<PackageReference Include="Fable.Remoting.Client" />
|
||||
<PackageReference Include="Fable.Remoting.MsgPack" />
|
||||
<PackageReference Include="Fable.OpenLayers" />
|
||||
<PackageReference Include="Fable.SignalR.Elmish" />
|
||||
<PackageReference Include="Fable.SimpleHttp" />
|
||||
<PackageReference Include="Feliz" />
|
||||
<PackageReference Include="Feliz.CompilerPlugins" />
|
||||
<PackageReference Include="Thoth.Fetch" />
|
||||
<PackageReference Include="Thoth.Json" />
|
||||
<PackageReference Include="Matplotlib.ColorMaps" />
|
||||
<PackageReference Include="FSharp.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Lib\Lib.fsproj" />
|
||||
|
||||
654
src/Atlantis/src/Client/Atlas/packages.lock.json
Normal file
654
src/Atlantis/src/Client/Atlas/packages.lock.json
Normal file
@@ -0,0 +1,654 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dependencies": {
|
||||
"net10.0": {
|
||||
"Fable.Browser.IndexedDB": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.2.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "6RU8aqUeb4qpAekPEjnpaWP+RRTyYMB4ICE06eZoMoTXPq0oGWxsEkHPgDJIPVTmyDuAGJ4YMcDCt2D8850xMw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Browser.Dom": "2.14.0",
|
||||
"Fable.Browser.Event": "1.5.0",
|
||||
"Fable.Core": "3.2.8"
|
||||
}
|
||||
},
|
||||
"Fable.Browser.WebGL": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.3.0, )",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "iQognakmr62KccqZg++oenn1J0eSdCexAFUII0fSWAz1tTfdaPxrFKIjagHd/3HWw5NettpyNJREVRDghklYTQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Browser.Dom": "2.16.0",
|
||||
"Fable.Browser.Event": "1.6.0",
|
||||
"Fable.Core": "3.2.8"
|
||||
}
|
||||
},
|
||||
"Fable.Core": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.4.0, )",
|
||||
"resolved": "4.4.0",
|
||||
"contentHash": "zVQdiC8RqCOBb3KACTp9ASU9Q46esXXWosZQT/Vu/RhCpkfVwXPmBxVayy3iyqaRWc7XSu4Af7pbOqlcL/RtdA=="
|
||||
},
|
||||
"Fable.Elmish": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.2.0, )",
|
||||
"resolved": "4.2.0",
|
||||
"contentHash": "A8lDcHbz2AKcwFa6IlnK8I/21nbsxBcP5Vxq6Gp+jT8dU7Vjpnk8Pbry5+zQrlqjwt1XHU/S5Oo0KZqaGemPUA==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Core": "3.7.1"
|
||||
}
|
||||
},
|
||||
"Fable.Fetch": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.7.0, )",
|
||||
"resolved": "2.7.0",
|
||||
"contentHash": "2ndGZZTqpX9Hyso51tnIxWAskN2zrHX+7LeAwfG4zew+DtMMGa/3IyJGl2BOYUwweq2MhfuVqs1K3avgBFDq+Q==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Browser.Blob": "1.2.0",
|
||||
"Fable.Browser.Event": "1.5.0",
|
||||
"Fable.Core": "3.7.1",
|
||||
"Fable.Promise": "2.2.2"
|
||||
}
|
||||
},
|
||||
"Fable.Lit": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.6.2-oceanbox, )",
|
||||
"resolved": "1.6.2-oceanbox",
|
||||
"contentHash": "ylo6UgB6FiGyINpDvryYt3GPl8MH6fvB5tiNizCmsNNerGxw/THFMGGJHmukQDh64NHru4ARhPTPgkBvsyOTVA==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "8.0.300",
|
||||
"Fable.Browser.Dom": "2.17.0",
|
||||
"Fable.Core": "4.3.0",
|
||||
"Fable.Promise": "3.2.0"
|
||||
}
|
||||
},
|
||||
"Fable.Lit.Elmish": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.6.2-oceanbox, )",
|
||||
"resolved": "1.6.2-oceanbox",
|
||||
"contentHash": "K0fBlpHWZs07s3OYcpBZXVo+xoot62f+USdw8Pi9yxd8a6rmfsbbPlDQvGe2k6VpkEelXNL0AMwEt9GxEY1DeQ==",
|
||||
"dependencies": {
|
||||
"Fable.Elmish": "4.2.0",
|
||||
"Fable.Lit": "1.6.2-oceanbox"
|
||||
}
|
||||
},
|
||||
"Fable.Lit.React": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.6.2-oceanbox, )",
|
||||
"resolved": "1.6.2-oceanbox",
|
||||
"contentHash": "+k0/F4mWZe91GuPDJxBTawUFKegQyNU48OjwAQTzzp3RlibCo1wvFtZjISJz83OvHcjuCSmO02i7uxWm9j6gFw==",
|
||||
"dependencies": {
|
||||
"Fable.Lit": "1.6.2-oceanbox",
|
||||
"Feliz": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Fable.OpenLayers": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.19.0, )",
|
||||
"resolved": "2.19.0",
|
||||
"contentHash": "zVwnqj8LHHUVuw4loS88ZvFCYILKDtG/NWzhGOLwZ5yqj+pRxlD6Mex7zsGrSc08y3P/D/LLdjKmJuE/Nbgo6Q==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "9.0.303",
|
||||
"Fable.Browser.Dom": "2.18.0",
|
||||
"Fable.Browser.WebGL": "1.3.0",
|
||||
"Fable.Core": "4.3.0"
|
||||
}
|
||||
},
|
||||
"Fable.Promise": {
|
||||
"type": "Direct",
|
||||
"requested": "[3.2.0, )",
|
||||
"resolved": "3.2.0",
|
||||
"contentHash": "4A+Iiembrny2h3AE2BIbchfuLmWHNhpkOTvbTtFXHtGzHVMqEVFRXrAfdy83wX2wK5Og3fqRo1y8t/Bqkd7j6g==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Core": "3.7.1"
|
||||
}
|
||||
},
|
||||
"Fable.React": {
|
||||
"type": "Direct",
|
||||
"requested": "[9.4.0, )",
|
||||
"resolved": "9.4.0",
|
||||
"contentHash": "c33FD2BumoYvu4/8bz2ToWaLZyfq2GMo7nq0RB/Bdoj7KdNObNBw2s1jWTi9whcf/s3tmikoXS4gZUKpD9MJ8g==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.React.Types": "18.3.0",
|
||||
"Fable.ReactDom.Types": "18.2.0"
|
||||
}
|
||||
},
|
||||
"Fable.Remoting.Client": {
|
||||
"type": "Direct",
|
||||
"requested": "[7.32.0, )",
|
||||
"resolved": "7.32.0",
|
||||
"contentHash": "PMZ0gj8UXXBKrLg71IwGGTMmy2woSdesjFYkrkDNYmhNDvz3Z/h05fJYOVXYYKXp/d2XRX0fHtGV0DuYppip7A==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Browser.XMLHttpRequest": "1.0.0",
|
||||
"Fable.Core": "3.1.5",
|
||||
"Fable.Remoting.MsgPack": "1.24.0",
|
||||
"Fable.SimpleJson": "3.24.0"
|
||||
}
|
||||
},
|
||||
"Fable.Remoting.MsgPack": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.24.0, )",
|
||||
"resolved": "1.24.0",
|
||||
"contentHash": "Bn3nzoZbib6lPk70bIJumEu2wFMxciB4o8k0Zw6tRfAOpNKvUsi79OOll2nW3FU1P6MVBepT43m+R8JvfYnNiw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2"
|
||||
}
|
||||
},
|
||||
"Fable.SignalR.Elmish": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.1.0, )",
|
||||
"resolved": "2.1.0",
|
||||
"contentHash": "sPPuEcpKlRGACbX7Hk4kh31+aii8GAM8toTwYpmrtU+Zl9QocwbWK6nPJaE0YbQ41ZJgohyU6bNhKt7+SPKZhw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "9.0.100",
|
||||
"Fable.Elmish": "4.2.0",
|
||||
"Fable.Promise": "3.2.0",
|
||||
"Fable.SignalR": "2.1.0"
|
||||
}
|
||||
},
|
||||
"Fable.SimpleHttp": {
|
||||
"type": "Direct",
|
||||
"requested": "[3.6.0, )",
|
||||
"resolved": "3.6.0",
|
||||
"contentHash": "RHXu3OQVxoxObErhUWl7J9JWXqDxLaQrpIXyo2MECF1a9ekNZ5bBnDGVB1RCEKRpVFB6SOun/pk+DB5wJDYmmg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.6.2",
|
||||
"Fable.Browser.Dom": "1.0.0",
|
||||
"Fable.Browser.XMLHttpRequest": "1.1.0",
|
||||
"Fable.Core": "3.0.0"
|
||||
}
|
||||
},
|
||||
"Feliz": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.9.0, )",
|
||||
"resolved": "2.9.0",
|
||||
"contentHash": "8nyGREGA60RysdSBamVWmr68MG+3lLy76W17fBiGaKi7uMFbtRcYBLyNtp2NyGZFfnuWCEyDAmAXM5YFnDhbhg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.ReactDom.Types": "18.2.0",
|
||||
"Feliz.CompilerPlugins": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Feliz.CompilerPlugins": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.2.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "ACkO++Hp4lUrEx/axeehIL5/3R8jMnak+CYpzd0/kLpejp9BETtrgjHK7oj6Lh3V9fB7WoAKsCxyPSrm4ADN2w==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.AST": "4.2.1"
|
||||
}
|
||||
},
|
||||
"FSharp.Core": {
|
||||
"type": "Direct",
|
||||
"requested": "[9.0.303, )",
|
||||
"resolved": "9.0.303",
|
||||
"contentHash": "6JlV8aD8qQvcmfoe/PMOxCHXc0uX4lR23u0fAyQtnVQxYULLoTZgwgZHSnRcuUHOvS3wULFWcwdnP1iwslH60g=="
|
||||
},
|
||||
"Matplotlib.ColorMaps": {
|
||||
"type": "Direct",
|
||||
"requested": "[3.0.1, )",
|
||||
"resolved": "3.0.1",
|
||||
"contentHash": "Amw/NumOXIOB4Z/YbBErDd7gcZrtNhG10aeF9MydXUVNmmf7BJKeHDroSnzMRbsUOf3oQCXhzyjng6mhmRA0LA==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.4"
|
||||
}
|
||||
},
|
||||
"Thoth.Fetch": {
|
||||
"type": "Direct",
|
||||
"requested": "[3.0.1, )",
|
||||
"resolved": "3.0.1",
|
||||
"contentHash": "5i8KQwTFzDEoIjE/fAwCw0GFICCsFzVkVq2w4uU1fRlOqbSfLlUNcCEq6JkeAvQ+Jj7syMKNPSH994T8NswcpA==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Core": "3.2.8",
|
||||
"Fable.Fetch": "2.1.0",
|
||||
"Fable.Promise": "2.0.0",
|
||||
"Thoth.Json": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Thoth.Json": {
|
||||
"type": "Direct",
|
||||
"requested": "[10.4.1, )",
|
||||
"resolved": "10.4.1",
|
||||
"contentHash": "hs76/uO+gHhvnlaxQDqbpUX2Y0L97ilEZ1Nx+LA4D6N7fuAYJmNwQWZB/KQLBE7wIeWK5oXMFHCuKdImSrF1Bg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "5.0.2",
|
||||
"Fable.Core": "4.1.0"
|
||||
}
|
||||
},
|
||||
"Dapr.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.16.0",
|
||||
"contentHash": "6JyPI8LxNXSjSpO9vTdbfJh78zOiiC0sgeaXuY8O6SJQh2epaRdEPw0UpamNnld3CkDjp69/VCphox7pU/lh1Q==",
|
||||
"dependencies": {
|
||||
"Dapr.Protos": "1.16.0",
|
||||
"Google.Api.CommonProtos": "2.17.0",
|
||||
"Google.Protobuf": "3.32.0",
|
||||
"Grpc.Net.Client": "2.71.0",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Dapr.Protos": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.16.0",
|
||||
"contentHash": "4k4iKjyRCsFwX7KY5tDcBWDe6JPkhnvN1nqd8zRhDw3YcajF/Br3SU072YdEQKUQ/MJNvqafvzCNPbqSbK3nqg==",
|
||||
"dependencies": {
|
||||
"Google.Api.CommonProtos": "2.17.0",
|
||||
"Google.Protobuf": "3.32.0",
|
||||
"Grpc.Net.Client": "2.71.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Fable.AST": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.2.1",
|
||||
"contentHash": "/4V6U7Qw/WIRRxm9NJ7b+YTXTRCTk6/YKeJnbKYaVbtT45MstA3jkFvRfV0FqVFtkG9AL4uccetreygTjK7nbQ=="
|
||||
},
|
||||
"Fable.Browser.Blob": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.4.0",
|
||||
"contentHash": "UlaxrIXUfMmABjP+8a4XJp/Af+eCRKa8KJ57Olq4sqphmPLn/gNtp3sk5hRNBZ385lwUszbO5yd3Q/rrl9BdOQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Core": "3.2.8"
|
||||
}
|
||||
},
|
||||
"Fable.Browser.Dom": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.18.0",
|
||||
"contentHash": "usu19HS3yRIPvzQ//Yj+Dp6SkJ1fkVUVOREaeDR4iLXGTKl0UqR1nPT1tEBX2GGMefj7dVrmG0dbONirOlVFBw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Browser.Blob": "1.4.0",
|
||||
"Fable.Browser.Event": "1.7.0",
|
||||
"Fable.Browser.WebStorage": "1.3.0",
|
||||
"Fable.Core": "3.2.8"
|
||||
}
|
||||
},
|
||||
"Fable.Browser.Event": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.7.0",
|
||||
"contentHash": "x+wqXQK0l4VlCnELDp68GC/mZAx6NbicDxYPliyAoNq8RPNDeR3R782icNwI5YmA+ufq11XvG6w1JjsL/ldy7w==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Browser.Gamepad": "1.3.0",
|
||||
"Fable.Core": "3.2.8"
|
||||
}
|
||||
},
|
||||
"Fable.Browser.Gamepad": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "C4HZDzCgff+U094QjpQlJh425W5j5/vojvOi2FV5UFS34l7TJ6YBgBPpKoro02QhAi/UF3AeocR+V2yiYxHb0A==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Core": "3.2.8"
|
||||
}
|
||||
},
|
||||
"Fable.Browser.WebStorage": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "x8JL9oEtPiK0JY4GrRTqhomiLxT6Jaiv5uu8VXiNeA78bFvUogZWxQeejsK83iNFGErK5wpdiPd0tsREZTRLeg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Browser.Event": "1.6.0",
|
||||
"Fable.Core": "3.2.8"
|
||||
}
|
||||
},
|
||||
"Fable.Browser.XMLHttpRequest": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.0",
|
||||
"contentHash": "27p/F8781NrnV9vQ23RhX10ww9MDkX+Yi3yTiV9s8U8Bufi/VCCjS4swX0LXvgKQANN3k87CwaNeiO75r2U7gw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.6.2",
|
||||
"Fable.Browser.Blob": "1.1.0",
|
||||
"Fable.Browser.Event": "1.0.0",
|
||||
"Fable.Core": "3.0.0"
|
||||
}
|
||||
},
|
||||
"Fable.Parsimmon": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.0",
|
||||
"contentHash": "AaHqEcwjjv8q5S2gCNu6XsVcpChYM8D6aEb3sjjsAiLspwLrNLqm6vOEKdJKGnh0gSLHg6UWzLGA/Q4jrk+t/w==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.6.2",
|
||||
"Fable.Core": "3.0.0"
|
||||
}
|
||||
},
|
||||
"Fable.React.Types": {
|
||||
"type": "Transitive",
|
||||
"resolved": "18.3.0",
|
||||
"contentHash": "/b8WZ3Bdfhqy9r60ZK9JGZaGNjIMb0ogsrvWIg3k7KfCEvJs5X6+7hCybVkyjVoxwzn9wLyYGRbh5wmuHQT/Vg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Browser.Dom": "2.4.4",
|
||||
"Fable.Core": "3.2.7"
|
||||
}
|
||||
},
|
||||
"Fable.ReactDom.Types": {
|
||||
"type": "Transitive",
|
||||
"resolved": "18.2.0",
|
||||
"contentHash": "2WoBjsLiSgrvR68OJXko0iVaqeMbkPM5Bx813A1WlxOSCJ50M9fwnlwG/MUEZtiOIhQmku/YTJY5a8E8r1+j2Q==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.React.Types": "18.3.0"
|
||||
}
|
||||
},
|
||||
"Fable.SignalR": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.0",
|
||||
"contentHash": "CTBaS44I4fGG++g9wRbNO/gOxy5gPKBkw1UPP9rA8j/bX0SpfJENtavVI0ZHJLltf5umy01RG9HMWlMpi1Q6Sw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "9.0.100",
|
||||
"Fable.Promise": "3.2.0",
|
||||
"Fable.Remoting.MsgPack": "1.24.0",
|
||||
"Fable.SimpleJson": "3.24.0"
|
||||
}
|
||||
},
|
||||
"Fable.SimpleJson": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.24.0",
|
||||
"contentHash": "mNk5s+8arkrrupT52/840xybT/DmaPUsJ926fTHk2uHOaWLnyNbUPY63Yg8zJZFCxSCzWrFpmB8rS9fcLVLJSg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.0",
|
||||
"Fable.Core": "3.1.5",
|
||||
"Fable.Parsimmon": "4.0.0"
|
||||
}
|
||||
},
|
||||
"Google.Api.CommonProtos": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.17.0",
|
||||
"contentHash": "elfQPknFr495hm7vdy6ZlgyQh6yzZq9TU7sS35L/Fj/fqjM/mUGau9gVJLhvQEtUlPjtR80hpn/m9HvBMyCXIw==",
|
||||
"dependencies": {
|
||||
"Google.Protobuf": "[3.31.1, 4.0.0]"
|
||||
}
|
||||
},
|
||||
"Google.Protobuf": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.32.0",
|
||||
"contentHash": "fsKxV5bhcvXmZi+cUo5+IxzRMBHwHeFO8G5utNa9f+Mu37kmfy8JcUVvWPt4cX7EuQWAjjHUjZqVl7nGSTRHRg=="
|
||||
},
|
||||
"Grpc.Core.Api": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.71.0",
|
||||
"contentHash": "QquqUC37yxsDzd1QaDRsH2+uuznWPTS8CVE2Yzwl3CvU4geTNkolQXoVN812M2IwT6zpv3jsZRc9ExJFNFslTg=="
|
||||
},
|
||||
"Grpc.Net.Client": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.71.0",
|
||||
"contentHash": "U1vr20r5ngoT9nlb7wejF28EKN+taMhJsV9XtK9MkiepTZwnKxxiarriiMfCHuDAfPUm9XUjFMn/RIuJ4YY61w==",
|
||||
"dependencies": {
|
||||
"Grpc.Net.Common": "2.71.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Grpc.Net.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.71.0",
|
||||
"contentHash": "v0c8R97TwRYwNXlC8GyRXwYTCNufpDfUtj9la+wUrZFzVWkFJuNAltU+c0yI3zu0jl54k7en6u2WKgZgd57r2Q==",
|
||||
"dependencies": {
|
||||
"Grpc.Core.Api": "2.71.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "6m+8Xgmf8UWL0p/oGqBM+0KbHE5/ePXbV1hKXgC59zEv0aa0DW5oiiyxDbK5kH5j4gIvyD5uWL0+HadKBJngvQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "yNou2KM35RvzOh4vUFtl2l33rWPvOCoba+nzEDJ+BgD8aOL/jew4WPCibQvntRfOJ2pJU8ARygSMD+pdjvDHuA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "0vK9DnYrYChdiH3yRZWkkp4x4LbrfkWEdBc5HOsQ8t/0CLOWKXKkkhOE8A1shlex0hGydbGrhObeypxz/QTm+w==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "JJjI2Fa+QtZcUyuNjbKn04OjIUX5IgFGFu/Xc+qvzh1rXdZHLcnqqVXhR4093bGirTwacRlHiVg1XYI9xum6QQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "xY3lTjj4+ZYmiKIkyWitddrp1uL5uYiweQjqo4BKBw01ZC4HhcfgLghDpPZcUlppgWAFqFy9SgkiYWOMx365pw=="
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "BKkLCFXzJvNmdngeYBf72VXoZqTJSb1orvjdzDLaGobicoGFBPW8ug2ru1nnEewMEwJzMgnsjHQY8EaKWmVhKg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "UDY7blv4DCyIJ/8CkNrQKLaAZFypXQavRZ2DWf/2zi1mxYYKKw2t8AOCBWxNntyPZHPGhtEmL3snFM98ADZqTw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Http": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "jDj+4aDByk47oESlDDTtk6LWzlXlmoCsjCn6ihd+i9OntN885aPLszUII5+w0B/7wYSZcS3KdjqLAIhKLSiBXQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "Z/7ze+0iheT7FJeZPqJKARYvyC2bmwu3whbm/48BJjdlGVvgDguoCqJIkI/67NkroTYobd5geai1WheNQvWrgA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "pYnAffJL7ARD/HCnnPvnFKSIHnTSmWz84WIlT9tPeQ4lHNiu0Az7N/8itihWvcF8sT+VVD5lq8V+ckMzu4SbOw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "OmTaQ0v4gxGQkehpwWIqPoEiwsPuG/u4HUsbOFoWGx4DKET2AXzopnFe/fE608FIhzc/kcg2p8JdyMRCCUzitQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "eW2s6n06x0w6w4nsX+SvpgsFYkl+Y0CttYAt6DKUXeqprX+hzNqjSfOh637fwNJBg7wRBrOIRHe49gKiTgJxzQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "9.0.8",
|
||||
"contentHash": "tizSIOEsIgSNSSh+hKeUVPK7xmTIjR8s+mJWOu1KXV3htvNQiPMFRMO17OdI1y/4ZApdBVk49u/08QGC9yvLug=="
|
||||
},
|
||||
"atlantis.api": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "[9.0.303, )",
|
||||
"Hipster.Api": "[1.0.1, )",
|
||||
"Petimeter.Api": "[1.0.0, )"
|
||||
}
|
||||
},
|
||||
"hipster.api": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Dapr.Actors": "[1.16.0, )",
|
||||
"Drifters.Api": "[6.22.0, )",
|
||||
"FSharp.Core": "[9.0.303, )"
|
||||
}
|
||||
},
|
||||
"lib": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Atlantis.Api": "[1.0.1, )",
|
||||
"FSharp.Core": "[9.0.303, )",
|
||||
"Fable.Browser.IndexedDB": "[2.2.0, )",
|
||||
"Fable.Browser.WebGL": "[1.3.0, )",
|
||||
"Fable.Core": "[4.4.0, )",
|
||||
"Fable.Elmish": "[4.2.0, )",
|
||||
"Fable.Fetch": "[2.7.0, )",
|
||||
"Fable.Lit": "[1.6.2-oceanbox, )",
|
||||
"Fable.Lit.Elmish": "[1.6.2-oceanbox, )",
|
||||
"Fable.Lit.React": "[1.6.2-oceanbox, )",
|
||||
"Fable.OpenLayers": "[2.19.0, )",
|
||||
"Fable.Promise": "[3.2.0, )",
|
||||
"Fable.React": "[9.4.0, )",
|
||||
"Fable.Remoting.Client": "[7.32.0, )",
|
||||
"Fable.Remoting.MsgPack": "[1.24.0, )",
|
||||
"Fable.SignalR.Elmish": "[2.1.0, )",
|
||||
"Fable.SimpleHttp": "[3.6.0, )",
|
||||
"Feliz": "[2.9.0, )",
|
||||
"Feliz.CompilerPlugins": "[2.2.0, )",
|
||||
"FsToolkit.ErrorHandling": "[5.0.1, )",
|
||||
"Hipster.Api": "[1.0.1, )",
|
||||
"Matplotlib.ColorMaps": "[3.0.1, )",
|
||||
"Oceanbox.DataAgent.Api": "[7.2.1, )",
|
||||
"Petimeter.Api": "[1.0.0, )",
|
||||
"Sorcerer.Api": "[4.19.0, )",
|
||||
"Thoth.Fetch": "[3.0.1, )",
|
||||
"Thoth.Json": "[10.4.1, )"
|
||||
}
|
||||
},
|
||||
"Oceanbox.DataAgent.Api": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "[9.0.303, )"
|
||||
}
|
||||
},
|
||||
"petimeter.api": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Dapr.Actors": "[1.16.0, )",
|
||||
"FSharp.Core": "[9.0.303, )"
|
||||
}
|
||||
},
|
||||
"sorcerer.api": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Drifters.Api": "[6.22.0, )",
|
||||
"FSharp.Core": "[9.0.303, )",
|
||||
"Oceanbox.DataAgent.Api": "[7.2.1, )"
|
||||
}
|
||||
},
|
||||
"Dapr.Actors": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.16.0, )",
|
||||
"resolved": "1.16.0",
|
||||
"contentHash": "s9v6VofXXYoRqZJQlQbvNYYSlGhkL+Z+bpqrx1TRo06kLhANeDmXA9yeVaD+1KwJIO1chUFj5O4iKuTxIkg1sA==",
|
||||
"dependencies": {
|
||||
"Dapr.Client": "1.16.0",
|
||||
"Dapr.Common": "1.16.0",
|
||||
"Google.Api.CommonProtos": "2.17.0",
|
||||
"Google.Protobuf": "3.32.0",
|
||||
"Grpc.Net.Client": "2.71.0",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Dapr.Client": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.16.0, )",
|
||||
"resolved": "1.16.0",
|
||||
"contentHash": "dFDKol+mtQrk1lIKlEyCx3k6W0Pf+0wC6xcsaDqa0Bg+XCWDc4juROuDcSb0/L1Y+Ev6LSLDMC/FgzNWMw9YtQ==",
|
||||
"dependencies": {
|
||||
"Dapr.Common": "1.16.0",
|
||||
"Dapr.Protos": "1.16.0",
|
||||
"Google.Api.CommonProtos": "2.17.0",
|
||||
"Google.Protobuf": "3.32.0",
|
||||
"Grpc.Net.Client": "2.71.0",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
}
|
||||
},
|
||||
"Drifters.Api": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[6.22.0, )",
|
||||
"resolved": "6.22.0",
|
||||
"contentHash": "EQguKE22Tfd3ayO/jdWiWMBK5R1uzcYo+8agG3ZzAJ1ltl72mIXHqr68BKqO4uhOLtiFs8ErZa4cZ9NVueYHWA==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "9.0.201"
|
||||
}
|
||||
},
|
||||
"FsToolkit.ErrorHandling": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[5.0.1, )",
|
||||
"resolved": "5.0.1",
|
||||
"contentHash": "93oG3WSogK05H4gkikAmx5pBf30TQJfO1Jky+o/N/nv+RTP3nfOfjlmCHzuyUjQCRFOQog/xQabcky+WBWceeQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "9.0.300"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,63 +16,46 @@ let fetchArchives modelAreaId callback =
|
||||
let! res = archmaester.getArchive modelAreaId
|
||||
|
||||
match res with
|
||||
| Error err ->
|
||||
console.error $"Fetch archives error: {err}"
|
||||
| Ok archives ->
|
||||
Some [| archives |]
|
||||
|> callback
|
||||
} |> Async.StartImmediate
|
||||
| Error err -> console.error $"Fetch archives error: {err}"
|
||||
| Ok archives -> Some [| archives |] |> callback
|
||||
}
|
||||
|> Async.StartImmediate
|
||||
|
||||
let fetchModelAreas callback =
|
||||
async {
|
||||
let! res = archmaester.getModelArea HelloWorld
|
||||
let! res = archmaester.getModelAreaArchives (HelloWorld, ArchiveType.FromString "*:*:*")
|
||||
|
||||
match res with
|
||||
| Error err ->
|
||||
console.error $"Fetch model areas error: {err}"
|
||||
| Ok modelAreas ->
|
||||
Some [| modelAreas |]
|
||||
|> callback
|
||||
| Error err -> console.error $"Fetch model areas error: {err}"
|
||||
| Ok modelAreas -> Some modelAreas |> callback
|
||||
}
|
||||
|
||||
[<LitElement("archive-listing")>]
|
||||
let ArchiveListing () =
|
||||
let _, _ =
|
||||
LitElement.init(fun init ->
|
||||
init.useShadowDom <- false
|
||||
)
|
||||
let _, _ = LitElement.init (fun init -> init.useShadowDom <- false)
|
||||
|
||||
let (modelAreas: ModelArea [] option), setModelAreas = Hook.useState None
|
||||
let (modelAreas: ArchiveProps[] option), setModelAreas = Hook.useState None
|
||||
|
||||
Hook.useEffectOnce(fun _ ->
|
||||
fetchModelAreas setModelAreas
|
||||
|> Async.StartImmediate
|
||||
)
|
||||
Hook.useEffectOnce (fun _ -> fetchModelAreas setModelAreas |> Async.StartImmediate)
|
||||
|
||||
let archiveId (a: Archmaester.Dto.ArchiveProps) = a.archiveId.ToString ()
|
||||
let archiveFiles files =
|
||||
let fileEntry (fileName, _) =
|
||||
html $"""<li>{fileName}</li>"""
|
||||
files
|
||||
|> Array.sortBy fst
|
||||
|> Lit.mapUnique fst fileEntry
|
||||
let fileEntry (fileName, _) = html $"""<li>{fileName}</li>"""
|
||||
files |> Array.sortBy fst |> Lit.mapUnique fst fileEntry
|
||||
|
||||
let archiveOwners (acl: ArchiveAcl option) =
|
||||
let owners =
|
||||
match acl with
|
||||
| Some x -> x.users
|
||||
| None -> [||]
|
||||
let userEntry name =
|
||||
html $"""<li>{name}</li>"""
|
||||
let users' =
|
||||
owners
|
||||
|> Array.map userEntry
|
||||
|> Lit.ofArray
|
||||
let userEntry name = html $"""<li>{name}</li>"""
|
||||
let users' = owners |> Array.map userEntry |> Lit.ofArray
|
||||
|
||||
if Array.isEmpty owners then
|
||||
Lit.nothing
|
||||
else
|
||||
html $"""
|
||||
html
|
||||
$"""
|
||||
<span>Owners:</span>
|
||||
<div class="overflow-y-scroll">
|
||||
<ul class="list-disc list-inside">
|
||||
@@ -86,17 +69,14 @@ let ArchiveListing () =
|
||||
match acl with
|
||||
| Some x -> x.users
|
||||
| None -> [||]
|
||||
let userEntry name =
|
||||
html $"""<li>{name}</li>"""
|
||||
let users' =
|
||||
users
|
||||
|> Array.map userEntry
|
||||
|> Lit.ofArray
|
||||
let userEntry name = html $"""<li>{name}</li>"""
|
||||
let users' = users |> Array.map userEntry |> Lit.ofArray
|
||||
|
||||
if Array.isEmpty users then
|
||||
Lit.nothing
|
||||
else
|
||||
html $"""
|
||||
html
|
||||
$"""
|
||||
<span>Users:</span>
|
||||
<div class="overflow-y-scroll">
|
||||
<ul class="list-disc list-inside">
|
||||
@@ -110,17 +90,14 @@ let ArchiveListing () =
|
||||
match acl with
|
||||
| Some x -> x.users
|
||||
| None -> [||]
|
||||
let groupEntry name =
|
||||
html $"""<li>{name}</li>"""
|
||||
let groups' =
|
||||
groups
|
||||
|> Array.map groupEntry
|
||||
|> Lit.ofArray
|
||||
let groupEntry name = html $"""<li>{name}</li>"""
|
||||
let groups' = groups |> Array.map groupEntry |> Lit.ofArray
|
||||
|
||||
if Array.isEmpty groups then
|
||||
Lit.nothing
|
||||
else
|
||||
html $"""
|
||||
html
|
||||
$"""
|
||||
<span>Groups:</span>
|
||||
<div class="overflow-y-scroll max-h-96">
|
||||
<ul class="list-disc list-inside">
|
||||
@@ -130,7 +107,8 @@ let ArchiveListing () =
|
||||
"""
|
||||
|
||||
let archiveItem (item: ArchiveProps) =
|
||||
html $"""
|
||||
html
|
||||
$"""
|
||||
<div class="card w-full shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
@@ -149,20 +127,22 @@ let ArchiveListing () =
|
||||
"""
|
||||
|
||||
let archiveName archiveName =
|
||||
html $"""
|
||||
html
|
||||
$"""
|
||||
<p>{archiveName}</p>
|
||||
"""
|
||||
|
||||
let modelAreaItem (item: ModelArea) =
|
||||
let archiveList =
|
||||
Array.map archiveName item.archives
|
||||
html $"""
|
||||
let modelAreaItem (item: ArchiveProps) =
|
||||
// let archiveList =
|
||||
// Array.map archiveName item.archiveType
|
||||
html
|
||||
$"""
|
||||
<div class="card w-full shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
{item.name}
|
||||
</h2>
|
||||
{archiveList}
|
||||
{item}
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
@@ -170,18 +150,16 @@ let ArchiveListing () =
|
||||
let modelAreaList =
|
||||
match modelAreas with
|
||||
| None -> html $"""<progress class="progress w-56"></progress>"""
|
||||
| Some [||] ->
|
||||
html $"""<h1>No ModelAreas</h1>"""
|
||||
| Some [||] -> html $"""<h1>No ModelAreas</h1>"""
|
||||
| Some models ->
|
||||
html $"""
|
||||
{models
|
||||
|> Lit.mapUnique
|
||||
(fun m -> m.name)
|
||||
modelAreaItem}
|
||||
html
|
||||
$"""
|
||||
{models |> Lit.mapUnique (fun m -> m.name) modelAreaItem}
|
||||
"""
|
||||
|
||||
html $"""
|
||||
html
|
||||
$"""
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{modelAreaList}
|
||||
</div>
|
||||
"""
|
||||
"""
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Version>6.20.0</Version>
|
||||
<RootNamespace>Archivist</RootNamespace>
|
||||
</PropertyGroup>
|
||||
@@ -10,9 +10,9 @@
|
||||
<Compile Include="App.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fable.Lit" Version="1.4.2" />
|
||||
<PackageReference Include="Fable.Remoting.Client" Version="7.32.0" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201" />
|
||||
<PackageReference Include="Fable.Lit" />
|
||||
<PackageReference Include="Fable.Remoting.Client" />
|
||||
<PackageReference Include="FSharp.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\Interfaces\Archmaester\Archmaester.Api.fsproj" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<DefineConstants>FABLE_COMPILER</DefineConstants>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<Version>2.102.0</Version>
|
||||
@@ -9,19 +9,19 @@
|
||||
<RootNamespace>Main</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="index.html"/>
|
||||
<None Include="map.html"/>
|
||||
<None Include="atlas.html"/>
|
||||
<None Include="./public/*.scss"/>
|
||||
<None Include="./public\js\*.js"/>
|
||||
<None Include="./public\js\modules\*"/>
|
||||
<Compile Include="App.fs"/>
|
||||
<None Include="index.html" />
|
||||
<None Include="map.html" />
|
||||
<None Include="atlas.html" />
|
||||
<None Include="./public/*.scss" />
|
||||
<None Include="./public\js\*.js" />
|
||||
<None Include="./public\js\modules\*" />
|
||||
<Compile Include="App.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201"/>
|
||||
<PackageReference Include="FSharp.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="Atlas\Atlas.fsproj"/>
|
||||
<ProjectReference Include="Mapster\Mapster.fsproj"/>
|
||||
<ProjectReference Include="Atlas\Atlas.fsproj" />
|
||||
<ProjectReference Include="Mapster\Mapster.fsproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,8 +1,10 @@
|
||||
module Auth
|
||||
|
||||
open System
|
||||
|
||||
open Browser
|
||||
open Thoth.Json
|
||||
|
||||
open Remoting
|
||||
|
||||
type private JwtToken = { exp: int }
|
||||
@@ -13,17 +15,26 @@ let private jwtDecoder =
|
||||
let establishAuthentication () =
|
||||
async {
|
||||
match! authApi.IsAuthenticated () with
|
||||
| Some _ ->
|
||||
console.debug $"user authenticated"
|
||||
| Some _ -> console.debug $"user authenticated"
|
||||
| None ->
|
||||
console.log "user not authenticated"
|
||||
console.error "User not authenticated"
|
||||
window.location.href <- "/signin"
|
||||
}
|
||||
|
||||
let setId () : Async<unit> =
|
||||
async {
|
||||
match! authApi.GetIdentity () with
|
||||
| Some id ->
|
||||
sessionStorage["id"] <- id.user
|
||||
| None ->
|
||||
console.error "[Auth] User not authenticated"
|
||||
window.location.href <- "/signin"
|
||||
}
|
||||
|
||||
let rec tokenRefreshLoop () =
|
||||
async {
|
||||
let decode (token: string) =
|
||||
localStorage[ token ].Split '.'
|
||||
localStorage[token].Split '.'
|
||||
|> fun x -> Utils.fromBase64String x[1]
|
||||
|> jwtDecoder
|
||||
|> function
|
||||
@@ -31,7 +42,7 @@ let rec tokenRefreshLoop () =
|
||||
| Error e ->
|
||||
console.log e
|
||||
0
|
||||
let t = DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()
|
||||
let t = DateTimeOffset(DateTime.Now).ToUnixTimeSeconds ()
|
||||
|
||||
do! Async.Sleep 1000
|
||||
let aExp = decode "access_token"
|
||||
@@ -39,29 +50,44 @@ let rec tokenRefreshLoop () =
|
||||
let dtA = int64 aExp - t
|
||||
let dtR = int64 rExp - t
|
||||
console.log $"{t} {dtA} {dtR}"
|
||||
if dtR < 0 then Dom.window.location.href <- "/signin"
|
||||
if dtR < 0 then
|
||||
window.location.href <- "/signin"
|
||||
if dtA < 30 then
|
||||
async {
|
||||
match! authApi.RefreshAccessToken localStorage["refresh_token"] with
|
||||
| Some (access, refresh) ->
|
||||
localStorage.setItem ("access_token", access)
|
||||
localStorage.setItem ("refresh_token", refresh)
|
||||
| None ->
|
||||
Dom.window.location.href <- "/signin"
|
||||
| None -> window.location.href <- "/signin"
|
||||
}
|
||||
|> Async.StartImmediate
|
||||
do! Async.Sleep((int dtA - 30) * 1000)
|
||||
do! Async.Sleep ((int dtA - 30) * 1000)
|
||||
tokenRefreshLoop ()
|
||||
}
|
||||
|> Async.StartImmediate
|
||||
|
||||
let startTokenRefreshLoopOrLogin () =
|
||||
async {
|
||||
match! authApi.IsAuthenticated() with
|
||||
match! authApi.IsAuthenticated () with
|
||||
| Some _ ->
|
||||
console.log "already authenticated"
|
||||
tokenRefreshLoop ()
|
||||
| None ->
|
||||
console.log "not already authenticated"
|
||||
Dom.window.location.href <- "/login"
|
||||
window.location.href <- "/login"
|
||||
}
|
||||
|
||||
let initSessionUrls () =
|
||||
async {
|
||||
try
|
||||
let! archiveUrl = servicesApi.GetArchiveService ()
|
||||
let! dataUrl = servicesApi.GetFileService ()
|
||||
|
||||
console.log $"Archive service: {archiveUrl}"
|
||||
sessionStorage["archmaester_url"] <- archiveUrl
|
||||
console.log $"Data service: {dataUrl}"
|
||||
sessionStorage["sorcerer_url"] <- dataUrl
|
||||
with e ->
|
||||
console.error("Failed fetching services. Redirecting to signin. %s", e.Message)
|
||||
window.location.href <- "/signin"
|
||||
}
|
||||
48
src/Atlantis/src/Client/Lib/Chaikin.fs
Normal file
48
src/Atlantis/src/Client/Lib/Chaikin.fs
Normal file
@@ -0,0 +1,48 @@
|
||||
module Chaikin
|
||||
|
||||
let private cut (start: float * float) (end': float * float) (ratio: float) =
|
||||
let startX, startY = start
|
||||
let endX, endY = end'
|
||||
|
||||
// Find point at a given ratio going from A to B
|
||||
let r1 =
|
||||
startX * (1.0 - ratio) + endX * ratio, startY * (1.0 - ratio) + endY * ratio
|
||||
|
||||
// Find point at a given ratio going from B to A
|
||||
let r2 =
|
||||
startX * ratio + endX * (1.0 - ratio), startY * ratio + endY * (1.0 - ratio)
|
||||
|
||||
r1, r2
|
||||
|
||||
let private chaikin (curve: (float * float) array) (iterations: int) (closed: bool) (ratio: float) =
|
||||
// If ratio is greater than 0.5 flip it so we avoid cutting across the midpoint of the line.
|
||||
let adjustedRatio = if ratio > 0.5 then 1.0 - ratio else ratio
|
||||
|
||||
let rec iterate (currentPoints: (float * float) array) remainingIterations =
|
||||
let len = currentPoints.Length
|
||||
if remainingIterations <= 0 || len = 0 then
|
||||
currentPoints
|
||||
else
|
||||
let refined = ResizeArray<float * float> ()
|
||||
|
||||
refined.Add (currentPoints[0])
|
||||
|
||||
for i in 0 .. len - 2 do
|
||||
let r1, r2 = cut currentPoints[i] currentPoints[i + 1] adjustedRatio
|
||||
refined.Add r1
|
||||
refined.Add r2
|
||||
|
||||
if closed then
|
||||
let r1, r2 = cut currentPoints[len - 1] currentPoints[0] adjustedRatio
|
||||
refined.Add r1
|
||||
refined.Add r2
|
||||
else
|
||||
refined.Add (currentPoints[len - 1])
|
||||
|
||||
iterate (refined.ToArray ()) (remainingIterations - 1)
|
||||
|
||||
iterate curve iterations
|
||||
|
||||
let chaikinDefault curve = chaikin curve 1 false 0.25
|
||||
let chaikinWithIterations iterations curve = chaikin curve iterations false 0.25
|
||||
let chaikinWithClosed closed curve = chaikin curve 1 closed 0.25
|
||||
20
src/Atlantis/src/Client/Lib/Colors.fs
Normal file
20
src/Atlantis/src/Client/Lib/Colors.fs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace Lib
|
||||
|
||||
module Colors =
|
||||
open Matplotlib.ColorMaps
|
||||
|
||||
open Atlantis.Types
|
||||
|
||||
let getColormap (colorMap: ColorMode * ColorMap) (lo, hi) =
|
||||
let mode, cmap = colorMap
|
||||
|
||||
let cm =
|
||||
match cmap with
|
||||
| ColorMap.Ocean name -> ColorMap<single>(name, lo, hi, 256, Ocean.colors)
|
||||
| ColorMap.Color16 name -> ColorMap<single>(name, lo, hi, 256, Color16.colors)
|
||||
| ColorMap.Custom _ -> failwith "not implemented"
|
||||
|
||||
match mode with
|
||||
| ColorMode.Normal -> cm
|
||||
| ColorMode.Mirror -> ColorMap<single>.mirrorPalette cm
|
||||
| ColorMode.Gray -> ColorMap<single>.toGrayscale cm
|
||||
@@ -43,9 +43,7 @@ module Types =
|
||||
let RGBAFormat: obj = jsNative
|
||||
|
||||
[<AllowNullLiteral>]
|
||||
type Matrix4 =
|
||||
interface
|
||||
end
|
||||
type Matrix4 = interface end
|
||||
|
||||
[<AllowNullLiteral>]
|
||||
type Euler =
|
||||
@@ -77,9 +75,7 @@ module Types =
|
||||
abstract Create: ?p1: obj * ?p2: obj * ?p3: obj * ?p4: obj -> Vector4
|
||||
|
||||
[<AllowNullLiteral>]
|
||||
type Float32BufferAttribute =
|
||||
interface
|
||||
end
|
||||
type Float32BufferAttribute = interface end
|
||||
and [<AllowNullLiteral>] Float32BufferAttributeType =
|
||||
[<Emit("new THREE.$0($1...)")>]
|
||||
abstract Create: p1: obj * p2: int -> Float32BufferAttribute
|
||||
@@ -221,9 +217,7 @@ module Types =
|
||||
abstract Create: unit -> DirectionalLight
|
||||
|
||||
[<AllowNullLiteral>]
|
||||
type EventDispatcher =
|
||||
interface
|
||||
end
|
||||
type EventDispatcher = interface end
|
||||
|
||||
// Type to resolve parameters for Geometries.
|
||||
[<AllowNullLiteral>]
|
||||
|
||||
@@ -91,7 +91,7 @@ module rec Timeline =
|
||||
abstract ``end``: DateTime option with set, get
|
||||
abstract start: DateTime with get, set
|
||||
abstract object: obj
|
||||
abstract type' : ItemType
|
||||
abstract type': ItemType
|
||||
|
||||
[<StringEnum>]
|
||||
[<RequireQualifiedAccess>]
|
||||
@@ -116,11 +116,14 @@ module rec Timeline =
|
||||
let inline mkTooltip (key: string) (value: obj) : TimelineTooltipOption = unbox (key, value)
|
||||
type tooltip' =
|
||||
static member inline template(value: string) : TimelineTooltipOption = mkTooltip "template" value
|
||||
static member inline template(value: (TimelineItem) -> string) : TimelineTooltipOption = mkTooltip "template" value
|
||||
static member inline template(value: (TimelineItem * TimelineItem) -> string) : TimelineTooltipOption = mkTooltip "template" value
|
||||
static member inline followMouse(value: bool): TimelineTooltipOption = mkTooltip "followMouse" value
|
||||
static member inline overflowMethod(value: TimelineTooltipOptionOverflowMethod): TimelineTooltipOption = mkTooltip "overflowMethod" value
|
||||
static member inline delay(value: int): TimelineTooltipOption = mkTooltip "delay" value
|
||||
static member inline template(value: (TimelineItem) -> string) : TimelineTooltipOption =
|
||||
mkTooltip "template" value
|
||||
static member inline template(value: (TimelineItem * TimelineItem) -> string) : TimelineTooltipOption =
|
||||
mkTooltip "template" value
|
||||
static member inline followMouse(value: bool) : TimelineTooltipOption = mkTooltip "followMouse" value
|
||||
static member inline overflowMethod(value: TimelineTooltipOptionOverflowMethod) : TimelineTooltipOption =
|
||||
mkTooltip "overflowMethod" value
|
||||
static member inline delay(value: int) : TimelineTooltipOption = mkTooltip "delay" value
|
||||
|
||||
|
||||
let private createTimelineItem options : TimelineItem = unbox options
|
||||
@@ -174,7 +177,8 @@ module rec Timeline =
|
||||
static member inline maxHeight(value: string) : TimelineOptions = mkTimelineOption "maxHeight" value
|
||||
/// This option allows you to scroll horizontally to move backwards and forwards in the time range.
|
||||
/// Only applicable when option zoomKey is defined or zoomable is false.
|
||||
static member inline horizontalScroll(value: bool) : TimelineOptions = mkTimelineOption "horizontalScroll" value
|
||||
static member inline horizontalScroll(value: bool) : TimelineOptions =
|
||||
mkTimelineOption "horizontalScroll" value
|
||||
/// NOTE: This probably does not work. Only functioning workaround we have found for nb locales is:
|
||||
///
|
||||
/// o?moment <- fun x ->
|
||||
@@ -202,18 +206,19 @@ module rec Timeline =
|
||||
static member inline groupOrder(value: string) : TimelineOptions = mkTimelineOption "groupOrder" value
|
||||
/// Use a function to render groups as react elements.
|
||||
/// Uses React.render in the bindings to apply the given function to all groups.
|
||||
static member inline groupTemplate(renderFunc: obj -> Feliz.ReactElement): TimelineOptions =
|
||||
static member inline groupTemplate(renderFunc: obj -> Feliz.ReactElement) : TimelineOptions =
|
||||
let value (item, elem, _data) =
|
||||
let root = Feliz.ReactDOM.createRoot elem
|
||||
root.render(renderFunc item)
|
||||
root.render (renderFunc item)
|
||||
mkTimelineOption "groupTemplate" value
|
||||
static member inline selectable(value: bool) : TimelineOptions = mkTimelineOption "selectable" value
|
||||
static member inline showWeekScale(value: bool) : TimelineOptions = mkTimelineOption "showWeekScale" value
|
||||
/// Reduces down to timeline.template, renamed to itemTemplate to match groupTemplate.
|
||||
/// Use a function to render items as react elements.
|
||||
/// Uses React.render in the bindings to apply the given function to all items.
|
||||
static member inline itemTemplate(renderFunc: obj -> Feliz.ReactElement): TimelineOptions =
|
||||
mkTimelineOption "template"
|
||||
static member inline itemTemplate(renderFunc: obj -> Feliz.ReactElement) : TimelineOptions =
|
||||
mkTimelineOption
|
||||
"template"
|
||||
(fun (item, element, data) ->
|
||||
Browser.Dom.console.log item
|
||||
Browser.Dom.console.log element
|
||||
@@ -223,7 +228,7 @@ module rec Timeline =
|
||||
()
|
||||
else
|
||||
let root = Feliz.ReactDOM.createRoot element
|
||||
root.render(renderFunc item)
|
||||
root.render (renderFunc item)
|
||||
)
|
||||
static member inline timeAxis(value: timeAxis) : TimelineOptions = mkTimelineOption "timeAxis" value
|
||||
static member inline tooltip(value: TimelineTooltipOption) : TimelineOptions = mkTimelineOption "tooltip" value
|
||||
@@ -231,7 +236,7 @@ module rec Timeline =
|
||||
/// Specifies whether the Timeline can be zoomed by pinching or scrolling in the window. Only applicable when option moveable is set true.
|
||||
static member inline zoomable(value: bool) : TimelineOptions = mkTimelineOption "zoomable" value
|
||||
/// Specifies how strong the zooming is for each scroll tick. Higher zooming friction will slow zooming speed.
|
||||
static member inline zoomFriction(value: float): TimelineOptions = mkTimelineOption "zoomFriction" value
|
||||
static member inline zoomFriction(value: float) : TimelineOptions = mkTimelineOption "zoomFriction" value
|
||||
/// Specifies whether the Timeline is only zoomed when an additional key is down.
|
||||
/// Available values are '' (does not apply), 'altKey', 'ctrlKey', 'shiftKey' or 'metaKey'.
|
||||
/// Only applicable when option moveable is set true.
|
||||
@@ -243,17 +248,10 @@ module rec Timeline =
|
||||
/// <example>36_000_000. ms is a minimum zoom of 1 hour in ms</example>
|
||||
static member inline zoomMin(value: float) : TimelineOptions = mkTimelineOption "zoomMin" value
|
||||
static member inline xssWhitelist(value: obj) : TimelineOptions =
|
||||
let xss = {|
|
||||
disabled = false
|
||||
filterOptions = {|
|
||||
whiteList = value
|
||||
|}
|
||||
|}
|
||||
let xss = {| disabled = false; filterOptions = {| whiteList = value |} |}
|
||||
mkTimelineOption "xss" xss
|
||||
|
||||
type timeAxis =
|
||||
interface
|
||||
end
|
||||
type timeAxis = interface end
|
||||
|
||||
[<StringEnum(CaseRules.LowerFirst)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
@@ -274,9 +272,7 @@ module rec Timeline =
|
||||
static member inline showStipes(value: bool) = mkTimelineOption "showStipes" value
|
||||
|
||||
// Timeline Options
|
||||
type EditableOption =
|
||||
interface
|
||||
end
|
||||
type EditableOption = interface end
|
||||
|
||||
let inline mkEditableOption (key: string) (value: obj) : EditableOption = unbox (key, value)
|
||||
|
||||
@@ -318,9 +314,9 @@ type IDataSet =
|
||||
[<Import("DataSet", "vis-timeline/standalone")>]
|
||||
type DataSet(data: U2<TimelineItem array, TimelineGroup array>, ?options: obj) =
|
||||
|
||||
new(data: TimelineItem array) = DataSet(U2.Case1 data)
|
||||
new(data: TimelineItem array) = DataSet (U2.Case1 data)
|
||||
|
||||
new(data: TimelineGroup array) = DataSet(U2.Case2 data)
|
||||
new(data: TimelineGroup array) = DataSet (U2.Case2 data)
|
||||
|
||||
/// <summary>
|
||||
/// Add one or multiple items to the DataSet. data can be a single item or an array with items. Adding an item will fail when there already is an item with the same id. The function returns an array with the ids of the added items. See section Data Manipulation.
|
||||
@@ -450,38 +446,34 @@ type DataSet(data: U2<TimelineItem array, TimelineGroup array>, ?options: obj) =
|
||||
type AnimationOptions =
|
||||
| Animation of AnimationOption
|
||||
| Bool of bool
|
||||
and AnimationOption = {
|
||||
duration: float
|
||||
easingFunction: EasingFunction
|
||||
}
|
||||
and
|
||||
[<StringEnum(CaseRules.LowerFirst)>]
|
||||
EasingFunction =
|
||||
| Linear
|
||||
| EaseInQuad
|
||||
| EaseOutQuad
|
||||
| EaseInOutQuad
|
||||
| EaseInCubic
|
||||
| EaseOutCubic
|
||||
| EaseInOutCubic
|
||||
| EaseInQuart
|
||||
| EaseOutQuart
|
||||
| EaseInOutQuart
|
||||
| EaseInQuint
|
||||
| EaseOutQuint
|
||||
| EaseInOutQuint
|
||||
and AnimationOption = { duration: float; easingFunction: EasingFunction }
|
||||
and [<StringEnum(CaseRules.LowerFirst)>] EasingFunction =
|
||||
| Linear
|
||||
| EaseInQuad
|
||||
| EaseOutQuad
|
||||
| EaseInOutQuad
|
||||
| EaseInCubic
|
||||
| EaseOutCubic
|
||||
| EaseInOutCubic
|
||||
| EaseInQuart
|
||||
| EaseOutQuart
|
||||
| EaseInOutQuart
|
||||
| EaseInQuint
|
||||
| EaseOutQuint
|
||||
| EaseInOutQuint
|
||||
|
||||
[<AllowNullLiteral>]
|
||||
[<Import("Timeline", "vis-timeline/standalone")>]
|
||||
type Timeline(container: HTMLElement, items: U2<TimelineItem seq, DataSet>, ?groups: U2<TimelineGroup seq, DataSet>, ?options: TimelineOptions) =
|
||||
type Timeline
|
||||
(
|
||||
container: HTMLElement,
|
||||
items: U2<TimelineItem seq, DataSet>,
|
||||
?groups: U2<TimelineGroup seq, DataSet>,
|
||||
?options: TimelineOptions
|
||||
) =
|
||||
|
||||
new(container, items, groups, options) =
|
||||
Timeline(
|
||||
container = container,
|
||||
items = U2.Case2 items,
|
||||
groups = U2.Case2 groups,
|
||||
options = options
|
||||
)
|
||||
Timeline (container = container, items = U2.Case2 items, groups = U2.Case2 groups, options = options)
|
||||
|
||||
/// <summary>
|
||||
/// Add new vertical bar representing a custom time that can be dragged by the user. Parameter time can be a Date,
|
||||
@@ -559,8 +551,8 @@ type Timeline(container: HTMLElement, items: U2<TimelineItem seq, DataSet>, ?gro
|
||||
member _.getCustomTime() : DateTime = jsNative
|
||||
member _.getCustomTime(ids: Id array) : DateTime = jsNative
|
||||
|
||||
member _.itemsData : IDataSet = jsNative
|
||||
member _.groupsData : IDataSet = jsNative
|
||||
member _.itemsData: IDataSet = jsNative
|
||||
member _.groupsData: IDataSet = jsNative
|
||||
member _.moveTo(time: DateTime, ?options, ?callback) : unit = jsNative
|
||||
|
||||
member _.on(_: string, _: 'a -> unit) : unit = jsNative
|
||||
@@ -601,7 +593,7 @@ type Timeline(container: HTMLElement, items: U2<TimelineItem seq, DataSet>, ?gro
|
||||
member _.setGroups(_: DataSet) : unit = jsNative
|
||||
|
||||
member _.setOptions(_: obj) : unit = jsNative
|
||||
member _.setSelection(_: string []) : unit = jsNative
|
||||
member _.setSelection(_: string[]) : unit = jsNative
|
||||
member _.setWindow(start: DateTime, end': DateTime, ?options: obj, ?callback: obj -> unit) : unit = jsNative
|
||||
member _.zoomIn(_: float) : unit = jsNative
|
||||
|
||||
@@ -630,10 +622,11 @@ type Timeline(container: HTMLElement, items: U2<TimelineItem seq, DataSet>, ?gro
|
||||
///
|
||||
/// A callback function can be passed as an optional parameter. This function will be called at the end of zoomOut function.
|
||||
/// </summary>
|
||||
member _.zoomOut(percentage: float, options: {| animation: AnimationOption |}, ?callback: obj -> unit) : unit = jsNative
|
||||
member _.zoomOut(percentage: float, options: {| animation: AnimationOption |}, ?callback: obj -> unit) : unit =
|
||||
jsNative
|
||||
member _.zoomOut(percentage: float, options: {| animation: bool |}, ?callback: obj -> unit) : unit = jsNative
|
||||
member _.zoomOut(percentage: float) : unit = jsNative
|
||||
|
||||
[<ImportDefault("moment")>]
|
||||
type Moment(timestamp: int) =
|
||||
member _.locale(_:string): Moment = jsNative
|
||||
member _.locale(_: string) : Moment = jsNative
|
||||
@@ -13,14 +13,14 @@ let floatingBox () =
|
||||
let this, props =
|
||||
LitElement.init (fun cfg ->
|
||||
cfg.useShadowDom <- true
|
||||
cfg.props <-
|
||||
{|
|
||||
title = Prop.Of ""
|
||||
xPos = Prop.Of (Dom.window.document.documentElement.clientWidth - 250.0)
|
||||
yPos = Prop.Of 50.0
|
||||
|}
|
||||
cfg.props <- {|
|
||||
title = Prop.Of ""
|
||||
xPos = Prop.Of (Dom.window.document.documentElement.clientWidth - 250.0)
|
||||
yPos = Prop.Of 50.0
|
||||
|}
|
||||
cfg.styles <- [
|
||||
css $"""
|
||||
css
|
||||
$"""
|
||||
#floating-box {{
|
||||
position: fixed;
|
||||
padding: 3px;
|
||||
@@ -38,8 +38,8 @@ let floatingBox () =
|
||||
font-family: Georgia;
|
||||
}}
|
||||
"""
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
let xPos = props.xPos.Value
|
||||
let yPos = props.yPos.Value
|
||||
@@ -47,35 +47,41 @@ let floatingBox () =
|
||||
if this.shadowRoot |> isNull |> not then
|
||||
Hook.useEffectOnce (fun () ->
|
||||
let document = Dom.document
|
||||
let floatingBox = getShadowElementById this "floating-box" :?> Browser.Types.HTMLDivElement
|
||||
let floatingBox =
|
||||
getShadowElementById this "floating-box" :?> Browser.Types.HTMLDivElement
|
||||
let mutable x, y = xPos, yPos
|
||||
let mutable x', y' = xPos, yPos
|
||||
floatingBox.onmousedown <- fun e ->
|
||||
this.dispatchCustomEvent("dragStart")
|
||||
// e.preventDefault ()
|
||||
// NOTE(SimenLK): Hacky attempt to prevent moving the floating box when pressing items within it
|
||||
x' <- e.clientX
|
||||
y' <- e.clientY
|
||||
floatingBox.onmousedown <-
|
||||
fun e ->
|
||||
this.dispatchCustomEvent ("dragStart")
|
||||
// e.preventDefault ()
|
||||
// NOTE(SimenLK): Hacky attempt to prevent moving the floating box when pressing items within it
|
||||
x' <- e.clientX
|
||||
y' <- e.clientY
|
||||
|
||||
floatingBox?style?cursor <- "grabbing"
|
||||
document.onmouseup <- fun _ ->
|
||||
this.dispatchCustomEvent("dragStop")
|
||||
floatingBox?style?cursor <- ""
|
||||
document.onmouseup <- fun _ -> ()
|
||||
document.onmousemove <- fun _ -> ()
|
||||
document.onmousemove <- fun e' ->
|
||||
this.dispatchCustomEvent("dragging")
|
||||
e.preventDefault ()
|
||||
x <- x' - e'.clientX
|
||||
y <- y' - e'.clientY
|
||||
x' <- e'.clientX
|
||||
y' <- e'.clientY
|
||||
floatingBox?style?left <- $"{(floatingBox.offsetLeft - x)}px" // $"{e'.clientX}px"
|
||||
floatingBox?style?top <- $"{(floatingBox.offsetTop - y)}px" // $"{e'.clientY}px"
|
||||
()
|
||||
())
|
||||
floatingBox?style?cursor <- "grabbing"
|
||||
document.onmouseup <-
|
||||
fun _ ->
|
||||
this.dispatchCustomEvent ("dragStop")
|
||||
floatingBox?style?cursor <- ""
|
||||
document.onmouseup <- fun _ -> ()
|
||||
document.onmousemove <- fun _ -> ()
|
||||
document.onmousemove <-
|
||||
fun e' ->
|
||||
this.dispatchCustomEvent ("dragging")
|
||||
e.preventDefault ()
|
||||
x <- x' - e'.clientX
|
||||
y <- y' - e'.clientY
|
||||
x' <- e'.clientX
|
||||
y' <- e'.clientY
|
||||
floatingBox?style?left <- $"{(floatingBox.offsetLeft - x)}px" // $"{e'.clientX}px"
|
||||
floatingBox?style?top <- $"{(floatingBox.offsetTop - y)}px" // $"{e'.clientY}px"
|
||||
()
|
||||
()
|
||||
)
|
||||
|
||||
html $"""
|
||||
html
|
||||
$"""
|
||||
<div
|
||||
id="floating-box" resize="both"
|
||||
style="top: {yPos}px; left: {xPos}px;"
|
||||
|
||||
@@ -11,74 +11,85 @@ let openDB () : IDBDatabase JS.Promise =
|
||||
Promise.create (fun resolve reject ->
|
||||
let openRequest = indexedDB.``open`` ("oceanbox", dbVersion)
|
||||
|
||||
openRequest.onerror <- (fun _ ->
|
||||
console.error "Failed opening oceanbox database"
|
||||
reject (unbox "Fail"))
|
||||
openRequest.onerror <-
|
||||
fun _ ->
|
||||
console.error "Failed opening oceanbox database"
|
||||
reject (unbox "Fail")
|
||||
|
||||
openRequest.onsuccess <-
|
||||
fun _ ->
|
||||
// console.log "oceanbox database opened"
|
||||
let db: IDBDatabase = unbox openRequest.result
|
||||
resolve db
|
||||
|
||||
openRequest.onupgradeneeded <-
|
||||
fun ev ->
|
||||
// console.log $"Upgrading oceanbox database"
|
||||
let db: IDBDatabase = ev.target?result
|
||||
db.onerror <- (fun ev -> console.error $"Could not upgrade database: {ev.target}")
|
||||
let archives =
|
||||
db.createObjectStore ("PlainGrids", !!{| keyPath = "GridSha"; autoIncrement = true |})
|
||||
archives.createIndex ("Vertices", "Vertices") |> ignore
|
||||
archives.createIndex ("Indices", "Indices") |> ignore
|
||||
|
||||
openRequest.onsuccess <- (fun _ ->
|
||||
// console.log "oceanbox database opened"
|
||||
let db: IDBDatabase = unbox openRequest.result
|
||||
resolve db
|
||||
)
|
||||
openRequest.onupgradeneeded <- (fun ev ->
|
||||
// console.log $"Upgrading oceanbox database"
|
||||
let db: IDBDatabase = ev.target?result
|
||||
db.onerror <- (fun ev -> console.error $"Could not upgrade database: {ev.target}")
|
||||
let archives = db.createObjectStore("PlainGrids", !!{| keyPath = "GridSha"; autoIncrement = true |})
|
||||
archives.createIndex("Vertices", "Vertices") |> ignore
|
||||
archives.createIndex("Indices", "Indices") |> ignore
|
||||
)
|
||||
)
|
||||
|
||||
let getFromIDB<'T> (db: IDBDatabase) (store: string) (sha: string): 'T option JS.Promise =
|
||||
let getFromIDB<'T> (db: IDBDatabase) (store: string) (sha: string) : 'T option JS.Promise =
|
||||
Promise.create (fun resolve reject ->
|
||||
let t = db.transaction(store, IDBTransactionMode.Readonly)
|
||||
let t = db.transaction (store, IDBTransactionMode.Readonly)
|
||||
let index = t.objectStore store
|
||||
let request = index.get sha
|
||||
t.commit ()
|
||||
|
||||
request.onerror <- (fun _ ->
|
||||
console.error $"Failed retrieving {store}: {sha}"
|
||||
reject (unbox false))
|
||||
request.onerror <-
|
||||
fun _ ->
|
||||
console.error $"Failed retrieving {store}: {sha}"
|
||||
reject (unbox false)
|
||||
|
||||
request.onsuccess <- (fun _ ->
|
||||
// console.log $"checking {store} {sha}"
|
||||
// NOTE(SimenLK): when getting on aid, if it is not present, the result will be undefined, otherwise, unbox
|
||||
// to get the DB archive grid
|
||||
request.result
|
||||
|> Option.map unbox<'T>
|
||||
|> resolve)
|
||||
request.onsuccess <-
|
||||
fun _ ->
|
||||
// console.log $"checking {store} {sha}"
|
||||
// NOTE(SimenLK): when getting on aid, if it is not present, the result will be undefined, otherwise, unbox
|
||||
// to get the DB archive grid
|
||||
request.result |> Option.map unbox<'T> |> resolve
|
||||
)
|
||||
|
||||
let saveToIDB (db: IDBDatabase) (store: string) item =
|
||||
Promise.create (fun resolve reject ->
|
||||
let t = db.transaction(store, IDBTransactionMode.Readwrite)
|
||||
let archives = t.objectStore(store)
|
||||
let t = db.transaction (store, IDBTransactionMode.Readwrite)
|
||||
let archives = t.objectStore (store)
|
||||
|
||||
let req = archives.add item
|
||||
req.onerror <- (fun ev ->
|
||||
let error = ev.target :?> IDBRequest
|
||||
console.error $"saveToIDB error: {error.error}"
|
||||
reject (error.error :?> exn))
|
||||
req.onsuccess <- (fun _ ->
|
||||
console.debug $"Successfully added {store} to indexedDB"
|
||||
resolve ())
|
||||
)
|
||||
req.onerror <-
|
||||
fun ev ->
|
||||
let error = ev.target :?> IDBRequest
|
||||
console.error $"saveToIDB error: {error.error}"
|
||||
reject (error.error :?> exn)
|
||||
|
||||
req.onsuccess <-
|
||||
fun _ ->
|
||||
console.debug $"Successfully added {store} to indexedDB"
|
||||
resolve ()
|
||||
)
|
||||
|
||||
let tryResetOutdatedIDB () =
|
||||
Promise.create (fun resolve reject ->
|
||||
openDB () |> Promise.iter (fun db ->
|
||||
openDB ()
|
||||
|> Promise.iter (fun db ->
|
||||
if db.objectStoreNames.contains "WireframeGrids" then
|
||||
db.close ()
|
||||
let req = indexedDB.deleteDatabase "oceanbox"
|
||||
req.onerror <- (fun ev ->
|
||||
let error = ev.target :?> IDBRequest
|
||||
console.error $"Reset indexDB error: {error.error}"
|
||||
reject (error.error :?> exn))
|
||||
req.onsuccess <- (fun _ ->
|
||||
console.debug $"Successfully reset indexedDB"
|
||||
resolve ())
|
||||
req.onerror <-
|
||||
fun ev ->
|
||||
let error = ev.target :?> IDBRequest
|
||||
console.error $"Reset indexDB error: {error.error}"
|
||||
reject (error.error :?> exn)
|
||||
|
||||
req.onsuccess <-
|
||||
fun _ ->
|
||||
console.debug $"Successfully reset indexedDB"
|
||||
resolve ()
|
||||
else
|
||||
resolve ()
|
||||
resolve ()
|
||||
)
|
||||
)
|
||||
@@ -5,11 +5,18 @@ open Fable.Core.JsInterop
|
||||
let register () = ()
|
||||
|
||||
importAll "../public/style.scss"
|
||||
|
||||
importSideEffects "@spectrum-web-components/theme/sp-theme.js"
|
||||
importSideEffects "@spectrum-web-components/theme/spectrum-two/scale-medium.js"
|
||||
importSideEffects "@spectrum-web-components/theme/spectrum-two/scale-large.js"
|
||||
importSideEffects "@spectrum-web-components/theme/spectrum-two/theme-light.js"
|
||||
importSideEffects "@spectrum-web-components/theme/spectrum-two/theme-dark.js"
|
||||
importSideEffects "@spectrum-web-components/accordion/sp-accordion.js"
|
||||
importSideEffects "@spectrum-web-components/accordion/sp-accordion-item.js"
|
||||
importSideEffects "@spectrum-web-components/action-button/sp-action-button.js"
|
||||
importSideEffects "@spectrum-web-components/action-group/sp-action-group.js"
|
||||
importSideEffects "@spectrum-web-components/action-menu/sp-action-menu.js"
|
||||
importSideEffects "@spectrum-web-components/action-menu/sync/sp-action-menu.js"
|
||||
importSideEffects "@spectrum-web-components/alert-banner/sp-alert-banner.js"
|
||||
importSideEffects "@spectrum-web-components/button/sp-button.js"
|
||||
importSideEffects "@spectrum-web-components/card/sp-card.js"
|
||||
importSideEffects "@spectrum-web-components/checkbox/sp-checkbox.js"
|
||||
@@ -24,13 +31,12 @@ importSideEffects "@spectrum-web-components/menu/sp-menu-group.js"
|
||||
importSideEffects "@spectrum-web-components/menu/sp-menu-item.js"
|
||||
importSideEffects "@spectrum-web-components/menu/sp-menu-divider.js"
|
||||
importSideEffects "@spectrum-web-components/number-field/sp-number-field.js"
|
||||
importSideEffects "@spectrum-web-components/picker/sp-picker.js"
|
||||
importSideEffects "@spectrum-web-components/popover/sp-popover.js"
|
||||
importSideEffects "@spectrum-web-components/progress-bar/sp-progress-bar.js"
|
||||
importSideEffects "@spectrum-web-components/progress-circle/sp-progress-circle.js"
|
||||
importSideEffects "@spectrum-web-components/radio/sp-radio.js"
|
||||
importSideEffects "@spectrum-web-components/radio/sp-radio-group.js"
|
||||
importSideEffects "@spectrum-web-components/slider/sp-slider.js"
|
||||
importSideEffects "@spectrum-web-components/slider/sync/sp-slider.js"
|
||||
importSideEffects "@spectrum-web-components/slider/sp-slider-handle.js"
|
||||
importSideEffects "@spectrum-web-components/split-view/sp-split-view.js"
|
||||
importSideEffects "@spectrum-web-components/switch/sp-switch.js"
|
||||
@@ -44,28 +50,31 @@ importSideEffects "@spectrum-web-components/table/sp-table-head-cell.js"
|
||||
importSideEffects "@spectrum-web-components/table/sp-table-row.js"
|
||||
importSideEffects "@spectrum-web-components/tabs/sp-tabs.js"
|
||||
importSideEffects "@spectrum-web-components/tabs/sp-tab.js"
|
||||
importSideEffects "@spectrum-web-components/tabs/sp-tab-panel.js"
|
||||
importSideEffects "@spectrum-web-components/textfield/sp-textfield.js"
|
||||
importSideEffects "@spectrum-web-components/theme/sp-theme.js"
|
||||
importSideEffects "@spectrum-web-components/theme/spectrum-two/scale-medium.js"
|
||||
importSideEffects "@spectrum-web-components/theme/spectrum-two/scale-large.js"
|
||||
importSideEffects "@spectrum-web-components/theme/spectrum-two/theme-light.js"
|
||||
importSideEffects "@spectrum-web-components/theme/spectrum-two/theme-dark.js"
|
||||
importSideEffects "@spectrum-web-components/toast/sp-toast.js"
|
||||
importSideEffects "@spectrum-web-components/top-nav/sp-top-nav.js"
|
||||
importSideEffects "@spectrum-web-components/top-nav/sp-top-nav-item.js"
|
||||
importSideEffects "@spectrum-web-components/underlay/sp-underlay.js"
|
||||
importSideEffects "@spectrum-web-components/overlay/overlay-trigger.js"
|
||||
importSideEffects "@spectrum-web-components/overlay/sync/overlay-trigger.js"
|
||||
importSideEffects "@spectrum-web-components/overlay/sp-overlay.js"
|
||||
importSideEffects "@spectrum-web-components/tooltip/sp-tooltip.js"
|
||||
importSideEffects "@spectrum-web-components/dialog/sp-dialog.js"
|
||||
importSideEffects "@spectrum-web-components/dialog/sp-dialog-base.js"
|
||||
importSideEffects "@spectrum-web-components/dialog/sp-dialog-wrapper.js"
|
||||
importSideEffects "@spectrum-web-components/infield-button/sp-infield-button.js"
|
||||
importSideEffects "@spectrum-web-components/picker/sync/sp-picker.js"
|
||||
importSideEffects "@spectrum-web-components/contextual-help/sp-contextual-help.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-add.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-add-circle.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-prototyping.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-close.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-copy.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-crosshairs.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-target.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-delete.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-color-harmony.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-deselect.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-erase.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-reorder.js"
|
||||
@@ -83,11 +92,17 @@ importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-asteris
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-bug.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-sampler.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-measure.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-ruler.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-circle.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-image-map-rectangle.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-histogram.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-chart-bar-vert.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-chart-trend.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-location.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-crop.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-download.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-edit.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-cancel.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-browse.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-filter.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-filter-remove.js"
|
||||
@@ -105,4 +120,5 @@ importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-social-
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-checkmark.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-rotate-cc-w.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-align-bottom.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-transform-perspective.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-transform-perspective.js"
|
||||
importSideEffects "@spectrum-web-components/icons-workflow/icons/sp-icon-search.js"
|
||||
41
src/Atlantis/src/Client/Lib/Intl.fs
Normal file
41
src/Atlantis/src/Client/Lib/Intl.fs
Normal file
@@ -0,0 +1,41 @@
|
||||
module Intl
|
||||
|
||||
open Browser
|
||||
open Fable.Core
|
||||
open Fable.Core.JsInterop
|
||||
|
||||
|
||||
[<Emit("new Intl.DateTimeFormat($0, $1)")>]
|
||||
let private dateTimeFormat (lang: string) (opt: obj) = jsNative
|
||||
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat
|
||||
let private uk : obj =
|
||||
let opts = {|
|
||||
dateStyle = "full"
|
||||
timeStyle = "short"
|
||||
|}
|
||||
|
||||
dateTimeFormat "en-GB" opts
|
||||
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat
|
||||
let private ukShort : obj =
|
||||
let opts = {|
|
||||
dateStyle = "short"
|
||||
|}
|
||||
|
||||
dateTimeFormat "en-GB" opts
|
||||
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat
|
||||
let private ukDateTimeShort : obj =
|
||||
let opts = {|
|
||||
dateStyle = "short"
|
||||
timeStyle = "short"
|
||||
|}
|
||||
|
||||
dateTimeFormat "en-GB" opts
|
||||
|
||||
/// Returns date string formatted as e.g.: "Wednesday 11 June 2025 at 06:00"
|
||||
let format (date: System.DateTime) : string = uk?format date
|
||||
|
||||
let shortDate (date: System.DateTime) : string = ukShort?format date
|
||||
let shortDateTime (date: System.DateTime) : string = ukDateTimeShort?format date
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<DefineConstants>FABLE_COMPILER</DefineConstants>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<Version>2.87.0</Version>
|
||||
@@ -9,41 +9,49 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="../../Shared/Atlantis.Shared.fs" />
|
||||
<Compile Include="Fable.VisJS.fs" />
|
||||
<Compile Include="Types.fs" />
|
||||
<Compile Include="Utils.fs" />
|
||||
<Compile Include="React.fs" />
|
||||
<Compile Include="Sentry.fs" />
|
||||
<Compile Include="Remoting.fs" />
|
||||
<Compile Include="Auth.fs" />
|
||||
<Compile Include="Search.fs" />
|
||||
<Compile Include="Imports.fs" />
|
||||
<Compile Include="Fable.VisJS.fs" />
|
||||
<Compile Include="IDB.fs" />
|
||||
<Compile Include="FloatingBox.fs" />
|
||||
<Compile Include="Turf.fs" />
|
||||
<Compile Include="Types.fs" />
|
||||
<Compile Include="Remoting.fs" />
|
||||
<Compile Include="Utils.fs" />
|
||||
<Compile Include="Auth.fs" />
|
||||
<Compile Include="Chaikin.fs" />
|
||||
<Compile Include="Umami.fs" />
|
||||
<Compile Include="StreamLayer.fs" />
|
||||
<Compile Include="WebGLLayer.fs" />
|
||||
<Compile Include="Intl.fs" />
|
||||
<Compile Include="Colors.fs" />
|
||||
<Compile Include="Maps.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fable.Browser.IndexedDB" Version="2.2.0" />
|
||||
<PackageReference Include="Fable.Browser.WebGL" Version="1.3.0" />
|
||||
<PackageReference Include="Fable.Core" Version="4.4.0" />
|
||||
<PackageReference Include="Fable.Elmish" Version="4.2.0" />
|
||||
<PackageReference Include="Fable.Fetch" Version="2.7.0" />
|
||||
<PackageReference Include="Fable.Lit" Version="1.6.2-oceanbox" />
|
||||
<PackageReference Include="Fable.Lit.React" Version="1.6.2-oceanbox" />
|
||||
<PackageReference Include="Fable.Lit.Elmish" Version="1.6.2-oceanbox" />
|
||||
<PackageReference Include="Fable.Promise" Version="3.2.0" />
|
||||
<PackageReference Include="Fable.React" Version="9.4.0" />
|
||||
<PackageReference Include="Fable.Remoting.Client" Version="7.32.0" />
|
||||
<PackageReference Include="Fable.Remoting.MsgPack" Version="1.24.0" />
|
||||
<PackageReference Include="Fable.OpenLayers" Version="2.18.0" />
|
||||
<PackageReference Include="Fable.SignalR.Elmish" Version="2.1.0" />
|
||||
<PackageReference Include="Fable.SimpleHttp" Version="3.6.0" />
|
||||
<PackageReference Include="Feliz" Version="2.9.0" />
|
||||
<PackageReference Include="Feliz.CompilerPlugins" Version="2.2.0" />
|
||||
<PackageReference Include="Thoth.Fetch" Version="3.0.1" />
|
||||
<PackageReference Include="Thoth.Json" Version="10.4.1" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201" />
|
||||
<PackageReference Include="Matplotlib.ColorMaps" Version="3.0.1" />
|
||||
<PackageReference Include="Fable.Browser.IndexedDB" />
|
||||
<PackageReference Include="Fable.Browser.WebGL" />
|
||||
<PackageReference Include="Fable.Core" />
|
||||
<PackageReference Include="Fable.Elmish" />
|
||||
<PackageReference Include="Fable.Fetch" />
|
||||
<PackageReference Include="Fable.Lit" />
|
||||
<PackageReference Include="Fable.Lit.React" />
|
||||
<PackageReference Include="Fable.Lit.Elmish" />
|
||||
<PackageReference Include="Fable.Promise" />
|
||||
<PackageReference Include="Fable.React" />
|
||||
<PackageReference Include="Fable.Remoting.Client" />
|
||||
<PackageReference Include="Fable.Remoting.MsgPack" />
|
||||
<PackageReference Include="Fable.OpenLayers" />
|
||||
<PackageReference Include="Fable.SignalR.Elmish" />
|
||||
<PackageReference Include="Fable.SimpleHttp" />
|
||||
<PackageReference Include="Feliz" />
|
||||
<PackageReference Include="Feliz.CompilerPlugins" />
|
||||
<PackageReference Include="FsToolkit.ErrorHandling" />
|
||||
<PackageReference Include="Thoth.Fetch" />
|
||||
<PackageReference Include="Thoth.Json" />
|
||||
<PackageReference Include="Matplotlib.ColorMaps" />
|
||||
<PackageReference Include="FSharp.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\Interfaces\Atlantis\Atlantis.Api.fsproj" />
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module Maps
|
||||
|
||||
open System.Text.RegularExpressions
|
||||
open Browser
|
||||
open Fable.Core
|
||||
open Fable.Core.JsInterop
|
||||
@@ -18,7 +17,7 @@ open Atlantis.Types
|
||||
|
||||
let theCenter = [| 14.39; 65.2 |]
|
||||
|
||||
let flyTo (map: OlMap) (zoom: float) (c: float []) =
|
||||
let flyTo (map: OlMap) (zoom: float) (c: float[]) =
|
||||
let v = map.getView ()
|
||||
|
||||
Animation.animationOptions [
|
||||
@@ -32,7 +31,7 @@ let flyTo (map: OlMap) (zoom: float) (c: float []) =
|
||||
|
||||
let zoomOut (map: OlMap) (zoom: Zoom) =
|
||||
let v = map.getView ()
|
||||
let center = v.getCenter()
|
||||
let center = v.getCenter ()
|
||||
let anim =
|
||||
Animation.animationOptions [
|
||||
Animation.animation.center center
|
||||
@@ -42,7 +41,7 @@ let zoomOut (map: OlMap) (zoom: Zoom) =
|
||||
Animation.animation.easing Animation.easeOut
|
||||
]
|
||||
|
||||
do v.animate(anim)
|
||||
do v.animate (anim)
|
||||
|
||||
module SimpleWebGLLayer =
|
||||
[<ImportDefault("../public/js/WebGLLayer")>]
|
||||
@@ -69,6 +68,7 @@ type barbTile =
|
||||
static member inline drawColor(value: string) = unbox ("drawColor", value)
|
||||
static member inline time(value: int) = unbox ("time", value)
|
||||
static member inline url(value: string) = unbox ("url", value)
|
||||
static member inline template(value: string) = unbox ("template", value)
|
||||
|
||||
module BarbTile =
|
||||
type BarbTile =
|
||||
@@ -103,50 +103,40 @@ let getInteractionByName (map: OlMap) name =
|
||||
|> fun c -> c.getArray ()
|
||||
|> Seq.tryFind (fun i ->
|
||||
let name' = i.get "name"
|
||||
name' = name)
|
||||
name' = name
|
||||
)
|
||||
|
||||
let simpleWebGL layerName (data: MapData) =
|
||||
webGLLayer [
|
||||
webglLayer.className layerName
|
||||
webglLayer.indices data.Grid.Indices
|
||||
webglLayer.props data.Props
|
||||
// NOTE(SimenLK): Breaks if you change the source from xyz
|
||||
// NOTE(simkir): Breaks if you change the source from xyz
|
||||
webglLayer.source (Source.xyz [])
|
||||
webglLayer.vertices data.Grid.Vertices
|
||||
webglLayer.opacity 0.15
|
||||
webglLayer.attenuate 0.0
|
||||
]
|
||||
|
||||
let osmLayer =
|
||||
Layer.tileLayer [
|
||||
layer.source (Source.osm [])
|
||||
]
|
||||
let osmLayer = Layer.tileLayer [ layer.source (Source.osm []) ]
|
||||
|
||||
let baseMapLayer =
|
||||
Layer.tileLayer [
|
||||
layer.source ((MapKind.MapTiler MapTiler.Basic).source())
|
||||
] :> Layer.Layer
|
||||
Layer.tileLayer [ layer.source ((MapKind.MapTiler MapTiler.Basic).source ()) ] :> Layer.Layer
|
||||
|
||||
let selectedMapLayer (kind: MapKind) =
|
||||
match kind with
|
||||
| OSM
|
||||
| MapTiler _ ->
|
||||
Layer.tileLayer [
|
||||
layer.source (kind.source())
|
||||
layer.source (kind.source ())
|
||||
layer.minZoom 0.0
|
||||
// layer.maxZoom 15.0
|
||||
] :> Layer.Layer
|
||||
// layer.maxZoom 15.0
|
||||
]
|
||||
:> Layer.Layer
|
||||
| NorgesKart Sentinel2
|
||||
| NorgesKart SeaRaster ->
|
||||
Layer.imageLayer [
|
||||
layer.source (kind.source ())
|
||||
layer.minZoom (kind.minZoom())
|
||||
] :> Layer.Layer
|
||||
| NorgesKart _ ->
|
||||
Layer.tileLayer [
|
||||
layer.source (kind.source ())
|
||||
layer.minZoom (kind.minZoom())
|
||||
] :> Layer.Layer
|
||||
Layer.imageLayer [ layer.source (kind.source ()); layer.minZoom (kind.minZoom ()) ] :> Layer.Layer
|
||||
| NorgesKart _ -> Layer.tileLayer [ layer.source (kind.source ()); layer.minZoom (kind.minZoom ()) ] :> Layer.Layer
|
||||
|
||||
let createStreamsLayer (data: MapData) uvFlat bbox =
|
||||
let streamIndices = data.Grid.Indices
|
||||
@@ -161,13 +151,20 @@ let createStreamsLayer (data: MapData) uvFlat bbox =
|
||||
]
|
||||
|
||||
// Example filter from openlayers example: https://openlayers.org/en/latest/examples/vector-wfs-getfeature.html
|
||||
let private wfsLoader (vectorSource: VectorSource) = // must return a lambda!
|
||||
fun (extent: Extent) (_: Resolution) (_: Projection) (success: Feature[] -> unit) (failure: unit -> unit) ->
|
||||
let private wfsLoader (vectorSource: VectorSource) = // NOTE: must return a lambda!
|
||||
fun
|
||||
(extent: Extent)
|
||||
(_resolution: Resolution)
|
||||
(projection: Projection)
|
||||
(success: Feature array -> unit)
|
||||
(failure: unit -> unit) ->
|
||||
let proj = projection?getCode()
|
||||
let url = Lokaliteter.wfsUrl ()
|
||||
let lower = extent[0], extent[1]
|
||||
let upper = extent[2], extent[3]
|
||||
// NOTE: THE XML IS CASE SENSITIVE!
|
||||
let filter = $"""
|
||||
let filter =
|
||||
$"""
|
||||
<fes:Filter>
|
||||
<fes:And>
|
||||
<fes:And>
|
||||
@@ -190,93 +187,118 @@ let private wfsLoader (vectorSource: VectorSource) = // must return a lambda!
|
||||
</fes:And>
|
||||
</fes:Filter>"""
|
||||
|
||||
let query = $"""
|
||||
<wfs:GetFeature service="WFS" version="2.0.0" outputFormat="GeoJSON"
|
||||
let query =
|
||||
$"""<wfs:GetFeature service="WFS" version="2.0.0" outputFormat="GeoJSON"
|
||||
xmlns:FiskeridirWFS="http://gis.fiskeridir.no/wfs/2.0"
|
||||
xmlns:wfs="http://www.opengis.net/wfs/2.0"
|
||||
xmlns:fes="http://www.opengis.net/fes/2.0"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2">
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2"
|
||||
>
|
||||
<wfs:Query typeName="FiskeridirWFS:Akvakultur_-_Lokaliteter" srsName="EPSG:3857">
|
||||
{filter}
|
||||
{filter}
|
||||
</wfs:Query>
|
||||
</wfs:GetFeature>"""
|
||||
let xhr = XMLHttpRequest.Create()
|
||||
|
||||
let xhr = XMLHttpRequest.Create ()
|
||||
xhr.``open`` ("POST", url)
|
||||
xhr.addEventListener("error", fun _ ->
|
||||
vectorSource.removeLoadedExtent(extent)
|
||||
failure ())
|
||||
xhr.addEventListener("load", fun _ ->
|
||||
if xhr.status = 200 then
|
||||
let fmt = vectorSource.getFormat () :?> GeoJSON
|
||||
let features = fmt.readFeatures(xhr.responseText)
|
||||
vectorSource.addFeatures features
|
||||
success(features)
|
||||
else
|
||||
xhr.addEventListener (
|
||||
"error",
|
||||
fun _ ->
|
||||
vectorSource.removeLoadedExtent extent
|
||||
failure ()
|
||||
)
|
||||
)
|
||||
xhr.addEventListener (
|
||||
"load",
|
||||
fun _ ->
|
||||
if xhr.status = 200 then
|
||||
let fmt = vectorSource.getFormat () :?> GeoJSON
|
||||
let features = fmt.readFeatures xhr.responseText
|
||||
|
||||
do
|
||||
features
|
||||
|> Array.iter (fun feature ->
|
||||
let geom = feature.getGeometry()
|
||||
let coords = geom?getCoordinates()
|
||||
let transformed = Utils.coordToEpsg3857 coords
|
||||
|
||||
geom?setCoordinates transformed
|
||||
)
|
||||
|
||||
vectorSource.addFeatures features
|
||||
success features
|
||||
else
|
||||
failure ()
|
||||
)
|
||||
xhr.send query
|
||||
|
||||
let private createAquacultureLocalityLayer () =
|
||||
// let f : FeatureUrlFunction = emitJsExpr urlFunc "$0"
|
||||
let vectorSource =
|
||||
Source.vectorSource [
|
||||
source.projection epsg3857
|
||||
source.format (Format.geoJSON [])
|
||||
source.strategy LoadingStrategy.bbox
|
||||
]
|
||||
let proj = vectorSource.getProjection()
|
||||
console.debug("[Maps] Vector source projection: %o", proj)
|
||||
// NOTE(simkir): Here is were we set the custom WFS loader
|
||||
do vectorSource.setLoader (wfsLoader vectorSource)
|
||||
let defaultStyle =
|
||||
Style.style [
|
||||
style.image (
|
||||
Style.circle [
|
||||
circle.radius 5.0
|
||||
circle.fill (
|
||||
Style.fill [
|
||||
fill.color "rgba(150, 0, 0, 1.0)"
|
||||
]
|
||||
)
|
||||
circle.stroke (
|
||||
Style.stroke [
|
||||
stroke.color "white"
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
let polygonStyle =
|
||||
Style.style [
|
||||
style.stroke (
|
||||
Style.stroke [
|
||||
stroke.color "white"
|
||||
stroke.width 1
|
||||
]
|
||||
)
|
||||
style.fill (
|
||||
Style.fill [
|
||||
fill.color "rgba(0.5, 0.5, 0.5, 0.1)"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
Layer.vectorLayer [
|
||||
layer.className (string MapLayer.Aquaculture)
|
||||
layer.zIndex 12
|
||||
layer.minZoom 7.5
|
||||
layer.source vectorSource
|
||||
layer.style (fun feature ->
|
||||
if feature.get "type" = "polygon" then
|
||||
polygonStyle
|
||||
else
|
||||
if feature.get "selected" = "true" then
|
||||
Style.style []
|
||||
else
|
||||
defaultStyle
|
||||
)
|
||||
]
|
||||
|
||||
// Ref: https://gis.fiskeridir.no/server/services/FiskeridirWFS_akva/MapServer/WFSServer?SERVICE=WFS&REQUEST=GetCapabilities
|
||||
// arcgis wfs info: https://enterprise.arcgis.com/en/server/latest/publish-services/linux/communicating-with-a-wfs-service-in-a-web-browser.htm
|
||||
let fiskeri (topic: InfoLayer) : Ol.Layer.Layer =
|
||||
if topic = Lokaliteter then
|
||||
console.debug("fiskeri")
|
||||
// let f : FeatureUrlFunction = emitJsExpr urlFunc "$0"
|
||||
let vectorSource =
|
||||
Source.vectorSource [
|
||||
source.projection epsg3857
|
||||
source.format (Format.geoJSON [])
|
||||
source.strategy LoadingStrategy.bbox
|
||||
]
|
||||
vectorSource.setLoader (wfsLoader vectorSource)
|
||||
let defaultStyle =
|
||||
Style.style [
|
||||
style.image (
|
||||
Style.circle [
|
||||
circle.radius 5.0
|
||||
circle.fill (
|
||||
Style.fill [
|
||||
fill.color "rgba(150, 0, 0, 1.0)"
|
||||
]
|
||||
)
|
||||
circle.stroke (
|
||||
Style.stroke [
|
||||
stroke.color "white"
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
let polygonStyle =
|
||||
Style.style [
|
||||
style.stroke (
|
||||
Style.stroke [
|
||||
stroke.color "white"
|
||||
stroke.width 1
|
||||
]
|
||||
)
|
||||
style.fill (
|
||||
Style.fill [
|
||||
fill.color "rgba(0.5, 0.5, 0.5, 0.1)"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
// TODO: Try webglPoints again
|
||||
Layer.vectorLayer [
|
||||
layer.className (string MapLayer.Aquaculture)
|
||||
layer.minZoom 7.5
|
||||
layer.source vectorSource
|
||||
layer.style (fun feature ->
|
||||
if feature.get "type" = "polygon" then
|
||||
polygonStyle
|
||||
else
|
||||
if feature.get "selected" = "true" then
|
||||
Style.style []
|
||||
else
|
||||
defaultStyle)
|
||||
layer.zIndex 12
|
||||
]
|
||||
console.debug ("[Map] Creating fiskeri OpenLayers Layer on topic %o", topic)
|
||||
createAquacultureLocalityLayer ()
|
||||
else
|
||||
let alpha =
|
||||
match topic with
|
||||
@@ -290,30 +312,22 @@ let fiskeri (topic: InfoLayer) : Ol.Layer.Layer =
|
||||
source.serverType Source.ServerType.Geoserver
|
||||
source.params' !!{| layers = string topic |}
|
||||
]
|
||||
Layer.imageLayer [
|
||||
layer.source source
|
||||
layer.opacity alpha
|
||||
]
|
||||
|
||||
Layer.imageLayer [ layer.source source; layer.opacity alpha ]
|
||||
|
||||
let toGeometry ((x, y): single * single) =
|
||||
Geometry.point [
|
||||
geometry.coordinates [|
|
||||
float x
|
||||
float y
|
||||
|]
|
||||
geometry.coordinates [| float x; float y |]
|
||||
geometry.layout GeometryLayout.XY
|
||||
]
|
||||
|
||||
let toFeature (p: single * single) =
|
||||
let g = toGeometry p
|
||||
let f =
|
||||
Feature.feature [
|
||||
feature.geometryOrProperties g
|
||||
]
|
||||
let f = Feature.feature [ feature.geometryOrProperties g ]
|
||||
f.setGeometry g
|
||||
f
|
||||
|
||||
let toFeatures (p: (single * single) []) = Array.map toFeature p
|
||||
let toFeatures (p: (single * single)[]) = Array.map toFeature p
|
||||
|
||||
// let conc (r, b) (p: Particles) =
|
||||
// let source =
|
||||
@@ -362,49 +376,38 @@ let createWebGLWireframeLayer (grid: WireframeGrid) =
|
||||
WebGLWireframeLayer.webGLWireframeLayer [
|
||||
layer.source (Source.osm [])
|
||||
layer.className "wireframe"
|
||||
(Interop.mkLayerProp "vertices" grid.Vertices)
|
||||
(Interop.mkLayerProp "barycentric" grid.BarycentricCoords)
|
||||
Interop.mkLayerProp "vertices" grid.Vertices
|
||||
Interop.mkLayerProp "barycentric" grid.BarycentricCoords
|
||||
]
|
||||
|
||||
let createMapWithLayers center (layers: Layer.Layer []) =
|
||||
let createMapWithLayers center (layers: Layer.Layer[]) =
|
||||
let lonLat = fromLonLat center
|
||||
let view =
|
||||
View.view [
|
||||
view.projection epsg3857
|
||||
view.center lonLat
|
||||
view.zoom 5.5
|
||||
]
|
||||
let view = View.view [ view.projection epsg3857; view.center lonLat; view.zoom 5.5 ]
|
||||
|
||||
OlMap.map [
|
||||
map.layers layers
|
||||
map.view view
|
||||
]
|
||||
OlMap.map [ map.layers layers; map.view view ]
|
||||
|
||||
let crossHairSelect (map: OlMap) (clickKey: Event.EventsKey option ref) onClick active =
|
||||
let elem = map.getTargetElement()
|
||||
let elem = map.getTargetElement ()
|
||||
let key =
|
||||
if active then
|
||||
elem?style?cursor <- "crosshair"
|
||||
map.on (
|
||||
"click",
|
||||
(fun (e: Event.MapBrowserEvent) ->
|
||||
onClick e)
|
||||
)
|
||||
|> Some
|
||||
map.on ("click", (fun (e: Event.MapBrowserEvent) -> onClick e)) |> Some
|
||||
else
|
||||
None
|
||||
|
||||
clickKey.contents <- key
|
||||
|
||||
Hook.createDisposable (fun () ->
|
||||
console.debug("Maps.crossHairSelect dispose")
|
||||
if not (isNullOrUndefined elem) then elem?style?cursor <- ""
|
||||
Observable.unByKey key)
|
||||
console.debug ("Maps.crossHairSelect dispose")
|
||||
if not (isNullOrUndefined elem) then
|
||||
elem?style?cursor <- ""
|
||||
Observable.unByKey key
|
||||
)
|
||||
|
||||
let private hmr = HMR.createToken ()
|
||||
|
||||
// let private olCss': {| ``default``: string |} =
|
||||
// importSideEffects "../public/ol.css"
|
||||
// importSideEffects "../public/ol.css"
|
||||
|
||||
// let private olCss = olCss'.``default``
|
||||
// console.log olCss
|
||||
@@ -413,15 +416,15 @@ let private hmr = HMR.createToken ()
|
||||
let unsafeCSS _ = jsNative
|
||||
|
||||
[<LitElement("ol-map")>]
|
||||
let OlMapElement() =
|
||||
let OlMapElement () =
|
||||
let this, props =
|
||||
LitElement.init (fun cfg ->
|
||||
cfg.useShadowDom <- true
|
||||
cfg.props <- {| map = Prop.Of(OlMap.map [], attribute = "map") |}
|
||||
cfg.styles <-
|
||||
[
|
||||
// unsafeCSS olCss
|
||||
unsafeCSS """
|
||||
cfg.props <- {| map = Prop.Of (OlMap.map [], attribute = "map") |}
|
||||
cfg.styles <- [
|
||||
// unsafeCSS olCss
|
||||
unsafeCSS
|
||||
"""
|
||||
:host {
|
||||
height: 100%;
|
||||
}
|
||||
@@ -447,12 +450,14 @@ let OlMapElement() =
|
||||
padding: 10px;
|
||||
}
|
||||
"""
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
Hook.useEffect (fun () ->
|
||||
if isNull this.shadowRoot |> not then
|
||||
let target = getShadowElementById this "map"
|
||||
props.map.Value.setTarget target)
|
||||
props.map.Value.setTarget target
|
||||
)
|
||||
|
||||
let classes = Lit.classes [ "map", true ]
|
||||
|
||||
|
||||
7
src/Atlantis/src/Client/Lib/React.fs
Normal file
7
src/Atlantis/src/Client/Lib/React.fs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Lib
|
||||
|
||||
module React =
|
||||
open Fable.Core
|
||||
open Feliz
|
||||
|
||||
let inline fromJsx (el: JSX.Element) : ReactElement = unbox el
|
||||
@@ -1,10 +1,32 @@
|
||||
module Remoting
|
||||
|
||||
open Browser
|
||||
open Fable.Remoting.Client
|
||||
open FsToolkit.ErrorHandling
|
||||
|
||||
open Atlantis
|
||||
open Sorcerer
|
||||
|
||||
let getArchiveUrl () = sessionStorage["archmaester_url"]
|
||||
let getDataUrl () = sessionStorage["sorcerer_url"]
|
||||
let tryGetArchiveUrl () = sessionStorage["archmaester_url"] |> Utils.tryStr
|
||||
let tryGetDataUrl () = sessionStorage["sorcerer_url"] |> Utils.tryStr
|
||||
|
||||
/// NOTE: This function will redirect the user on a ProxyRequestException
|
||||
let tryCatch (comp: Async<'T>) : Async<Result<'T, exn>> =
|
||||
comp
|
||||
|> Async.Catch
|
||||
|> Async.map (fun choice ->
|
||||
choice
|
||||
|> Result.ofChoice
|
||||
|> Result.teeError (function
|
||||
| :? ProxyRequestException as ex ->
|
||||
console.error("[Remoting] Proxy request error: %o", ex.Response)
|
||||
window.location.href <- "/signin"
|
||||
| _ -> ()
|
||||
)
|
||||
)
|
||||
|
||||
let authApi =
|
||||
Remoting.createApi ()
|
||||
|> Remoting.withCredentials true
|
||||
@@ -87,6 +109,7 @@ type DriftersApi(url) =
|
||||
member val Particles = createBinApi Remoting.buildProxy<Api.Drifters.Particles>
|
||||
member val FieldMetaData = createBinApi Remoting.buildProxy<Api.Drifters.FieldMetaData>
|
||||
member val Sedimentation = createBinApi Remoting.buildProxy<Api.Drifters.Sedimentation>
|
||||
member val WaterContact = createBinApi Remoting.buildProxy<Api.Drifters.WaterContact>
|
||||
member val Field2D = createBinApi Remoting.buildProxy<Api.Drifters.Field2D>
|
||||
member val Field3D = createBinApi Remoting.buildProxy<Api.Drifters.Field3D>
|
||||
member val Network = createApi Remoting.buildProxy<Api.Drifters.Network>
|
||||
@@ -109,12 +132,17 @@ type StatsApi(url) =
|
||||
|> Remoting.withRouteBuilder Api.Stats.routeBuilder
|
||||
|> f
|
||||
|
||||
member val FvStatsInfo =
|
||||
createApi Remoting.buildProxy<Api.Stats.FvStatsInfo>
|
||||
member val FvStatsInfo = createApi Remoting.buildProxy<Api.Stats.FvStatsInfo>
|
||||
member val FvStatsByLayer =
|
||||
createApi (Remoting.withBinarySerialization >> Remoting.buildProxy<Api.Stats.FvStatsByLayer>)
|
||||
createApi (
|
||||
Remoting.withBinarySerialization
|
||||
>> Remoting.buildProxy<Api.Stats.FvStatsByLayer>
|
||||
)
|
||||
member val FvStatsByIndex =
|
||||
createApi (Remoting.withBinarySerialization >> Remoting.buildProxy<Api.Stats.FvStatsByIndex>)
|
||||
createApi (
|
||||
Remoting.withBinarySerialization
|
||||
>> Remoting.buildProxy<Api.Stats.FvStatsByIndex>
|
||||
)
|
||||
member val FvStatsSeries =
|
||||
createApi (Remoting.withBinarySerialization >> Remoting.buildProxy<Api.Stats.FvStatsSeries>)
|
||||
|
||||
@@ -124,8 +152,6 @@ let driftersJobApi () =
|
||||
|> Remoting.withRouteBuilder Api.authorizedRouteBuilder
|
||||
|> Remoting.buildProxy<Api.Drifters>
|
||||
|
||||
let archiveUrl = Browser.WebStorage.sessionStorage["archmaester_url"]
|
||||
|
||||
let archiveApi () =
|
||||
Remoting.createApi ()
|
||||
|> Remoting.withCredentials true
|
||||
@@ -161,4 +187,16 @@ let cropStatsApi url =
|
||||
|> Remoting.withBaseUrl url
|
||||
|> Remoting.withRouteBuilder Api.Crop.routeBuilder
|
||||
|> Remoting.withBinarySerialization
|
||||
|> Remoting.buildProxy<Api.Crop.Stats>
|
||||
|> Remoting.buildProxy<Api.Crop.Stats>
|
||||
|
||||
let plumeApi () =
|
||||
Remoting.createApi ()
|
||||
|> Remoting.withCredentials true
|
||||
|> Remoting.withRouteBuilder Api.authorizedRouteBuilder
|
||||
|> Remoting.buildProxy<Api.Plume>
|
||||
|
||||
let xtractApi () =
|
||||
Remoting.createApi ()
|
||||
|> Remoting.withCredentials true
|
||||
|> Remoting.withRouteBuilder Api.authorizedRouteBuilder
|
||||
|> Remoting.buildProxy<Api.Xtract>
|
||||
44
src/Atlantis/src/Client/Lib/Search.fs
Normal file
44
src/Atlantis/src/Client/Lib/Search.fs
Normal file
@@ -0,0 +1,44 @@
|
||||
module Search
|
||||
|
||||
open FsToolkit.ErrorHandling
|
||||
|
||||
open Sorcerer.Types
|
||||
|
||||
/// Search an archive for the closest node and elem idx based on the given coordinate
|
||||
let tryGetNearestNodeAndElement aid (x, y) : Async<Option<NodeIdx * ElemIdx>> =
|
||||
async {
|
||||
let dataSvc = Remoting.getDataUrl ()
|
||||
let api = Remoting.proximityApi dataSvc
|
||||
let! nodes = api.GetNearestNodes (aid, [| x, y |])
|
||||
let! elems = api.GetNearestElements (aid, [| x, y |])
|
||||
let firstNode = nodes |> Array.tryHead |> Option.flatten
|
||||
let firstElem = elems |> Array.tryHead |> Option.flatten
|
||||
let result =
|
||||
firstNode
|
||||
|> Option.bind (fun node -> firstElem |> Option.map (fun elem -> node, elem))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/// Search an archive for the closest node and elem idx based on the given coordinate
|
||||
let tryGetNearestNodeAndElementRes dataSvc aid (x, y) : Async<Result<NodeIdx * ElemIdx, exn>> =
|
||||
asyncResult {
|
||||
let api = Remoting.proximityApi dataSvc
|
||||
let! nodes = api.GetNearestNodes (aid, [| x, y |]) |> Remoting.tryCatch
|
||||
let! elems = api.GetNearestElements (aid, [| x, y |]) |> Remoting.tryCatch
|
||||
let firstNode = nodes |> Array.tryHead |> Option.flatten
|
||||
let firstElem = elems |> Array.tryHead |> Option.flatten
|
||||
let result =
|
||||
firstNode
|
||||
|> Option.bind (fun node -> firstElem |> Option.map (fun elem -> node, elem))
|
||||
|> Result.requireSome (exn "Could not find node")
|
||||
|
||||
return! result
|
||||
}
|
||||
|
||||
let probePoint (aid: System.Guid) (point: float * float) : Async<Option<(float * float) * Atlantis.Types.GridIdx>> =
|
||||
async {
|
||||
let! idxOpt = tryGetNearestNodeAndElement aid point
|
||||
let res = idxOpt |> Option.map (fun idx -> point, idx)
|
||||
return res
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user