mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-18 21:35:51 -04:00
Compare commits
620 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bdc7733faf | |||
| 7f4be53db0 | |||
| 27d998d6f2 | |||
| 5eb593f453 | |||
| 4652db0583 | |||
| 35d43480bf | |||
| 3e7c136a7f | |||
| 05f9f6b413 | |||
| 67f6eb544a | |||
| 3c11e934a8 | |||
| 627a39b8fc | |||
| 95c7b96dff | |||
| dadd59fc3a | |||
| e67d3d3666 | |||
| f4718243ed | |||
| fcec787eb6 | |||
| 5fe8f65d64 | |||
| c2a21cd238 | |||
| a31ca4e80b | |||
| db14ac4605 | |||
| 5f229b78be | |||
| 543f2e7ddc | |||
| d6b7ab6260 | |||
| d7ab9292fb | |||
| 4300d8d8c6 | |||
| 446b2ffff9 | |||
| 695720b552 | |||
| c47934c5ca | |||
| 9938737cd7 | |||
| 58326f05e0 | |||
| 04ad5ec9c0 | |||
| 2c008384dd | |||
| a9b605c872 | |||
| cd9b469823 | |||
| df4bfa501c | |||
| 194a1e5154 | |||
| e53b2bb83c | |||
| 10772c09ef | |||
| f9ed15409a | |||
| f75ab93458 | |||
| 7755a8bd3b | |||
| 017c7998be | |||
| f40ddfef10 | |||
| 80049909eb | |||
| fc22264f89 | |||
| aba2e10b5c | |||
| 4b6874d551 | |||
| 58934a30ce | |||
| 33a960f325 | |||
| 8560ff43fe | |||
| c88a47b275 | |||
| 67fe9101d9 | |||
| af99c78352 | |||
| df3253f55c | |||
| b9abc1be11 | |||
| 5c0ee04271 | |||
| 5e2cd3798b | |||
| 83041b1d37 | |||
| 9f6c48191b | |||
| 5696fa2efe | |||
| d38311b717 | |||
| aa522066ee | |||
| d2ba70c4d7 | |||
| ca2e62492d | |||
| 02bcb4d865 | |||
| 36962f176f | |||
| 0a2afe692f | |||
| 5140ee8f2e | |||
| e47ceae0c5 | |||
| 906f8c1049 | |||
| 27e871656e | |||
| 1ff147c541 | |||
| 7028bfb082 | |||
| efdb9c20d4 | |||
| 9bf872c9fa | |||
| feaeda9186 | |||
| e9cf9d05f5 | |||
| a1211f54de | |||
| c7b5e6204c | |||
| 788404ee27 | |||
| 8ef4429b9e | |||
| 7c5fc1e4b0 | |||
| c66f7abea5 | |||
| ce6f52552a | |||
| 7807e2e13a | |||
| d5aa73fe8f | |||
| cb5bf86d8e | |||
| 8d17f0b1db | |||
| 2e62aad279 | |||
| f2c9fcde7c | |||
| 2716bd6ae1 | |||
| b67f6b98ae | |||
| 7de2c8d41f | |||
| 5dabec5cc8 | |||
| fc61687e82 | |||
| 398fc4dca2 | |||
| f883cab6db | |||
| 0a18898e36 | |||
| 19d533b50a | |||
| 4ce98d689d | |||
| ef9c1bf0a4 | |||
| bec8312d61 | |||
| ac5736c05b | |||
| 35abd99b3f | |||
| 0fb8aabb41 | |||
| cbc14a1a2c | |||
| 627ab64fd0 | |||
| 7fdfd0cfb7 | |||
| 4052e7160c | |||
| f5d3defa52 | |||
| 4cb87309b2 | |||
| c6ec9c316d | |||
| fc26f78558 | |||
| 4eaad6ca4b | |||
| 7abbe2c8c0 | |||
| 40839424be | |||
| 3234cff09c | |||
| d715bb4437 | |||
| df88d9a8bf | |||
| a3f4695442 | |||
| 321ce87d4d | |||
| 30e9a7a1b9 | |||
| f26b00444f | |||
| e088a7258e | |||
| f705692fb7 | |||
| 92feeb49a6 | |||
| 0d7d647291 | |||
| 2ddaef5c50 | |||
| 0aaf0f702b | |||
| 97e9d64397 | |||
| f1583dcb13 | |||
| dc4dbf4610 | |||
| bb21798c42 | |||
| 07b2890f30 | |||
| d9534a857f | |||
| 2b17b5310e | |||
| b330a15431 | |||
| ad79250783 | |||
| 845b96508f | |||
| cff95eb251 | |||
| d8542f4689 | |||
| 99642f15fe | |||
| 5d1c600062 | |||
| 5cee22f207 | |||
| bb3871e9ea | |||
| 434c095c54 | |||
| 4808fb1429 | |||
| 7dd6805512 | |||
| c31070ab91 | |||
| e6974eb99e | |||
| a72e3d78d7 | |||
| 7c707babff | |||
| 3b254fd54f | |||
| d9e9df6c26 | |||
| c6b969cd61 | |||
| 5ccee34107 | |||
| b8724c384a | |||
| acd82e36c5 | |||
| afd2b7a29e | |||
| 74a26b02db | |||
| 356926a445 | |||
| 19128e70e7 | |||
| aa75bc241d | |||
| 88780f33a4 | |||
| 1ed30713f5 | |||
| 3b3dbfec60 | |||
| e011614570 | |||
| 2a1b2187ba | |||
| ea3a6171fa | |||
| c9477d4b5a | |||
| cc466b9e5b | |||
| e9ece8a319 | |||
| 22a5304ad8 | |||
| bcb16d484a | |||
| 50ebd283dd | |||
| 53b9332675 | |||
| bfc969c45c | |||
| 31770cd889 | |||
| 6267497fc0 | |||
| efeb216383 | |||
| 8eb0f33718 | |||
| 176bf7ce32 | |||
| 4340b6b922 | |||
| ec2c7ec5af | |||
| f3fb67a62e | |||
| ec8d1c4ae6 | |||
| ea3e523f8d | |||
| e50550bb33 | |||
| e0957bfd20 | |||
| 582322adfb | |||
| 7a3964c42a | |||
| b2f6c4dcdc | |||
| 45f8700689 | |||
| 7c5fe561e0 | |||
| 5145a4a211 | |||
| 2aa2164763 | |||
| 05bde70b14 | |||
| d8c138694d | |||
| ad8504fa89 | |||
| 2f26a955d1 | |||
| 3d7808745b | |||
| 1d7082593d | |||
| 82420d6956 | |||
| 77b84be8d1 | |||
| 24330beca9 | |||
| dd50f1c564 | |||
| 4f63015a3e | |||
| 568185c908 | |||
| b56525de27 | |||
| 4673736b67 | |||
| ffae7d6b31 | |||
| 42146fc366 | |||
| de6a465370 | |||
| bef12f10a8 | |||
| 8064a43dee | |||
| 3c2e127601 | |||
| 6ea370870d | |||
| f6f8934ce3 | |||
| 3c59b6aac0 | |||
| 2e0d603f4a | |||
| e8972f2273 | |||
| 578ce25166 | |||
| fc12770495 | |||
| 5d5e66f0d7 | |||
| fe2af13fae | |||
| 10205da1c3 | |||
| 914d3764dc | |||
| 59f8a4d2e2 | |||
| 024000275d | |||
| a3723b5ad7 | |||
| e9e034d193 | |||
| 52dbcfe852 | |||
| f488fe75e0 | |||
| 47e85e6388 | |||
| 3264de3a96 | |||
| 1c04aad92e | |||
| 3b2cf55788 | |||
| b66ce95139 | |||
| f6753bf2c2 | |||
| 2a981c3bbc | |||
| 82004b6535 | |||
| eb36a1c134 | |||
| 02109437e4 | |||
| 38872ffc0a | |||
| 5e940330b4 | |||
| 53b3b58477 | |||
| d6101259ad | |||
| cf94178623 | |||
| 999f6cbcd3 | |||
| f0191525a1 | |||
| 596803cf0b | |||
| e90465c4ae | |||
| 0c21467411 | |||
| d9d1d8ecad | |||
| d9faeb11c2 | |||
| 7b13ec0dbd | |||
| 6ffc57c106 | |||
| ee1bcb20dc | |||
| 19d8604022 | |||
| 5926ca5d8a | |||
| 24de3fdee6 | |||
| be40a0d738 | |||
| 2b97352661 | |||
| 88bc44f7ba | |||
| 95527218af | |||
| 8a062d1cba | |||
| 4acd885f19 | |||
| a19c292779 | |||
| aa9880b8dd | |||
| abe8a06c11 | |||
| 7ea749e93c | |||
| f85fc5e578 | |||
| 20e3a357a5 | |||
| 60ac9d3ad7 | |||
| e5fc423f29 | |||
| 3f5ff23210 | |||
| a9792973ee | |||
| 90289de22c | |||
| a68011988e | |||
| 2fd030bd5c | |||
| 33cd9f555e | |||
| 94df76b6e6 | |||
| 065846464d | |||
| 108609d064 | |||
| 0fcad533eb | |||
| c7b5a42bea | |||
| fa6b7ad287 | |||
| b51ce06e04 | |||
| 63cf10c29a | |||
| 6b5e743583 | |||
| 743946b929 | |||
| cf89533b37 | |||
| 7031a8fe44 | |||
| d8c962a911 | |||
| 6702c7d21b | |||
| e64dd799e6 | |||
| 47c2a15b70 | |||
| 4bf726cc66 | |||
| dd61480d60 | |||
| b0753ab153 | |||
| 281afe7d9d | |||
| bd0fe16b52 | |||
| 901723b8e3 | |||
| 3a146ea667 | |||
| 88b9a47c79 | |||
| fe5445ba31 | |||
| 39f08b6283 | |||
| 8831fd7b50 | |||
| 70e4324a7c | |||
| 35a53c5627 | |||
| 9b85f328a6 | |||
| 012fe53acc | |||
| 566c1405c2 | |||
| 83c637e8cb | |||
| fd612f9258 | |||
| 621edba82d | |||
| f03dfda2f0 | |||
| e623efefd3 | |||
| 7742a81782 | |||
| 8588d2e2a3 | |||
| 86c5f06c5b | |||
| 6d7fb3de25 | |||
| a0d2af54e8 | |||
| ad3ddd11cf | |||
| 1372abecc0 | |||
| 3ddbd30604 | |||
| eff2e11652 | |||
| aa95781d5d | |||
| 6e46720d7b | |||
| 7e70166b62 | |||
| 444305aa65 | |||
| 8fd1f75e21 | |||
| 625cdab04a | |||
| 325a9c34e3 | |||
| a7e4078c53 | |||
| d2bfddc182 | |||
| a6777015f7 | |||
| f8b211c561 | |||
| fce86db9c5 | |||
| 2ff07a1368 | |||
| 208b17e9f5 | |||
| e0ce7b3294 | |||
| 7af75da694 | |||
| 86213d91a2 | |||
| eed4a4ec68 | |||
| 24d4390550 | |||
| 4983cb9745 | |||
| e71e386cb1 | |||
| d03a37ed60 | |||
| 5ea88f6bcd | |||
| d74415a3d7 | |||
| f4deefd21e | |||
| 6296356e42 | |||
| a777880a91 | |||
| eb311f33ef | |||
| 34ba436204 | |||
| 45bb108127 | |||
| 0443cc34c6 | |||
| 6ad6bf270f | |||
| 2237624333 | |||
| 39d11b4669 | |||
| 70faa123ee | |||
| f4869e6bc9 | |||
| 2a3fc81b8a | |||
| a2182e2fca | |||
| fe23c985a2 | |||
| 4ffd0d2ddb | |||
| efd3aad6b0 | |||
| 11b4967629 | |||
| b6e46ad8fd | |||
| c28b62da2a | |||
| 600c7e3391 | |||
| 7107aeaddc | |||
| 913766f9af | |||
| 9e7ea6f55b | |||
| c2c4186965 | |||
| 1a755bd3c0 | |||
| e5f66da087 | |||
| 2a93686360 | |||
| f33f004aa9 | |||
| 30293bc7cc | |||
| a1db7a8f1e | |||
| 539fcb91c9 | |||
| 970848acc3 | |||
| 2b7a383886 | |||
| 4dc67c027b | |||
| a12395b468 | |||
| 19dceb35fa | |||
| b56043504b | |||
| f2efdd8b6d | |||
| 13b14f4d38 | |||
| ecc2996669 | |||
| 1df31f9059 | |||
| 79d4e0da80 | |||
| 0dcb07f170 | |||
| e8040a0819 | |||
| 553a8f2a0a | |||
| c892b827af | |||
| 1b36b512d7 | |||
| 560dc1ffed | |||
| 14d43e6d6b | |||
| bc1e131e49 | |||
| 61509b53d1 | |||
| b7f680ac98 | |||
| c9526b7dfd | |||
| 9f6bca0810 | |||
| 114549ca7b | |||
| 481863ca1f | |||
| 13e55f7c37 | |||
| 397442f32e | |||
| 71ae27fc0c | |||
| 286468e6ab | |||
| aafd82ba73 | |||
| cff5c03af3 | |||
| c394fcc085 | |||
| a6f237bd70 | |||
| 013915be62 | |||
| 9bec7d2ad0 | |||
| 808797f403 | |||
| 230a3df3f3 | |||
| 26f2b6a3d9 | |||
| e039dd81df | |||
| cd6dd33359 | |||
| 8803ef4dbd | |||
| 5f0b2c91a1 | |||
| 1684fbb119 | |||
| 326bcdc18c | |||
| ac0845eedf | |||
| aa00959010 | |||
| 986f8d43c0 | |||
| 07f5312d43 | |||
| 7754589353 | |||
| 8428de7a00 | |||
| d210082dad | |||
| 4f9df6a114 | |||
| a5726cd65e | |||
| 3bfb08c3ff | |||
| ceeea9f7c6 | |||
| 83b1e037d5 | |||
| 9cc5343547 | |||
| e3cc4f4cb1 | |||
| f0bb614360 | |||
| 9241f4a40d | |||
| 8e6157074d | |||
| 188b02e5c7 | |||
| acb8e1d3c8 | |||
| ab31cccfb2 | |||
| 42afaa17ee | |||
| c6123a076f | |||
| 0f0aaeef4b | |||
| 2983e27dcd | |||
| a18036eed4 | |||
| 2013e1f580 | |||
| 1e396ead5e | |||
| 5ea3ad45cb | |||
| 26a04c9fd1 | |||
| 7f29af6d4d | |||
| 92f3a18e17 | |||
| 7836246b05 | |||
| e2b2061ee1 | |||
| 8d651e6f7a | |||
| 25c0ed1cd0 | |||
| 638db3d8d7 | |||
| 3a5d18f52d | |||
| c8d0a6a4ea | |||
| 553b8b1945 | |||
| e263d066da | |||
| cdaf88efa1 | |||
| ea801665e4 | |||
| a81b6f41af | |||
| 177d77db69 | |||
| 8dafa29f8c | |||
| 6b3bdb4f88 | |||
| 56bb319934 | |||
| 6de847a361 | |||
| 94591dea93 | |||
| 5cb20b0dac | |||
| 69954c50cb | |||
| e5d72bb995 | |||
| ae7c78ba48 | |||
| 84498d9e92 | |||
| d12b75e223 | |||
| b27367088e | |||
| 570bc87ab7 | |||
| 1ae4c53e27 | |||
| cd84045161 | |||
| 667fdc64e3 | |||
| e424264504 | |||
| 7716c31ebd | |||
| 6d729416d9 | |||
| 1668978fc6 | |||
| 874840c921 | |||
| defd08addf | |||
| c072e0a2ca | |||
| d9ce781dfa | |||
| a438d43c57 | |||
| 81f0fd38ac | |||
| bbc9de464c | |||
| 0738e35583 | |||
| 6e2f13f76b | |||
| 2fb36f7c6c | |||
| 5ead82903c | |||
| b4c03aae6d | |||
| 2a8a2ce3b0 | |||
| c75a9dfe34 | |||
| 7410a2db5d | |||
| 74c89e1d44 | |||
| f120b84c43 | |||
| 88ec106ec6 | |||
| 99b75a3089 | |||
| 50592d5bb6 | |||
| 9fce6b1026 | |||
| 5f32627bfb | |||
| 56b658cc96 | |||
| c22ae12c1f | |||
| 4bac44e893 | |||
| 1c58e26183 | |||
| 4d965955d1 | |||
| 23b9d657ce | |||
| c046c3c229 | |||
| f734ba2323 | |||
| 44fa36373c | |||
| e6afcb68f3 | |||
| c8c900251a | |||
| 915e7ce589 | |||
| 5bab42b712 | |||
| f499e846d9 | |||
| 80a744eff5 | |||
| 82dfaf0ea5 | |||
| 8f78953191 | |||
| 9261efa843 | |||
| b9a8166f9f | |||
| 8cccde48c1 | |||
| 96384521c5 | |||
| f90211b0d3 | |||
| d1bebd3e5b | |||
| a32bc21907 | |||
| 4f7dc94b94 | |||
| 5ca1a1d086 | |||
| 7d763b8ba0 | |||
| 23c197bd3b | |||
| 8c892a732e | |||
| 140547e42a | |||
| 3ab9af0663 | |||
| a71874db8d | |||
| 226ee34fec | |||
| eb5add1198 | |||
| 3759625386 | |||
| b85f3f0e35 | |||
| 286b083da4 | |||
| 912273b5dd | |||
| 73d1486392 | |||
| 063c6fb85c | |||
| c95573a7da | |||
| a6cf524fe7 | |||
| bb264e9a8a | |||
| ca0cabe985 | |||
| 48c3aea9bb | |||
| 4122b82601 | |||
| 3abf67aaf0 | |||
| 2b860aab36 | |||
| 85bfcd72ff | |||
| df15c636a4 | |||
| 1136de29e5 | |||
| ffcb34f9f0 | |||
| 877b6c0fcf | |||
| 854c1a6866 | |||
| cd8ed08376 | |||
| b64c938188 | |||
| bd930f3b8d | |||
| 0880cd6ffc | |||
| c2a96ff485 | |||
| 21e92e7fcf | |||
| 96f0bb2f90 | |||
| c0e1b97f29 | |||
| fd4fb88ce1 | |||
| 003686d68f | |||
| 3e0e4ba1fd | |||
| 45ecfb05f4 | |||
| ab620d373c | |||
| 9b3faefc8e | |||
| dd577f9db0 | |||
| 5c0939d9df | |||
| bdb818b1b6 | |||
| 4550ef13a4 | |||
| 98f0769c5d | |||
| 6f854ddd56 | |||
| 98ae094733 | |||
| 15e4dc18b9 | |||
| d5a7479b2e | |||
| e1bff99a93 | |||
| 9d31aed9da | |||
| 9fbc1df74c | |||
| 2d9c77ec5e | |||
| ede7d37cae | |||
| b580b4f829 | |||
| 4f281669fc | |||
| 9fbedc32ed | |||
| 745007209e | |||
| 3e1cfe0033 | |||
| 94b94041a8 | |||
| 791a32b939 | |||
| af395f554e | |||
| 39640a710f | |||
| 6557f72600 | |||
| 14b127e60d | |||
| e6e6205799 | |||
| 083c4750fb | |||
| 099d0b6e67 | |||
| 17615e9ace | |||
| 9179b9e0eb | |||
| 3389cc0cf8 | |||
| 21c297024f | |||
| c4324c8e47 | |||
| ac8fa1ee93 | |||
| 93cff9c6ef | |||
| 3d0e993a53 | |||
| 87330c8ab9 | |||
| 785ad5d62e | |||
| 0ddf19d384 |
+12
-1
@@ -110,13 +110,13 @@ dotnet_diagnostic.SA1643.severity = none
|
|||||||
dotnet_diagnostic.SA1648.severity = none
|
dotnet_diagnostic.SA1648.severity = none
|
||||||
dotnet_diagnostic.SA1649.severity = none
|
dotnet_diagnostic.SA1649.severity = none
|
||||||
dotnet_diagnostic.SA1651.severity = none
|
dotnet_diagnostic.SA1651.severity = none
|
||||||
dotnet_diagnostic.SX1101.severity = warning
|
|
||||||
dotnet_diagnostic.SX1309.severity = warning
|
dotnet_diagnostic.SX1309.severity = warning
|
||||||
|
|
||||||
# Microsoft Analyzers that fail and need to be sorted thru
|
# Microsoft Analyzers that fail and need to be sorted thru
|
||||||
dotnet_diagnostic.ASP0000.severity = suggestion
|
dotnet_diagnostic.ASP0000.severity = suggestion
|
||||||
dotnet_diagnostic.CA1000.severity = suggestion
|
dotnet_diagnostic.CA1000.severity = suggestion
|
||||||
dotnet_diagnostic.CA1001.severity = suggestion
|
dotnet_diagnostic.CA1001.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1002.severity = suggestion
|
||||||
dotnet_diagnostic.CA1003.severity = suggestion
|
dotnet_diagnostic.CA1003.severity = suggestion
|
||||||
dotnet_diagnostic.CA1008.severity = suggestion
|
dotnet_diagnostic.CA1008.severity = suggestion
|
||||||
dotnet_diagnostic.CA1010.severity = suggestion
|
dotnet_diagnostic.CA1010.severity = suggestion
|
||||||
@@ -163,10 +163,16 @@ dotnet_diagnostic.CA1304.severity = suggestion
|
|||||||
dotnet_diagnostic.CA1305.severity = suggestion
|
dotnet_diagnostic.CA1305.severity = suggestion
|
||||||
dotnet_diagnostic.CA1307.severity = suggestion
|
dotnet_diagnostic.CA1307.severity = suggestion
|
||||||
dotnet_diagnostic.CA1308.severity = suggestion
|
dotnet_diagnostic.CA1308.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1309.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1310.severity = suggestion
|
||||||
dotnet_diagnostic.CA1401.severity = suggestion
|
dotnet_diagnostic.CA1401.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1416.severity = suggestion
|
||||||
dotnet_diagnostic.CA1507.severity = suggestion
|
dotnet_diagnostic.CA1507.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1508.severity = suggestion
|
||||||
dotnet_diagnostic.CA1707.severity = suggestion
|
dotnet_diagnostic.CA1707.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1708.severity = suggestion
|
||||||
dotnet_diagnostic.CA1710.severity = suggestion
|
dotnet_diagnostic.CA1710.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1711.severity = suggestion
|
||||||
dotnet_diagnostic.CA1712.severity = suggestion
|
dotnet_diagnostic.CA1712.severity = suggestion
|
||||||
dotnet_diagnostic.CA1714.severity = suggestion
|
dotnet_diagnostic.CA1714.severity = suggestion
|
||||||
dotnet_diagnostic.CA1715.severity = suggestion
|
dotnet_diagnostic.CA1715.severity = suggestion
|
||||||
@@ -175,12 +181,14 @@ dotnet_diagnostic.CA1717.severity = suggestion
|
|||||||
dotnet_diagnostic.CA1720.severity = suggestion
|
dotnet_diagnostic.CA1720.severity = suggestion
|
||||||
dotnet_diagnostic.CA1721.severity = suggestion
|
dotnet_diagnostic.CA1721.severity = suggestion
|
||||||
dotnet_diagnostic.CA1724.severity = suggestion
|
dotnet_diagnostic.CA1724.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1725.severity = suggestion
|
||||||
dotnet_diagnostic.CA1801.severity = suggestion
|
dotnet_diagnostic.CA1801.severity = suggestion
|
||||||
dotnet_diagnostic.CA1802.severity = suggestion
|
dotnet_diagnostic.CA1802.severity = suggestion
|
||||||
dotnet_diagnostic.CA1805.severity = suggestion
|
dotnet_diagnostic.CA1805.severity = suggestion
|
||||||
dotnet_diagnostic.CA1806.severity = suggestion
|
dotnet_diagnostic.CA1806.severity = suggestion
|
||||||
dotnet_diagnostic.CA1810.severity = suggestion
|
dotnet_diagnostic.CA1810.severity = suggestion
|
||||||
dotnet_diagnostic.CA1812.severity = suggestion
|
dotnet_diagnostic.CA1812.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA1813.severity = suggestion
|
||||||
dotnet_diagnostic.CA1814.severity = suggestion
|
dotnet_diagnostic.CA1814.severity = suggestion
|
||||||
dotnet_diagnostic.CA1815.severity = suggestion
|
dotnet_diagnostic.CA1815.severity = suggestion
|
||||||
dotnet_diagnostic.CA1816.severity = suggestion
|
dotnet_diagnostic.CA1816.severity = suggestion
|
||||||
@@ -202,6 +210,7 @@ dotnet_diagnostic.CA2101.severity = suggestion
|
|||||||
dotnet_diagnostic.CA2119.severity = suggestion
|
dotnet_diagnostic.CA2119.severity = suggestion
|
||||||
dotnet_diagnostic.CA2153.severity = suggestion
|
dotnet_diagnostic.CA2153.severity = suggestion
|
||||||
dotnet_diagnostic.CA2200.severity = suggestion
|
dotnet_diagnostic.CA2200.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA2201.severity = suggestion
|
||||||
dotnet_diagnostic.CA2207.severity = suggestion
|
dotnet_diagnostic.CA2207.severity = suggestion
|
||||||
dotnet_diagnostic.CA2208.severity = suggestion
|
dotnet_diagnostic.CA2208.severity = suggestion
|
||||||
dotnet_diagnostic.CA2211.severity = suggestion
|
dotnet_diagnostic.CA2211.severity = suggestion
|
||||||
@@ -247,6 +256,8 @@ dotnet_diagnostic.CA5374.severity = suggestion
|
|||||||
dotnet_diagnostic.CA5379.severity = suggestion
|
dotnet_diagnostic.CA5379.severity = suggestion
|
||||||
dotnet_diagnostic.CA5384.severity = suggestion
|
dotnet_diagnostic.CA5384.severity = suggestion
|
||||||
dotnet_diagnostic.CA5385.severity = suggestion
|
dotnet_diagnostic.CA5385.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA5392.severity = suggestion
|
||||||
|
dotnet_diagnostic.CA5394.severity = suggestion
|
||||||
dotnet_diagnostic.CA5397.severity = suggestion
|
dotnet_diagnostic.CA5397.severity = suggestion
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,37 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: Support Requests will be closed immediately, if you are unsure go to our Reddit or Discord first. Exceptions do not mean you found a bug!
|
about: Support Requests will be closed immediately, if you are not 100% certain this is a bug please go to our Reddit or Discord first. Exceptions do not mean you found a bug!
|
||||||
title: ''
|
title: ''
|
||||||
labels: bug
|
labels: 'Type: Bug'
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
<!-- Support Requests will be closed immediately, if you are unsure go to our Reddit or Discord first. Exceptions do not mean you found a bug! -->
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
Steps to reproduce the behavior:
|
<!-- Steps to reproduce the behavior:
|
||||||
1. Go to '...'
|
1. Go to '...'
|
||||||
2. Click on '....'
|
2. Click on '....'
|
||||||
3. Scroll down to '....'
|
3. Scroll down to '....'
|
||||||
4. See error
|
4. See error -->
|
||||||
|
|
||||||
**Expected behavior**
|
**Expected behavior**
|
||||||
A clear and concise description of what you expected to happen.
|
<!-- A clear and concise description of what you expected to happen.-->
|
||||||
|
|
||||||
**Screenshots**
|
**Screenshots**
|
||||||
If applicable, add screenshots to help explain your problem.
|
<!-- If applicable, add screenshots to help explain your problem.-->
|
||||||
|
|
||||||
**Platform Information (please complete the following information):**
|
**Platform Information (please complete the following information):**
|
||||||
- OS: [e.g. Windows 10 2004 / Ubuntu 20.10]
|
- OS: <!-- [e.g. Windows 10 2004 / Ubuntu 20.04] -->
|
||||||
- Docker: [Yes/No]
|
- Docker: <!-- [Yes/No] -->
|
||||||
- Mono or.NET Core Version: [e.g. Mono 5.8 or .Net Core 3.1.10] (found under System -> Status)
|
- Mono or .NET Version (System -> Status): <!--[e.g. Mono 5.8 or .Net Core 3.1.10 or .NET 5.0.1] -->
|
||||||
- Browser and Version [e.g. chrome 86.0.4240.198] (Only needed for UI issues)
|
- Browser and Version (Only needed for UI issues): <!--[e.g. chrome 86.0.4240.198] -->
|
||||||
- Radarr Version [e.g. 3.0.0.2956]
|
- Radarr Version: <!--[e.g. 3.0.1.4259, 3.0.2.4369]-->
|
||||||
- Radarr Branch [e.g. master]
|
- Radarr Branch: <!--[e.g. master, develop]-->
|
||||||
|
|
||||||
**Trace Logs**
|
**Trace Logs**
|
||||||
Turn on Trace logs under Settings -> General and wait for the bug to occur again. **Upload the full log file here (or another site (e.g. pastebin) and link it). Issues will be closed, if they do not include this!**
|
Turn on Trace logs under Settings -> General and wait for the bug to occur again.
|
||||||
|
**Upload the full log file here (or another site (e.g. pastebin) and link it). Issues will be closed, if they do not include this!**
|
||||||
|
<!-- Trace logs are named Radarr.trace.txt or Radarr.trace.#.txt and will contain "trace" in them-->
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Support via Discord
|
- name: Support via Discord
|
||||||
url: https://discord.gg/r5wJPt9
|
url: https://radarr.video/discord
|
||||||
about: Chat with users and devs on support and setup related topics.
|
about: Chat with users and devs on support and setup related topics.
|
||||||
- name: Support via Reddit
|
- name: Support via Reddit
|
||||||
url: https://reddit.com/r/radarr
|
url: https://reddit.com/r/radarr
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ assignees: ''
|
|||||||
---
|
---
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
**Is your feature request related to a problem? Please describe.**
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
**Describe the solution you'd like**
|
||||||
A clear and concise description of what you want to happen.
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
**Describe alternatives you've considered**
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context or screenshots about the feature request here.
|
<!-- Add any other context or screenshots about the feature request here. -->
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
todo:
|
|
||||||
keyword: "TODO"
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
|
|
||||||
|
|
||||||
# Number of days of inactivity before a closed issue or pull request is locked
|
|
||||||
daysUntilLock: 60
|
|
||||||
|
|
||||||
# Skip issues and pull requests created before a given timestamp. Timestamp must
|
|
||||||
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
|
|
||||||
skipCreatedBefore: false
|
|
||||||
|
|
||||||
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
|
|
||||||
exemptLabels: []
|
|
||||||
|
|
||||||
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
|
||||||
lockLabel: false
|
|
||||||
|
|
||||||
# Comment to post before locking. Set to `false` to disable
|
|
||||||
lockComment: >
|
|
||||||
This thread has been automatically locked since there has not been
|
|
||||||
any recent activity after it was closed. Please open a new issue for
|
|
||||||
related bugs.
|
|
||||||
|
|
||||||
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
|
||||||
setLockReason: true
|
|
||||||
|
|
||||||
# Limit to only `issues` or `pulls`
|
|
||||||
# only: issues
|
|
||||||
|
|
||||||
# Optionally, specify configuration settings just for `issues` or `pulls`
|
|
||||||
# issues:
|
|
||||||
# exemptLabels:
|
|
||||||
# - help-wanted
|
|
||||||
# lockLabel: outdated
|
|
||||||
|
|
||||||
# pulls:
|
|
||||||
# daysUntilLock: 30
|
|
||||||
|
|
||||||
# Repository to extend settings from
|
|
||||||
# _extends: repo
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
+1
-3
@@ -5,12 +5,10 @@ daysUntilClose: 7
|
|||||||
# Issues with these labels will never be considered stale
|
# Issues with these labels will never be considered stale
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- feature request
|
- feature request
|
||||||
- parser
|
- 'Status: Confirmed'
|
||||||
- confirmed
|
|
||||||
- sonarr-pull
|
- sonarr-pull
|
||||||
- lidarr-pull
|
- lidarr-pull
|
||||||
- readarr-pull
|
- readarr-pull
|
||||||
- v3
|
|
||||||
# Label to use when marking an issue as stale
|
# Label to use when marking an issue as stale
|
||||||
staleLabel: stale
|
staleLabel: stale
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# Configuration for support-requests - https://github.com/dessant/support-requests
|
|
||||||
|
|
||||||
# Label used to mark issues as support requests
|
|
||||||
supportLabel: support
|
|
||||||
# Comment to post on issues marked as support requests. Add a link
|
|
||||||
# to a support page, or set to `false` to disable
|
|
||||||
supportComment: >
|
|
||||||
We use the issue tracker exclusively for bug reports and feature requests.
|
|
||||||
However, this issue appears to be a support request. Please hop over onto our [Discord](https://discord.gg/r5wJPt9) or [Subreddit](https://reddit.com/r/radarr)
|
|
||||||
# Whether to close issues marked as support requests
|
|
||||||
close: true
|
|
||||||
# Whether to lock issues marked as support requests
|
|
||||||
lock: false
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
name: 'Lock threads'
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lock:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: dessant/lock-threads@v2
|
||||||
|
with:
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
issue-lock-inactive-days: '90'
|
||||||
|
issue-exclude-created-before: ''
|
||||||
|
issue-exclude-labels: ''
|
||||||
|
issue-lock-labels: ''
|
||||||
|
issue-lock-comment: ''
|
||||||
|
issue-lock-reason: 'resolved'
|
||||||
|
process-only: ''
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
name: 'Support requests'
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [labeled, unlabeled, reopened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
support:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: dessant/support-requests@v2
|
||||||
|
with:
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
support-label: 'Type: Support'
|
||||||
|
issue-comment: >
|
||||||
|
:wave: @{issue-author}, we use the issue tracker exclusively
|
||||||
|
for bug reports and feature requests. However, this issue appears
|
||||||
|
to be a support request. Please hop over onto our [Discord](https://radarr.video/discord)
|
||||||
|
or [Subreddit](https://reddit.com/r/radarr)
|
||||||
|
close-issue: true
|
||||||
|
lock-issue: false
|
||||||
+5
-5
@@ -11,19 +11,19 @@ Setup guides, FAQ, the more information we have on the [wiki](https://wiki.serva
|
|||||||
- Visual Studio 2019 or higher (https://www.visualstudio.com/vs/). The community version is free and works (https://www.visualstudio.com/downloads/).
|
- Visual Studio 2019 or higher (https://www.visualstudio.com/vs/). The community version is free and works (https://www.visualstudio.com/downloads/).
|
||||||
- HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc)
|
- HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc)
|
||||||
- [Git](https://git-scm.com/downloads)
|
- [Git](https://git-scm.com/downloads)
|
||||||
- [NodeJS](https://nodejs.org/en/download/) (Node 10.X.X or higher)
|
- [NodeJS](https://nodejs.org/en/download/) (Node 12.X.X or higher)
|
||||||
- [Yarn](https://yarnpkg.com/)
|
- [Yarn](https://yarnpkg.com/)
|
||||||
- .NET Core 3.1.
|
- .NET Core 5.0.
|
||||||
|
|
||||||
### Getting started ###
|
### Getting started ###
|
||||||
|
|
||||||
1. Fork Radarr
|
1. Fork Radarr
|
||||||
2. Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
|
2. Clone the repository into your development machine. [*info*](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository-from-github)
|
||||||
3. Install the required Node Packages `yarn install`
|
3. Install the required Node Packages `yarn install`
|
||||||
4. Start gulp to monitor your dev environment for any changes that need post processing using `yarn start` command.
|
4. Start gulp to monitor your dev environment for any changes that need post processing using `yarn start` command.
|
||||||
5. Build the project in Visual Studio, Setting startup project to `Radarr.Console` and framework to `netcoreapp31`
|
5. Build the project in Visual Studio, Setting startup project to `Radarr.Console` and framework to `net5.0`
|
||||||
6. Debug the project in Visual Studio
|
6. Debug the project in Visual Studio
|
||||||
7. Open http://localhost:8686
|
7. Open http://localhost:7878
|
||||||
|
|
||||||
### Contributing Code ###
|
### Contributing Code ###
|
||||||
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Radarr/Radarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
|
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Radarr/Radarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
|
||||||
|
|||||||
@@ -28,18 +28,20 @@ Radarr is a movie collection manager for Usenet and BitTorrent users. It can mon
|
|||||||
* Adding metadata such as posters and information for Kodi and others to use
|
* Adding metadata such as posters and information for Kodi and others to use
|
||||||
* Advanced customization for profiles, such that Radarr will always download the copy you want
|
* Advanced customization for profiles, such that Radarr will always download the copy you want
|
||||||
|
|
||||||
## Feature Requests
|
|
||||||
|
|
||||||
[Feature Requests](https://github.com/lidarr/Radarr/issues/new?assignees=&labels=Type%3A+Enhancement&template=feature_request.md&title=)
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
Note: GitHub Issues are for Bugs and Feature Requests Only
|
||||||
|
|
||||||
[](https://discord.gg/r5wJPt9)
|
[](https://radarr.video/discord)
|
||||||
[](https://www.reddit.com/r/Radarr)
|
[](https://www.reddit.com/r/Radarr)
|
||||||
[](https://github.com/Radarr/Radarr/issues)
|
[](https://github.com/Radarr/Radarr/issues)
|
||||||
[](https://wiki.servarr.com/Radarr)
|
[](https://wiki.servarr.com/Radarr)
|
||||||
|
|
||||||
## Contributors
|
## Feature Requests
|
||||||
|
|
||||||
|
[Feature Requests](https://github.com/Radarr/Radarr/issues/new?assignees=&labels=Type%3A+Enhancement&template=feature_request.md&title=)
|
||||||
|
|
||||||
|
## Contributors & Developers
|
||||||
|
[API Documentation](https://radarr.video/docs/api/)
|
||||||
|
|
||||||
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
|
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
|
||||||
<a href="https://github.com/Radarr/Radarr/graphs/contributors"><img src="https://opencollective.com/Radarr/contributors.svg?width=890&button=false" /></a>
|
<a href="https://github.com/Radarr/Radarr/graphs/contributors"><img src="https://opencollective.com/Radarr/contributors.svg?width=890&button=false" /></a>
|
||||||
@@ -72,4 +74,4 @@ Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrai
|
|||||||
### License
|
### License
|
||||||
|
|
||||||
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
||||||
* Copyright 2010-2020
|
* Copyright 2010-2021
|
||||||
|
|||||||
+138
-49
@@ -7,13 +7,13 @@ variables:
|
|||||||
outputFolder: './_output'
|
outputFolder: './_output'
|
||||||
artifactsFolder: './_artifacts'
|
artifactsFolder: './_artifacts'
|
||||||
testsFolder: './_tests'
|
testsFolder: './_tests'
|
||||||
majorVersion: '3.0.0'
|
majorVersion: '3.2.1'
|
||||||
minorVersion: $[counter('minorVersion', 2000)]
|
minorVersion: $[counter('minorVersion', 2000)]
|
||||||
radarrVersion: '$(majorVersion).$(minorVersion)'
|
radarrVersion: '$(majorVersion).$(minorVersion)'
|
||||||
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
||||||
sentryOrg: 'servarr'
|
sentryOrg: 'servarr'
|
||||||
sentryUrl: 'https://sentry.servarr.com'
|
sentryUrl: 'https://sentry.servarr.com'
|
||||||
dotnetVersion: '3.1.404'
|
dotnetVersion: '5.0.202'
|
||||||
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
@@ -23,7 +23,12 @@ trigger:
|
|||||||
- master
|
- master
|
||||||
|
|
||||||
pr:
|
pr:
|
||||||
- develop
|
branches:
|
||||||
|
include:
|
||||||
|
- develop
|
||||||
|
paths:
|
||||||
|
exclude:
|
||||||
|
- src/NzbDrone.Core/Localization/Core
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- stage: Setup
|
- stage: Setup
|
||||||
@@ -59,18 +64,21 @@ stages:
|
|||||||
Linux:
|
Linux:
|
||||||
osName: 'Linux'
|
osName: 'Linux'
|
||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
|
enableAnalysis: 'true'
|
||||||
Mac:
|
Mac:
|
||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
imageName: 'macos-10.14'
|
imageName: 'macos-10.14'
|
||||||
|
enableAnalysis: 'false'
|
||||||
Windows:
|
Windows:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
|
enableAnalysis: 'false'
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: $(imageName)
|
vmImage: $(imageName)
|
||||||
variables:
|
variables:
|
||||||
# Disable stylecop here - linting errors get caught by the analyze task
|
# Disable stylecop here - linting errors get caught by the analyze task
|
||||||
EnableAnalyzers: 'false'
|
EnableAnalyzers: $(enableAnalysis)
|
||||||
steps:
|
steps:
|
||||||
- checkout: self
|
- checkout: self
|
||||||
submodules: true
|
submodules: true
|
||||||
@@ -79,7 +87,18 @@ stages:
|
|||||||
displayName: 'Install .net core'
|
displayName: 'Install .net core'
|
||||||
inputs:
|
inputs:
|
||||||
version: $(dotnetVersion)
|
version: $(dotnetVersion)
|
||||||
- bash: ./build.sh --backend
|
- bash: |
|
||||||
|
BUNDLEDVERSIONS=${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}/Microsoft.NETCoreSdk.BundledVersions.props
|
||||||
|
echo $BUNDLEDVERSIONS
|
||||||
|
grep osx-x64 $BUNDLEDVERSIONS
|
||||||
|
if grep -q freebsd-x64 $BUNDLEDVERSIONS; then
|
||||||
|
echo "BSD already enabled"
|
||||||
|
else
|
||||||
|
echo "Enabling BSD support"
|
||||||
|
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' $BUNDLEDVERSIONS
|
||||||
|
fi
|
||||||
|
displayName: Enable FreeBSD Support
|
||||||
|
- bash: ./build.sh --backend --enable-bsd
|
||||||
displayName: Build Radarr Backend
|
displayName: Build Radarr Backend
|
||||||
- bash: |
|
- bash: |
|
||||||
find ${OUTPUTFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \;
|
find ${OUTPUTFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \;
|
||||||
@@ -92,23 +111,27 @@ stages:
|
|||||||
artifact: '$(osName)Backend'
|
artifact: '$(osName)Backend'
|
||||||
displayName: Publish Backend
|
displayName: Publish Backend
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/netcoreapp3.1/win-x64/publish'
|
- publish: '$(testsFolder)/net5.0/win-x64/publish'
|
||||||
artifact: WindowsCoreTests
|
artifact: WindowsCoreTests
|
||||||
displayName: Publish Windows Test Package
|
displayName: Publish Windows Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/net462/linux-x64/publish'
|
- publish: '$(testsFolder)/net472/linux-x64/publish'
|
||||||
artifact: LinuxTests
|
artifact: LinuxTests
|
||||||
displayName: Publish Linux Mono Test Package
|
displayName: Publish Linux Mono Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/netcoreapp3.1/linux-x64/publish'
|
- publish: '$(testsFolder)/net5.0/linux-x64/publish'
|
||||||
artifact: LinuxCoreTests
|
artifact: LinuxCoreTests
|
||||||
displayName: Publish Linux Test Package
|
displayName: Publish Linux Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/netcoreapp3.1/linux-musl-x64/publish'
|
- publish: '$(testsFolder)/net5.0/linux-musl-x64/publish'
|
||||||
artifact: LinuxMuslCoreTests
|
artifact: LinuxMuslCoreTests
|
||||||
displayName: Publish Linux Musl Test Package
|
displayName: Publish Linux Musl Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/netcoreapp3.1/osx-x64/publish'
|
- publish: '$(testsFolder)/net5.0/freebsd-x64/publish'
|
||||||
|
artifact: FreebsdCoreTests
|
||||||
|
displayName: Publish FreeBSD Test Package
|
||||||
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
|
- publish: '$(testsFolder)/net5.0/osx-x64/publish'
|
||||||
artifact: MacCoreTests
|
artifact: MacCoreTests
|
||||||
displayName: Publish MacOS Test Package
|
displayName: Publish MacOS Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
@@ -135,7 +158,7 @@ stages:
|
|||||||
- task: NodeTool@0
|
- task: NodeTool@0
|
||||||
displayName: Set Node.js version
|
displayName: Set Node.js version
|
||||||
inputs:
|
inputs:
|
||||||
versionSpec: '10.x'
|
versionSpec: '12.x'
|
||||||
- checkout: self
|
- checkout: self
|
||||||
submodules: true
|
submodules: true
|
||||||
fetchDepth: 1
|
fetchDepth: 1
|
||||||
@@ -184,12 +207,12 @@ stages:
|
|||||||
- bash: ./build.sh --packages
|
- bash: ./build.sh --packages
|
||||||
displayName: Create Packages
|
displayName: Create Packages
|
||||||
- bash: |
|
- bash: |
|
||||||
setup/inno/ISCC.exe setup/radarr.iss //DFramework=netcoreapp3.1 //DRuntime=win-x86
|
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net5.0 //DRuntime=win-x86
|
||||||
cp setup/output/Radarr.*windows.netcoreapp3.1.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
|
cp setup/output/Radarr.*windows.net5.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
|
||||||
displayName: Create .NET Core Windows installer
|
displayName: Create .NET Core Windows installer
|
||||||
- bash: |
|
- bash: |
|
||||||
setup/inno/ISCC.exe setup/radarr.iss //DFramework=netcoreapp3.1 //DRuntime=win-x64
|
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net5.0 //DRuntime=win-x64
|
||||||
cp setup/output/Radarr.*windows.netcoreapp3.1.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
|
cp setup/output/Radarr.*windows.net5.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
|
||||||
displayName: Create .NET Core Windows installer
|
displayName: Create .NET Core Windows installer
|
||||||
- publish: $(Build.ArtifactStagingDirectory)
|
- publish: $(Build.ArtifactStagingDirectory)
|
||||||
artifact: 'WindowsInstaller'
|
artifact: 'WindowsInstaller'
|
||||||
@@ -219,7 +242,7 @@ stages:
|
|||||||
artifactName: WindowsFrontend
|
artifactName: WindowsFrontend
|
||||||
targetPath: _output
|
targetPath: _output
|
||||||
displayName: Fetch Frontend
|
displayName: Fetch Frontend
|
||||||
- bash: ./build.sh --packages
|
- bash: ./build.sh --packages --enable-bsd
|
||||||
displayName: Create Packages
|
displayName: Create Packages
|
||||||
- bash: |
|
- bash: |
|
||||||
find . -name "Radarr" -exec chmod a+x {} \;
|
find . -name "Radarr" -exec chmod a+x {} \;
|
||||||
@@ -231,21 +254,21 @@ stages:
|
|||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x64.zip'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x64.zip'
|
||||||
archiveType: 'zip'
|
archiveType: 'zip'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/win-x64/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/win-x64/net5.0
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create Windows x86 Core zip
|
displayName: Create Windows x86 Core zip
|
||||||
inputs:
|
inputs:
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x86.zip'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x86.zip'
|
||||||
archiveType: 'zip'
|
archiveType: 'zip'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/win-x86/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/win-x86/net5.0
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create MacOS Core app
|
displayName: Create MacOS Core app
|
||||||
inputs:
|
inputs:
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-app-core-x64.zip'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-app-core-x64.zip'
|
||||||
archiveType: 'zip'
|
archiveType: 'zip'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/macos-app/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/macos-app/net5.0
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create MacOS Core tar
|
displayName: Create MacOS Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -253,7 +276,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/macos/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/macos/net5.0
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create Linux Mono tar
|
displayName: Create Linux Mono tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -261,7 +284,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-x64/net462
|
rootFolderOrFile: $(artifactsFolder)/linux-x64/net472
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create Linux Core tar
|
displayName: Create Linux Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -269,7 +292,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-x64/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/linux-x64/net5.0
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create Linux Musl Core tar
|
displayName: Create Linux Musl Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -277,7 +300,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net5.0
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create ARM32 Linux Core tar
|
displayName: Create ARM32 Linux Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -285,7 +308,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-arm/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/linux-arm/net5.0
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create ARM64 Linux Core tar
|
displayName: Create ARM64 Linux Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -293,7 +316,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-arm64/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/linux-arm64/net5.0
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create ARM64 Linux Musl Core tar
|
displayName: Create ARM64 Linux Musl Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -301,7 +324,15 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/netcoreapp3.1
|
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net5.0
|
||||||
|
- task: ArchiveFiles@2
|
||||||
|
displayName: Create FreeBSD Core Core tar
|
||||||
|
inputs:
|
||||||
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).freebsd-core-x64.tar.gz'
|
||||||
|
archiveType: 'tar'
|
||||||
|
tarCompression: 'gz'
|
||||||
|
includeRootFolder: false
|
||||||
|
rootFolderOrFile: $(artifactsFolder)/freebsd-x64/net5.0
|
||||||
- publish: $(Build.ArtifactStagingDirectory)
|
- publish: $(Build.ArtifactStagingDirectory)
|
||||||
artifact: 'Packages'
|
artifact: 'Packages'
|
||||||
displayName: Publish Packages
|
displayName: Publish Packages
|
||||||
@@ -355,24 +386,34 @@ stages:
|
|||||||
displayName: Unit Native
|
displayName: Unit Native
|
||||||
dependsOn: Prepare
|
dependsOn: Prepare
|
||||||
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
||||||
|
workspace:
|
||||||
|
clean: all
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
MacCore:
|
MacCore:
|
||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
testName: 'MacCore'
|
testName: 'MacCore'
|
||||||
|
poolName: 'Azure Pipelines'
|
||||||
imageName: 'macos-10.14'
|
imageName: 'macos-10.14'
|
||||||
WindowsCore:
|
WindowsCore:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
testName: 'WindowsCore'
|
testName: 'WindowsCore'
|
||||||
|
poolName: 'Azure Pipelines'
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
LinuxCore:
|
LinuxCore:
|
||||||
osName: 'Linux'
|
osName: 'Linux'
|
||||||
testName: 'LinuxCore'
|
testName: 'LinuxCore'
|
||||||
|
poolName: 'Azure Pipelines'
|
||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
pattern: 'Radarr.**.linux-core-x64.tar.gz'
|
FreebsdCore:
|
||||||
|
osName: 'Linux'
|
||||||
|
testName: 'FreebsdCore'
|
||||||
|
poolName: 'FreeBSD'
|
||||||
|
imageName:
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
|
name: $(poolName)
|
||||||
vmImage: $(imageName)
|
vmImage: $(imageName)
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -381,6 +422,7 @@ stages:
|
|||||||
displayName: 'Install .net core'
|
displayName: 'Install .net core'
|
||||||
inputs:
|
inputs:
|
||||||
version: $(dotnetVersion)
|
version: $(dotnetVersion)
|
||||||
|
condition: ne(variables['poolName'], 'FreeBSD')
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
displayName: Download Test Artifact
|
displayName: Download Test Artifact
|
||||||
inputs:
|
inputs:
|
||||||
@@ -393,7 +435,7 @@ stages:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --allow-unauthenticated libmediainfo-dev libmediainfo0v5 mediainfo
|
sudo apt-get install -y --allow-unauthenticated libmediainfo-dev libmediainfo0v5 mediainfo
|
||||||
displayName: Install mediainfo
|
displayName: Install mediainfo
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Linux'))
|
condition: and(succeeded(), eq(variables['testName'], 'LinuxCore'))
|
||||||
- powershell: Set-Service SCardSvr -StartupType Manual
|
- powershell: Set-Service SCardSvr -StartupType Manual
|
||||||
displayName: Enable Windows Test Service
|
displayName: Enable Windows Test Service
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
@@ -431,19 +473,19 @@ stages:
|
|||||||
mono520:
|
mono520:
|
||||||
testName: 'Mono 5.20'
|
testName: 'Mono 5.20'
|
||||||
artifactName: LinuxTests
|
artifactName: LinuxTests
|
||||||
containerImage: servarr/testimages:mono-5.20
|
containerImage: ghcr.io/servarr/testimages:mono-5.20
|
||||||
mono610:
|
mono610:
|
||||||
testName: 'Mono 6.10'
|
testName: 'Mono 6.10'
|
||||||
artifactName: LinuxTests
|
artifactName: LinuxTests
|
||||||
containerImage: servarr/testimages:mono-6.10
|
containerImage: ghcr.io/servarr/testimages:mono-6.10
|
||||||
mono612:
|
mono612:
|
||||||
testName: 'Mono 6.12'
|
testName: 'Mono 6.12'
|
||||||
artifactName: LinuxTests
|
artifactName: LinuxTests
|
||||||
containerImage: servarr/testimages:mono-6.12
|
containerImage: ghcr.io/servarr/testimages:mono-6.12
|
||||||
alpine:
|
alpine:
|
||||||
testName: 'Musl Net Core'
|
testName: 'Musl Net Core'
|
||||||
artifactName: LinuxMuslCoreTests
|
artifactName: LinuxMuslCoreTests
|
||||||
containerImage: servarr/testimages:alpine
|
containerImage: ghcr.io/servarr/testimages:alpine
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-18.04'
|
vmImage: 'ubuntu-18.04'
|
||||||
@@ -508,17 +550,17 @@ stages:
|
|||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
testName: 'MacCore'
|
testName: 'MacCore'
|
||||||
imageName: 'macos-10.14'
|
imageName: 'macos-10.14'
|
||||||
pattern: 'Radarr.**.osx-core-x64.tar.gz'
|
pattern: 'Radarr.*.osx-core-x64.tar.gz'
|
||||||
WindowsCore:
|
WindowsCore:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
testName: 'WindowsCore'
|
testName: 'WindowsCore'
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
pattern: 'Radarr.**.windows-core-x64.zip'
|
pattern: 'Radarr.*.windows-core-x64.zip'
|
||||||
LinuxCore:
|
LinuxCore:
|
||||||
osName: 'Linux'
|
osName: 'Linux'
|
||||||
testName: 'LinuxCore'
|
testName: 'LinuxCore'
|
||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
pattern: 'Radarr.**.linux-core-x64.tar.gz'
|
pattern: 'Radarr.*.linux-core-x64.tar.gz'
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: $(imageName)
|
vmImage: $(imageName)
|
||||||
@@ -571,6 +613,52 @@ stages:
|
|||||||
failTaskOnFailedTests: true
|
failTaskOnFailedTests: true
|
||||||
displayName: Publish Test Results
|
displayName: Publish Test Results
|
||||||
|
|
||||||
|
- job: Integration_FreeBSD
|
||||||
|
displayName: Integration Native FreeBSD
|
||||||
|
dependsOn: Prepare
|
||||||
|
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
||||||
|
workspace:
|
||||||
|
clean: all
|
||||||
|
variables:
|
||||||
|
pattern: 'Radarr.*.freebsd-core-x64.tar.gz'
|
||||||
|
pool:
|
||||||
|
name: 'FreeBSD'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- checkout: none
|
||||||
|
- task: DownloadPipelineArtifact@2
|
||||||
|
displayName: Download Test Artifact
|
||||||
|
inputs:
|
||||||
|
buildType: 'current'
|
||||||
|
artifactName: 'FreebsdCoreTests'
|
||||||
|
targetPath: $(testsFolder)
|
||||||
|
- task: DownloadPipelineArtifact@2
|
||||||
|
displayName: Download Build Artifact
|
||||||
|
inputs:
|
||||||
|
buildType: 'current'
|
||||||
|
artifactName: Packages
|
||||||
|
itemPattern: '/$(pattern)'
|
||||||
|
targetPath: $(Build.ArtifactStagingDirectory)
|
||||||
|
- bash: |
|
||||||
|
mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin
|
||||||
|
tar xf ${BUILD_ARTIFACTSTAGINGDIRECTORY}/$(pattern) -C ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin
|
||||||
|
displayName: Extract Package
|
||||||
|
- bash: |
|
||||||
|
mkdir -p ./bin/
|
||||||
|
cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Radarr/. ./bin/
|
||||||
|
displayName: Move Package Contents
|
||||||
|
- bash: |
|
||||||
|
chmod a+x ${TESTSFOLDER}/test.sh
|
||||||
|
${TESTSFOLDER}/test.sh Linux Integration Test
|
||||||
|
displayName: Run Integration Tests
|
||||||
|
- task: PublishTestResults@2
|
||||||
|
inputs:
|
||||||
|
testResultsFormat: 'NUnit'
|
||||||
|
testResultsFiles: '**/TestResult.xml'
|
||||||
|
testRunTitle: 'FreeBSD Integration Tests'
|
||||||
|
failTaskOnFailedTests: true
|
||||||
|
displayName: Publish Test Results
|
||||||
|
|
||||||
- job: Integration_Docker
|
- job: Integration_Docker
|
||||||
displayName: Integration Docker
|
displayName: Integration Docker
|
||||||
dependsOn: Prepare
|
dependsOn: Prepare
|
||||||
@@ -580,23 +668,23 @@ stages:
|
|||||||
mono520:
|
mono520:
|
||||||
testName: 'Mono 5.20'
|
testName: 'Mono 5.20'
|
||||||
artifactName: LinuxTests
|
artifactName: LinuxTests
|
||||||
containerImage: servarr/testimages:mono-5.20
|
containerImage: ghcr.io/servarr/testimages:mono-5.20
|
||||||
pattern: 'Radarr.**.linux.tar.gz'
|
pattern: 'Radarr.*.linux.tar.gz'
|
||||||
mono610:
|
mono610:
|
||||||
testName: 'Mono 6.10'
|
testName: 'Mono 6.10'
|
||||||
artifactName: LinuxTests
|
artifactName: LinuxTests
|
||||||
containerImage: servarr/testimages:mono-6.10
|
containerImage: ghcr.io/servarr/testimages:mono-6.10
|
||||||
pattern: 'Radarr.**.linux.tar.gz'
|
pattern: 'Radarr.*.linux.tar.gz'
|
||||||
mono612:
|
mono612:
|
||||||
testName: 'Mono 6.12'
|
testName: 'Mono 6.12'
|
||||||
artifactName: LinuxTests
|
artifactName: LinuxTests
|
||||||
containerImage: servarr/testimages:mono-6.12
|
containerImage: ghcr.io/servarr/testimages:mono-6.12
|
||||||
pattern: 'Radarr.**.linux.tar.gz'
|
pattern: 'Radarr.*.linux.tar.gz'
|
||||||
alpine:
|
alpine:
|
||||||
testName: 'Musl Net Core'
|
testName: 'Musl Net Core'
|
||||||
artifactName: LinuxMuslCoreTests
|
artifactName: LinuxMuslCoreTests
|
||||||
containerImage: servarr/testimages:alpine
|
containerImage: ghcr.io/servarr/testimages:alpine
|
||||||
pattern: 'Radarr.**.linux-musl-core-x64.tar.gz'
|
pattern: 'Radarr.*.linux-musl-core-x64.tar.gz'
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-18.04'
|
vmImage: 'ubuntu-18.04'
|
||||||
|
|
||||||
@@ -655,17 +743,17 @@ stages:
|
|||||||
Linux:
|
Linux:
|
||||||
osName: 'Linux'
|
osName: 'Linux'
|
||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
pattern: 'Radarr.**.linux-core-x64.tar.gz'
|
pattern: 'Radarr.*.linux-core-x64.tar.gz'
|
||||||
failBuild: true
|
failBuild: true
|
||||||
Mac:
|
Mac:
|
||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
imageName: 'macos-10.14'
|
imageName: 'macos-10.14'
|
||||||
pattern: 'Radarr.**.osx-core-x64.tar.gz'
|
pattern: 'Radarr.*.osx-core-x64.tar.gz'
|
||||||
failBuild: true
|
failBuild: true
|
||||||
Windows:
|
Windows:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
pattern: 'Radarr.**.windows-core-x64.zip'
|
pattern: 'Radarr.*.windows-core-x64.zip'
|
||||||
failBuild: true
|
failBuild: true
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
@@ -757,7 +845,7 @@ stages:
|
|||||||
- task: NodeTool@0
|
- task: NodeTool@0
|
||||||
displayName: Set Node.js version
|
displayName: Set Node.js version
|
||||||
inputs:
|
inputs:
|
||||||
versionSpec: '10.x'
|
versionSpec: '12.x'
|
||||||
- checkout: self
|
- checkout: self
|
||||||
submodules: true
|
submodules: true
|
||||||
fetchDepth: 1
|
fetchDepth: 1
|
||||||
@@ -803,6 +891,7 @@ stages:
|
|||||||
|
|
||||||
variables:
|
variables:
|
||||||
disable.coverage.autogenerate: 'true'
|
disable.coverage.autogenerate: 'true'
|
||||||
|
EnableAnalyzers: 'false'
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: windows-2019
|
vmImage: windows-2019
|
||||||
@@ -831,8 +920,8 @@ stages:
|
|||||||
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
|
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
|
||||||
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
|
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
|
||||||
- bash: |
|
- bash: |
|
||||||
./build.sh --backend -f netcoreapp3.1 -r win-x64
|
./build.sh --backend -f net5.0 -r win-x64
|
||||||
TEST_DIR=_tests/netcoreapp3.1/win-x64/publish/ ./test.sh Windows Unit Coverage
|
TEST_DIR=_tests/net5.0/win-x64/publish/ ./test.sh Windows Unit Coverage
|
||||||
displayName: Coverage Unit Tests
|
displayName: Coverage Unit Tests
|
||||||
- task: SonarCloudAnalyze@1
|
- task: SonarCloudAnalyze@1
|
||||||
condition: eq(variables['System.PullRequest.IsFork'], 'False')
|
condition: eq(variables['System.PullRequest.IsFork'], 'False')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#! /bin/bash
|
#! /usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
outputFolder='_output'
|
outputFolder='_output'
|
||||||
@@ -25,6 +25,18 @@ UpdateVersionNumber()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnableBsdSupport()
|
||||||
|
{
|
||||||
|
#todo enable sdk with
|
||||||
|
#SDK_PATH=$(dotnet --list-sdks | grep -P '5\.\d\.\d+' | head -1 | sed 's/\(5\.[0-9]*\.[0-9]*\).*\[\(.*\)\]/\2\/\1/g')
|
||||||
|
# BUNDLED_VERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
|
||||||
|
|
||||||
|
if grep -qv freebsd-x64 src/Directory.Build.props; then
|
||||||
|
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64</RuntimeIdentifiers>^g" src/Directory.Build.props
|
||||||
|
sed -i'' -e "s^<ExcludedRuntimeFrameworkPairs>\(.*\)</ExcludedRuntimeFrameworkPairs>^<ExcludedRuntimeFrameworkPairs>\1;freebsd-x64:net472</ExcludedRuntimeFrameworkPairs>^g" src/Directory.Build.props
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
LintUI()
|
LintUI()
|
||||||
{
|
{
|
||||||
ProgressStart 'ESLint'
|
ProgressStart 'ESLint'
|
||||||
@@ -75,11 +87,11 @@ YarnInstall()
|
|||||||
ProgressEnd 'yarn install'
|
ProgressEnd 'yarn install'
|
||||||
}
|
}
|
||||||
|
|
||||||
RunGulp()
|
RunWebpack()
|
||||||
{
|
{
|
||||||
ProgressStart 'Running gulp'
|
ProgressStart 'Running webpack'
|
||||||
yarn run build --production
|
yarn run build --env production
|
||||||
ProgressEnd 'Running gulp'
|
ProgressEnd 'Running webpack'
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageFiles()
|
PackageFiles()
|
||||||
@@ -118,7 +130,7 @@ PackageLinux()
|
|||||||
|
|
||||||
echo "Adding Radarr.Mono to UpdatePackage"
|
echo "Adding Radarr.Mono to UpdatePackage"
|
||||||
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
||||||
if [ "$framework" = "netcoreapp3.1" ]; then
|
if [ "$framework" = "net5.0" ]; then
|
||||||
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
||||||
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
||||||
fi
|
fi
|
||||||
@@ -136,7 +148,7 @@ PackageMacOS()
|
|||||||
|
|
||||||
PackageFiles "$folder" "$framework" "osx-x64"
|
PackageFiles "$folder" "$framework" "osx-x64"
|
||||||
|
|
||||||
if [ "$framework" = "net462" ]; then
|
if [ "$framework" = "net472" ]; then
|
||||||
echo "Adding Startup script"
|
echo "Adding Startup script"
|
||||||
cp macOS/Radarr $folder
|
cp macOS/Radarr $folder
|
||||||
fi
|
fi
|
||||||
@@ -150,7 +162,7 @@ PackageMacOS()
|
|||||||
|
|
||||||
echo "Adding Radarr.Mono to UpdatePackage"
|
echo "Adding Radarr.Mono to UpdatePackage"
|
||||||
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
||||||
if [ "$framework" = "netcoreapp3.1" ]; then
|
if [ "$framework" = "net5.0" ]; then
|
||||||
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
||||||
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
||||||
fi
|
fi
|
||||||
@@ -190,6 +202,7 @@ PackageWindows()
|
|||||||
local folder=$artifactsFolder/$runtime/$framework/Radarr
|
local folder=$artifactsFolder/$runtime/$framework/Radarr
|
||||||
|
|
||||||
PackageFiles "$folder" "$framework" "$runtime"
|
PackageFiles "$folder" "$framework" "$runtime"
|
||||||
|
cp -r $outputFolder/$framework-windows/$runtime/publish/* $folder
|
||||||
|
|
||||||
echo "Removing Radarr.Mono"
|
echo "Removing Radarr.Mono"
|
||||||
rm -f $folder/Radarr.Mono.*
|
rm -f $folder/Radarr.Mono.*
|
||||||
@@ -211,7 +224,7 @@ Package()
|
|||||||
IFS='-' read -ra SPLIT <<< "$runtime"
|
IFS='-' read -ra SPLIT <<< "$runtime"
|
||||||
|
|
||||||
case "${SPLIT[0]}" in
|
case "${SPLIT[0]}" in
|
||||||
linux)
|
linux|freebsd*)
|
||||||
PackageLinux "$framework" "$runtime"
|
PackageLinux "$framework" "$runtime"
|
||||||
;;
|
;;
|
||||||
win)
|
win)
|
||||||
@@ -256,6 +269,7 @@ if [ $# -eq 0 ]; then
|
|||||||
FRONTEND=YES
|
FRONTEND=YES
|
||||||
PACKAGES=YES
|
PACKAGES=YES
|
||||||
LINT=YES
|
LINT=YES
|
||||||
|
ENABLE_BSD=NO
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]
|
while [[ $# -gt 0 ]]
|
||||||
@@ -267,6 +281,10 @@ case $key in
|
|||||||
BACKEND=YES
|
BACKEND=YES
|
||||||
shift # past argument
|
shift # past argument
|
||||||
;;
|
;;
|
||||||
|
--enable-bsd)
|
||||||
|
ENABLE_BSD=YES
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
-r|--runtime)
|
-r|--runtime)
|
||||||
RID="$2"
|
RID="$2"
|
||||||
shift # past argument
|
shift # past argument
|
||||||
@@ -307,15 +325,23 @@ set -- "${POSITIONAL[@]}" # restore positional parameters
|
|||||||
if [ "$BACKEND" = "YES" ];
|
if [ "$BACKEND" = "YES" ];
|
||||||
then
|
then
|
||||||
UpdateVersionNumber
|
UpdateVersionNumber
|
||||||
|
if [ "$ENABLE_BSD" = "YES" ];
|
||||||
|
then
|
||||||
|
EnableBsdSupport
|
||||||
|
fi
|
||||||
Build
|
Build
|
||||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||||
then
|
then
|
||||||
PackageTests "netcoreapp3.1" "win-x64"
|
PackageTests "net5.0" "win-x64"
|
||||||
PackageTests "netcoreapp3.1" "win-x86"
|
PackageTests "net5.0" "win-x86"
|
||||||
PackageTests "netcoreapp3.1" "linux-x64"
|
PackageTests "net5.0" "linux-x64"
|
||||||
PackageTests "netcoreapp3.1" "linux-musl-x64"
|
PackageTests "net5.0" "linux-musl-x64"
|
||||||
PackageTests "netcoreapp3.1" "osx-x64"
|
PackageTests "net5.0" "osx-x64"
|
||||||
PackageTests "net462" "linux-x64"
|
PackageTests "net472" "linux-x64"
|
||||||
|
if [ "$ENABLE_BSD" = "YES" ];
|
||||||
|
then
|
||||||
|
PackageTests "net5.0" "freebsd-x64"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
PackageTests "$FRAMEWORK" "$RID"
|
PackageTests "$FRAMEWORK" "$RID"
|
||||||
fi
|
fi
|
||||||
@@ -324,7 +350,7 @@ fi
|
|||||||
if [ "$FRONTEND" = "YES" ];
|
if [ "$FRONTEND" = "YES" ];
|
||||||
then
|
then
|
||||||
YarnInstall
|
YarnInstall
|
||||||
RunGulp
|
RunWebpack
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$LINT" = "YES" ];
|
if [ "$LINT" = "YES" ];
|
||||||
@@ -343,15 +369,19 @@ then
|
|||||||
|
|
||||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||||
then
|
then
|
||||||
Package "netcoreapp3.1" "win-x64"
|
Package "net5.0" "win-x64"
|
||||||
Package "netcoreapp3.1" "win-x86"
|
Package "net5.0" "win-x86"
|
||||||
Package "netcoreapp3.1" "linux-x64"
|
Package "net5.0" "linux-x64"
|
||||||
Package "netcoreapp3.1" "linux-musl-x64"
|
Package "net5.0" "linux-musl-x64"
|
||||||
Package "netcoreapp3.1" "linux-arm64"
|
Package "net5.0" "linux-arm64"
|
||||||
Package "netcoreapp3.1" "linux-musl-arm64"
|
Package "net5.0" "linux-musl-arm64"
|
||||||
Package "netcoreapp3.1" "linux-arm"
|
Package "net5.0" "linux-arm"
|
||||||
Package "netcoreapp3.1" "osx-x64"
|
Package "net5.0" "osx-x64"
|
||||||
Package "net462" "linux-x64"
|
Package "net472" "linux-x64"
|
||||||
|
if [ "$ENABLE_BSD" = "YES" ];
|
||||||
|
then
|
||||||
|
Package "net5.0" "freebsd-x64"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
Package "$FRAMEWORK" "$RID"
|
Package "$FRAMEWORK" "$RID"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ const dirs = fs
|
|||||||
.map((dirent) => dirent.name)
|
.map((dirent) => dirent.name)
|
||||||
.join('|');
|
.join('|');
|
||||||
|
|
||||||
|
const frontendFolder = __dirname;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
parser: 'babel-eslint',
|
parser: '@babel/eslint-parser',
|
||||||
|
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
@@ -25,6 +27,9 @@ module.exports = {
|
|||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 6,
|
ecmaVersion: 6,
|
||||||
sourceType: 'module',
|
sourceType: 'module',
|
||||||
|
babelOptions: {
|
||||||
|
configFile: `${frontendFolder}/babel.config.js`
|
||||||
|
},
|
||||||
ecmaFeatures: {
|
ecmaFeatures: {
|
||||||
modules: true,
|
modules: true,
|
||||||
impliedStrict: true
|
impliedStrict: true
|
||||||
@@ -271,7 +276,7 @@ module.exports = {
|
|||||||
|
|
||||||
// ImportSort
|
// ImportSort
|
||||||
|
|
||||||
'simple-import-sort/sort': 'error',
|
'simple-import-sort/imports': 'error',
|
||||||
'import/newline-after-import': 'error',
|
'import/newline-after-import': 'error',
|
||||||
|
|
||||||
// React
|
// React
|
||||||
@@ -309,7 +314,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
files: ['*.js'],
|
files: ['*.js'],
|
||||||
rules: {
|
rules: {
|
||||||
'simple-import-sort/sort': [
|
'simple-import-sort/imports': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
groups: [
|
groups: [
|
||||||
|
|||||||
@@ -0,0 +1,269 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const LiveReloadPlugin = require('webpack-livereload-plugin');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
|
|
||||||
|
module.exports = (env) => {
|
||||||
|
const uiFolder = 'UI';
|
||||||
|
const frontendFolder = path.join(__dirname, '..');
|
||||||
|
const srcFolder = path.join(frontendFolder, 'src');
|
||||||
|
const isProduction = !!env.production;
|
||||||
|
const isProfiling = isProduction && !!env.profile;
|
||||||
|
const inlineWebWorkers = 'no-fallback';
|
||||||
|
|
||||||
|
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
|
||||||
|
|
||||||
|
console.log('Source Folder:', srcFolder);
|
||||||
|
console.log('Output Folder:', distFolder);
|
||||||
|
console.log('isProduction:', isProduction);
|
||||||
|
console.log('isProfiling:', isProfiling);
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
mode: isProduction ? 'production' : 'development',
|
||||||
|
devtool: 'source-map',
|
||||||
|
|
||||||
|
stats: {
|
||||||
|
children: false
|
||||||
|
},
|
||||||
|
|
||||||
|
watchOptions: {
|
||||||
|
ignored: /node_modules/
|
||||||
|
},
|
||||||
|
|
||||||
|
entry: {
|
||||||
|
index: 'index.js'
|
||||||
|
},
|
||||||
|
|
||||||
|
resolve: {
|
||||||
|
modules: [
|
||||||
|
srcFolder,
|
||||||
|
path.join(srcFolder, 'Shims'),
|
||||||
|
'node_modules'
|
||||||
|
],
|
||||||
|
alias: {
|
||||||
|
jquery: 'jquery/src/jquery'
|
||||||
|
},
|
||||||
|
fallback: {
|
||||||
|
buffer: false,
|
||||||
|
http: false,
|
||||||
|
https: false,
|
||||||
|
url: false,
|
||||||
|
util: false,
|
||||||
|
net: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: distFolder,
|
||||||
|
publicPath: '/',
|
||||||
|
filename: '[name].js',
|
||||||
|
sourceMapFilename: '[file].map'
|
||||||
|
},
|
||||||
|
|
||||||
|
optimization: {
|
||||||
|
moduleIds: 'deterministic',
|
||||||
|
chunkIds: 'named',
|
||||||
|
splitChunks: {
|
||||||
|
chunks: 'initial',
|
||||||
|
name: 'vendors'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
performance: {
|
||||||
|
hints: false
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
__DEV__: !isProduction,
|
||||||
|
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
|
||||||
|
}),
|
||||||
|
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: 'Content/styles.css'
|
||||||
|
}),
|
||||||
|
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: 'frontend/src/index.html',
|
||||||
|
filename: 'index.html',
|
||||||
|
publicPath: '/'
|
||||||
|
}),
|
||||||
|
|
||||||
|
new CopyPlugin({
|
||||||
|
patterns: [
|
||||||
|
// HTML
|
||||||
|
{
|
||||||
|
from: 'frontend/src/*.html',
|
||||||
|
to: path.join(distFolder, '[name][ext]'),
|
||||||
|
globOptions: {
|
||||||
|
ignore: ['**/index.html']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
{
|
||||||
|
from: 'frontend/src/Content/Fonts/*.*',
|
||||||
|
to: path.join(distFolder, 'Content/Fonts', '[name][ext]')
|
||||||
|
},
|
||||||
|
|
||||||
|
// Icon Images
|
||||||
|
{
|
||||||
|
from: 'frontend/src/Content/Images/Icons/*.*',
|
||||||
|
to: path.join(distFolder, 'Content/Images/Icons', '[name][ext]')
|
||||||
|
},
|
||||||
|
|
||||||
|
// Images
|
||||||
|
{
|
||||||
|
from: 'frontend/src/Content/Images/*.*',
|
||||||
|
to: path.join(distFolder, 'Content/Images', '[name][ext]')
|
||||||
|
},
|
||||||
|
|
||||||
|
// Robots
|
||||||
|
{
|
||||||
|
from: 'frontend/src/Content/robots.txt',
|
||||||
|
to: path.join(distFolder, 'Content', '[name][ext]')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
new LiveReloadPlugin()
|
||||||
|
],
|
||||||
|
|
||||||
|
resolveLoader: {
|
||||||
|
modules: [
|
||||||
|
'node_modules',
|
||||||
|
'frontend/build/webpack/'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.worker\.js$/,
|
||||||
|
use: {
|
||||||
|
loader: 'worker-loader',
|
||||||
|
options: {
|
||||||
|
filename: '[name].js',
|
||||||
|
inline: inlineWebWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js?$/,
|
||||||
|
exclude: /(node_modules|JsLibraries)/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
configFile: `${frontendFolder}/babel.config.js`,
|
||||||
|
envName: isProduction ? 'production' : 'development',
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
|
{
|
||||||
|
modules: false,
|
||||||
|
loose: true,
|
||||||
|
debug: false,
|
||||||
|
useBuiltIns: 'entry',
|
||||||
|
corejs: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// CSS Modules
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
exclude: /(node_modules|globals.css)/,
|
||||||
|
use: [
|
||||||
|
{ loader: MiniCssExtractPlugin.loader },
|
||||||
|
{
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: {
|
||||||
|
importLoaders: 1,
|
||||||
|
modules: {
|
||||||
|
localIdentName: '[name]/[local]/[hash:base64:5]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
|
postcssOptions: {
|
||||||
|
config: 'frontend/postcss.config.js'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// Global styles
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
include: /(node_modules|globals.css)/,
|
||||||
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
{
|
||||||
|
loader: 'css-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
{
|
||||||
|
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10240,
|
||||||
|
mimetype: 'application/font-woff',
|
||||||
|
emitFile: false,
|
||||||
|
name: 'Content/Fonts/[name].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
emitFile: false,
|
||||||
|
name: 'Content/Fonts/[name].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isProfiling) {
|
||||||
|
config.resolve.alias['react-dom$'] = 'react-dom/profiling';
|
||||||
|
config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
|
||||||
|
|
||||||
|
config.optimization.minimizer = [
|
||||||
|
new TerserPlugin({
|
||||||
|
cache: true,
|
||||||
|
parallel: true,
|
||||||
|
sourceMap: true, // Must be set to true if using source-maps in production
|
||||||
|
terserOptions: {
|
||||||
|
mangle: false,
|
||||||
|
keep_classnames: true,
|
||||||
|
keep_fnames: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
const gulp = require('gulp');
|
|
||||||
|
|
||||||
require('./clean');
|
|
||||||
require('./copy');
|
|
||||||
require('./webpack');
|
|
||||||
|
|
||||||
gulp.task('build',
|
|
||||||
gulp.series('clean',
|
|
||||||
gulp.parallel(
|
|
||||||
'webpack',
|
|
||||||
'copyHtml',
|
|
||||||
'copyFonts',
|
|
||||||
'copyImages'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
const gulp = require('gulp');
|
|
||||||
const del = require('del');
|
|
||||||
|
|
||||||
const paths = require('./helpers/paths');
|
|
||||||
|
|
||||||
gulp.task('clean', () => {
|
|
||||||
return del([paths.dest.root]);
|
|
||||||
});
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const gulp = require('gulp');
|
|
||||||
const print = require('gulp-print').default;
|
|
||||||
const cache = require('gulp-cached');
|
|
||||||
const livereload = require('gulp-livereload');
|
|
||||||
const paths = require('./helpers/paths.js');
|
|
||||||
|
|
||||||
gulp.task('copyHtml', () => {
|
|
||||||
return gulp.src(paths.src.html, { base: paths.src.root })
|
|
||||||
.pipe(cache('copyHtml'))
|
|
||||||
.pipe(print())
|
|
||||||
.pipe(gulp.dest(paths.dest.root))
|
|
||||||
.pipe(livereload());
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('copyFonts', () => {
|
|
||||||
return gulp.src(
|
|
||||||
path.join(paths.src.fonts, '**', '*.*'), { base: paths.src.root }
|
|
||||||
)
|
|
||||||
.pipe(cache('copyFonts'))
|
|
||||||
.pipe(print())
|
|
||||||
.pipe(gulp.dest(paths.dest.root))
|
|
||||||
.pipe(livereload());
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('copyImages', () => {
|
|
||||||
return gulp.src(
|
|
||||||
path.join(paths.src.images, '**', '*.*'), { base: paths.src.root }
|
|
||||||
)
|
|
||||||
.pipe(cache('copyImages'))
|
|
||||||
.pipe(print())
|
|
||||||
.pipe(gulp.dest(paths.dest.root))
|
|
||||||
.pipe(livereload());
|
|
||||||
});
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
require('./build.js');
|
|
||||||
require('./clean.js');
|
|
||||||
require('./copy.js');
|
|
||||||
require('./watch.js');
|
|
||||||
require('./webpack.js');
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
const colors = require('ansi-colors');
|
|
||||||
|
|
||||||
module.exports = function errorHandler(error) {
|
|
||||||
console.log(colors.red(`Error (${error.plugin}): ${error.message}`));
|
|
||||||
this.emit('end');
|
|
||||||
};
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
const root = './frontend/src';
|
|
||||||
|
|
||||||
const paths = {
|
|
||||||
src: {
|
|
||||||
root,
|
|
||||||
html: `${root}/*.html`,
|
|
||||||
scripts: `${root}/**/*.js`,
|
|
||||||
content: `${root}/Content/`,
|
|
||||||
fonts: `${root}/Content/Fonts/`,
|
|
||||||
images: `${root}/Content/Images/`,
|
|
||||||
exclude: {
|
|
||||||
libs: `!${root}/JsLibraries/**`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dest: {
|
|
||||||
root: './_output/UI/',
|
|
||||||
content: './_output/UI/Content/',
|
|
||||||
fonts: './_output/UI/Content/Fonts/',
|
|
||||||
images: './_output/UI/Content/Images/'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = paths;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
const gulp = require('gulp');
|
|
||||||
const livereload = require('gulp-livereload');
|
|
||||||
const gulpWatch = require('gulp-watch');
|
|
||||||
const paths = require('./helpers/paths.js');
|
|
||||||
|
|
||||||
require('./copy.js');
|
|
||||||
require('./webpack.js');
|
|
||||||
|
|
||||||
function watch() {
|
|
||||||
livereload.listen({ start: true });
|
|
||||||
|
|
||||||
gulp.task('webpackWatch')();
|
|
||||||
gulpWatch(paths.src.html, gulp.series('copyHtml'));
|
|
||||||
gulpWatch(`${paths.src.fonts}**/*.*`, gulp.series('copyFonts'));
|
|
||||||
gulpWatch(`${paths.src.images}**/*.*`, gulp.series('copyImages'));
|
|
||||||
}
|
|
||||||
|
|
||||||
gulp.task('watch', gulp.series('build', watch));
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
const gulp = require('gulp');
|
|
||||||
const webpackStream = require('webpack-stream');
|
|
||||||
const livereload = require('gulp-livereload');
|
|
||||||
const path = require('path');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const errorHandler = require('./helpers/errorHandler');
|
|
||||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
const HtmlWebpackPluginHtmlTags = require('html-webpack-plugin/lib/html-tags');
|
|
||||||
const TerserPlugin = require('terser-webpack-plugin');
|
|
||||||
|
|
||||||
const uiFolder = 'UI';
|
|
||||||
const frontendFolder = path.join(__dirname, '..');
|
|
||||||
const srcFolder = path.join(frontendFolder, 'src');
|
|
||||||
const isProduction = process.argv.indexOf('--production') > -1;
|
|
||||||
const isProfiling = isProduction && process.argv.indexOf('--profile') > -1;
|
|
||||||
const inlineWebWorkers = 'no-fallback';
|
|
||||||
|
|
||||||
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
|
|
||||||
|
|
||||||
console.log('Source Folder:', srcFolder);
|
|
||||||
console.log('Output Folder:', distFolder);
|
|
||||||
console.log('isProduction:', isProduction);
|
|
||||||
console.log('isProfiling:', isProfiling);
|
|
||||||
|
|
||||||
const cssVarsFiles = [
|
|
||||||
'../src/Styles/Variables/colors',
|
|
||||||
'../src/Styles/Variables/dimensions',
|
|
||||||
'../src/Styles/Variables/fonts',
|
|
||||||
'../src/Styles/Variables/animations',
|
|
||||||
'../src/Styles/Variables/zIndexes'
|
|
||||||
].map(require.resolve);
|
|
||||||
|
|
||||||
// Override the way HtmlWebpackPlugin injects the scripts
|
|
||||||
// TODO: Find a better way to get these paths without
|
|
||||||
HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function(html, assets, assetTags) {
|
|
||||||
const head = assetTags.headTags.map((v) => {
|
|
||||||
const href = v.attributes.href
|
|
||||||
.replace('\\', '/')
|
|
||||||
.replace('%5C', '/');
|
|
||||||
|
|
||||||
v.attributes = { rel: 'stylesheet', type: 'text/css', href: `/${href}` };
|
|
||||||
return HtmlWebpackPluginHtmlTags.htmlTagObjectToString(v, this.options.xhtml);
|
|
||||||
});
|
|
||||||
const body = assetTags.bodyTags.map((v) => {
|
|
||||||
v.attributes = { src: `/${v.attributes.src}` };
|
|
||||||
return HtmlWebpackPluginHtmlTags.htmlTagObjectToString(v, this.options.xhtml);
|
|
||||||
});
|
|
||||||
|
|
||||||
return html
|
|
||||||
.replace('<!-- webpack bundles head -->', head.join('\r\n '))
|
|
||||||
.replace('<!-- webpack bundles body -->', body.join('\r\n '));
|
|
||||||
};
|
|
||||||
|
|
||||||
const plugins = [
|
|
||||||
new OptimizeCssAssetsPlugin({}),
|
|
||||||
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
__DEV__: !isProduction,
|
|
||||||
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
|
|
||||||
}),
|
|
||||||
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
filename: path.join('Content', 'styles.css')
|
|
||||||
}),
|
|
||||||
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: 'frontend/src/index.html',
|
|
||||||
filename: 'index.html'
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
mode: isProduction ? 'production' : 'development',
|
|
||||||
devtool: '#source-map',
|
|
||||||
|
|
||||||
stats: {
|
|
||||||
children: false
|
|
||||||
},
|
|
||||||
|
|
||||||
watchOptions: {
|
|
||||||
ignored: /node_modules/
|
|
||||||
},
|
|
||||||
|
|
||||||
entry: {
|
|
||||||
index: 'index.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
resolve: {
|
|
||||||
modules: [
|
|
||||||
srcFolder,
|
|
||||||
path.join(srcFolder, 'Shims'),
|
|
||||||
'node_modules'
|
|
||||||
],
|
|
||||||
alias: {
|
|
||||||
jquery: 'jquery/src/jquery'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: distFolder,
|
|
||||||
filename: '[name].js',
|
|
||||||
sourceMapFilename: '[file].map'
|
|
||||||
},
|
|
||||||
|
|
||||||
optimization: {
|
|
||||||
chunkIds: 'named',
|
|
||||||
splitChunks: {
|
|
||||||
chunks: 'initial'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
performance: {
|
|
||||||
hints: false
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins,
|
|
||||||
|
|
||||||
resolveLoader: {
|
|
||||||
modules: [
|
|
||||||
'node_modules',
|
|
||||||
'frontend/gulp/webpack/'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.worker\.js$/,
|
|
||||||
use: {
|
|
||||||
loader: 'worker-loader',
|
|
||||||
options: {
|
|
||||||
filename: '[name].js',
|
|
||||||
inline: inlineWebWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js?$/,
|
|
||||||
exclude: /(node_modules|JsLibraries)/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
configFile: `${frontendFolder}/babel.config.js`,
|
|
||||||
envName: isProduction ? 'production' : 'development',
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
'@babel/preset-env',
|
|
||||||
{
|
|
||||||
modules: false,
|
|
||||||
loose: true,
|
|
||||||
debug: false,
|
|
||||||
useBuiltIns: 'entry',
|
|
||||||
corejs: 3
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
// CSS Modules
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
exclude: /(node_modules|globals.css)/,
|
|
||||||
use: [
|
|
||||||
{ loader: MiniCssExtractPlugin.loader },
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
importLoaders: 1,
|
|
||||||
modules: {
|
|
||||||
localIdentName: '[name]/[local]/[hash:base64:5]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'postcss-loader',
|
|
||||||
options: {
|
|
||||||
ident: 'postcss',
|
|
||||||
config: {
|
|
||||||
ctx: {
|
|
||||||
cssVarsFiles
|
|
||||||
},
|
|
||||||
path: 'frontend/postcss.config.js'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
// Global styles
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
include: /(node_modules|globals.css)/,
|
|
||||||
use: [
|
|
||||||
'style-loader',
|
|
||||||
{
|
|
||||||
loader: 'css-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
// Fonts
|
|
||||||
{
|
|
||||||
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10240,
|
|
||||||
mimetype: 'application/font-woff',
|
|
||||||
emitFile: false,
|
|
||||||
name: 'Content/Fonts/[name].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'file-loader',
|
|
||||||
options: {
|
|
||||||
emitFile: false,
|
|
||||||
name: 'Content/Fonts/[name].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isProfiling) {
|
|
||||||
config.resolve.alias['react-dom$'] = 'react-dom/profiling';
|
|
||||||
config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
|
|
||||||
|
|
||||||
config.optimization.minimizer = [
|
|
||||||
new TerserPlugin({
|
|
||||||
cache: true,
|
|
||||||
parallel: true,
|
|
||||||
sourceMap: true, // Must be set to true if using source-maps in production
|
|
||||||
terserOptions: {
|
|
||||||
mangle: false,
|
|
||||||
keep_classnames: true,
|
|
||||||
keep_fnames: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
gulp.task('webpack', () => {
|
|
||||||
return webpackStream(config)
|
|
||||||
.pipe(gulp.dest('_output/UI'));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('webpackWatch', () => {
|
|
||||||
config.watch = true;
|
|
||||||
|
|
||||||
return webpackStream(config, webpack)
|
|
||||||
.on('error', errorHandler)
|
|
||||||
.pipe(gulp.dest('_output/UI'))
|
|
||||||
.on('error', errorHandler)
|
|
||||||
.pipe(livereload())
|
|
||||||
.on('error', errorHandler);
|
|
||||||
});
|
|
||||||
+29
-20
@@ -1,23 +1,32 @@
|
|||||||
const reload = require('require-nocache')(module);
|
const reload = require('require-nocache')(module);
|
||||||
|
|
||||||
module.exports = (ctx, configPath, options) => {
|
const cssVarsFiles = [
|
||||||
const config = {
|
'./src/Styles/Variables/colors',
|
||||||
plugins: {
|
'./src/Styles/Variables/dimensions',
|
||||||
'postcss-mixins': {
|
'./src/Styles/Variables/fonts',
|
||||||
mixinsDir: [
|
'./src/Styles/Variables/animations',
|
||||||
'frontend/src/Styles/Mixins'
|
'./src/Styles/Variables/zIndexes'
|
||||||
]
|
].map(require.resolve);
|
||||||
},
|
|
||||||
'postcss-simple-vars': {
|
|
||||||
variables: () =>
|
|
||||||
ctx.options.cssVarsFiles.reduce((acc, vars) => {
|
|
||||||
return Object.assign(acc, reload(vars));
|
|
||||||
}, {})
|
|
||||||
},
|
|
||||||
'postcss-color-function': {},
|
|
||||||
'postcss-nested': {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return config;
|
const mixinsFiles = [
|
||||||
};
|
'frontend/src/Styles/Mixins/cover.css',
|
||||||
|
'frontend/src/Styles/Mixins/linkOverlay.css',
|
||||||
|
'frontend/src/Styles/Mixins/scroller.css',
|
||||||
|
'frontend/src/Styles/Mixins/truncate.css'
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
['postcss-mixins', {
|
||||||
|
mixinsFiles
|
||||||
|
}],
|
||||||
|
['postcss-simple-vars', {
|
||||||
|
variables: () =>
|
||||||
|
cssVarsFiles.reduce((acc, vars) => {
|
||||||
|
return Object.assign(acc, reload(vars));
|
||||||
|
}, {})
|
||||||
|
}],
|
||||||
|
'postcss-color-function',
|
||||||
|
'postcss-nested'
|
||||||
|
]
|
||||||
|
};
|
||||||
@@ -32,6 +32,8 @@ class Queue extends Component {
|
|||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
|
this._shouldBlockRefresh = false;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
allSelected: false,
|
allSelected: false,
|
||||||
allUnselected: false,
|
allUnselected: false,
|
||||||
@@ -43,6 +45,14 @@ class Queue extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
if (this._shouldBlockRefresh) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
@@ -85,6 +95,10 @@ class Queue extends Component {
|
|||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
|
onQueueRowModalOpenOrClose = (isOpen) => {
|
||||||
|
this._shouldBlockRefresh = isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
onSelectAllChange = ({ value }) => {
|
onSelectAllChange = ({ value }) => {
|
||||||
this.setState(selectAll(this.state.selectedState, value));
|
this.setState(selectAll(this.state.selectedState, value));
|
||||||
}
|
}
|
||||||
@@ -100,15 +114,19 @@ class Queue extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRemoveSelectedPress = () => {
|
onRemoveSelectedPress = () => {
|
||||||
this.setState({ isConfirmRemoveModalOpen: true });
|
this.setState({ isConfirmRemoveModalOpen: true }, () => {
|
||||||
|
this._shouldBlockRefresh = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveSelectedConfirmed = (payload) => {
|
onRemoveSelectedConfirmed = (payload) => {
|
||||||
|
this._shouldBlockRefresh = false;
|
||||||
this.props.onRemoveSelectedPress({ ids: this.getSelectedIds(), ...payload });
|
this.props.onRemoveSelectedPress({ ids: this.getSelectedIds(), ...payload });
|
||||||
this.setState({ isConfirmRemoveModalOpen: false });
|
this.setState({ isConfirmRemoveModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onConfirmRemoveModalClose = () => {
|
onConfirmRemoveModalClose = () => {
|
||||||
|
this._shouldBlockRefresh = false;
|
||||||
this.setState({ isConfirmRemoveModalOpen: false });
|
this.setState({ isConfirmRemoveModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +226,7 @@ class Queue extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isPopulated && !hasError && !items.length &&
|
isAllPopulated && !hasError && !items.length &&
|
||||||
<div>
|
<div>
|
||||||
{translate('QueueIsEmpty')}
|
{translate('QueueIsEmpty')}
|
||||||
</div>
|
</div>
|
||||||
@@ -237,6 +255,7 @@ class Queue extends Component {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
{...item}
|
{...item}
|
||||||
onSelectedChange={this.onSelectedChange}
|
onSelectedChange={this.onSelectedChange}
|
||||||
|
onQueueRowModalOpenOrClose={this.onQueueRowModalOpenOrClose}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class QueueConnector extends Component {
|
|||||||
const {
|
const {
|
||||||
useCurrentPage,
|
useCurrentPage,
|
||||||
fetchQueue,
|
fetchQueue,
|
||||||
|
fetchQueueStatus,
|
||||||
gotoQueueFirstPage
|
gotoQueueFirstPage
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -53,6 +54,8 @@ class QueueConnector extends Component {
|
|||||||
} else {
|
} else {
|
||||||
gotoQueueFirstPage();
|
gotoQueueFirstPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchQueueStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
@@ -152,6 +155,7 @@ QueueConnector.propTypes = {
|
|||||||
useCurrentPage: PropTypes.bool.isRequired,
|
useCurrentPage: PropTypes.bool.isRequired,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
fetchQueue: PropTypes.func.isRequired,
|
fetchQueue: PropTypes.func.isRequired,
|
||||||
|
fetchQueueStatus: PropTypes.func.isRequired,
|
||||||
gotoQueueFirstPage: PropTypes.func.isRequired,
|
gotoQueueFirstPage: PropTypes.func.isRequired,
|
||||||
gotoQueuePreviousPage: PropTypes.func.isRequired,
|
gotoQueuePreviousPage: PropTypes.func.isRequired,
|
||||||
gotoQueueNextPage: PropTypes.func.isRequired,
|
gotoQueueNextPage: PropTypes.func.isRequired,
|
||||||
|
|||||||
@@ -43,19 +43,32 @@ class QueueRow extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRemoveQueueItemModalConfirmed = (blacklist) => {
|
onRemoveQueueItemModalConfirmed = (blacklist) => {
|
||||||
this.props.onRemoveQueueItemPress(blacklist);
|
const {
|
||||||
|
onRemoveQueueItemPress,
|
||||||
|
onQueueRowModalOpenOrClose
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
onQueueRowModalOpenOrClose(false);
|
||||||
|
onRemoveQueueItemPress(blacklist);
|
||||||
|
|
||||||
this.setState({ isRemoveQueueItemModalOpen: false });
|
this.setState({ isRemoveQueueItemModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveQueueItemModalClose = () => {
|
onRemoveQueueItemModalClose = () => {
|
||||||
|
this.props.onQueueRowModalOpenOrClose(false);
|
||||||
|
|
||||||
this.setState({ isRemoveQueueItemModalOpen: false });
|
this.setState({ isRemoveQueueItemModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onInteractiveImportPress = () => {
|
onInteractiveImportPress = () => {
|
||||||
|
this.props.onQueueRowModalOpenOrClose(true);
|
||||||
|
|
||||||
this.setState({ isInteractiveImportModalOpen: true });
|
this.setState({ isInteractiveImportModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onInteractiveImportModalClose = () => {
|
onInteractiveImportModalClose = () => {
|
||||||
|
this.props.onQueueRowModalOpenOrClose(false);
|
||||||
|
|
||||||
this.setState({ isInteractiveImportModalOpen: false });
|
this.setState({ isInteractiveImportModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +372,8 @@ QueueRow.propTypes = {
|
|||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
onSelectedChange: PropTypes.func.isRequired,
|
onSelectedChange: PropTypes.func.isRequired,
|
||||||
onGrabPress: PropTypes.func.isRequired,
|
onGrabPress: PropTypes.func.isRequired,
|
||||||
onRemoveQueueItemPress: PropTypes.func.isRequired
|
onRemoveQueueItemPress: PropTypes.func.isRequired,
|
||||||
|
onQueueRowModalOpenOrClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
QueueRow.defaultProps = {
|
QueueRow.defaultProps = {
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ class AddNewMovie extends Component {
|
|||||||
const {
|
const {
|
||||||
error,
|
error,
|
||||||
items,
|
items,
|
||||||
hasExistingMovies
|
hasExistingMovies,
|
||||||
|
colorImpairedMode
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const term = this.state.term;
|
const term = this.state.term;
|
||||||
@@ -141,6 +142,7 @@ class AddNewMovie extends Component {
|
|||||||
return (
|
return (
|
||||||
<AddNewMovieSearchResultConnector
|
<AddNewMovieSearchResultConnector
|
||||||
key={item.tmdbId}
|
key={item.tmdbId}
|
||||||
|
colorImpairedMode={colorImpairedMode}
|
||||||
{...item}
|
{...item}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -213,7 +215,8 @@ AddNewMovie.propTypes = {
|
|||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
hasExistingMovies: PropTypes.bool.isRequired,
|
hasExistingMovies: PropTypes.bool.isRequired,
|
||||||
onMovieLookupChange: PropTypes.func.isRequired,
|
onMovieLookupChange: PropTypes.func.isRequired,
|
||||||
onClearMovieLookup: PropTypes.func.isRequired
|
onClearMovieLookup: PropTypes.func.isRequired,
|
||||||
|
colorImpairedMode: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddNewMovie;
|
export default AddNewMovie;
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import React, { Component } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { clearAddMovie, lookupMovie } from 'Store/Actions/addMovieActions';
|
import { clearAddMovie, lookupMovie } from 'Store/Actions/addMovieActions';
|
||||||
|
import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions';
|
||||||
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
||||||
import { fetchImportExclusions } from 'Store/Actions/Settings/importExclusions';
|
import { fetchImportExclusions } from 'Store/Actions/Settings/importExclusions';
|
||||||
|
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||||
import parseUrl from 'Utilities/String/parseUrl';
|
import parseUrl from 'Utilities/String/parseUrl';
|
||||||
import AddNewMovie from './AddNewMovie';
|
import AddNewMovie from './AddNewMovie';
|
||||||
|
|
||||||
@@ -13,13 +15,15 @@ function createMapStateToProps() {
|
|||||||
(state) => state.addMovie,
|
(state) => state.addMovie,
|
||||||
(state) => state.movies.items.length,
|
(state) => state.movies.items.length,
|
||||||
(state) => state.router.location,
|
(state) => state.router.location,
|
||||||
(addMovie, existingMoviesCount, location) => {
|
createUISettingsSelector(),
|
||||||
|
(addMovie, existingMoviesCount, location, uiSettings) => {
|
||||||
const { params } = parseUrl(location.search);
|
const { params } = parseUrl(location.search);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...addMovie,
|
...addMovie,
|
||||||
term: params.term,
|
term: params.term,
|
||||||
hasExistingMovies: existingMoviesCount > 0
|
hasExistingMovies: existingMoviesCount > 0,
|
||||||
|
colorImpairedMode: uiSettings.enableColorImpairedMode
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -29,7 +33,9 @@ const mapDispatchToProps = {
|
|||||||
lookupMovie,
|
lookupMovie,
|
||||||
clearAddMovie,
|
clearAddMovie,
|
||||||
fetchRootFolders,
|
fetchRootFolders,
|
||||||
fetchImportExclusions
|
fetchImportExclusions,
|
||||||
|
fetchQueueDetails,
|
||||||
|
clearQueueDetails
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddNewMovieConnector extends Component {
|
class AddNewMovieConnector extends Component {
|
||||||
@@ -46,6 +52,7 @@ class AddNewMovieConnector extends Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchRootFolders();
|
this.props.fetchRootFolders();
|
||||||
this.props.fetchImportExclusions();
|
this.props.fetchImportExclusions();
|
||||||
|
this.props.fetchQueueDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@@ -54,6 +61,7 @@ class AddNewMovieConnector extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.props.clearAddMovie();
|
this.props.clearAddMovie();
|
||||||
|
this.props.clearQueueDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -102,7 +110,9 @@ AddNewMovieConnector.propTypes = {
|
|||||||
lookupMovie: PropTypes.func.isRequired,
|
lookupMovie: PropTypes.func.isRequired,
|
||||||
clearAddMovie: PropTypes.func.isRequired,
|
clearAddMovie: PropTypes.func.isRequired,
|
||||||
fetchRootFolders: PropTypes.func.isRequired,
|
fetchRootFolders: PropTypes.func.isRequired,
|
||||||
fetchImportExclusions: PropTypes.func.isRequired
|
fetchImportExclusions: PropTypes.func.isRequired,
|
||||||
|
fetchQueueDetails: PropTypes.func.isRequired,
|
||||||
|
clearQueueDetails: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewMovieConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewMovieConnector);
|
||||||
|
|||||||
@@ -17,30 +17,15 @@ import styles from './AddNewMovieModalContent.css';
|
|||||||
|
|
||||||
class AddNewMovieModalContent extends Component {
|
class AddNewMovieModalContent extends Component {
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
searchForMovie: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onSearchForMissingMovieChange = ({ value }) => {
|
|
||||||
this.setState({ searchForMovie: value });
|
|
||||||
}
|
|
||||||
|
|
||||||
onQualityProfileIdChange = ({ value }) => {
|
onQualityProfileIdChange = ({ value }) => {
|
||||||
this.props.onInputChange({ name: 'qualityProfileId', value: parseInt(value) });
|
this.props.onInputChange({ name: 'qualityProfileId', value: parseInt(value) });
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddMoviePress = () => {
|
onAddMoviePress = () => {
|
||||||
this.props.onAddMoviePress(this.state.searchForMovie);
|
this.props.onAddMoviePress();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -57,6 +42,7 @@ class AddNewMovieModalContent extends Component {
|
|||||||
monitor,
|
monitor,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
minimumAvailability,
|
minimumAvailability,
|
||||||
|
searchForMovie,
|
||||||
folder,
|
folder,
|
||||||
tags,
|
tags,
|
||||||
isSmallScreen,
|
isSmallScreen,
|
||||||
@@ -175,8 +161,8 @@ class AddNewMovieModalContent extends Component {
|
|||||||
containerClassName={styles.searchForMissingMovieContainer}
|
containerClassName={styles.searchForMissingMovieContainer}
|
||||||
className={styles.searchForMissingMovieInput}
|
className={styles.searchForMissingMovieInput}
|
||||||
name="searchForMovie"
|
name="searchForMovie"
|
||||||
value={this.state.searchForMovie}
|
onChange={onInputChange}
|
||||||
onChange={this.onSearchForMissingMovieChange}
|
{...searchForMovie}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -205,6 +191,7 @@ AddNewMovieModalContent.propTypes = {
|
|||||||
monitor: PropTypes.object.isRequired,
|
monitor: PropTypes.object.isRequired,
|
||||||
qualityProfileId: PropTypes.object,
|
qualityProfileId: PropTypes.object,
|
||||||
minimumAvailability: PropTypes.object.isRequired,
|
minimumAvailability: PropTypes.object.isRequired,
|
||||||
|
searchForMovie: PropTypes.object.isRequired,
|
||||||
folder: PropTypes.string.isRequired,
|
folder: PropTypes.string.isRequired,
|
||||||
tags: PropTypes.object.isRequired,
|
tags: PropTypes.object.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
|
|||||||
@@ -53,13 +53,14 @@ class AddNewMovieModalContentConnector extends Component {
|
|||||||
this.props.setAddMovieDefault({ [name]: value });
|
this.props.setAddMovieDefault({ [name]: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddMoviePress = (searchForMovie) => {
|
onAddMoviePress = () => {
|
||||||
const {
|
const {
|
||||||
tmdbId,
|
tmdbId,
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
monitor,
|
monitor,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
minimumAvailability,
|
minimumAvailability,
|
||||||
|
searchForMovie,
|
||||||
tags
|
tags
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -69,8 +70,8 @@ class AddNewMovieModalContentConnector extends Component {
|
|||||||
monitor: monitor.value,
|
monitor: monitor.value,
|
||||||
qualityProfileId: qualityProfileId.value,
|
qualityProfileId: qualityProfileId.value,
|
||||||
minimumAvailability: minimumAvailability.value,
|
minimumAvailability: minimumAvailability.value,
|
||||||
tags: tags.value,
|
searchForMovie: searchForMovie.value,
|
||||||
searchForMovie
|
tags: tags.value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +95,7 @@ AddNewMovieModalContentConnector.propTypes = {
|
|||||||
monitor: PropTypes.object.isRequired,
|
monitor: PropTypes.object.isRequired,
|
||||||
qualityProfileId: PropTypes.object,
|
qualityProfileId: PropTypes.object,
|
||||||
minimumAvailability: PropTypes.object.isRequired,
|
minimumAvailability: PropTypes.object.isRequired,
|
||||||
|
searchForMovie: PropTypes.object.isRequired,
|
||||||
tags: PropTypes.object.isRequired,
|
tags: PropTypes.object.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
setAddMovieDefault: PropTypes.func.isRequired,
|
setAddMovieDefault: PropTypes.func.isRequired,
|
||||||
|
|||||||
@@ -27,9 +27,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.poster {
|
.poster {
|
||||||
flex: 0 0 170px;
|
position: relative;
|
||||||
|
display: block;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
|
background-color: $defaultColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -86,6 +88,28 @@
|
|||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.posterContainer {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certification {
|
||||||
|
margin-left: 2px;
|
||||||
|
padding: 0 5px;
|
||||||
|
border: 1px solid;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.runtime {
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusContainer {
|
||||||
|
margin-right: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointMedium) {
|
||||||
.titleRow {
|
.titleRow {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ import Link from 'Components/Link/Link';
|
|||||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||||
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
|
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
|
||||||
import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks';
|
import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks';
|
||||||
|
import MovieStatusLabel from 'Movie/Details/MovieStatusLabel';
|
||||||
|
import MovieIndexProgressBar from 'Movie/Index/ProgressBar/MovieIndexProgressBar';
|
||||||
import MoviePoster from 'Movie/MoviePoster';
|
import MoviePoster from 'Movie/MoviePoster';
|
||||||
|
import formatRuntime from 'Utilities/Date/formatRuntime';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import AddNewMovieModal from './AddNewMovieModal';
|
import AddNewMovieModal from './AddNewMovieModal';
|
||||||
import styles from './AddNewMovieSearchResult.css';
|
import styles from './AddNewMovieSearchResult.css';
|
||||||
@@ -65,7 +68,17 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
images,
|
images,
|
||||||
isExistingMovie,
|
isExistingMovie,
|
||||||
isExclusionMovie,
|
isExclusionMovie,
|
||||||
isSmallScreen
|
isSmallScreen,
|
||||||
|
colorImpairedMode,
|
||||||
|
id,
|
||||||
|
monitored,
|
||||||
|
hasFile,
|
||||||
|
isAvailable,
|
||||||
|
queueStatus,
|
||||||
|
queueState,
|
||||||
|
runtime,
|
||||||
|
movieRuntimeFormat,
|
||||||
|
certification
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -85,12 +98,30 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
{
|
{
|
||||||
isSmallScreen ?
|
isSmallScreen ?
|
||||||
null :
|
null :
|
||||||
<MoviePoster
|
<div>
|
||||||
className={styles.poster}
|
<div className={styles.posterContainer}>
|
||||||
images={images}
|
<MoviePoster
|
||||||
size={250}
|
className={styles.poster}
|
||||||
overflow={true}
|
images={images}
|
||||||
/>
|
size={250}
|
||||||
|
overflow={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
isExistingMovie &&
|
||||||
|
<MovieIndexProgressBar
|
||||||
|
monitored={monitored}
|
||||||
|
hasFile={hasFile}
|
||||||
|
status={status}
|
||||||
|
posterWidth={167}
|
||||||
|
detailedProgressBar={true}
|
||||||
|
queueStatus={queueStatus}
|
||||||
|
queueState={queueState}
|
||||||
|
isAvailable={isAvailable}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
@@ -133,6 +164,22 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
!!certification &&
|
||||||
|
<span className={styles.certification}>
|
||||||
|
{certification}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
!!runtime &&
|
||||||
|
<span className={styles.runtime}>
|
||||||
|
{formatRuntime(runtime, movieRuntimeFormat)}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label size={sizes.LARGE}>
|
<Label size={sizes.LARGE}>
|
||||||
<HeartRating
|
<HeartRating
|
||||||
@@ -176,13 +223,15 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{
|
{
|
||||||
status === 'ended' &&
|
isExistingMovie && isSmallScreen &&
|
||||||
<Label
|
<MovieStatusLabel
|
||||||
kind={kinds.DANGER}
|
hasMovieFiles={hasFile}
|
||||||
size={sizes.LARGE}
|
monitored={monitored}
|
||||||
>
|
isAvailable={isAvailable}
|
||||||
Ended
|
id={id}
|
||||||
</Label>
|
useLabel={true}
|
||||||
|
colorImpairedMode={colorImpairedMode}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -222,7 +271,18 @@ AddNewMovieSearchResult.propTypes = {
|
|||||||
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
isExistingMovie: PropTypes.bool.isRequired,
|
isExistingMovie: PropTypes.bool.isRequired,
|
||||||
isExclusionMovie: PropTypes.bool.isRequired,
|
isExclusionMovie: PropTypes.bool.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
|
id: PropTypes.number,
|
||||||
|
queueItems: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
monitored: PropTypes.bool.isRequired,
|
||||||
|
hasFile: PropTypes.bool.isRequired,
|
||||||
|
isAvailable: PropTypes.bool.isRequired,
|
||||||
|
colorImpairedMode: PropTypes.bool,
|
||||||
|
queueStatus: PropTypes.string,
|
||||||
|
queueState: PropTypes.string,
|
||||||
|
runtime: PropTypes.number.isRequired,
|
||||||
|
movieRuntimeFormat: PropTypes.string.isRequired,
|
||||||
|
certification: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddNewMovieSearchResult;
|
export default AddNewMovieSearchResult;
|
||||||
|
|||||||
@@ -10,11 +10,17 @@ function createMapStateToProps() {
|
|||||||
createExistingMovieSelector(),
|
createExistingMovieSelector(),
|
||||||
createExclusionMovieSelector(),
|
createExclusionMovieSelector(),
|
||||||
createDimensionsSelector(),
|
createDimensionsSelector(),
|
||||||
(isExistingMovie, isExclusionMovie, dimensions) => {
|
(state) => state.queue.details.items,
|
||||||
|
(state, { internalId }) => internalId,
|
||||||
|
(isExistingMovie, isExclusionMovie, dimensions, queueItems, internalId) => {
|
||||||
|
const firstQueueItem = queueItems.find((q) => q.movieId === internalId && internalId > 0);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isExistingMovie,
|
isExistingMovie,
|
||||||
isExclusionMovie,
|
isExclusionMovie,
|
||||||
isSmallScreen: dimensions.isSmallScreen
|
isSmallScreen: dimensions.isSmallScreen,
|
||||||
|
queueStatus: firstQueueItem ? firstQueueItem.status : null,
|
||||||
|
queueState: firstQueueItem ? firstQueueItem.trackedDownloadState : null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ function ImportMovieHeader(props) {
|
|||||||
{translate('Folder')}
|
{translate('Folder')}
|
||||||
</VirtualTableHeaderCell>
|
</VirtualTableHeaderCell>
|
||||||
|
|
||||||
|
<VirtualTableHeaderCell
|
||||||
|
className={styles.movie}
|
||||||
|
name="movie"
|
||||||
|
>
|
||||||
|
{translate('Movie')}
|
||||||
|
</VirtualTableHeaderCell>
|
||||||
|
|
||||||
<VirtualTableHeaderCell
|
<VirtualTableHeaderCell
|
||||||
className={styles.monitor}
|
className={styles.monitor}
|
||||||
name="monitor"
|
name="monitor"
|
||||||
@@ -48,13 +55,6 @@ function ImportMovieHeader(props) {
|
|||||||
>
|
>
|
||||||
{translate('QualityProfile')}
|
{translate('QualityProfile')}
|
||||||
</VirtualTableHeaderCell>
|
</VirtualTableHeaderCell>
|
||||||
|
|
||||||
<VirtualTableHeaderCell
|
|
||||||
className={styles.movie}
|
|
||||||
name="movie"
|
|
||||||
>
|
|
||||||
{translate('Movie')}
|
|
||||||
</VirtualTableHeaderCell>
|
|
||||||
</VirtualTableHeader>
|
</VirtualTableHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,13 @@ function ImportMovieRow(props) {
|
|||||||
{id}
|
{id}
|
||||||
</VirtualTableRowCell>
|
</VirtualTableRowCell>
|
||||||
|
|
||||||
|
<VirtualTableRowCell className={styles.movie}>
|
||||||
|
<ImportMovieSelectMovieConnector
|
||||||
|
id={id}
|
||||||
|
isExistingMovie={isExistingMovie}
|
||||||
|
/>
|
||||||
|
</VirtualTableRowCell>
|
||||||
|
|
||||||
<VirtualTableRowCell className={styles.monitor}>
|
<VirtualTableRowCell className={styles.monitor}>
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.MOVIE_MONITORED_SELECT}
|
type={inputTypes.MOVIE_MONITORED_SELECT}
|
||||||
@@ -60,13 +67,6 @@ function ImportMovieRow(props) {
|
|||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
/>
|
/>
|
||||||
</VirtualTableRowCell>
|
</VirtualTableRowCell>
|
||||||
|
|
||||||
<VirtualTableRowCell className={styles.movie}>
|
|
||||||
<ImportMovieSelectMovieConnector
|
|
||||||
id={id}
|
|
||||||
isExistingMovie={isExistingMovie}
|
|
||||||
/>
|
|
||||||
</VirtualTableRowCell>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ class ImportMovieSelectFolder extends Component {
|
|||||||
<ul>
|
<ul>
|
||||||
<li className={styles.tip} dangerouslySetInnerHTML={{ __html: translate('ImportIncludeQuality', ['<code>movie.2008.bluray.mkv</code>']) }} />
|
<li className={styles.tip} dangerouslySetInnerHTML={{ __html: translate('ImportIncludeQuality', ['<code>movie.2008.bluray.mkv</code>']) }} />
|
||||||
<li className={styles.tip} dangerouslySetInnerHTML={{ __html: translate('ImportRootPath', [`<code>${isWindows ? 'C:\\movies' : '/movies'}</code>`, `<code>${isWindows ? 'C:\\movies\\the matrix' : '/movies/the matrix'}</code>`]) }} />
|
<li className={styles.tip} dangerouslySetInnerHTML={{ __html: translate('ImportRootPath', [`<code>${isWindows ? 'C:\\movies' : '/movies'}</code>`, `<code>${isWindows ? 'C:\\movies\\the matrix' : '/movies/the matrix'}</code>`]) }} />
|
||||||
|
<li className={styles.tip}>{translate('ImportNotForDownloads')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,47 @@ import UpdateChanges from 'System/Updates/UpdateChanges';
|
|||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './AppUpdatedModalContent.css';
|
import styles from './AppUpdatedModalContent.css';
|
||||||
|
|
||||||
|
function mergeUpdates(items, version, prevVersion) {
|
||||||
|
let installedIndex = items.findIndex((u) => u.version === version);
|
||||||
|
let installedPreviouslyIndex = items.findIndex((u) => u.version === prevVersion);
|
||||||
|
|
||||||
|
if (installedIndex === -1) {
|
||||||
|
installedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (installedPreviouslyIndex === -1) {
|
||||||
|
installedPreviouslyIndex = items.length;
|
||||||
|
} else if (installedPreviouslyIndex === installedIndex && items.length) {
|
||||||
|
installedPreviouslyIndex += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appliedUpdates = items.slice(installedIndex, installedPreviouslyIndex);
|
||||||
|
|
||||||
|
if (!appliedUpdates.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appliedChanges = { new: [], fixed: [] };
|
||||||
|
appliedUpdates.forEach((u) => {
|
||||||
|
if (u.changes) {
|
||||||
|
appliedChanges.new.push(... u.changes.new);
|
||||||
|
appliedChanges.fixed.push(... u.changes.fixed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mergedUpdate = Object.assign({}, appliedUpdates[0], { changes: appliedChanges });
|
||||||
|
|
||||||
|
if (!appliedChanges.new.length && !appliedChanges.fixed.length) {
|
||||||
|
mergedUpdate.changes = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergedUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
function AppUpdatedModalContent(props) {
|
function AppUpdatedModalContent(props) {
|
||||||
const {
|
const {
|
||||||
version,
|
version,
|
||||||
|
prevVersion,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
items,
|
items,
|
||||||
@@ -21,7 +59,7 @@ function AppUpdatedModalContent(props) {
|
|||||||
onModalClose
|
onModalClose
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const update = items[0];
|
const update = mergeUpdates(items, version, prevVersion);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalContent onModalClose={onModalClose}>
|
<ModalContent onModalClose={onModalClose}>
|
||||||
@@ -89,6 +127,7 @@ function AppUpdatedModalContent(props) {
|
|||||||
|
|
||||||
AppUpdatedModalContent.propTypes = {
|
AppUpdatedModalContent.propTypes = {
|
||||||
version: PropTypes.string.isRequired,
|
version: PropTypes.string.isRequired,
|
||||||
|
prevVersion: PropTypes.string,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ import AppUpdatedModalContent from './AppUpdatedModalContent';
|
|||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.app.version,
|
(state) => state.app.version,
|
||||||
|
(state) => state.app.prevVersion,
|
||||||
(state) => state.system.updates,
|
(state) => state.system.updates,
|
||||||
(version, updates) => {
|
(version, prevVersion, updates) => {
|
||||||
const {
|
const {
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
@@ -18,6 +19,7 @@ function createMapStateToProps() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
version,
|
version,
|
||||||
|
prevVersion,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
items
|
items
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.time {
|
.time {
|
||||||
flex: 0 0 120px;
|
flex: 0 0 125px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function createMissingMovieIdsSelector() {
|
|||||||
const inCinemas = movie.inCinemas;
|
const inCinemas = movie.inCinemas;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!movie.movieFileId &&
|
!movie.hasFile &&
|
||||||
moment(inCinemas).isAfter(start) &&
|
moment(inCinemas).isAfter(start) &&
|
||||||
moment(inCinemas).isBefore(end) &&
|
moment(inCinemas).isBefore(end) &&
|
||||||
isBefore(movie.inCinemas) &&
|
isBefore(movie.inCinemas) &&
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ function getUrls(state) {
|
|||||||
tags
|
tags
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
let icalUrl = `${window.location.host}${window.Radarr.urlBase}/feed/calendar/Radarr.ics?`;
|
let icalUrl = `${window.location.host}${window.Radarr.urlBase}/feed/v3/calendar/Radarr.ics?`;
|
||||||
|
|
||||||
if (unmonitored) {
|
if (unmonitored) {
|
||||||
icalUrl += 'unmonitored=true&';
|
icalUrl += 'unmonitored=true&';
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function createTagListSelector() {
|
|||||||
(selectedFilterBuilderProp.type === filterBuilderTypes.NUMBER ||
|
(selectedFilterBuilderProp.type === filterBuilderTypes.NUMBER ||
|
||||||
selectedFilterBuilderProp.type === filterBuilderTypes.STRING) &&
|
selectedFilterBuilderProp.type === filterBuilderTypes.STRING) &&
|
||||||
filterType !== filterTypes.EQUAL &&
|
filterType !== filterTypes.EQUAL &&
|
||||||
filterType !== filterBuilderTypes.NOT_EQUAL ||
|
filterType !== filterTypes.NOT_EQUAL ||
|
||||||
!selectedFilterBuilderProp.optionsSelector
|
!selectedFilterBuilderProp.optionsSelector
|
||||||
) {
|
) {
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -85,3 +85,21 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 5px -5px 5px 0;
|
margin: 5px -5px 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobileCloseButtonContainer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
height: 40px;
|
||||||
|
border-bottom: 1px solid $borderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobileCloseButton {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $modalCloseButtonHoverColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -479,6 +479,7 @@ class EnhancedSelectInput extends Component {
|
|||||||
<OptionComponent
|
<OptionComponent
|
||||||
key={v.key}
|
key={v.key}
|
||||||
id={v.key}
|
id={v.key}
|
||||||
|
dividerAfter={v.dividerAfter}
|
||||||
depth={depth}
|
depth={depth}
|
||||||
isSelected={isSelectedItem(index, this.props)}
|
isSelected={isSelectedItem(index, this.props)}
|
||||||
isDisabled={parentSelected}
|
isDisabled={parentSelected}
|
||||||
@@ -518,6 +519,18 @@ class EnhancedSelectInput extends Component {
|
|||||||
scrollDirection={scrollDirections.NONE}
|
scrollDirection={scrollDirections.NONE}
|
||||||
>
|
>
|
||||||
<Scroller className={styles.optionsModalScroller}>
|
<Scroller className={styles.optionsModalScroller}>
|
||||||
|
<div className={styles.mobileCloseButtonContainer}>
|
||||||
|
<Link
|
||||||
|
className={styles.mobileCloseButton}
|
||||||
|
onPress={this.onOptionsModalClose}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name={icons.CLOSE}
|
||||||
|
size={18}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
values.map((v, index) => {
|
values.map((v, index) => {
|
||||||
const hasParent = v.parentKey !== undefined;
|
const hasParent = v.parentKey !== undefined;
|
||||||
@@ -527,6 +540,7 @@ class EnhancedSelectInput extends Component {
|
|||||||
<OptionComponent
|
<OptionComponent
|
||||||
key={v.key}
|
key={v.key}
|
||||||
id={v.key}
|
id={v.key}
|
||||||
|
dividerAfter={v.dividerAfter}
|
||||||
depth={depth}
|
depth={depth}
|
||||||
isSelected={isSelectedItem(index, this.props)}
|
isSelected={isSelectedItem(index, this.props)}
|
||||||
isMultiSelect={isMultiSelect}
|
isMultiSelect={isMultiSelect}
|
||||||
|
|||||||
@@ -54,4 +54,8 @@
|
|||||||
&:last-child {
|
&:last-child {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ class EnhancedSelectInputOption extends Component {
|
|||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onPress = () => {
|
onPress = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
onSelect
|
onSelect
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
|
|||||||
import FormInputHelpText from './FormInputHelpText';
|
import FormInputHelpText from './FormInputHelpText';
|
||||||
import IndexerFlagsSelectInputConnector from './IndexerFlagsSelectInputConnector';
|
import IndexerFlagsSelectInputConnector from './IndexerFlagsSelectInputConnector';
|
||||||
import KeyValueListInput from './KeyValueListInput';
|
import KeyValueListInput from './KeyValueListInput';
|
||||||
|
import LanguageSelectInputConnector from './LanguageSelectInputConnector';
|
||||||
import MovieMonitoredSelectInput from './MovieMonitoredSelectInput';
|
import MovieMonitoredSelectInput from './MovieMonitoredSelectInput';
|
||||||
import NumberInput from './NumberInput';
|
import NumberInput from './NumberInput';
|
||||||
import OAuthInputConnector from './OAuthInputConnector';
|
import OAuthInputConnector from './OAuthInputConnector';
|
||||||
@@ -72,6 +73,9 @@ function getComponent(type) {
|
|||||||
case inputTypes.INDEXER_FLAGS_SELECT:
|
case inputTypes.INDEXER_FLAGS_SELECT:
|
||||||
return IndexerFlagsSelectInputConnector;
|
return IndexerFlagsSelectInputConnector;
|
||||||
|
|
||||||
|
case inputTypes.LANGUAGE_SELECT:
|
||||||
|
return LanguageSelectInputConnector;
|
||||||
|
|
||||||
case inputTypes.SELECT:
|
case inputTypes.SELECT:
|
||||||
return EnhancedSelectInput;
|
return EnhancedSelectInput;
|
||||||
|
|
||||||
|
|||||||
@@ -21,3 +21,8 @@
|
|||||||
color: $darkGray;
|
color: $darkGray;
|
||||||
font-size: $smallFontSize;
|
font-size: $smallFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid $lightGray;
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,37 +12,46 @@ function HintedSelectInputOption(props) {
|
|||||||
depth,
|
depth,
|
||||||
isSelected,
|
isSelected,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
|
dividerAfter,
|
||||||
isMultiSelect,
|
isMultiSelect,
|
||||||
isMobile,
|
isMobile,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EnhancedSelectInputOption
|
<div>
|
||||||
id={id}
|
<EnhancedSelectInputOption
|
||||||
depth={depth}
|
id={id}
|
||||||
isSelected={isSelected}
|
depth={depth}
|
||||||
isDisabled={isDisabled}
|
isSelected={isSelected}
|
||||||
isHidden={isDisabled}
|
isDisabled={isDisabled}
|
||||||
isMultiSelect={isMultiSelect}
|
isHidden={isDisabled}
|
||||||
isMobile={isMobile}
|
isMultiSelect={isMultiSelect}
|
||||||
{...otherProps}
|
isMobile={isMobile}
|
||||||
>
|
{...otherProps}
|
||||||
<div className={classNames(
|
|
||||||
styles.optionText,
|
|
||||||
isMobile && styles.isMobile
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<div>{value}</div>
|
<div className={classNames(
|
||||||
|
styles.optionText,
|
||||||
|
isMobile && styles.isMobile
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div>{value}</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
hint != null &&
|
hint != null &&
|
||||||
<div className={styles.hintText}>
|
<div className={styles.hintText}>
|
||||||
{hint}
|
{hint}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</EnhancedSelectInputOption>
|
</EnhancedSelectInputOption>
|
||||||
|
|
||||||
|
{
|
||||||
|
dividerAfter ?
|
||||||
|
<div className={styles.divider} /> :
|
||||||
|
null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,15 +59,18 @@ HintedSelectInputOption.propTypes = {
|
|||||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
hint: PropTypes.node,
|
hint: PropTypes.node,
|
||||||
|
name: PropTypes.string,
|
||||||
depth: PropTypes.number,
|
depth: PropTypes.number,
|
||||||
isSelected: PropTypes.bool.isRequired,
|
isSelected: PropTypes.bool.isRequired,
|
||||||
isDisabled: PropTypes.bool.isRequired,
|
isDisabled: PropTypes.bool.isRequired,
|
||||||
|
dividerAfter: PropTypes.bool.isRequired,
|
||||||
isMultiSelect: PropTypes.bool.isRequired,
|
isMultiSelect: PropTypes.bool.isRequired,
|
||||||
isMobile: PropTypes.bool.isRequired
|
isMobile: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
HintedSelectInputOption.defaultProps = {
|
HintedSelectInputOption.defaultProps = {
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
|
dividerAfter: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
isMultiSelect: false
|
isMultiSelect: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||||
|
|
||||||
|
function createMapStateToProps() {
|
||||||
|
return createSelector(
|
||||||
|
(state, { values }) => values,
|
||||||
|
( languages ) => {
|
||||||
|
|
||||||
|
const minId = languages.reduce((min, v) => (v.key < 1 ? v.key : min), languages[0].key);
|
||||||
|
|
||||||
|
const values = languages.map(({ key, value }) => {
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
dividerAfter: minId < 1 ? key === minId : false
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
values
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LanguageSelectInputConnector extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EnhancedSelectInput
|
||||||
|
{...this.props}
|
||||||
|
onChange={this.props.onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LanguageSelectInputConnector.propTypes = {
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
value: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]).isRequired,
|
||||||
|
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(createMapStateToProps)(LanguageSelectInputConnector);
|
||||||
@@ -49,6 +49,7 @@ function getSelectValues(selectOptions) {
|
|||||||
result.push({
|
result.push({
|
||||||
key: option.value,
|
key: option.value,
|
||||||
value: option.name,
|
value: option.name,
|
||||||
|
dividerAfter: option.dividerAfter,
|
||||||
hint: option.hint
|
hint: option.hint
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,16 @@ const ADD_NEW_KEY = 'addNew';
|
|||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.rootFolders,
|
(state) => state.rootFolders,
|
||||||
|
(state, { value }) => value,
|
||||||
|
(state, { includeMissingValue }) => includeMissingValue,
|
||||||
(state, { includeNoChange }) => includeNoChange,
|
(state, { includeNoChange }) => includeNoChange,
|
||||||
(rootFolders, includeNoChange) => {
|
(rootFolders, value, includeMissingValue, includeNoChange) => {
|
||||||
const values = rootFolders.items.map((rootFolder) => {
|
const values = rootFolders.items.map((rootFolder) => {
|
||||||
return {
|
return {
|
||||||
key: rootFolder.path,
|
key: rootFolder.path,
|
||||||
value: rootFolder.path,
|
value: rootFolder.path,
|
||||||
freeSpace: rootFolder.freeSpace
|
freeSpace: rootFolder.freeSpace,
|
||||||
|
isMissing: false
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -24,7 +27,8 @@ function createMapStateToProps() {
|
|||||||
values.unshift({
|
values.unshift({
|
||||||
key: 'noChange',
|
key: 'noChange',
|
||||||
value: 'No Change',
|
value: 'No Change',
|
||||||
isDisabled: true
|
isDisabled: true,
|
||||||
|
isMissing: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,6 +41,15 @@ function createMapStateToProps() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (includeMissingValue && !values.find((v) => v.key === value)) {
|
||||||
|
values.push({
|
||||||
|
key: value,
|
||||||
|
value,
|
||||||
|
isMissing: true,
|
||||||
|
isDisabled: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
values.push({
|
values.push({
|
||||||
key: ADD_NEW_KEY,
|
key: ADD_NEW_KEY,
|
||||||
value: 'Add a new path'
|
value: 'Add a new path'
|
||||||
@@ -151,7 +164,8 @@ RootFolderSelectInputConnector.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RootFolderSelectInputConnector.defaultProps = {
|
RootFolderSelectInputConnector.defaultProps = {
|
||||||
includeNoChange: false
|
includeNoChange: false,
|
||||||
|
value: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, createMapDispatchToProps)(RootFolderSelectInputConnector);
|
export default connect(createMapStateToProps, createMapDispatchToProps)(RootFolderSelectInputConnector);
|
||||||
|
|||||||
@@ -29,3 +29,9 @@
|
|||||||
color: $darkGray;
|
color: $darkGray;
|
||||||
font-size: $smallFontSize;
|
font-size: $smallFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.isMissing {
|
||||||
|
margin-left: 15px;
|
||||||
|
color: $dangerColor;
|
||||||
|
font-size: $smallFontSize;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ function RootFolderSelectInputOption(props) {
|
|||||||
id,
|
id,
|
||||||
value,
|
value,
|
||||||
freeSpace,
|
freeSpace,
|
||||||
|
isMissing,
|
||||||
movieFolder,
|
movieFolder,
|
||||||
isMobile,
|
isMobile,
|
||||||
isWindows,
|
isWindows,
|
||||||
@@ -43,11 +44,20 @@ function RootFolderSelectInputOption(props) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
freeSpace != null &&
|
freeSpace == null ?
|
||||||
|
null :
|
||||||
<div className={styles.freeSpace}>
|
<div className={styles.freeSpace}>
|
||||||
{formatBytes(freeSpace)} Free
|
{formatBytes(freeSpace)} Free
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
isMissing ?
|
||||||
|
<div className={styles.isMissing}>
|
||||||
|
Missing
|
||||||
|
</div> :
|
||||||
|
null
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</EnhancedSelectInputOption>
|
</EnhancedSelectInputOption>
|
||||||
);
|
);
|
||||||
@@ -58,6 +68,7 @@ RootFolderSelectInputOption.propTypes = {
|
|||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
freeSpace: PropTypes.number,
|
freeSpace: PropTypes.number,
|
||||||
movieFolder: PropTypes.string,
|
movieFolder: PropTypes.string,
|
||||||
|
isMissing: PropTypes.boolean,
|
||||||
isMobile: PropTypes.bool.isRequired,
|
isMobile: PropTypes.bool.isRequired,
|
||||||
isWindows: PropTypes.bool
|
isWindows: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,10 @@
|
|||||||
&.outline {
|
&.outline {
|
||||||
color: $dangerColor;
|
color: $dangerColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:global(.colorImpaired) {
|
||||||
|
background: repeating-linear-gradient(90deg, color($dangerColor shade(5%)), color($dangerColor shade(5%)) 5px, color($dangerColor shade(15%)) 5px, color($dangerColor shade(15%)) 10px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.default {
|
.default {
|
||||||
@@ -85,6 +89,10 @@
|
|||||||
&.outline {
|
&.outline {
|
||||||
color: $warningColor;
|
color: $warningColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:global(.colorImpaired) {
|
||||||
|
background: repeating-linear-gradient(45deg, $warningColor, $warningColor 5px, color($warningColor tint(15%)) 5px, color($warningColor tint(15%)) 10px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue {
|
.queue {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ function Label(props) {
|
|||||||
size,
|
size,
|
||||||
outline,
|
outline,
|
||||||
children,
|
children,
|
||||||
|
colorImpairedMode,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@@ -20,7 +21,8 @@ function Label(props) {
|
|||||||
className,
|
className,
|
||||||
styles[kind],
|
styles[kind],
|
||||||
styles[size],
|
styles[size],
|
||||||
outline && styles.outline
|
outline && styles.outline,
|
||||||
|
colorImpairedMode && 'colorImpaired'
|
||||||
)}
|
)}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
@@ -34,14 +36,16 @@ Label.propTypes = {
|
|||||||
kind: PropTypes.oneOf(kinds.all).isRequired,
|
kind: PropTypes.oneOf(kinds.all).isRequired,
|
||||||
size: PropTypes.oneOf(sizes.all).isRequired,
|
size: PropTypes.oneOf(sizes.all).isRequired,
|
||||||
outline: PropTypes.bool.isRequired,
|
outline: PropTypes.bool.isRequired,
|
||||||
children: PropTypes.node.isRequired
|
children: PropTypes.node.isRequired,
|
||||||
|
colorImpairedMode: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
Label.defaultProps = {
|
Label.defaultProps = {
|
||||||
className: styles.label,
|
className: styles.label,
|
||||||
kind: kinds.DEFAULT,
|
kind: kinds.DEFAULT,
|
||||||
size: sizes.SMALL,
|
size: sizes.SMALL,
|
||||||
outline: false
|
outline: false,
|
||||||
|
colorImpairedMode: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Label;
|
export default Label;
|
||||||
|
|||||||
@@ -38,24 +38,33 @@ class Link extends Component {
|
|||||||
const linkProps = { target };
|
const linkProps = { target };
|
||||||
let el = component;
|
let el = component;
|
||||||
|
|
||||||
if (to) {
|
if (to && typeof to === 'string') {
|
||||||
if ((/\w+?:\/\//).test(to)) {
|
if ((/\w+?:\/\//).test(to)) {
|
||||||
el = 'a';
|
el = 'a';
|
||||||
linkProps.href = to;
|
linkProps.href = to;
|
||||||
linkProps.target = target || '_blank';
|
linkProps.target = target || '_blank';
|
||||||
|
linkProps.rel = 'noreferrer';
|
||||||
} else if (noRouter) {
|
} else if (noRouter) {
|
||||||
el = 'a';
|
el = 'a';
|
||||||
linkProps.href = to;
|
linkProps.href = to;
|
||||||
linkProps.target = target || '_self';
|
linkProps.target = target || '_self';
|
||||||
} else if (to.startsWith(`${window.Radarr.urlBase}/`)) {
|
|
||||||
el = RouterLink;
|
|
||||||
linkProps.to = to;
|
|
||||||
linkProps.target = target;
|
|
||||||
} else {
|
} else {
|
||||||
el = RouterLink;
|
el = RouterLink;
|
||||||
linkProps.to = `${window.Radarr.urlBase}/${to.replace(/^\//, '')}`;
|
linkProps.to = `${window.Radarr.urlBase}/${to.replace(/^\//, '')}`;
|
||||||
linkProps.target = target;
|
linkProps.target = target;
|
||||||
}
|
}
|
||||||
|
} else if (to && typeof to === 'object') {
|
||||||
|
el = RouterLink;
|
||||||
|
linkProps.target = target;
|
||||||
|
if (to.pathname.startsWith(`${window.Radarr.urlBase}/`)) {
|
||||||
|
linkProps.to = to;
|
||||||
|
} else {
|
||||||
|
const pathname = `${window.Radarr.urlBase}/${to.pathname.replace(/^\//, '')}`;
|
||||||
|
linkProps.to = {
|
||||||
|
...to,
|
||||||
|
pathname
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el === 'button' || el === 'input') {
|
if (el === 'button' || el === 'input') {
|
||||||
@@ -86,7 +95,7 @@ class Link extends Component {
|
|||||||
Link.propTypes = {
|
Link.propTypes = {
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
to: PropTypes.string,
|
to: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||||
target: PropTypes.string,
|
target: PropTypes.string,
|
||||||
isDisabled: PropTypes.bool,
|
isDisabled: PropTypes.bool,
|
||||||
noRouter: PropTypes.bool,
|
noRouter: PropTypes.bool,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.loadingMessage {
|
.loadingMessage {
|
||||||
margin: 50px 10px 0;
|
margin: 10px 10px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const messages = [
|
|||||||
'Hum something loud while others stare',
|
'Hum something loud while others stare',
|
||||||
'Loading humorous message... Please Wait',
|
'Loading humorous message... Please Wait',
|
||||||
'I could\'ve been faster in Python',
|
'I could\'ve been faster in Python',
|
||||||
'Don\'t forget to rewind your tracks',
|
'Don\'t forget to rewind your movies',
|
||||||
'Congratulations! you are the 1000th visitor.',
|
'Congratulations! you are the 1000th visitor.',
|
||||||
'HELP! I\'m being held hostage and forced to write these stupid lines!',
|
'HELP! I\'m being held hostage and forced to write these stupid lines!',
|
||||||
'RE-calibrating the internet...',
|
'RE-calibrating the internet...',
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ function ConfirmModal(props) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
bindShortcut('enter', onConfirm);
|
bindShortcut('enter', onConfirm);
|
||||||
} else {
|
|
||||||
unbindShortcut('enter', onConfirm);
|
return () => unbindShortcut('enter', onConfirm);
|
||||||
}
|
}
|
||||||
}, [onConfirm]);
|
}, [isOpen, onConfirm]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -53,7 +53,13 @@ class PageHeader extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<div className={styles.logoContainer}>
|
<div className={styles.logoContainer}>
|
||||||
<Link to={`${window.Radarr.urlBase}/`}>
|
<Link
|
||||||
|
className={styles.logoLink}
|
||||||
|
to={{
|
||||||
|
pathname: '/',
|
||||||
|
state: { restoreScrollPosition: true }
|
||||||
|
}}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
className={isSmallScreen ? styles.logo : styles.logoFull}
|
className={isSmallScreen ? styles.logo : styles.logoFull}
|
||||||
src={isSmallScreen ? `${window.Radarr.urlBase}/Content/Images/logo.png` : `${window.Radarr.urlBase}/Content/Images/logo-full.png`}
|
src={isSmallScreen ? `${window.Radarr.urlBase}/Content/Images/logo.png` : `${window.Radarr.urlBase}/Content/Images/logo-full.png`}
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
.page {
|
.page {
|
||||||
composes: page from '~./Page.css';
|
composes: page from '~./Page.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logoFull {
|
||||||
|
margin-top: 50px;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
width: 120px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -30,7 +30,7 @@ const links = [
|
|||||||
to: '/add/new'
|
to: '/add/new'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: translate('Import'),
|
title: translate('ImportLibrary'),
|
||||||
to: '/add/import'
|
to: '/add/import'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import SpinnerIcon from 'Components/SpinnerIcon';
|
|||||||
import { forEach } from 'Helpers/elementChildren';
|
import { forEach } from 'Helpers/elementChildren';
|
||||||
import { align, icons } from 'Helpers/Props';
|
import { align, icons } from 'Helpers/Props';
|
||||||
import dimensions from 'Styles/Variables/dimensions';
|
import dimensions from 'Styles/Variables/dimensions';
|
||||||
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './PageToolbarSection.css';
|
import styles from './PageToolbarSection.css';
|
||||||
|
|
||||||
const BUTTON_WIDTH = parseInt(dimensions.toolbarButtonWidth);
|
const BUTTON_WIDTH = parseInt(dimensions.toolbarButtonWidth);
|
||||||
@@ -161,7 +162,7 @@ class PageToolbarSection extends Component {
|
|||||||
<ToolbarMenuButton
|
<ToolbarMenuButton
|
||||||
className={styles.overflowMenuButton}
|
className={styles.overflowMenuButton}
|
||||||
iconName={icons.OVERFLOW}
|
iconName={icons.OVERFLOW}
|
||||||
text="More"
|
text={translate('More')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MenuContent>
|
<MenuContent>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd-multi-backend';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import HTML5toTouch from 'react-dnd-multi-backend/dist/esm/HTML5toTouch';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
@@ -128,7 +128,7 @@ class TableOptionsModal extends Component {
|
|||||||
const isDraggingDown = isDragging && dropIndex > dragIndex;
|
const isDraggingDown = isDragging && dropIndex > dragIndex;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider options={HTML5toTouch}>
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ class VirtualTable extends Component {
|
|||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
width: 0
|
width: 0,
|
||||||
|
scrollRestored: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this._grid = null;
|
this._grid = null;
|
||||||
@@ -48,11 +49,13 @@ class VirtualTable extends Component {
|
|||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
scrollIndex
|
scrollIndex,
|
||||||
|
scrollTop
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
width
|
width,
|
||||||
|
scrollRestored
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
if (this._grid &&
|
if (this._grid &&
|
||||||
@@ -68,6 +71,11 @@ class VirtualTable extends Component {
|
|||||||
columnIndex: 0
|
columnIndex: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._grid && scrollTop !== undefined && scrollTop !== 0 && !scrollRestored) {
|
||||||
|
this.setState({ scrollRestored: true });
|
||||||
|
this._grid.scrollToPosition({ scrollTop });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -96,6 +104,7 @@ class VirtualTable extends Component {
|
|||||||
items,
|
items,
|
||||||
scroller,
|
scroller,
|
||||||
focusScroller,
|
focusScroller,
|
||||||
|
scrollTop: ignored,
|
||||||
header,
|
header,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
rowRenderer,
|
rowRenderer,
|
||||||
@@ -180,6 +189,7 @@ VirtualTable.propTypes = {
|
|||||||
className: PropTypes.string.isRequired,
|
className: PropTypes.string.isRequired,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
scrollIndex: PropTypes.number,
|
scrollIndex: PropTypes.number,
|
||||||
|
scrollTop: PropTypes.number,
|
||||||
scroller: PropTypes.instanceOf(Element).isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
focusScroller: PropTypes.bool.isRequired,
|
focusScroller: PropTypes.bool.isRequired,
|
||||||
header: PropTypes.node.isRequired,
|
header: PropTypes.node.isRequired,
|
||||||
|
|||||||
@@ -77,8 +77,10 @@ function keyboardShortcuts(WrappedComponent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unbindShortcut = (key) => {
|
unbindShortcut = (key) => {
|
||||||
delete this._mousetrapBindings[key];
|
if (this._mousetrap != null) {
|
||||||
this._mousetrap.unbind(key);
|
delete this._mousetrapBindings[key];
|
||||||
|
this._mousetrap.unbind(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unbindAllShortcuts = () => {
|
unbindAllShortcuts = () => {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ function withScrollPosition(WrappedComponent, scrollPositionKey) {
|
|||||||
history
|
history
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const scrollTop = history.action === 'POP' ?
|
const scrollTop = history.action === 'POP' || (history.location.state && history.location.state.restoreScrollPosition) ?
|
||||||
scrollPositions[scrollPositionKey] :
|
scrollPositions[scrollPositionKey] :
|
||||||
0;
|
0;
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
@@ -53,13 +53,14 @@ class AddNewDiscoverMovieModalContentConnector extends Component {
|
|||||||
this.props.setAddMovieDefault({ [name]: value });
|
this.props.setAddMovieDefault({ [name]: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddMoviePress = (searchForMovie) => {
|
onAddMoviePress = () => {
|
||||||
const {
|
const {
|
||||||
tmdbId,
|
tmdbId,
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
monitor,
|
monitor,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
minimumAvailability,
|
minimumAvailability,
|
||||||
|
searchForMovie,
|
||||||
tags
|
tags
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -69,8 +70,8 @@ class AddNewDiscoverMovieModalContentConnector extends Component {
|
|||||||
monitor: monitor.value,
|
monitor: monitor.value,
|
||||||
qualityProfileId: qualityProfileId.value,
|
qualityProfileId: qualityProfileId.value,
|
||||||
minimumAvailability: minimumAvailability.value,
|
minimumAvailability: minimumAvailability.value,
|
||||||
tags: tags.value,
|
searchForMovie: searchForMovie.value,
|
||||||
searchForMovie
|
tags: tags.value
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.onModalClose(true);
|
this.props.onModalClose(true);
|
||||||
@@ -96,6 +97,7 @@ AddNewDiscoverMovieModalContentConnector.propTypes = {
|
|||||||
monitor: PropTypes.object.isRequired,
|
monitor: PropTypes.object.isRequired,
|
||||||
qualityProfileId: PropTypes.object,
|
qualityProfileId: PropTypes.object,
|
||||||
minimumAvailability: PropTypes.object.isRequired,
|
minimumAvailability: PropTypes.object.isRequired,
|
||||||
|
searchForMovie: PropTypes.object.isRequired,
|
||||||
tags: PropTypes.object.isRequired,
|
tags: PropTypes.object.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
setAddMovieDefault: PropTypes.func.isRequired,
|
setAddMovieDefault: PropTypes.func.isRequired,
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ export const PAGE_LAST = fasFastForward;
|
|||||||
export const PARENT = fasLevelUpAlt;
|
export const PARENT = fasLevelUpAlt;
|
||||||
export const PAUSED = fasPause;
|
export const PAUSED = fasPause;
|
||||||
export const PENDING = farClock;
|
export const PENDING = farClock;
|
||||||
|
export const PLAY = fasPlay;
|
||||||
export const PROFILE = fasUser;
|
export const PROFILE = fasUser;
|
||||||
export const POSTER = fasTh;
|
export const POSTER = fasTh;
|
||||||
export const QUEUED = fasCloud;
|
export const QUEUED = fasCloud;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export const AVAILABILITY_SELECT = 'availabilitySelect';
|
|||||||
export const CAPTCHA = 'captcha';
|
export const CAPTCHA = 'captcha';
|
||||||
export const CHECK = 'check';
|
export const CHECK = 'check';
|
||||||
export const DEVICE = 'device';
|
export const DEVICE = 'device';
|
||||||
|
export const KEY_VALUE_LIST = 'keyValueList';
|
||||||
export const MOVIE_MONITORED_SELECT = 'movieMonitoredSelect';
|
export const MOVIE_MONITORED_SELECT = 'movieMonitoredSelect';
|
||||||
export const NUMBER = 'number';
|
export const NUMBER = 'number';
|
||||||
export const OAUTH = 'oauth';
|
export const OAUTH = 'oauth';
|
||||||
@@ -11,6 +12,7 @@ export const PATH = 'path';
|
|||||||
export const QUALITY_PROFILE_SELECT = 'qualityProfileSelect';
|
export const QUALITY_PROFILE_SELECT = 'qualityProfileSelect';
|
||||||
export const ROOT_FOLDER_SELECT = 'rootFolderSelect';
|
export const ROOT_FOLDER_SELECT = 'rootFolderSelect';
|
||||||
export const INDEXER_FLAGS_SELECT = 'indexerFlagsSelect';
|
export const INDEXER_FLAGS_SELECT = 'indexerFlagsSelect';
|
||||||
|
export const LANGUAGE_SELECT = 'languageSelect';
|
||||||
export const SELECT = 'select';
|
export const SELECT = 'select';
|
||||||
export const DYNAMIC_SELECT = 'dynamicSelect';
|
export const DYNAMIC_SELECT = 'dynamicSelect';
|
||||||
export const TAG = 'tag';
|
export const TAG = 'tag';
|
||||||
@@ -26,6 +28,7 @@ export const all = [
|
|||||||
CAPTCHA,
|
CAPTCHA,
|
||||||
CHECK,
|
CHECK,
|
||||||
DEVICE,
|
DEVICE,
|
||||||
|
KEY_VALUE_LIST,
|
||||||
MOVIE_MONITORED_SELECT,
|
MOVIE_MONITORED_SELECT,
|
||||||
NUMBER,
|
NUMBER,
|
||||||
OAUTH,
|
OAUTH,
|
||||||
@@ -34,6 +37,7 @@ export const all = [
|
|||||||
QUALITY_PROFILE_SELECT,
|
QUALITY_PROFILE_SELECT,
|
||||||
ROOT_FOLDER_SELECT,
|
ROOT_FOLDER_SELECT,
|
||||||
INDEXER_FLAGS_SELECT,
|
INDEXER_FLAGS_SELECT,
|
||||||
|
LANGUAGE_SELECT,
|
||||||
SELECT,
|
SELECT,
|
||||||
DYNAMIC_SELECT,
|
DYNAMIC_SELECT,
|
||||||
TAG,
|
TAG,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export const DANGER = 'danger';
|
export const DANGER = 'danger';
|
||||||
export const DEFAULT = 'default';
|
export const DEFAULT = 'default';
|
||||||
|
export const DELETE = 'delete';
|
||||||
export const DISABLED = 'disabled';
|
export const DISABLED = 'disabled';
|
||||||
export const INFO = 'info';
|
export const INFO = 'info';
|
||||||
export const INVERSE = 'inverse';
|
export const INVERSE = 'inverse';
|
||||||
@@ -13,6 +14,7 @@ export const QUEUE = 'queue';
|
|||||||
export const all = [
|
export const all = [
|
||||||
DANGER,
|
DANGER,
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
|
DELETE,
|
||||||
DISABLED,
|
DISABLED,
|
||||||
INFO,
|
INFO,
|
||||||
INVERSE,
|
INVERSE,
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ class InteractiveImportModalContent extends Component {
|
|||||||
isPopulated && !!items.length && !isFetching && !isFetching &&
|
isPopulated && !!items.length && !isFetching && !isFetching &&
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
horizontalScroll={false}
|
horizontalScroll={true}
|
||||||
selectAll={true}
|
selectAll={true}
|
||||||
allSelected={allSelected}
|
allSelected={allSelected}
|
||||||
allUnselected={allUnselected}
|
allUnselected={allUnselected}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
||||||
import { fetchLanguages } from 'Store/Actions/settingsActions';
|
import { fetchLanguages } from 'Store/Actions/settingsActions';
|
||||||
import SelectLanguageModalContent from './SelectLanguageModalContent';
|
import SelectLanguageModalContent from './SelectLanguageModalContent';
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ function createMapStateToProps() {
|
|||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
dispatchFetchLanguages: fetchLanguages,
|
dispatchFetchLanguages: fetchLanguages,
|
||||||
|
dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems,
|
||||||
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems
|
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -51,6 +52,12 @@ class SelectLanguageModalContentConnector extends Component {
|
|||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onLanguageSelect = ({ languageIds }) => {
|
onLanguageSelect = ({ languageIds }) => {
|
||||||
|
const {
|
||||||
|
ids,
|
||||||
|
dispatchUpdateInteractiveImportItems,
|
||||||
|
dispatchReprocessInteractiveImportItems
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
const languages = [];
|
const languages = [];
|
||||||
|
|
||||||
languageIds.forEach((languageId) => {
|
languageIds.forEach((languageId) => {
|
||||||
@@ -62,11 +69,13 @@ class SelectLanguageModalContentConnector extends Component {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.dispatchUpdateInteractiveImportItems({
|
dispatchUpdateInteractiveImportItems({
|
||||||
ids: this.props.ids,
|
ids,
|
||||||
languages
|
languages
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dispatchReprocessInteractiveImportItems({ ids });
|
||||||
|
|
||||||
this.props.onModalClose(true);
|
this.props.onModalClose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +100,7 @@ SelectLanguageModalContentConnector.propTypes = {
|
|||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
dispatchFetchLanguages: PropTypes.func.isRequired,
|
dispatchFetchLanguages: PropTypes.func.isRequired,
|
||||||
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
|
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
|
||||||
|
dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
||||||
import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
||||||
import getQualities from 'Utilities/Quality/getQualities';
|
import getQualities from 'Utilities/Quality/getQualities';
|
||||||
import SelectQualityModalContent from './SelectQualityModalContent';
|
import SelectQualityModalContent from './SelectQualityModalContent';
|
||||||
@@ -31,6 +31,7 @@ function createMapStateToProps() {
|
|||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
dispatchFetchQualityProfileSchema: fetchQualityProfileSchema,
|
dispatchFetchQualityProfileSchema: fetchQualityProfileSchema,
|
||||||
|
dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems,
|
||||||
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems
|
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,6 +50,12 @@ class SelectQualityModalContentConnector extends Component {
|
|||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onQualitySelect = ({ qualityId, proper, real }) => {
|
onQualitySelect = ({ qualityId, proper, real }) => {
|
||||||
|
const {
|
||||||
|
ids,
|
||||||
|
dispatchUpdateInteractiveImportItems,
|
||||||
|
dispatchReprocessInteractiveImportItems
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
const quality = _.find(this.props.items,
|
const quality = _.find(this.props.items,
|
||||||
(item) => item.id === qualityId);
|
(item) => item.id === qualityId);
|
||||||
|
|
||||||
@@ -57,14 +64,16 @@ class SelectQualityModalContentConnector extends Component {
|
|||||||
real: real ? 1 : 0
|
real: real ? 1 : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
this.props.dispatchUpdateInteractiveImportItems({
|
dispatchUpdateInteractiveImportItems({
|
||||||
ids: this.props.ids,
|
ids,
|
||||||
quality: {
|
quality: {
|
||||||
quality,
|
quality,
|
||||||
revision
|
revision
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dispatchReprocessInteractiveImportItems({ ids });
|
||||||
|
|
||||||
this.props.onModalClose(true);
|
this.props.onModalClose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +97,7 @@ SelectQualityModalContentConnector.propTypes = {
|
|||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
dispatchFetchQualityProfileSchema: PropTypes.func.isRequired,
|
dispatchFetchQualityProfileSchema: PropTypes.func.isRequired,
|
||||||
|
dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired,
|
||||||
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
|
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,6 +22,20 @@ const columns = [
|
|||||||
isSortable: true,
|
isSortable: true,
|
||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'releaseWeight',
|
||||||
|
label: React.createElement(Icon, { name: icons.DOWNLOAD }),
|
||||||
|
isSortable: true,
|
||||||
|
fixedSortDirection: sortDirections.ASCENDING,
|
||||||
|
isVisible: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejections',
|
||||||
|
label: React.createElement(Icon, { name: icons.DANGER }),
|
||||||
|
isSortable: true,
|
||||||
|
fixedSortDirection: sortDirections.ASCENDING,
|
||||||
|
isVisible: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'title',
|
name: 'title',
|
||||||
label: translate('Title'),
|
label: translate('Title'),
|
||||||
@@ -85,20 +99,6 @@ const columns = [
|
|||||||
label: React.createElement(Icon, { name: icons.FLAG }),
|
label: React.createElement(Icon, { name: icons.FLAG }),
|
||||||
isSortable: true,
|
isSortable: true,
|
||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'rejections',
|
|
||||||
label: React.createElement(Icon, { name: icons.DANGER }),
|
|
||||||
isSortable: true,
|
|
||||||
fixedSortDirection: sortDirections.ASCENDING,
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'releaseWeight',
|
|
||||||
label: React.createElement(Icon, { name: icons.DOWNLOAD }),
|
|
||||||
isSortable: true,
|
|
||||||
fixedSortDirection: sortDirections.ASCENDING,
|
|
||||||
isVisible: true
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -55,12 +55,10 @@
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
composes: cell;
|
composes: cell;
|
||||||
|
|
||||||
max-width: 30vw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title div {
|
.title div {
|
||||||
@add-mixin truncate;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history {
|
.history {
|
||||||
|
|||||||
@@ -145,6 +145,46 @@ class InteractiveSearchRow extends Component {
|
|||||||
{formatAge(age, ageHours, ageMinutes)}
|
{formatAge(age, ageHours, ageMinutes)}
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
|
<TableRowCell className={styles.download}>
|
||||||
|
<SpinnerIconButton
|
||||||
|
name={getDownloadIcon(isGrabbing, isGrabbed, grabError)}
|
||||||
|
kind={grabError ? kinds.DANGER : kinds.DEFAULT}
|
||||||
|
title={getDownloadTooltip(isGrabbing, isGrabbed, grabError)}
|
||||||
|
isDisabled={isGrabbed}
|
||||||
|
isSpinning={isGrabbing}
|
||||||
|
onPress={downloadAllowed ? this.onGrabPress : this.onConfirmGrabPress}
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
|
||||||
|
<TableRowCell className={styles.rejected}>
|
||||||
|
{
|
||||||
|
!!rejections.length &&
|
||||||
|
<Popover
|
||||||
|
anchor={
|
||||||
|
<Icon
|
||||||
|
name={icons.DANGER}
|
||||||
|
kind={kinds.DANGER}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={translate('ReleaseRejected')}
|
||||||
|
body={
|
||||||
|
<ul>
|
||||||
|
{
|
||||||
|
rejections.map((rejection, index) => {
|
||||||
|
return (
|
||||||
|
<li key={index}>
|
||||||
|
{rejection}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
position={tooltipPositions.BOTTOM}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</TableRowCell>
|
||||||
|
|
||||||
<TableRowCell className={styles.title}>
|
<TableRowCell className={styles.title}>
|
||||||
<Link
|
<Link
|
||||||
to={infoUrl}
|
to={infoUrl}
|
||||||
@@ -252,51 +292,11 @@ class InteractiveSearchRow extends Component {
|
|||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
position={tooltipPositions.LEFT}
|
position={tooltipPositions.BOTTOM}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
<TableRowCell className={styles.rejected}>
|
|
||||||
{
|
|
||||||
!!rejections.length &&
|
|
||||||
<Popover
|
|
||||||
anchor={
|
|
||||||
<Icon
|
|
||||||
name={icons.DANGER}
|
|
||||||
kind={kinds.DANGER}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
title={translate('ReleaseRejected')}
|
|
||||||
body={
|
|
||||||
<ul>
|
|
||||||
{
|
|
||||||
rejections.map((rejection, index) => {
|
|
||||||
return (
|
|
||||||
<li key={index}>
|
|
||||||
{rejection}
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
position={tooltipPositions.LEFT}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</TableRowCell>
|
|
||||||
|
|
||||||
<TableRowCell className={styles.download}>
|
|
||||||
<SpinnerIconButton
|
|
||||||
name={getDownloadIcon(isGrabbing, isGrabbed, grabError)}
|
|
||||||
kind={grabError ? kinds.DANGER : kinds.DEFAULT}
|
|
||||||
title={getDownloadTooltip(isGrabbing, isGrabbed, grabError)}
|
|
||||||
isDisabled={isGrabbed}
|
|
||||||
isSpinning={isGrabbing}
|
|
||||||
onPress={downloadAllowed ? this.onGrabPress : this.onConfirmGrabPress}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
|
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
isOpen={this.state.isConfirmGrabModalOpen}
|
isOpen={this.state.isConfirmGrabModalOpen}
|
||||||
kind={kinds.WARNING}
|
kind={kinds.WARNING}
|
||||||
|
|||||||
@@ -54,22 +54,18 @@ class DeleteMovieModalContent extends Component {
|
|||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
path,
|
path,
|
||||||
statistics,
|
hasFile,
|
||||||
|
sizeOnDisk,
|
||||||
onModalClose
|
onModalClose
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
|
||||||
movieFileCount,
|
|
||||||
sizeOnDisk
|
|
||||||
} = statistics;
|
|
||||||
|
|
||||||
const deleteFiles = this.state.deleteFiles;
|
const deleteFiles = this.state.deleteFiles;
|
||||||
const addImportExclusion = this.state.addImportExclusion;
|
const addImportExclusion = this.state.addImportExclusion;
|
||||||
|
|
||||||
let deleteFilesLabel = translate('DeleteFilesLabel', [movieFileCount]);
|
let deleteFilesLabel = hasFile ? translate('DeleteFileLabel', [1]) : translate('DeleteFilesLabel', [0]);
|
||||||
let deleteFilesHelpText = translate('DeleteFilesHelpText');
|
let deleteFilesHelpText = translate('DeleteFilesHelpText');
|
||||||
|
|
||||||
if (movieFileCount === 0) {
|
if (!hasFile) {
|
||||||
deleteFilesLabel = translate('DeleteMovieFolderLabel');
|
deleteFilesLabel = translate('DeleteMovieFolderLabel');
|
||||||
deleteFilesHelpText = translate('DeleteMovieFolderHelpText');
|
deleteFilesHelpText = translate('DeleteMovieFolderHelpText');
|
||||||
}
|
}
|
||||||
@@ -92,6 +88,21 @@ class DeleteMovieModalContent extends Component {
|
|||||||
{path}
|
{path}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>
|
||||||
|
{translate('AddListExclusion')}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.CHECK}
|
||||||
|
name="addImportExclusion"
|
||||||
|
value={addImportExclusion}
|
||||||
|
helpText={translate('AddImportExclusionHelpText')}
|
||||||
|
kind={kinds.DANGER}
|
||||||
|
onChange={this.onAddImportExclusionChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>{deleteFilesLabel}</FormLabel>
|
<FormLabel>{deleteFilesLabel}</FormLabel>
|
||||||
|
|
||||||
@@ -113,29 +124,14 @@ class DeleteMovieModalContent extends Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
!!movieFileCount &&
|
!!hasFile &&
|
||||||
<div>
|
<div>
|
||||||
{movieFileCount} {translate('MovieFilesTotaling')} {formatBytes(sizeOnDisk)}
|
{hasFile} {translate('MovieFilesTotaling')} {formatBytes(sizeOnDisk)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<FormGroup>
|
|
||||||
<FormLabel>
|
|
||||||
{translate('AddListExclusion')}
|
|
||||||
</FormLabel>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.CHECK}
|
|
||||||
name="addImportExclusion"
|
|
||||||
value={addImportExclusion}
|
|
||||||
helpText={translate('AddImportExclusionHelpText')}
|
|
||||||
kind={kinds.DANGER}
|
|
||||||
onChange={this.onAddImportExclusionChange}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
@@ -158,15 +154,10 @@ class DeleteMovieModalContent extends Component {
|
|||||||
DeleteMovieModalContent.propTypes = {
|
DeleteMovieModalContent.propTypes = {
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
statistics: PropTypes.object.isRequired,
|
hasFile: PropTypes.bool.isRequired,
|
||||||
|
sizeOnDisk: PropTypes.string.isRequired,
|
||||||
onDeletePress: PropTypes.func.isRequired,
|
onDeletePress: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
DeleteMovieModalContent.defaultProps = {
|
|
||||||
statistics: {
|
|
||||||
movieFileCount: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DeleteMovieModalContent;
|
export default DeleteMovieModalContent;
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
|
||||||
import MovieCreditPosters from '../MovieCreditPosters';
|
import MovieCreditPosters from '../MovieCreditPosters';
|
||||||
import MovieCastPoster from './MovieCastPoster';
|
import MovieCastPoster from './MovieCastPoster';
|
||||||
|
|
||||||
@@ -26,19 +24,8 @@ function createMapStateToProps() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
fetchRootFolders
|
|
||||||
};
|
|
||||||
|
|
||||||
class MovieCastPostersConnector extends Component {
|
class MovieCastPostersConnector extends Component {
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.fetchRootFolders();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
@@ -53,8 +40,4 @@ class MovieCastPostersConnector extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MovieCastPostersConnector.propTypes = {
|
export default connect(createMapStateToProps)(MovieCastPostersConnector);
|
||||||
fetchRootFolders: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(MovieCastPostersConnector);
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
|
||||||
import MovieCreditPosters from '../MovieCreditPosters';
|
import MovieCreditPosters from '../MovieCreditPosters';
|
||||||
import MovieCrewPoster from './MovieCrewPoster';
|
import MovieCrewPoster from './MovieCrewPoster';
|
||||||
|
|
||||||
@@ -26,19 +24,8 @@ function createMapStateToProps() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
fetchRootFolders
|
|
||||||
};
|
|
||||||
|
|
||||||
class MovieCrewPostersConnector extends Component {
|
class MovieCrewPostersConnector extends Component {
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.fetchRootFolders();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
@@ -53,8 +40,4 @@ class MovieCrewPostersConnector extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MovieCrewPostersConnector.propTypes = {
|
export default connect(createMapStateToProps)(MovieCrewPostersConnector);
|
||||||
fetchRootFolders: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(MovieCrewPostersConnector);
|
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ class MovieDetails extends Component {
|
|||||||
onMonitorTogglePress,
|
onMonitorTogglePress,
|
||||||
onRefreshPress,
|
onRefreshPress,
|
||||||
onSearchPress,
|
onSearchPress,
|
||||||
queueDetails,
|
queueItems,
|
||||||
movieRuntimeFormat
|
movieRuntimeFormat
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -318,7 +318,6 @@ class MovieDetails extends Component {
|
|||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label={translate('SearchMovie')}
|
label={translate('SearchMovie')}
|
||||||
iconName={icons.SEARCH}
|
iconName={icons.SEARCH}
|
||||||
isDisabled={!monitored}
|
|
||||||
isSpinning={isSearching}
|
isSpinning={isSearching}
|
||||||
title={undefined}
|
title={undefined}
|
||||||
onPress={onSearchPress}
|
onPress={onSearchPress}
|
||||||
@@ -523,7 +522,7 @@ class MovieDetails extends Component {
|
|||||||
hasMovieFiles={hasMovieFiles}
|
hasMovieFiles={hasMovieFiles}
|
||||||
monitored={monitored}
|
monitored={monitored}
|
||||||
isAvailable={isAvailable}
|
isAvailable={isAvailable}
|
||||||
queueDetails={queueDetails}
|
queueItem={(queueItems.length > 0) ? queueItems[0] : null}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</InfoLabel>
|
</InfoLabel>
|
||||||
@@ -794,7 +793,7 @@ MovieDetails.propTypes = {
|
|||||||
onRefreshPress: PropTypes.func.isRequired,
|
onRefreshPress: PropTypes.func.isRequired,
|
||||||
onSearchPress: PropTypes.func.isRequired,
|
onSearchPress: PropTypes.func.isRequired,
|
||||||
onGoToMovie: PropTypes.func.isRequired,
|
onGoToMovie: PropTypes.func.isRequired,
|
||||||
queueDetails: PropTypes.object,
|
queueItems: PropTypes.arrayOf(PropTypes.object),
|
||||||
movieRuntimeFormat: PropTypes.string.isRequired
|
movieRuntimeFormat: PropTypes.string.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -89,10 +89,10 @@ function createMapStateToProps() {
|
|||||||
createAllMoviesSelector(),
|
createAllMoviesSelector(),
|
||||||
createCommandsSelector(),
|
createCommandsSelector(),
|
||||||
createDimensionsSelector(),
|
createDimensionsSelector(),
|
||||||
(state) => state.queue.details,
|
(state) => state.queue.details.items,
|
||||||
(state) => state.app.isSidebarVisible,
|
(state) => state.app.isSidebarVisible,
|
||||||
(state) => state.settings.ui.item.movieRuntimeFormat,
|
(state) => state.settings.ui.item.movieRuntimeFormat,
|
||||||
(titleSlug, movieFiles, movieCredits, extraFiles, allMovies, commands, dimensions, queueDetails, isSidebarVisible, movieRuntimeFormat) => {
|
(titleSlug, movieFiles, movieCredits, extraFiles, allMovies, commands, dimensions, queueItems, isSidebarVisible, movieRuntimeFormat) => {
|
||||||
const sortedMovies = _.orderBy(allMovies, 'sortTitle');
|
const sortedMovies = _.orderBy(allMovies, 'sortTitle');
|
||||||
const movieIndex = _.findIndex(sortedMovies, { titleSlug });
|
const movieIndex = _.findIndex(sortedMovies, { titleSlug });
|
||||||
const movie = sortedMovies[movieIndex];
|
const movie = sortedMovies[movieIndex];
|
||||||
@@ -165,7 +165,7 @@ function createMapStateToProps() {
|
|||||||
nextMovie,
|
nextMovie,
|
||||||
isSmallScreen: dimensions.isSmallScreen,
|
isSmallScreen: dimensions.isSmallScreen,
|
||||||
isSidebarVisible,
|
isSidebarVisible,
|
||||||
queueDetails,
|
queueItems,
|
||||||
movieRuntimeFormat
|
movieRuntimeFormat
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,19 @@ function MovieDetailsLinks(props) {
|
|||||||
</Label>
|
</Label>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
className={styles.link}
|
||||||
|
to={`https://letterboxd.com/tmdb/${tmdbId}`}
|
||||||
|
>
|
||||||
|
<Label
|
||||||
|
className={styles.linkLabel}
|
||||||
|
kind={kinds.INFO}
|
||||||
|
size={sizes.LARGE}
|
||||||
|
>
|
||||||
|
{translate('Letterboxd')}
|
||||||
|
</Label>
|
||||||
|
</Link>
|
||||||
|
|
||||||
{
|
{
|
||||||
!!imdbId &&
|
!!imdbId &&
|
||||||
<Link
|
<Link
|
||||||
@@ -61,7 +74,7 @@ function MovieDetailsLinks(props) {
|
|||||||
!!imdbId &&
|
!!imdbId &&
|
||||||
<Link
|
<Link
|
||||||
className={styles.link}
|
className={styles.link}
|
||||||
to={` https://moviechat.org/${imdbId}/`}
|
to={`https://moviechat.org/${imdbId}/`}
|
||||||
>
|
>
|
||||||
<Label
|
<Label
|
||||||
className={styles.linkLabel}
|
className={styles.linkLabel}
|
||||||
@@ -77,7 +90,7 @@ function MovieDetailsLinks(props) {
|
|||||||
!!youTubeTrailerId &&
|
!!youTubeTrailerId &&
|
||||||
<Link
|
<Link
|
||||||
className={styles.link}
|
className={styles.link}
|
||||||
to={` https://www.youtube.com/watch?v=${youTubeTrailerId}/`}
|
to={`https://www.youtube.com/watch?v=${youTubeTrailerId}/`}
|
||||||
>
|
>
|
||||||
<Label
|
<Label
|
||||||
className={styles.linkLabel}
|
className={styles.linkLabel}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
|||||||
import NotFound from 'Components/NotFound';
|
import NotFound from 'Components/NotFound';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
import PageContentBody from 'Components/Page/PageContentBody';
|
import PageContentBody from 'Components/Page/PageContentBody';
|
||||||
|
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
||||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import MovieDetailsConnector from './MovieDetailsConnector';
|
import MovieDetailsConnector from './MovieDetailsConnector';
|
||||||
@@ -46,7 +47,8 @@ function createMapStateToProps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
push
|
push,
|
||||||
|
fetchRootFolders
|
||||||
};
|
};
|
||||||
|
|
||||||
class MovieDetailsPageConnector extends Component {
|
class MovieDetailsPageConnector extends Component {
|
||||||
@@ -54,6 +56,10 @@ class MovieDetailsPageConnector extends Component {
|
|||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.fetchRootFolders();
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (!this.props.titleSlug) {
|
if (!this.props.titleSlug) {
|
||||||
this.props.push(`${window.Radarr.urlBase}/`);
|
this.props.push(`${window.Radarr.urlBase}/`);
|
||||||
@@ -112,7 +118,8 @@ MovieDetailsPageConnector.propTypes = {
|
|||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
match: PropTypes.shape({ params: PropTypes.shape({ titleSlug: PropTypes.string.isRequired }).isRequired }).isRequired,
|
match: PropTypes.shape({ params: PropTypes.shape({ titleSlug: PropTypes.string.isRequired }).isRequired }).isRequired,
|
||||||
push: PropTypes.func.isRequired
|
push: PropTypes.func.isRequired,
|
||||||
|
fetchRootFolders: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(MovieDetailsPageConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(MovieDetailsPageConnector);
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
.missing {
|
|
||||||
padding-left: 2px;
|
|
||||||
border-left: 4px solid $dangerColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.downloaded {
|
|
||||||
padding-left: 2px;
|
|
||||||
border-left: 4px solid $successColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notAvailable {
|
|
||||||
padding-left: 2px;
|
|
||||||
border-left: 4px solid $primaryColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unmonitored {
|
|
||||||
padding-left: 2px;
|
|
||||||
border-left: 4px solid $warningColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.queue {
|
.queue {
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
border-left: 4px solid $queueColor;
|
border-left: 4px solid $queueColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.continuing {
|
||||||
|
padding-left: 2px;
|
||||||
|
border-left: 4px solid $primaryColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.availNotMonitored {
|
||||||
|
padding-left: 2px;
|
||||||
|
border-left: 4px solid $darkGray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ended {
|
||||||
|
padding-left: 2px;
|
||||||
|
border-left: 4px solid $successColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.missingMonitored {
|
||||||
|
padding-left: 2px;
|
||||||
|
border-left: 4px solid $dangerColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.missingUnmonitored {
|
||||||
|
padding-left: 2px;
|
||||||
|
border-left: 4px solid $warningColor;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Label from 'Components/Label';
|
||||||
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
import getQueueStatusText from 'Utilities/Movie/getQueueStatusText';
|
import getQueueStatusText from 'Utilities/Movie/getQueueStatusText';
|
||||||
import firstCharToUpper from 'Utilities/String/firstCharToUpper';
|
import firstCharToUpper from 'Utilities/String/firstCharToUpper';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './MovieStatusLabel.css';
|
import styles from './MovieStatusLabel.css';
|
||||||
|
|
||||||
function getMovieStatus(hasFile, isMonitored, isAvailable, queueDetails = false) {
|
function getMovieStatus(hasFile, isMonitored, isAvailable, queueItem = false) {
|
||||||
|
|
||||||
if (queueDetails.items[0]) {
|
if (queueItem) {
|
||||||
const queueStatus = queueDetails.items[0].status;
|
const queueStatus = queueItem.status;
|
||||||
const queueState = queueDetails.items[0].trackedDownloadStatus;
|
const queueState = queueItem.trackedDownloadStatus;
|
||||||
const queueStatusText = getQueueStatusText(queueStatus, queueState);
|
const queueStatusText = getQueueStatusText(queueStatus, queueState);
|
||||||
|
|
||||||
if (queueStatusText) {
|
if (queueStatusText) {
|
||||||
@@ -17,19 +19,23 @@ function getMovieStatus(hasFile, isMonitored, isAvailable, queueDetails = false)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasFile) {
|
if (hasFile && !isMonitored) {
|
||||||
return 'downloaded';
|
return 'availNotMonitored';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isMonitored) {
|
if (hasFile) {
|
||||||
return 'unmonitored';
|
return 'ended';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAvailable && !isMonitored && !hasFile) {
|
||||||
|
return 'missingUnmonitored';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAvailable && !hasFile) {
|
if (isAvailable && !hasFile) {
|
||||||
return 'missing';
|
return 'missingMonitored';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'notAvailable';
|
return 'continuing';
|
||||||
}
|
}
|
||||||
|
|
||||||
function MovieStatusLabel(props) {
|
function MovieStatusLabel(props) {
|
||||||
@@ -37,16 +43,61 @@ function MovieStatusLabel(props) {
|
|||||||
hasMovieFiles,
|
hasMovieFiles,
|
||||||
monitored,
|
monitored,
|
||||||
isAvailable,
|
isAvailable,
|
||||||
queueDetails
|
queueItem,
|
||||||
|
useLabel,
|
||||||
|
colorImpairedMode
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const status = getMovieStatus(hasMovieFiles, monitored, isAvailable, queueDetails);
|
let status = getMovieStatus(hasMovieFiles, monitored, isAvailable, queueItem);
|
||||||
let statusClass = status;
|
let statusClass = status;
|
||||||
|
|
||||||
if (queueDetails.items.length) {
|
if (status === 'availNotMonitored' || status === 'ended') {
|
||||||
|
status = 'downloaded';
|
||||||
|
}
|
||||||
|
if (status === 'missingMonitored' || status === 'missingUnmonitored') {
|
||||||
|
status = 'missing';
|
||||||
|
}
|
||||||
|
if (status === 'continuing') {
|
||||||
|
status = 'notAvailable';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queueItem) {
|
||||||
statusClass = 'queue';
|
statusClass = 'queue';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useLabel) {
|
||||||
|
let kind = kinds.SUCCESS;
|
||||||
|
|
||||||
|
switch (statusClass) {
|
||||||
|
case 'queue':
|
||||||
|
kind = kinds.QUEUE;
|
||||||
|
break;
|
||||||
|
case 'missingMonitored':
|
||||||
|
kind = kinds.DANGER;
|
||||||
|
break;
|
||||||
|
case 'continuing':
|
||||||
|
kind = kinds.INFO;
|
||||||
|
break;
|
||||||
|
case 'availNotMonitored':
|
||||||
|
kind = kinds.DEFAULT;
|
||||||
|
break;
|
||||||
|
case 'missingUnmonitored':
|
||||||
|
kind = kinds.WARNING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Label
|
||||||
|
kind={kind}
|
||||||
|
size={sizes.LARGE}
|
||||||
|
colorImpairedMode={colorImpairedMode}
|
||||||
|
>
|
||||||
|
{translate(firstCharToUpper(status))}
|
||||||
|
</Label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={styles[statusClass]}
|
className={styles[statusClass]}
|
||||||
@@ -60,7 +111,9 @@ MovieStatusLabel.propTypes = {
|
|||||||
hasMovieFiles: PropTypes.bool.isRequired,
|
hasMovieFiles: PropTypes.bool.isRequired,
|
||||||
monitored: PropTypes.bool.isRequired,
|
monitored: PropTypes.bool.isRequired,
|
||||||
isAvailable: PropTypes.bool.isRequired,
|
isAvailable: PropTypes.bool.isRequired,
|
||||||
queueDetails: PropTypes.object
|
queueItem: PropTypes.object,
|
||||||
|
useLabel: PropTypes.bool,
|
||||||
|
colorImpairedMode: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
MovieStatusLabel.defaultProps = {
|
MovieStatusLabel.defaultProps = {
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ class MovieIndexOverviews extends Component {
|
|||||||
columnCount: 1,
|
columnCount: 1,
|
||||||
posterWidth: 162,
|
posterWidth: 162,
|
||||||
posterHeight: 238,
|
posterHeight: 238,
|
||||||
rowHeight: calculateRowHeight(238, null, props.isSmallScreen, {})
|
rowHeight: calculateRowHeight(238, null, props.isSmallScreen, {}),
|
||||||
|
scrollRestored: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this._grid = null;
|
this._grid = null;
|
||||||
@@ -72,13 +73,15 @@ class MovieIndexOverviews extends Component {
|
|||||||
sortKey,
|
sortKey,
|
||||||
overviewOptions,
|
overviewOptions,
|
||||||
jumpToCharacter,
|
jumpToCharacter,
|
||||||
|
scrollTop,
|
||||||
isMovieEditorActive,
|
isMovieEditorActive,
|
||||||
isSmallScreen
|
isSmallScreen
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
width,
|
width,
|
||||||
rowHeight
|
rowHeight,
|
||||||
|
scrollRestored
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
if (prevProps.sortKey !== sortKey ||
|
if (prevProps.sortKey !== sortKey ||
|
||||||
@@ -97,6 +100,11 @@ class MovieIndexOverviews extends Component {
|
|||||||
this._grid.recomputeGridSize();
|
this._grid.recomputeGridSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._grid && scrollTop !== 0 && !scrollRestored) {
|
||||||
|
this.setState({ scrollRestored: true });
|
||||||
|
this._grid.scrollToPosition({ scrollTop });
|
||||||
|
}
|
||||||
|
|
||||||
if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) {
|
if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) {
|
||||||
const index = getIndexOfFirstCharacter(items, jumpToCharacter);
|
const index = getIndexOfFirstCharacter(items, jumpToCharacter);
|
||||||
|
|
||||||
@@ -262,6 +270,7 @@ MovieIndexOverviews.propTypes = {
|
|||||||
sortKey: PropTypes.string,
|
sortKey: PropTypes.string,
|
||||||
overviewOptions: PropTypes.object.isRequired,
|
overviewOptions: PropTypes.object.isRequired,
|
||||||
jumpToCharacter: PropTypes.string,
|
jumpToCharacter: PropTypes.string,
|
||||||
|
scrollTop: PropTypes.number.isRequired,
|
||||||
scroller: PropTypes.instanceOf(Element).isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
showRelativeDates: PropTypes.bool.isRequired,
|
showRelativeDates: PropTypes.bool.isRequired,
|
||||||
shortDateFormat: PropTypes.string.isRequired,
|
shortDateFormat: PropTypes.string.isRequired,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks';
|
|||||||
import EditMovieModalConnector from 'Movie/Edit/EditMovieModalConnector';
|
import EditMovieModalConnector from 'Movie/Edit/EditMovieModalConnector';
|
||||||
import MovieIndexProgressBar from 'Movie/Index/ProgressBar/MovieIndexProgressBar';
|
import MovieIndexProgressBar from 'Movie/Index/ProgressBar/MovieIndexProgressBar';
|
||||||
import MoviePoster from 'Movie/MoviePoster';
|
import MoviePoster from 'Movie/MoviePoster';
|
||||||
|
import getRelativeDate from 'Utilities/Date/getRelativeDate';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import MovieIndexPosterInfo from './MovieIndexPosterInfo';
|
import MovieIndexPosterInfo from './MovieIndexPosterInfo';
|
||||||
import styles from './MovieIndexPoster.css';
|
import styles from './MovieIndexPoster.css';
|
||||||
@@ -101,6 +102,11 @@ class MovieIndexPoster extends Component {
|
|||||||
showSearchAction,
|
showSearchAction,
|
||||||
showRelativeDates,
|
showRelativeDates,
|
||||||
shortDateFormat,
|
shortDateFormat,
|
||||||
|
showReleaseDate,
|
||||||
|
showCinemaRelease,
|
||||||
|
inCinemas,
|
||||||
|
physicalRelease,
|
||||||
|
digitalRelease,
|
||||||
timeFormat,
|
timeFormat,
|
||||||
isRefreshingMovie,
|
isRefreshingMovie,
|
||||||
isSearchingMovie,
|
isSearchingMovie,
|
||||||
@@ -127,6 +133,19 @@ class MovieIndexPoster extends Component {
|
|||||||
height: `${posterHeight}px`
|
height: `${posterHeight}px`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let releaseDate = '';
|
||||||
|
let releaseDateType = '';
|
||||||
|
if (physicalRelease && digitalRelease) {
|
||||||
|
releaseDate = (physicalRelease < digitalRelease) ? physicalRelease : digitalRelease;
|
||||||
|
releaseDateType = (physicalRelease < digitalRelease) ? 'Released' : 'Digital';
|
||||||
|
} else if (physicalRelease && !digitalRelease) {
|
||||||
|
releaseDate = physicalRelease;
|
||||||
|
releaseDateType = 'Released';
|
||||||
|
} else if (digitalRelease && !physicalRelease) {
|
||||||
|
releaseDate = digitalRelease;
|
||||||
|
releaseDateType = 'Digital';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<div className={styles.posterContainer}>
|
<div className={styles.posterContainer}>
|
||||||
@@ -253,12 +272,67 @@ class MovieIndexPoster extends Component {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
showCinemaRelease && inCinemas &&
|
||||||
|
<div className={styles.title}>
|
||||||
|
<Icon
|
||||||
|
name={icons.IN_CINEMAS}
|
||||||
|
/> {getRelativeDate(
|
||||||
|
inCinemas,
|
||||||
|
shortDateFormat,
|
||||||
|
showRelativeDates,
|
||||||
|
{
|
||||||
|
timeFormat,
|
||||||
|
timeForToday: false
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
showReleaseDate && releaseDateType === 'Released' &&
|
||||||
|
<div className={styles.title}>
|
||||||
|
<Icon
|
||||||
|
name={icons.DISC}
|
||||||
|
/> {getRelativeDate(
|
||||||
|
releaseDate,
|
||||||
|
shortDateFormat,
|
||||||
|
showRelativeDates,
|
||||||
|
{
|
||||||
|
timeFormat,
|
||||||
|
timeForToday: false
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
showReleaseDate && releaseDateType === 'Digital' &&
|
||||||
|
<div className={styles.title}>
|
||||||
|
<Icon
|
||||||
|
name={icons.MOVIE_FILE}
|
||||||
|
/> {getRelativeDate(
|
||||||
|
releaseDate,
|
||||||
|
shortDateFormat,
|
||||||
|
showRelativeDates,
|
||||||
|
{
|
||||||
|
timeFormat,
|
||||||
|
timeForToday: false
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<MovieIndexPosterInfo
|
<MovieIndexPosterInfo
|
||||||
qualityProfile={qualityProfile}
|
qualityProfile={qualityProfile}
|
||||||
showQualityProfile={showQualityProfile}
|
showQualityProfile={showQualityProfile}
|
||||||
|
showReleaseDate={showReleaseDate}
|
||||||
showRelativeDates={showRelativeDates}
|
showRelativeDates={showRelativeDates}
|
||||||
shortDateFormat={shortDateFormat}
|
shortDateFormat={shortDateFormat}
|
||||||
timeFormat={timeFormat}
|
timeFormat={timeFormat}
|
||||||
|
inCinemas={inCinemas}
|
||||||
|
physicalRelease={physicalRelease}
|
||||||
|
digitalRelease={digitalRelease}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -298,6 +372,11 @@ MovieIndexPoster.propTypes = {
|
|||||||
showSearchAction: PropTypes.bool.isRequired,
|
showSearchAction: PropTypes.bool.isRequired,
|
||||||
showRelativeDates: PropTypes.bool.isRequired,
|
showRelativeDates: PropTypes.bool.isRequired,
|
||||||
shortDateFormat: PropTypes.string.isRequired,
|
shortDateFormat: PropTypes.string.isRequired,
|
||||||
|
showCinemaRelease: PropTypes.bool.isRequired,
|
||||||
|
showReleaseDate: PropTypes.bool.isRequired,
|
||||||
|
inCinemas: PropTypes.string,
|
||||||
|
physicalRelease: PropTypes.string,
|
||||||
|
digitalRelease: PropTypes.string,
|
||||||
timeFormat: PropTypes.string.isRequired,
|
timeFormat: PropTypes.string.isRequired,
|
||||||
isRefreshingMovie: PropTypes.bool.isRequired,
|
isRefreshingMovie: PropTypes.bool.isRequired,
|
||||||
isSearchingMovie: PropTypes.bool.isRequired,
|
isSearchingMovie: PropTypes.bool.isRequired,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Icon from 'Components/Icon';
|
||||||
|
import { icons } from 'Helpers/Props';
|
||||||
import getRelativeDate from 'Utilities/Date/getRelativeDate';
|
import getRelativeDate from 'Utilities/Date/getRelativeDate';
|
||||||
import formatBytes from 'Utilities/Number/formatBytes';
|
import formatBytes from 'Utilities/Number/formatBytes';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
@@ -10,6 +12,7 @@ function MovieIndexPosterInfo(props) {
|
|||||||
studio,
|
studio,
|
||||||
qualityProfile,
|
qualityProfile,
|
||||||
showQualityProfile,
|
showQualityProfile,
|
||||||
|
showReleaseDate,
|
||||||
added,
|
added,
|
||||||
inCinemas,
|
inCinemas,
|
||||||
digitalRelease,
|
digitalRelease,
|
||||||
@@ -57,7 +60,7 @@ function MovieIndexPosterInfo(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortKey === 'inCinemas' && inCinemas) {
|
if (sortKey === 'inCinemas' && inCinemas && !showReleaseDate) {
|
||||||
const inCinemasDate = getRelativeDate(
|
const inCinemasDate = getRelativeDate(
|
||||||
inCinemas,
|
inCinemas,
|
||||||
shortDateFormat,
|
shortDateFormat,
|
||||||
@@ -70,12 +73,14 @@ function MovieIndexPosterInfo(props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
{translate('InCinemas')}: {inCinemasDate}
|
<Icon
|
||||||
|
name={icons.IN_CINEMAS}
|
||||||
|
/> {inCinemasDate}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortKey === 'digitalRelease' && digitalRelease) {
|
if (sortKey === 'digitalRelease' && digitalRelease && !showReleaseDate) {
|
||||||
const digitalReleaseDate = getRelativeDate(
|
const digitalReleaseDate = getRelativeDate(
|
||||||
digitalRelease,
|
digitalRelease,
|
||||||
shortDateFormat,
|
shortDateFormat,
|
||||||
@@ -88,12 +93,14 @@ function MovieIndexPosterInfo(props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
{translate('Digital')}: {digitalReleaseDate}
|
<Icon
|
||||||
|
name={icons.MOVIE_FILE}
|
||||||
|
/> {digitalReleaseDate}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortKey === 'physicalRelease' && physicalRelease) {
|
if (sortKey === 'physicalRelease' && physicalRelease && !showReleaseDate) {
|
||||||
const physicalReleaseDate = getRelativeDate(
|
const physicalReleaseDate = getRelativeDate(
|
||||||
physicalRelease,
|
physicalRelease,
|
||||||
shortDateFormat,
|
shortDateFormat,
|
||||||
@@ -106,7 +113,9 @@ function MovieIndexPosterInfo(props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
{translate('Released')}: {physicalReleaseDate}
|
<Icon
|
||||||
|
name={icons.DISC}
|
||||||
|
/> {physicalReleaseDate}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -150,6 +159,7 @@ MovieIndexPosterInfo.propTypes = {
|
|||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
sizeOnDisk: PropTypes.number,
|
sizeOnDisk: PropTypes.number,
|
||||||
sortKey: PropTypes.string.isRequired,
|
sortKey: PropTypes.string.isRequired,
|
||||||
|
showReleaseDate: PropTypes.bool.isRequired,
|
||||||
showRelativeDates: PropTypes.bool.isRequired,
|
showRelativeDates: PropTypes.bool.isRequired,
|
||||||
shortDateFormat: PropTypes.string.isRequired,
|
shortDateFormat: PropTypes.string.isRequired,
|
||||||
timeFormat: PropTypes.string.isRequired
|
timeFormat: PropTypes.string.isRequired
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user