Compare commits
835 Commits
feature/cr
...
main
Author | SHA1 | Date |
---|---|---|
David Morlitz | a94198f2eb | |
David Morlitz | a6e7e6efa6 | |
David Morlitz | 6f5f7b190a | |
kolaente | 0473c385d6 | |
kolaente | 68a76faacc | |
kolaente | 4579dd3ce7 | |
renovate | f4fee26fe4 | |
renovate | 00398085fd | |
renovate | 13c8e6dbcd | |
renovate | 1b5f8a069b | |
renovate | 21fec9461d | |
renovate | df3af739f8 | |
renovate | b08d34bc96 | |
renovate | be03efd015 | |
renovate | c353fd151d | |
renovate | c32e9badf0 | |
renovate | 8f64ab5dce | |
renovate | 63ca8ffc7c | |
renovate | fe9ddf33ca | |
renovate | 74777d6bed | |
renovate | 76d1c56fab | |
renovate | f75e9135c2 | |
renovate | 480f0f8da9 | |
renovate | ac832186d6 | |
renovate | 738e1e8370 | |
Dominik Pschenitschni | 9b85817ddb | |
Dominik Pschenitschni | 49a6569db0 | |
renovate | e762f7f073 | |
renovate | e5d2b23cb3 | |
renovate | 6eddf23c0d | |
renovate | 70934c6a0b | |
Dominik Pschenitschni | 49955eb03a | |
renovate | 2b302974cc | |
Dominik Pschenitschni | 64d632b0a5 | |
Dominik Pschenitschni | e28f0f5be4 | |
konrad | c618b7e0b6 | |
renovate | 380af7fbf2 | |
renovate | 9d3ef30be6 | |
renovate | fc00169863 | |
renovate | b652225a12 | |
Dominik Pschenitschni | 29d8422e94 | |
Dominik Pschenitschni | cdbd1c2ac4 | |
Dominik Pschenitschni | cb37fd773d | |
kolaente | d2577f1df6 | |
kolaente | 27534a98e9 | |
kolaente | de77393905 | |
renovate | dd450263fb | |
renovate | d8106dcb73 | |
Dominik Pschenitschni | 8114012997 | |
renovate | bc4ea82639 | |
renovate | cd97cfe612 | |
renovate | e6136fdee4 | |
renovate | 2c395c720a | |
renovate | 8b639fd4af | |
renovate | f7bd5f13ac | |
renovate | 0ae774b95c | |
renovate | be899c3eb0 | |
renovate | dc02827a33 | |
renovate | 951e511bf9 | |
renovate | 5f1d936ca4 | |
renovate | c3845e5690 | |
renovate | f4db2df37b | |
renovate | 5668fc7a2c | |
renovate | 12a0099fbf | |
renovate | 7f4027cbe8 | |
renovate | b57aa33cae | |
renovate | b80de79594 | |
renovate | ead3e45a59 | |
konrad | 4a7d2d8414 | |
kolaente | 0befa58908 | |
kolaente | 8ae84eaf42 | |
Dominik Pschenitschni | cd10bc9d7a | |
renovate | f4545fbe2f | |
renovate | c6ffe8acab | |
renovate | 2fb16f9a77 | |
renovate | be427449e4 | |
renovate | 5e889ebe36 | |
renovate | 8c62c96109 | |
renovate | 7908a1e657 | |
renovate | 09b62da2ae | |
renovate | 076494afa5 | |
renovate | b604d5da75 | |
renovate | 59889cccf3 | |
renovate | f8ffb428d3 | |
drone | c2ea932c09 | |
renovate | 033d97e919 | |
renovate | 4694c14760 | |
renovate | 7e8e26679c | |
renovate | 838db379ff | |
renovate | 77da84d21a | |
renovate | 91b80cba67 | |
renovate | ac57c8572a | |
renovate | 858448b877 | |
renovate | 8409db98f6 | |
renovate | 04cc01daaf | |
renovate | 70f8d46b6c | |
renovate | 15114e487b | |
renovate | 7f79f2a7b3 | |
renovate | 7387112172 | |
Dominik Pschenitschni | 3743cdc058 | |
Dominik Pschenitschni | ce02462cfe | |
Dominik Pschenitschni | 7af21c48d5 | |
Dominik Pschenitschni | 943e554a58 | |
renovate | e885d8ae70 | |
renovate | 2cef6cb343 | |
Michaelpalacce | 7ebca9afc5 | |
renovate | d86eb9ea0b | |
Dominik Pschenitschni | 063592ca3d | |
renovate | d9fa0dd2bc | |
renovate | 4cbacafbbb | |
renovate | 2ce260bcf1 | |
renovate | d606be3459 | |
renovate | d79b14221d | |
renovate | fdbacc2084 | |
renovate | dd123dadd2 | |
renovate | b088a5e864 | |
renovate | 63008e59a3 | |
renovate | 3a1da44c94 | |
renovate | fccb0dcc61 | |
Dominik Pschenitschni | b3b7669983 | |
renovate | d114c673d8 | |
renovate | a6771b8d37 | |
renovate | 91b06a9af6 | |
renovate | 08502619c4 | |
renovate | 26de8e66fa | |
Dominik Pschenitschni | f944c35e99 | |
kolaente | 36fb250d1f | |
kolaente | b7aa7891e9 | |
kolaente | ccaed029f2 | |
renovate | 770578240a | |
renovate | 791678720b | |
drone | 21e44e15bd | |
renovate | 9a612849a3 | |
renovate | c4173c3c35 | |
renovate | 46afeb159a | |
renovate | 940494a02d | |
renovate | 1a55d04c97 | |
renovate | 8ccfe716f6 | |
renovate | e3243f012d | |
renovate | eef37c4f70 | |
renovate | e7e1cc0e55 | |
renovate | f8031b5aef | |
renovate | ac61e8d449 | |
renovate | 2c671c6a13 | |
renovate | d01c3eabb9 | |
renovate | d85d86eaa7 | |
renovate | e1b04eed72 | |
konrad | 543dae2f30 | |
renovate | 40479d0c6e | |
renovate | f5fba7880f | |
renovate | ed332f5dd3 | |
drone | 9ecd18a5ee | |
renovate | 63070e63bd | |
konrad | 32353e3b76 | |
renovate | 14f1ee1885 | |
kolaente | 8440869bcd | |
kolaente | 14397ffb31 | |
Dominik Pschenitschni | c3c4d2a0a5 | |
renovate | b03d5d80cd | |
renovate | 2bf9be3676 | |
kolaente | 807fb6a9fe | |
kolaente | a106511646 | |
renovate | 7ed71f66ea | |
renovate | 4463b83b78 | |
renovate | 14f14f6d3e | |
renovate | e1449642bd | |
renovate | 5dfaeb39ca | |
renovate | 9584ef127a | |
Dominik Pschenitschni | cb9e1e891d | |
renovate | 41c0594bd2 | |
renovate | 9acc9039a6 | |
renovate | f530d4763e | |
renovate | 3f4bcbcecd | |
renovate | 89d8c9d639 | |
renovate | 2de523f2e0 | |
renovate | 22e62a2cea | |
renovate | 92c89d145c | |
drone | 306d562f65 | |
renovate | 4b8a7e1556 | |
renovate | d0c6576efa | |
renovate | e684e9a90b | |
drone | 805e1bc554 | |
drone | 8ee793c054 | |
konrad | 1a119f97c5 | |
kolaente | 10fe38cef6 | |
renovate | b4cbe1e1fd | |
konrad | 8b8e413af0 | |
renovate | c8029ec3c4 | |
renovate | 6225c54447 | |
renovate | 809e876091 | |
renovate | 470022899f | |
renovate | 8d1d60ba80 | |
renovate | 028ad3dc14 | |
renovate | f4df628e47 | |
renovate | 150b847638 | |
renovate | 684acc01bd | |
renovate | 3218cf60f0 | |
kolaente | bba9a8e008 | |
renovate | 852d71e8b7 | |
renovate | c65bb4e93b | |
renovate | 1c3f655323 | |
renovate | bd19234041 | |
Dominik Pschenitschni | ac630ac775 | |
renovate | f758eefa88 | |
Dominik Pschenitschni | 4137bab7fc | |
renovate | d253d2e743 | |
renovate | fe5770082a | |
renovate | 2041722b8a | |
renovate | 648b947a05 | |
renovate | f58e114947 | |
renovate | 144e7bd10c | |
Dominik Pschenitschni | b96e89ca8c | |
Dominik Pschenitschni | 20f0496fa5 | |
renovate | e535584412 | |
renovate | c5b9e2a1ff | |
Dominik Pschenitschni | e45bc83132 | |
Dominik Pschenitschni | bc8b04fc7a | |
Dominik Pschenitschni | 84284a6211 | |
Dominik Pschenitschni | 716de2c99c | |
Dominik Pschenitschni | 769d94e879 | |
Dominik Pschenitschni | baa86530c8 | |
renovate | 7613afbf27 | |
renovate | aeb886e4c5 | |
renovate | 306bd1c179 | |
renovate | f3cf79fa65 | |
renovate | 8c945b049a | |
renovate | f69111c105 | |
renovate | 03afbfc6c8 | |
renovate | c07288dd8b | |
renovate | 03f3c52548 | |
renovate | 384037c694 | |
kolaente | 734db0795c | |
renovate | 8f6c0f3738 | |
drone | f3324c6aaf | |
konrad | f8d009a6aa | |
dpschen | 59e915cc10 | |
dpschen | 0c9dad9891 | |
dpschen | b7ad29f056 | |
renovate | a7434f24df | |
drone | f61d5bac46 | |
renovate | 2911dee3cc | |
kolaente | 58c361ee29 | |
renovate | d3fc1439b5 | |
renovate | bb544c353c | |
renovate | cc90a1cea5 | |
renovate | cffba33748 | |
renovate | 055e0a2901 | |
renovate | c8d1921bcd | |
renovate | 9e09314f75 | |
renovate | c3833d90d8 | |
renovate | e24cb55e1b | |
renovate | f897611ad1 | |
renovate | ea8fe297d9 | |
renovate | c6b604f1fa | |
renovate | 4792adfbd1 | |
dpschen | 04c94418d7 | |
renovate | 12bec04c42 | |
renovate | e8eb94d71b | |
renovate | 5137f9f6cb | |
renovate | a2f65d86c2 | |
renovate | 08dcc897cc | |
renovate | c975fb0fee | |
drone | b73cf344b6 | |
kolaente | d4b45dc255 | |
kolaente | e2beaba3b9 | |
renovate | dd9be97793 | |
konrad | 6cde8e2640 | |
renovate | 5c6fcffd75 | |
kolaente | 9b243873c5 | |
kolaente | dc347ed8ba | |
renovate | d0d1086dac | |
renovate | fb91b71395 | |
dpschen | b688f35446 | |
dpschen | 91580f97a1 | |
renovate | d95fc32d67 | |
drone | 6b5ac20ef8 | |
drone | 66f0df5037 | |
dpschen | 981babd691 | |
adrinux | 46fa43d67f | |
kolaente | 4ef54f1bc2 | |
dpschen | b029889f27 | |
dpschen | 44f8e3ea9b | |
dpschen | ae36c041a7 | |
renovate | 8a722f294c | |
renovate | 5674acbee6 | |
renovate | bf9371c60a | |
renovate | 181930f537 | |
renovate | cee22a1942 | |
renovate | 673458b41d | |
renovate | b56e99bfdf | |
renovate | a5b5d99129 | |
renovate | e1b9a9921c | |
renovate | 709ebdf567 | |
renovate | d41ee3dc8c | |
renovate | e342f6e3ed | |
renovate | 8b2450d6f9 | |
renovate | 943eab5e7e | |
renovate | d55328e03b | |
renovate | 30aa1cd1cf | |
renovate | 01f3196938 | |
renovate | ced8e0fd3c | |
dpschen | b838e7494d | |
renovate | 745b4b56ec | |
renovate | c5b539912d | |
dpschen | ed6dc94873 | |
renovate | 233b9693eb | |
dpschen | 2656c74f37 | |
renovate | 28b571588e | |
konrad | ae5d3ecac5 | |
kolaente | 26213d5e8c | |
renovate | ae0ecb9f23 | |
renovate | 75af78eecc | |
renovate | cf202738be | |
dpschen | ed78a83ed9 | |
renovate | d0635ae4a1 | |
renovate | 552751b346 | |
renovate | e83cf50e51 | |
renovate | 810635f5a5 | |
renovate | 213cbfb440 | |
renovate | 11e5ff42a6 | |
konrad | bb64452382 | |
renovate | e31d388ec1 | |
drone | a4dd8ec0d1 | |
renovate | 7b4b97b0d3 | |
konrad | 665cc84174 | |
konrad | 6c6ccc647e | |
kolaente | 0684806db0 | |
dpschen | d0d4096f8b | |
konrad | 507a73e74c | |
kolaente | 1fa164453c | |
konrad | fcadbc352b | |
renovate | 7824ba089a | |
konrad | 31f344503c | |
dpschen | e63fd587c8 | |
kolaente | c1c6f21ad2 | |
renovate | 060057e268 | |
renovate | 4e02f77382 | |
drone | 780ac4eb74 | |
drone | d46374839e | |
drone | ce45034776 | |
renovate | 7fada671fc | |
konrad | feea191ecf | |
konrad | db605e0d21 | |
konrad | 0fe433891a | |
konrad | 0a2d5ef820 | |
konrad | 31f0c384ac | |
kolaente | 73651ef964 | |
konrad | 03eee061ff | |
drone | 9a499f68e8 | |
renovate | b5927be136 | |
kolaente | be78fc177d | |
dpschen | 30cc89fe25 | |
dpschen | 8e6e52bf02 | |
dpschen | 20e059c921 | |
renovate | 36f1e846bb | |
renovate | 1e50aeebd8 | |
renovate | 05e624ce39 | |
renovate | 4e6b9f4cbd | |
renovate | 17bc35864b | |
renovate | 52c115cea8 | |
renovate | df1a7dd19e | |
renovate | 34994e919b | |
drone | d6669fa8e2 | |
renovate | 6d86d4ce59 | |
renovate | 15da2657d3 | |
drone | 1c23a8c570 | |
kolaente | 054f804427 | |
LordGaav | 052cd36085 | |
konrad | e49fd16a3a | |
drone | c92b59db1d | |
adrinux | 1cef4f6e0b | |
renovate | 46e3a9516a | |
renovate | 8674c5da47 | |
renovate | f299241a6c | |
renovate | 038fb55801 | |
dpschen | 8f43619f73 | |
konrad | 9b7882de7a | |
renovate | 70a50ca1c2 | |
renovate | 99d38e1f8e | |
renovate | 00be1d4095 | |
renovate | 04a971e767 | |
renovate | 917006b69f | |
renovate | a87d5836c1 | |
dpschen | e23f3c2570 | |
dpschen | b7207c6eaf | |
konrad | 58986c4a7a | |
konrad | 7e82aa83e6 | |
drone | b6c4bb1801 | |
kolaente | a47d106926 | |
renovate | 3be15b0a5f | |
renovate | 6e44f9eaba | |
renovate | 525ff7903c | |
kolaente | 6e043e3b9e | |
konrad | b34213c301 | |
kolaente | e831c3eb65 | |
dpschen | d3c303ba2a | |
dpschen | 108e7af578 | |
dpschen | d1ff800b41 | |
dpschen | ee430b8687 | |
renovate | 4e6f961a24 | |
renovate | f72f0424cc | |
renovate | 061e2b42c9 | |
renovate | b2aa2df59d | |
renovate | ead145b9ce | |
konrad | d8d4803e2d | |
renovate | b06b419817 | |
kolaente | 14472a45ed | |
dpschen | 28a448a1aa | |
konrad | ecb5be4b17 | |
konrad | 1873c74776 | |
konrad | 7aede352f1 | |
konrad | 5b406b0172 | |
kolaente | a515b0c3a4 | |
kolaente | 85e85aa2bb | |
kolaente | 54c5cabf48 | |
kolaente | 8389587a60 | |
renovate | 8bbdbe62a4 | |
renovate | 1dda3240e7 | |
renovate | 2c47102c56 | |
renovate | 6d61a4b24d | |
renovate | 65ea02d861 | |
renovate | e9d58d12f4 | |
renovate | 8bbbfde5aa | |
renovate | 9b84d57f0e | |
kolaente | ab1f5047a1 | |
renovate | 3c11660cf7 | |
renovate | 776bd2e86f | |
renovate | 226319a6f0 | |
renovate | 7298ecb7b7 | |
konrad | 5040a76781 | |
konrad | e1a7fb4999 | |
kolaente | 6394485524 | |
renovate | 1e4dd415cf | |
konrad | 1774fdc604 | |
dpschen | 782abbb82a | |
dpschen | 3bd9b02768 | |
renovate | a0903dd7be | |
dpschen | 2f2e639a6e | |
dpschen | 77fc5c0c6f | |
dpschen | d4fe3781f7 | |
renovate | 27c8bb3d19 | |
renovate | 20d57c2446 | |
kolaente | 48224e28b8 | |
renovate | 54148683f8 | |
renovate | fd3f058d22 | |
renovate | e9ad3c2126 | |
renovate | fac41b63b9 | |
renovate | 283b7c7082 | |
renovate | 5058046018 | |
renovate | 8e7e86808e | |
renovate | dd26d0de0f | |
renovate | 8d90d61fd2 | |
renovate | e0645d4525 | |
renovate | 3293e9892c | |
kolaente | 8a6774f8e3 | |
kolaente | 2004478c88 | |
kolaente | 4d48090411 | |
renovate | 02b30832b3 | |
konrad | 877b243c69 | |
Dominik Pschenitschni | c6b24dd8f1 | |
Dominik Pschenitschni | 89cd8eafc4 | |
Dominik Pschenitschni | 9e6afdb752 | |
Dominik Pschenitschni | 2645edc9e0 | |
Dominik Pschenitschni | 87d2b4fed3 | |
Dominik Pschenitschni | f496c9d678 | |
Dominik Pschenitschni | 19a4b17004 | |
Dominik Pschenitschni | 4f8cce0f45 | |
Dominik Pschenitschni | 32a0106819 | |
Dominik Pschenitschni | 7ca355db66 | |
Dominik Pschenitschni | 6ba974f9fa | |
Dominik Pschenitschni | 986130a0ac | |
Dominik Pschenitschni | 7824ddc13f | |
Dominik Pschenitschni | 57d5afa530 | |
Dominik Pschenitschni | 3e456782df | |
Dominik Pschenitschni | 2aecf3245b | |
Dominik Pschenitschni | 4d2c27e74e | |
Dominik Pschenitschni | 4a6126287a | |
Dominik Pschenitschni | 14dd49e4b0 | |
Dominik Pschenitschni | e0fd5f8fe0 | |
Dominik Pschenitschni | c9e23cdd29 | |
Dominik Pschenitschni | f7c7ea50eb | |
Dominik Pschenitschni | 55bed2e5e8 | |
Dominik Pschenitschni | 370186726a | |
Dominik Pschenitschni | 0aff057f7b | |
Dominik Pschenitschni | a5a716e09b | |
Dominik Pschenitschni | 0f7caafd54 | |
Dominik Pschenitschni | 0eb87663e0 | |
Dominik Pschenitschni | 87f7a515a6 | |
Dominik Pschenitschni | 4d15f7ae98 | |
Dominik Pschenitschni | 4223d23ce5 | |
Dominik Pschenitschni | f74cf516d2 | |
Dominik Pschenitschni | 9ca8857d89 | |
Dominik Pschenitschni | ba1942e757 | |
Dominik Pschenitschni | 3cb68c945f | |
Dominik Pschenitschni | 46ebd45a74 | |
Dominik Pschenitschni | be35c73f6e | |
Dominik Pschenitschni | 08f84bf7e3 | |
Dominik Pschenitschni | 265081417d | |
Dominik Pschenitschni | 6195637001 | |
Dominik Pschenitschni | b304712b1e | |
Dominik Pschenitschni | b9eba00603 | |
Dominik Pschenitschni | a33758e37e | |
Dominik Pschenitschni | 1f5283d548 | |
Dominik Pschenitschni | a0ca6bb8fb | |
dpschen | e0fe8dc673 | |
dpschen | 0fdfcccee9 | |
renovate | de33dc6c89 | |
renovate | bbb3c81f68 | |
renovate | 149defddda | |
renovate | cb95a569d3 | |
renovate | 3918da3bc7 | |
renovate | a6bb2daf81 | |
renovate | 6f11102153 | |
renovate | 53ff2e0209 | |
renovate | 59add72cd6 | |
renovate | 0c72d836fe | |
renovate | b5b5facde6 | |
renovate | 5bcd51cc5f | |
renovate | cb00c869e1 | |
renovate | cb81497e8d | |
renovate | b24145c47c | |
dpschen | 1ce5a21e66 | |
dpschen | a70b92253a | |
kolaente | bc7b577748 | |
kolaente | 1a784d0709 | |
dpschen | ee2c56156b | |
kolaente | 6d472bf5ca | |
kolaente | c7b4c25caa | |
kolaente | 852b864ee6 | |
kolaente | f795d2d0f3 | |
kolaente | 3ba9cd2d99 | |
Dominik Pschenitschni | c1a981c60b | |
dpschen | 0a1d0084e2 | |
kolaente | 1fc857d9a2 | |
kolaente | 571b019c00 | |
kolaente | 1864359751 | |
kolaente | 4c24118b48 | |
dpschen | dd0e04b106 | |
kolaente | 49cd66581d | |
kolaente | eb7b1bf432 | |
kolaente | f4372ecd05 | |
Dominik Pschenitschni | 3f61c6b21a | |
kolaente | 36d5262f1d | |
dpschen | 4e893a3196 | |
kolaente | 1d46b85170 | |
Dominik Pschenitschni | ae971b23bc | |
kolaente | 2de94bc902 | |
kolaente | 9fc158831b | |
kolaente | 9d48700cd9 | |
renovate | a3657abaf3 | |
Dominik Pschenitschni | 2ac3d29c13 | |
kolaente | 0cc7166767 | |
kolaente | 1c8e26bdc6 | |
kolaente | cc32ca244c | |
Dominik Pschenitschni | c1078255fc | |
kolaente | c329c37c7b | |
kolaente | 2fc96cb6a7 | |
kolaente | 74d785d606 | |
Dominik Pschenitschni | 56365591cf | |
kolaente | f884020c55 | |
kolaente | 1d2abf56f9 | |
kolaente | e52c139c9f | |
kolaente | 529b3d2890 | |
kolaente | 7e29dde717 | |
renovate | a85e27b497 | |
kolaente | 5766ae48d7 | |
kolaente | df32893ce6 | |
Dominik Pschenitschni | a60ad77bdc | |
Dominik Pschenitschni | 7f5f44d7f0 | |
Dominik Pschenitschni | 54d456e886 | |
Dominik Pschenitschni | 1d43d1bd65 | |
Dominik Pschenitschni | 12a3c238b8 | |
Dominik Pschenitschni | a6db1e7391 | |
Dominik Pschenitschni | bb94c1ba3a | |
Dominik Pschenitschni | a776e1d2f3 | |
Dominik Pschenitschni | 3b940cb56c | |
Dominik Pschenitschni | 6f51921588 | |
Dominik Pschenitschni | b79d238bdc | |
konrad | f05e81190f | |
konrad | 373a766f5c | |
renovate | 515300d43a | |
Dominik Pschenitschni | 80163ee992 | |
Dominik Pschenitschni | 9c730d3381 | |
renovate | f6d46ce394 | |
renovate | 526d2c0cfc | |
renovate | 3ee8231b9e | |
renovate | fc320d0067 | |
renovate | b988e3c0ec | |
IDDQD69 | 26568fe5c6 | |
renovate | accd3ef392 | |
renovate | f36e1d78b2 | |
renovate | a105883ef0 | |
renovate | 3271144406 | |
renovate | 1965535605 | |
renovate | b8a2160a93 | |
renovate | 2b12b0fafd | |
renovate | ccce0c6ac4 | |
renovate | f101cf4f82 | |
renovate | d072a7d277 | |
renovate | 217eb9102e | |
renovate | e6f140912e | |
renovate | ee3de6730c | |
renovate | 51e55732ff | |
renovate | 81a1aa202f | |
renovate | 10c262fe96 | |
renovate | ba4f825bc6 | |
Dominik Pschenitschni | 8e1ab8e09b | |
Dominik Pschenitschni | fa54e1f1de | |
kolaente | 2bf83a672c | |
kolaente | 435535f8cd | |
kolaente | 9a2f95ecc6 | |
kolaente | 97dd55d946 | |
kolaente | 4fef047d74 | |
kolaente | 3f96ce6d60 | |
kolaente | c30c2e00cb | |
kolaente | b5b56a6e4a | |
kolaente | 69821fb663 | |
Dominik Pschenitschni | 50fa592aad | |
Dominik Pschenitschni | a3a3ef850c | |
dpschen | e6a935f49d | |
Dominik Pschenitschni | cc8b03778c | |
Dominik Pschenitschni | 18c31482df | |
Dominik Pschenitschni | 427f18d59e | |
Dominik Pschenitschni | d1b61a1489 | |
Dominik Pschenitschni | 5cfb99bfc2 | |
Dominik Pschenitschni | 18d7ca0820 | |
Dominik Pschenitschni | fd77aaa123 | |
Dominik Pschenitschni | e0456cdfa1 | |
Dominik Pschenitschni | 0b68a473ef | |
Dominik Pschenitschni | 7c3ece5816 | |
Dominik Pschenitschni | d7ed5b8f11 | |
Dominik Pschenitschni | dfe401a9dc | |
Dominik Pschenitschni | 0bf68effb8 | |
Dominik Pschenitschni | 9b2e9fc17f | |
Dominik Pschenitschni | 35c861b711 | |
Dominik Pschenitschni | 3750b0f78b | |
Dominik Pschenitschni | eec02a55a4 | |
Dominik Pschenitschni | 60ef07da0f | |
Dominik Pschenitschni | e064c3bf96 | |
Dominik Pschenitschni | 1964c1352c | |
Dominik Pschenitschni | 6fee114610 | |
Dominik Pschenitschni | 4ae18ec162 | |
Dominik Pschenitschni | d66ad12f5c | |
Dominik Pschenitschni | 43b22360a5 | |
Dominik Pschenitschni | 17d791027c | |
dpschen | 3c5c3cad10 | |
dpschen | 36d4599276 | |
Dominik Pschenitschni | 59401bc1da | |
Dominik Pschenitschni | 3a7a4bdc42 | |
dpschen | faa2daa876 | |
konrad | a76d115baf | |
konrad | 7e1a7f3f19 | |
kolaente | 49fcce043d | |
kolaente | d284db672e | |
kolaente | 99fb78dbd4 | |
dpschen | 813982e833 | |
kolaente | 2a1004ac68 | |
kolaente | e941394147 | |
kolaente | a558f5b35a | |
kolaente | d583cb2094 | |
kolaente | 240e8594cc | |
kolaente | 19a561c8e6 | |
kolaente | 22ef7785fd | |
kolaente | cc22d8d4e9 | |
kolaente | 587f2edd83 | |
kolaente | 0453758117 | |
kolaente | 78ec87360e | |
dpschen | a843cddbc9 | |
dpschen | b59b5def57 | |
Dominik Pschenitschni | 66648be6d5 | |
Dominik Pschenitschni | 117980a8fc | |
Dominik Pschenitschni | 34d0f28678 | |
dpschen | 3f9917dfab | |
kolaente | d13f3b9b19 | |
Dominik Pschenitschni | 0cbffad49d | |
kolaente | 50799a7b3e | |
kolaente | 234951fe3b | |
dpschen | 7488378f5c | |
dpschen | 64abb1ce37 | |
kolaente | c3b6e13009 | |
Dominik Pschenitschni | 7bb1b1b769 | |
Dominik Pschenitschni | 6b358107b6 | |
Dominik Pschenitschni | 15640e98ec | |
Dominik Pschenitschni | 8d88b3792d | |
Dominik Pschenitschni | 672d63fbed | |
Dominik Pschenitschni | aeabc42844 | |
Dominik Pschenitschni | 8fc01f774a | |
Dominik Pschenitschni | a745966984 | |
Dominik Pschenitschni | e779681905 | |
Dominik Pschenitschni | 7c3c2945f8 | |
Dominik Pschenitschni | 3d6aca3510 | |
Dominik Pschenitschni | 72518212da | |
Dominik Pschenitschni | b31da0cefe | |
Dominik Pschenitschni | b75c79fd5e | |
Dominik Pschenitschni | 421ff9a188 | |
Dominik Pschenitschni | 51a740f53c | |
Dominik Pschenitschni | 2ef2bb7700 | |
Dominik Pschenitschni | ecc3d3cf3f | |
Dominik Pschenitschni | db49b9b532 | |
Dominik Pschenitschni | 2b20f328cb | |
Dominik Pschenitschni | 3c89147ee2 | |
Dominik Pschenitschni | 78a5096e0d | |
Dominik Pschenitschni | 4ee7a8bac6 | |
Dominik Pschenitschni | 0c678b6e44 | |
Zoker | 9a72d3dc36 | |
renovate | b7ff5473eb | |
kolaente | e7ffba5322 | |
kolaente | 1b7a6cecfe | |
kolaente | 4a1b402e62 | |
renovate | e20be7b788 | |
kolaente | 416380025e | |
kolaente | 96ef25ba01 | |
Christoph Schmatzler | 7cd3394da5 | |
kolaente | 4bd2c94256 | |
konrad | 96523f1fbf | |
konrad | d47b13647e | |
renovate | 3b58756285 | |
renovate | 924b77d10f | |
renovate | 08521d7eb9 | |
renovate | dd74b9f957 | |
renovate | 5e8fb32c71 | |
renovate | 8596d501dd | |
renovate | 4c0bdbb908 | |
kolaente | 2691a84610 | |
kolaente | e17116dac1 | |
konrad | c0d744cfaa | |
konrad | 442e6b12e0 | |
kolaente | 3dfa286a12 | |
kolaente | a955488cdf | |
dpschen | 8cd4bbccf6 | |
dpschen | 166539c7e8 | |
dpschen | 7579222bb0 | |
kolaente | 8b01dc6b71 | |
kolaente | 4b64e27d2b | |
kolaente | 403d77ce14 | |
kolaente | e918b82cfa | |
renovate | 75f1a5a97f | |
dpschen | e9978548d8 | |
dpschen | c551bf5836 | |
dpschen | feb34c8cc1 | |
renovate | 72627d13c6 | |
kolaente | f762d8ad4d | |
Dominik Pschenitschni | 697ea12c8e | |
Dominik Pschenitschni | fe27a432c7 | |
Dominik Pschenitschni | f51371bbe0 | |
Dominik Pschenitschni | ebeca48be4 | |
Dominik Pschenitschni | 0da7a46612 | |
Dominik Pschenitschni | 4454e6cf22 | |
kolaente | 77f8b27dc6 | |
dpschen | 1bc6d66895 | |
dpschen | 41331c8a86 | |
dpschen | 4f2378ff02 | |
kolaente | 97416ab2d5 | |
kolaente | dedf6cbf21 | |
renovate | dab6bc23ed | |
renovate | c44db22b99 | |
renovate | 4e62ab2b79 | |
dpschen | 6b1bf27bf8 | |
dpschen | 3245752a80 | |
renovate | 649bbd8c9b | |
renovate | ab954fcb9a | |
dpschen | 17d11c6ce3 | |
renovate | d72d69debb | |
renovate | 7d59e64c61 | |
renovate | 6d72ac1ef3 | |
renovate | da4bac09f8 | |
renovate | 64f4852d76 | |
renovate | 1ae8f84b1c | |
renovate | 2f506ea653 | |
renovate | e5158d9438 | |
renovate | c758c00f54 | |
renovate | 1a0b47a581 | |
renovate | 35a9532b86 | |
renovate | 68947b77e9 | |
dpschen | 7719ef1bef | |
dpschen | 2ff0976da6 | |
dpschen | 77352e7a8c | |
simon1506 | d88e299358 | |
dpschen | 9122a184d6 | |
dpschen | 728dfc52e5 | |
dpschen | 47ad115738 | |
dpschen | 3ac25c9f08 | |
renovate | 7fbd9c6ab0 | |
renovate | 681b76b3a5 | |
renovate | 857fdc35e4 | |
renovate | b70c88b3f3 | |
renovate | b6ad09e3d8 | |
renovate | eddb2cbce0 | |
renovate | 1cf0316b3b | |
dpschen | 50c1a2e4d5 | |
dpschen | 07a6a31f47 | |
dpschen | 0295113f50 | |
dpschen | b5df941e39 | |
konrad | 077fe264f0 | |
dpschen | dae441a373 | |
dpschen | 0376ef53e3 | |
renovate | 7ab308b846 | |
renovate | 33447c4a09 | |
dpschen | d0e46e59e8 | |
dpschen | 0ed3cf2553 | |
renovate | 33f1480284 | |
dpschen | 432c6babf2 | |
dpschen | 96ef926dde | |
dpschen | 87c70cec0e | |
renovate | 4689de7f1f | |
renovate | b0f616d784 | |
renovate | 11b5d0574d | |
kolaente | 134a09c9f2 | |
kolaente | c7c3ef79be | |
kolaente | 2bae8e95e5 | |
dpschen | c4095327ad | |
dpschen | c9631c1e71 | |
dpschen | 4fc8858c64 | |
kolaente | 9cee720ac9 | |
kolaente | 6f89863c81 | |
kolaente | debdc83f1b | |
renovate | 033b30d6cd | |
renovate | c23d3c1488 | |
renovate | 4f305b28fd | |
renovate | 33926a2d11 | |
kolaente | 332dbc1598 | |
renovate | 28a4b1c533 | |
kolaente | 78346f9ac6 | |
renovate | 8f916c275b | |
renovate | cb0e2a7bc1 | |
kolaente | 2d804c3af3 | |
renovate | 6868fb134d | |
kolaente | b7ec975384 | |
kolaente | 75174c2496 | |
kolaente | e0c9332634 | |
kolaente | 7a4e568898 | |
kolaente | fb20afae92 | |
kolaente | db0e023d35 | |
kolaente | 13f01cdc30 | |
kolaente | b4919a5662 |
285
.drone.yml
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
kind: pipeline
|
||||
name: build
|
||||
|
||||
|
@ -12,29 +13,30 @@ trigger:
|
|||
|
||||
services:
|
||||
- name: api
|
||||
image: vikunja/api
|
||||
image: vikunja/api:unstable
|
||||
environment:
|
||||
VIKUNJA_SERVICE_TESTINGTOKEN: averyLongSecretToSe33dtheDB
|
||||
VIKUNJA_LOG_LEVEL: DEBUG
|
||||
|
||||
steps:
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: cache_aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: cache_aws_secret_access_key
|
||||
settings:
|
||||
restore: true
|
||||
bucket: kolaente.dev-drone-dependency-cache
|
||||
endpoint: https://s3.fr-par.scw.cloud
|
||||
region: fr-par
|
||||
path_style: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}'
|
||||
mount:
|
||||
- '.cache'
|
||||
# Disabled until we figure out why it is so slow
|
||||
# - name: restore-cache
|
||||
# image: meltwater/drone-cache:dev
|
||||
# pull: true
|
||||
# environment:
|
||||
# AWS_ACCESS_KEY_ID:
|
||||
# from_secret: cache_aws_access_key_id
|
||||
# AWS_SECRET_ACCESS_KEY:
|
||||
# from_secret: cache_aws_secret_access_key
|
||||
# settings:
|
||||
# restore: true
|
||||
# bucket: kolaente.dev-drone-dependency-cache
|
||||
# endpoint: https://s3.fr-par.scw.cloud
|
||||
# region: fr-par
|
||||
# path_style: true
|
||||
# cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}'
|
||||
# mount:
|
||||
# - '.cache'
|
||||
|
||||
- name: dependencies
|
||||
image: node:16
|
||||
|
@ -44,28 +46,28 @@ steps:
|
|||
CYPRESS_CACHE_FOLDER: .cache/cypress/
|
||||
commands:
|
||||
- yarn --frozen-lockfile --network-timeout 100000
|
||||
depends_on:
|
||||
- restore-cache
|
||||
# depends_on:
|
||||
# - restore-cache
|
||||
|
||||
- name: rebuild-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: cache_aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: cache_aws_secret_access_key
|
||||
settings:
|
||||
rebuild: true
|
||||
bucket: kolaente.dev-drone-dependency-cache
|
||||
endpoint: https://s3.fr-par.scw.cloud
|
||||
region: fr-par
|
||||
path_style: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}'
|
||||
mount:
|
||||
- '.cache'
|
||||
depends_on:
|
||||
- dependencies
|
||||
# - name: rebuild-cache
|
||||
# image: meltwater/drone-cache:dev
|
||||
# pull: true
|
||||
# environment:
|
||||
# AWS_ACCESS_KEY_ID:
|
||||
# from_secret: cache_aws_access_key_id
|
||||
# AWS_SECRET_ACCESS_KEY:
|
||||
# from_secret: cache_aws_secret_access_key
|
||||
# settings:
|
||||
# rebuild: true
|
||||
# bucket: kolaente.dev-drone-dependency-cache
|
||||
# endpoint: https://s3.fr-par.scw.cloud
|
||||
# region: fr-par
|
||||
# path_style: true
|
||||
# cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}'
|
||||
# mount:
|
||||
# - '.cache'
|
||||
# depends_on:
|
||||
# - dependencies
|
||||
|
||||
- name: lint
|
||||
image: node:16
|
||||
|
@ -78,25 +80,13 @@ steps:
|
|||
depends_on:
|
||||
- dependencies
|
||||
|
||||
# Building in dev mode to avoid the service worker for testing
|
||||
- name: build-dev
|
||||
image: node:16
|
||||
pull: true
|
||||
environment:
|
||||
YARN_CACHE_FOLDER: .cache/yarn/
|
||||
CYPRESS_CACHE_FOLDER: .cache/cypress/
|
||||
commands:
|
||||
- yarn build:dev
|
||||
depends_on:
|
||||
- dependencies
|
||||
|
||||
- name: build-prod
|
||||
image: node:16
|
||||
pull: true
|
||||
environment:
|
||||
YARN_CACHE_FOLDER: .cache/yarn/
|
||||
commands:
|
||||
- yarn build --dest dist-prod
|
||||
- yarn build
|
||||
depends_on:
|
||||
- dependencies
|
||||
|
||||
|
@ -108,8 +98,17 @@ steps:
|
|||
depends_on:
|
||||
- dependencies
|
||||
|
||||
- name: typecheck
|
||||
failure: ignore
|
||||
image: node:16
|
||||
pull: true
|
||||
commands:
|
||||
- yarn typecheck
|
||||
depends_on:
|
||||
- dependencies
|
||||
|
||||
- name: test-frontend
|
||||
image: cypress/browsers:node14.17.0-chrome91-ff89
|
||||
image: cypress/browsers:node16.5.0-chrome94-ff93
|
||||
pull: true
|
||||
environment:
|
||||
CYPRESS_API_URL: http://api:3456/api/v1
|
||||
|
@ -118,15 +117,15 @@ steps:
|
|||
CYPRESS_CACHE_FOLDER: .cache/cypress/
|
||||
CYPRESS_DEFAULT_COMMAND_TIMEOUT: 60000
|
||||
commands:
|
||||
- sed -i 's/localhost/api/g' dist-dev/index.html
|
||||
- yarn serve:dist-dev & npx wait-on http://localhost:5000
|
||||
- sed -i 's/localhost/api/g' dist/index.html
|
||||
- yarn serve:dist & npx wait-on http://localhost:5000
|
||||
- yarn test:frontend --browser chrome
|
||||
depends_on:
|
||||
- dependencies
|
||||
- build-dev
|
||||
- build-prod
|
||||
|
||||
- name: upload-test-results
|
||||
image: plugins/s3:1
|
||||
image: plugins/s3
|
||||
pull: true
|
||||
settings:
|
||||
bucket: drone-test-results
|
||||
|
@ -147,6 +146,26 @@ steps:
|
|||
- failure
|
||||
- success
|
||||
|
||||
- name: deploy-preview
|
||||
image: node:16
|
||||
pull: true
|
||||
environment:
|
||||
NETLIFY_AUTH_TOKEN:
|
||||
from_secret: netlify_auth_token
|
||||
NETLIFY_SITE_ID:
|
||||
from_secret: netlify_site_id
|
||||
GITEA_TOKEN:
|
||||
from_secret: gitea_token
|
||||
commands:
|
||||
- shasum -a 384 -c ./scripts/deploy-preview-netlify.js.sha384
|
||||
- node ./scripts/deploy-preview-netlify.js
|
||||
depends_on:
|
||||
- build-prod
|
||||
when:
|
||||
event:
|
||||
include:
|
||||
- pull_request
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: release-latest
|
||||
|
@ -166,23 +185,23 @@ steps:
|
|||
commands:
|
||||
- git fetch --tags
|
||||
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: cache_aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: cache_aws_secret_access_key
|
||||
settings:
|
||||
restore: true
|
||||
bucket: kolaente.dev-drone-dependency-cache
|
||||
endpoint: https://s3.fr-par.scw.cloud
|
||||
region: fr-par
|
||||
path_style: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}'
|
||||
mount:
|
||||
- '.cache'
|
||||
# - name: restore-cache
|
||||
# image: meltwater/drone-cache:dev
|
||||
# pull: true
|
||||
# environment:
|
||||
# AWS_ACCESS_KEY_ID:
|
||||
# from_secret: cache_aws_access_key_id
|
||||
# AWS_SECRET_ACCESS_KEY:
|
||||
# from_secret: cache_aws_secret_access_key
|
||||
# settings:
|
||||
# restore: true
|
||||
# bucket: kolaente.dev-drone-dependency-cache
|
||||
# endpoint: https://s3.fr-par.scw.cloud
|
||||
# region: fr-par
|
||||
# path_style: true
|
||||
# cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}'
|
||||
# mount:
|
||||
# - '.cache'
|
||||
|
||||
- name: build
|
||||
image: node:16
|
||||
|
@ -196,8 +215,8 @@ steps:
|
|||
- "echo '{\"VERSION\": \"'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'\"}' > src/version.json"
|
||||
- yarn run build
|
||||
- sed -i 's/http\:\\/\\/localhost\\:3456\\/api\\/v1/\\/api\\/v1/g' dist/index.html # Override the default api url used for developing
|
||||
depends_on:
|
||||
- restore-cache
|
||||
# depends_on:
|
||||
# - restore-cache
|
||||
|
||||
- name: static
|
||||
image: kolaente/zip
|
||||
|
@ -209,7 +228,7 @@ steps:
|
|||
depends_on: [ build ]
|
||||
|
||||
- name: release
|
||||
image: plugins/s3:1
|
||||
image: plugins/s3
|
||||
pull: true
|
||||
settings:
|
||||
bucket: vikunja-releases
|
||||
|
@ -241,23 +260,23 @@ steps:
|
|||
commands:
|
||||
- git fetch --tags
|
||||
|
||||
- name: restore-cache
|
||||
image: meltwater/drone-cache:dev
|
||||
pull: true
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: cache_aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: cache_aws_secret_access_key
|
||||
settings:
|
||||
restore: true
|
||||
bucket: kolaente.dev-drone-dependency-cache
|
||||
endpoint: https://s3.fr-par.scw.cloud
|
||||
region: fr-par
|
||||
path_style: true
|
||||
cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}'
|
||||
mount:
|
||||
- '.cache'
|
||||
# - name: restore-cache
|
||||
# image: meltwater/drone-cache:dev
|
||||
# pull: true
|
||||
# environment:
|
||||
# AWS_ACCESS_KEY_ID:
|
||||
# from_secret: cache_aws_access_key_id
|
||||
# AWS_SECRET_ACCESS_KEY:
|
||||
# from_secret: cache_aws_secret_access_key
|
||||
# settings:
|
||||
# restore: true
|
||||
# bucket: kolaente.dev-drone-dependency-cache
|
||||
# endpoint: https://s3.fr-par.scw.cloud
|
||||
# region: fr-par
|
||||
# path_style: true
|
||||
# cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}'
|
||||
# mount:
|
||||
# - '.cache'
|
||||
|
||||
- name: build
|
||||
image: node:16
|
||||
|
@ -271,8 +290,8 @@ steps:
|
|||
- "echo '{\"VERSION\": \"'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'\"}' > src/version.json"
|
||||
- yarn run build
|
||||
- sed -i 's/http\:\\/\\/localhost\\:3456\\/api\\/v1/\\/api\\/v1/g' dist/index.html # Override the default api url used for developing
|
||||
depends_on:
|
||||
- restore-cache
|
||||
# depends_on:
|
||||
# - restore-cache
|
||||
|
||||
- name: static
|
||||
image: kolaente/zip
|
||||
|
@ -284,7 +303,7 @@ steps:
|
|||
depends_on: [ build ]
|
||||
|
||||
- name: release
|
||||
image: plugins/s3:1
|
||||
image: plugins/s3
|
||||
pull: true
|
||||
settings:
|
||||
bucket: vikunja-releases
|
||||
|
@ -339,9 +358,12 @@ trigger:
|
|||
ref:
|
||||
- refs/heads/main
|
||||
- "refs/tags/**"
|
||||
event:
|
||||
exclude:
|
||||
- cron
|
||||
|
||||
steps:
|
||||
- name: docker-latest
|
||||
- name: docker-unstable
|
||||
image: plugins/docker:linux-arm
|
||||
pull: true
|
||||
settings:
|
||||
|
@ -350,7 +372,7 @@ steps:
|
|||
password:
|
||||
from_secret: docker_password
|
||||
repo: vikunja/frontend
|
||||
tags: latest-linux-arm
|
||||
tags: unstable-linux-arm
|
||||
build_args:
|
||||
- USE_RELEASE=true
|
||||
- RELEASE_VERSION=unstable
|
||||
|
@ -380,7 +402,7 @@ steps:
|
|||
depends_on:
|
||||
- clone
|
||||
|
||||
- name: docker-latest-arm64
|
||||
- name: docker-unstable-arm64
|
||||
image: plugins/docker:linux-arm64
|
||||
pull: true
|
||||
settings:
|
||||
|
@ -389,7 +411,7 @@ steps:
|
|||
password:
|
||||
from_secret: docker_password
|
||||
repo: vikunja/frontend
|
||||
tags: latest-linux-arm64
|
||||
tags: unstable-linux-arm64
|
||||
build_args:
|
||||
- USE_RELEASE=true
|
||||
- RELEASE_VERSION=unstable
|
||||
|
@ -436,9 +458,12 @@ trigger:
|
|||
ref:
|
||||
- refs/heads/main
|
||||
- "refs/tags/**"
|
||||
event:
|
||||
exclude:
|
||||
- cron
|
||||
|
||||
steps:
|
||||
- name: docker-latest
|
||||
- name: docker-unstable
|
||||
image: plugins/docker:linux-amd64
|
||||
pull: true
|
||||
settings:
|
||||
|
@ -447,7 +472,7 @@ steps:
|
|||
password:
|
||||
from_secret: docker_password
|
||||
repo: vikunja/frontend
|
||||
tags: latest-linux-amd64
|
||||
tags: unstable-linux-amd64
|
||||
build_args:
|
||||
- USE_RELEASE=true
|
||||
- RELEASE_VERSION=unstable
|
||||
|
@ -482,18 +507,21 @@ trigger:
|
|||
ref:
|
||||
- refs/heads/main
|
||||
- "refs/tags/**"
|
||||
event:
|
||||
exclude:
|
||||
- cron
|
||||
|
||||
depends_on:
|
||||
- docker-amd64-release
|
||||
- docker-arm-release
|
||||
|
||||
steps:
|
||||
- name: manifest-latest
|
||||
- name: manifest-unstable
|
||||
pull: always
|
||||
image: plugins/manifest
|
||||
settings:
|
||||
tags: latest
|
||||
spec: docker-manifest-latest.tmpl
|
||||
tags: unstable
|
||||
spec: docker-manifest-unstable.tmpl
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -516,6 +544,23 @@ steps:
|
|||
when:
|
||||
ref:
|
||||
- "refs/tags/**"
|
||||
|
||||
- name: manifest-release-latest
|
||||
pull: always
|
||||
image: plugins/manifest
|
||||
depends_on:
|
||||
- clone
|
||||
settings:
|
||||
tags: latest
|
||||
ignore_missing: true
|
||||
spec: docker-manifest.tmpl
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
from_secret: docker_username
|
||||
when:
|
||||
ref:
|
||||
- "refs/tags/**"
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
|
@ -526,6 +571,9 @@ trigger:
|
|||
ref:
|
||||
- refs/heads/main
|
||||
- "refs/tags/**"
|
||||
event:
|
||||
exclude:
|
||||
- cron
|
||||
|
||||
depends_on:
|
||||
- build
|
||||
|
@ -555,14 +603,16 @@ kind: pipeline
|
|||
type: docker
|
||||
name: update-translations
|
||||
|
||||
#depends_on:
|
||||
# - build
|
||||
depends_on:
|
||||
- build
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- push
|
||||
- cron
|
||||
cron:
|
||||
- update_translations
|
||||
|
||||
steps:
|
||||
- name: download
|
||||
|
@ -577,9 +627,19 @@ steps:
|
|||
CROWDIN_KEY:
|
||||
from_secret: crowdin_key
|
||||
|
||||
- name: move-files
|
||||
pull: always
|
||||
image: bash
|
||||
depends_on:
|
||||
- download
|
||||
commands:
|
||||
- mv src/i18n/lang/*/*.json src/i18n/lang
|
||||
|
||||
- name: push
|
||||
pull: always
|
||||
image: appleboy/drone-git-push
|
||||
depends_on:
|
||||
- move-files
|
||||
settings:
|
||||
author_email: "frederik@vikunja.io"
|
||||
author_name: Frederick [Bot]
|
||||
|
@ -593,6 +653,8 @@ steps:
|
|||
- name: upload
|
||||
pull: always
|
||||
image: jonasfranz/crowdin
|
||||
depends_on:
|
||||
- clone
|
||||
settings:
|
||||
files:
|
||||
en.json: src/i18n/lang/en.json
|
||||
|
@ -601,3 +663,8 @@ steps:
|
|||
environment:
|
||||
CROWDIN_KEY:
|
||||
from_secret: crowdin_key
|
||||
---
|
||||
kind: signature
|
||||
hmac: 188ee90100c5fc5922a445e531e7a47453121edddb2a64a182eb23ed2bf602de
|
||||
|
||||
...
|
||||
|
|
|
@ -19,4 +19,11 @@ indent_size = 2
|
|||
|
||||
[*.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
indent_size = 2
|
||||
|
||||
[*.{scss,css}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[.nvmrc]
|
||||
insert_final_newline = false
|
|
@ -26,3 +26,6 @@ stats.html
|
|||
# Test files
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"codezombiech.gitignore",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"editorconfig.editorconfig",
|
||||
"johnsoncodehk.volar",
|
||||
"lokalise.i18n-ally",
|
||||
"mgmcdermott.vscode-language-babel",
|
||||
"mikestead.dotenv",
|
||||
"Syler.sass-indented"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"eslint.packageManager": "yarn",
|
||||
"editor.formatOnSave": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": true
|
||||
},
|
||||
"eslint.format.enable": true,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
|
||||
// https://eslint.vuejs.org/user-guide/#editor-integrations
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"vue"
|
||||
],
|
||||
"vetur.validation.template": false,
|
||||
|
||||
// i18n ally
|
||||
"i18n-ally.localesPaths": [
|
||||
"src/i18n/lang"
|
||||
],
|
||||
"i18n-ally.sortKeys": true,
|
||||
"i18n-ally.keepFulfilled": true,
|
||||
"i18n-ally.keystyle": "nested",
|
||||
}
|
353
CHANGELOG.md
|
@ -2,13 +2,354 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
|
||||
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
All releases can be found on https://code.vikunja.io/frontend/releases.
|
||||
|
||||
The releases aim at the api versions which is why there are missing versions.
|
||||
|
||||
## [0.18.2] - 2021-11-23
|
||||
|
||||
### Fixed
|
||||
|
||||
* fix(docker): properly replace api url
|
||||
* fix: edit saved filter title
|
||||
|
||||
## [0.18.1] - 2021-09-08
|
||||
|
||||
### Added
|
||||
|
||||
* feat: make it possible to fake online state via dev env (#720)
|
||||
|
||||
### Fixed
|
||||
|
||||
* fix: call to /null from background image (#714)
|
||||
* Fix data export download progress
|
||||
* fix: kanban-card mutatation violation (#712)
|
||||
* Fix missing translation when creating a new task on the kanban board
|
||||
* Fix rearranging tasks in a kanban bucket when its limit was reached
|
||||
* Fix sort order for table view
|
||||
* Fix task attributes overridden when saving the task title with enter
|
||||
* Fix translation badge
|
||||
|
||||
### Dependency Updates
|
||||
|
||||
* Update dependency @4tw/cypress-drag-drop to v2 (#711)
|
||||
* Update dependency axios to v0.21.4 (#705)
|
||||
* Update dependency jest to v27.1.1 (#716)
|
||||
* Update dependency vite-plugin-vue2 to v1.8.2 (#707)
|
||||
* Update dependency vite to v2.5.4 (#708)
|
||||
* Update dependency vite to v2.5.5 (#709)
|
||||
* Update typescript-eslint monorepo to v4.31.0 (#706)
|
||||
|
||||
|
||||
## [0.18.0] - 2021-09-05
|
||||
|
||||
### Added
|
||||
|
||||
* Add a button to copy an attachment url from the attachment overview
|
||||
* Add collapsing kanban buckets
|
||||
* Add confirm with enter when setting a new password
|
||||
* Add default list setting & creating tasks from home (#520)
|
||||
* Add depends_on for push step
|
||||
* Add depends_on for upload step
|
||||
* Add drag delay on mobile
|
||||
* Add express for serve:dev
|
||||
* Add filters for quick action bar
|
||||
* Add frontend tests for list history
|
||||
* Add making tasks favorite from the task detail view
|
||||
* Add missing position property to list and bucket models
|
||||
* Add more debug logs for gantt charts
|
||||
* Add more global state tests (#521)
|
||||
* Add proofread languages to available languages
|
||||
* Add quick action bar shortcut to shortcut overview
|
||||
* Add setting for the first day of the week
|
||||
* Add showing version info in GUI
|
||||
* Add syncing translations to crowdin
|
||||
* Add timeout to fix race condition when authenticating as a link share and renewing the token simultaneously
|
||||
* Add translations (#562)
|
||||
* Add typescript support for helper functions (#598)
|
||||
* Add vite (#416)
|
||||
* Allow failure of the weblate update step
|
||||
* Always set the kanban board to full width for share links
|
||||
* Another day, another js date edge-case
|
||||
* Automatically update approved translations from crowdin
|
||||
* Break long list titles in list overview
|
||||
* Preload labels and use locally stored in vuex
|
||||
* PWA improvments (#622)
|
||||
* Quick Actions & global search (#528)
|
||||
* Quick add magic for tasks (#570)
|
||||
* Reorder tasks, lists and kanban buckets (#620)
|
||||
* Show last visited list on home page
|
||||
* Show recently visited lists in quick actions
|
||||
* Show salutation based on the time of day
|
||||
* Sort labels alphabetically on tasks
|
||||
* Switch the :latest docker image tag to contain the latest release instead of the latest unstable
|
||||
|
||||
### Changed
|
||||
|
||||
* Change building latest docker image
|
||||
* Change desktop downstream trigger plugin with our own debug build
|
||||
* Change menu hamburger icon
|
||||
* Change quick add magic characters to be more familiar with the todoist ones
|
||||
* Change the docker builder image to a working one on arm
|
||||
* chore: discard old font file formats (#673)
|
||||
* chore: only import common languages (#671)
|
||||
* Cleanup broken sw functions
|
||||
* Cleanup drone pipeline
|
||||
* Cleanup old vue cli config
|
||||
* Configure tests retries
|
||||
* Decrease page padding on task detail page
|
||||
* Directly redirect to the openid auth provider if that's the only auth method
|
||||
* Don't allow dragging a list when the user does not have the rights
|
||||
* Don't load already loaded task attachments again when saving an edited task description
|
||||
* Don't prefetch all i18n files
|
||||
* Don't show archived lists/namespaces in quick actions
|
||||
* feat: provide global variables in all components (#669)
|
||||
* Hide favorite list edit menu
|
||||
* Hide keyboard shortcuts indicator on mobile
|
||||
* Improve chunk size
|
||||
* Improve some translations (#581)
|
||||
* Improve tests
|
||||
* Indicate done tasks in quick actions
|
||||
* Load list background in list card
|
||||
* Make editor edit button at the bottom the default and make sure the done button stands out more
|
||||
* Make saving a text edit a button
|
||||
* Make sure highlight.js is always lazy-loaded
|
||||
* Make sure the task popup view takes up all the space it can on mobile
|
||||
* Make tests less flaky
|
||||
* Make the logo smaller on link shared lists
|
||||
* Make the progress bar color lighter
|
||||
* Move creation of new items to the bottom of the multiselect list
|
||||
* Move general settings to the top
|
||||
* Move translated files after downloading them
|
||||
* Move weblate ping to shell script
|
||||
* Only add a drag delay if on mobile instead of setting it to 0
|
||||
* Only build a bundle for modern browsers
|
||||
* Refactor success and error messages
|
||||
* Refactor success and error notifications to prevent html in them
|
||||
* Remove logout button for link shares
|
||||
* Run frontend-tests with dist in ci (#605)
|
||||
* Save auth tokens from link shares only in memory, don't persist them to localStorage
|
||||
* Search namespaces locally only when duplicating a list
|
||||
* Show errors from openid provider
|
||||
* Show labels alphabetically sorted in the overview
|
||||
* Small cleanups & code improvements
|
||||
* TOTP UX improvements & translation fixes
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fix changing the repeat mode of a task when no value is entered yet
|
||||
* Fix comment on different task after clicking on a task notification
|
||||
* Fix CTA spacings
|
||||
* Fix date parsing parsing words with weekdays in them (#607)
|
||||
* fix(deps): update dependency marked to v3.0.1 (#677)
|
||||
* fix(deps): update dependency marked to v3.0.2 (#682)
|
||||
* Fix error property already defined as a function
|
||||
* Fix flickering pre-loaded search results when focusing the search input
|
||||
* Fix Gantt layout overflowsing on mobile
|
||||
* Fix gantt months being wrong
|
||||
* Fix git push remote to update crowdin translations
|
||||
* Fix global mutation of has tasks state
|
||||
* Fix header layout for long list titles
|
||||
* Fix highlight.js in editor
|
||||
* Fix home page tests
|
||||
* Fix keyboard shortcuts not working on the task detail page
|
||||
* Fix label changes appearing to be saved immediately when editing them
|
||||
* Fix labels list in saved filter spacing
|
||||
* Fix lint
|
||||
* Fix list archived notification mobile layout
|
||||
* Fix list settings not being available when list backgrounds are disabled
|
||||
* Fix lists showing up multiple times in history
|
||||
* Fix llama background url
|
||||
* Fix loading a list when it was already partially saved in vuex
|
||||
* Fix loading & disabled state on inputs when creating a new task
|
||||
* Fix loading labels when editing a saved filter
|
||||
* Fix menu styles
|
||||
* Fix missing background for tasks on a shared list with a background
|
||||
* Fix multiselect search padding
|
||||
* Fix new lists created with quick actions not showing up in the menu
|
||||
* fix: non unique ids (#672)
|
||||
* Fix not reloading tasks of a saved filter after editing it
|
||||
* Fix not updating list name in store when changing it
|
||||
* Fix other values getting pushed away when creating a new one through multiselect
|
||||
* Fix padding for kanban cards
|
||||
* Fix parsing dates on the last day of the month
|
||||
* Fix populating task details ater updating the description
|
||||
* Fix quick actions not opening
|
||||
* Fix quick actions not working when nonexisting lists where left over in history
|
||||
* Fix redirecting to /login for some routes
|
||||
* Fix removing a namespace from state after it was deleted
|
||||
* Fix resetting date filters from upcoming after viewing a task detail page (popup)
|
||||
* Fix sass division
|
||||
* Fix saving showing archived setting
|
||||
* Fix selecting a single value from multiselect
|
||||
* Fix sending openid scopes when authenticating
|
||||
* Fix sending the user back to the list view they came from when opening a task in detail view
|
||||
* Fix setting a task as favorite button
|
||||
* Fix setting delete button for newly created task comments
|
||||
* Fix setting filters for reminders
|
||||
* Fix setting secret for updating translations
|
||||
* Fix setting task favorite status in test fixtures
|
||||
* Fix showing an editor save button in cases where it wasn't required
|
||||
* Fix showing edit buttons when the user does not have the rights to use them
|
||||
* Fix showing import tasks cta when tasks are loading
|
||||
* Fix some translation strings
|
||||
* Fix sorting labels
|
||||
* Fix spacing for task detail view in lists with a background
|
||||
* Fix table headers wrapping in table view
|
||||
* Fix table text alignment in task detail page
|
||||
* Fix table view scrolling on mobile
|
||||
* Fix test for saving a task description
|
||||
* Fix tests failing on thursdays
|
||||
* Fix token in storage not getting renewed
|
||||
* Fix translating dates
|
||||
* Fix usage of / in sass
|
||||
* Fix user name and avatar alignment in navbar
|
||||
* Fix users not removed from the list in settings when unshared
|
||||
* Fix user test fixtures
|
||||
* fix: vuex mutation violation from draggable (#674)
|
||||
|
||||
### Dependency Updates
|
||||
|
||||
* chore(deps): update dependency @4tw/cypress-drag-drop to v1.8.1 (#693)
|
||||
* chore(deps): update dependency autoprefixer to v10.3.3 (#684)
|
||||
* chore(deps): update dependency autoprefixer to v10.3.4 (#697)
|
||||
* chore(deps): update dependency axios to v0.21.2 (#698)
|
||||
* chore(deps): update dependency axios to v0.21.3 (#700)
|
||||
* chore(deps): update dependency cypress to v8.3.1 (#689)
|
||||
* chore(deps): update dependency esbuild to v0.12.23 (#683)
|
||||
* chore(deps): update dependency esbuild to v0.12.24 (#688)
|
||||
* chore(deps): update dependency esbuild to v0.12.25 (#696)
|
||||
* chore(deps): update dependency eslint-plugin-vue to v7.17.0 (#686)
|
||||
* chore(deps): update dependency jest to v27.1.0 (#687)
|
||||
* chore(deps): update dependency sass to v1.38.1 (#679)
|
||||
* chore(deps): update dependency sass to v1.38.2 (#690)
|
||||
* chore(deps): update dependency sass to v1.39.0 (#695)
|
||||
* chore(deps): update dependency typescript to v4.4.2 (#685)
|
||||
* chore(deps): update dependency vite-plugin-pwa to v0.11.2 (#681)
|
||||
* chore(deps): update dependency vite to v2.5.1 (#680)
|
||||
* chore(deps): update dependency vite to v2.5.2 (#692)
|
||||
* chore(deps): update dependency vite to v2.5.3 (#694)
|
||||
* chore(deps): update typescript-eslint monorepo to v4.29.3 (#676)
|
||||
* chore(deps): update typescript-eslint monorepo to v4.30.0 (#691)
|
||||
* Update dependency autoprefixer to v10.3.2 (#670)
|
||||
* Update dependency browserslist to v4.16.7 (#634)
|
||||
* Update dependency browserslist to v4.16.8 (#664)
|
||||
* Update dependency browserslist to v4.17.0 (#701)
|
||||
* Update dependency bulma to v0.9.3 (#554)
|
||||
* Update dependency cypress-file-upload to v5.0.8 (#556)
|
||||
* Update dependency cypress to v7.3.0 (#507)
|
||||
* Update dependency cypress to v7.4.0 (#517)
|
||||
* Update dependency cypress to v7.5.0 (#541)
|
||||
* Update dependency cypress to v7.6.0 (#561)
|
||||
* Update dependency cypress to v7.7.0 (#577)
|
||||
* Update dependency cypress to v8.1.0 (#624)
|
||||
* Update dependency cypress to v8.2.0 (#637)
|
||||
* Update dependency cypress to v8.3.0 (#660)
|
||||
* Update dependency cypress to v8 (#601)
|
||||
* Update dependency date-fns to v2.22.0 (#523)
|
||||
* Update dependency date-fns to v2.22.1 (#524)
|
||||
* Update dependency date-fns to v2.23.0 (#604)
|
||||
* Update dependency dompurify to v2.2.9 (#529)
|
||||
* Update dependency dompurify to v2.3.0 (#573)
|
||||
* Update dependency dompurify to v2.3.1 (#655)
|
||||
* Update dependency esbuild to v0.12.15 (#610)
|
||||
* Update dependency esbuild to v0.12.16 (#614)
|
||||
* Update dependency esbuild to v0.12.17 (#623)
|
||||
* Update dependency esbuild to v0.12.18 (#638)
|
||||
* Update dependency esbuild to v0.12.19 (#643)
|
||||
* Update dependency esbuild to v0.12.20 (#654)
|
||||
* Update dependency esbuild to v0.12.21 (#666)
|
||||
* Update dependency esbuild to v0.12.22 (#668)
|
||||
* Update dependency eslint-plugin-vue to v7.10.0 (#525)
|
||||
* Update dependency eslint-plugin-vue to v7.11.0 (#547)
|
||||
* Update dependency eslint-plugin-vue to v7.11.1 (#548)
|
||||
* Update dependency eslint-plugin-vue to v7.12.1 (#565)
|
||||
* Update dependency eslint-plugin-vue to v7.13.0 (#574)
|
||||
* Update dependency eslint-plugin-vue to v7.14.0 (#597)
|
||||
* Update dependency eslint-plugin-vue to v7.15.0 (#625)
|
||||
* Update dependency eslint-plugin-vue to v7.15.1 (#633)
|
||||
* Update dependency eslint-plugin-vue to v7.16.0 (#648)
|
||||
* Update dependency eslint to v7.27.0 (#514)
|
||||
* Update dependency eslint to v7.28.0 (#539)
|
||||
* Update dependency eslint to v7.29.0 (#555)
|
||||
* Update dependency eslint to v7.30.0 (#571)
|
||||
* Update dependency eslint to v7.31.0 (#596)
|
||||
* Update dependency eslint to v7.32.0 (#627)
|
||||
* Update dependency highlight.js to v11.0.1 (#538)
|
||||
* Update dependency highlight.js to v11.1.0 (#582)
|
||||
* Update dependency highlight.js to v11.2.0 (#630)
|
||||
* Update dependency highlight.js to v11 (#527)
|
||||
* Update dependency jest to v27.0.3 (#526)
|
||||
* Update dependency jest to v27.0.4 (#535)
|
||||
* Update dependency jest to v27.0.5 (#558)
|
||||
* Update dependency jest to v27.0.6 (#569)
|
||||
* Update dependency jest to v27 (#519)
|
||||
* Update dependency marked to v2.0.4 (#510)
|
||||
* Update dependency marked to v2.0.5 (#513)
|
||||
* Update dependency marked to v2.0.6 (#522)
|
||||
* Update dependency marked to v2.0.7 (#532)
|
||||
* Update dependency marked to v2.1.0 (#552)
|
||||
* Update dependency marked to v2.1.1 (#553)
|
||||
* Update dependency marked to v2.1.2 (#559)
|
||||
* Update dependency marked to v2.1.3 (#567)
|
||||
* Update dependency marked to v3 (#657)
|
||||
* Update dependency @rollup/plugin-commonjs to v19.0.2 (#617)
|
||||
* Update dependency sass to v1.33.0 (#512)
|
||||
* Update dependency sass to v1.34.0 (#515)
|
||||
* Update dependency sass to v1.34.1 (#534)
|
||||
* Update dependency sass to v1.35.0 (#550)
|
||||
* Update dependency sass to v1.35.1 (#551)
|
||||
* Update dependency sass to v1.35.2 (#579)
|
||||
* Update dependency sass to v1.36.0 (#606)
|
||||
* Update dependency sass to v1.37.0 (#628)
|
||||
* Update dependency sass to v1.37.2 (#632)
|
||||
* Update dependency sass to v1.37.5 (#635)
|
||||
* Update dependency sass to v1.38.0 (#661)
|
||||
* Update dependency ts-jest to v27.0.4 (#602)
|
||||
* Update dependency ts-jest to v27.0.5 (#662)
|
||||
* Update dependency @types/jest to v27.0.1 (#653)
|
||||
* Update dependency @types/jest to v27 (#650)
|
||||
* Update dependency vite-plugin-pwa to v0.10.0 (#644)
|
||||
* Update dependency vite-plugin-pwa to v0.11.0 (#667)
|
||||
* Update dependency vite-plugin-pwa to v0.8.2 (#612)
|
||||
* Update dependency vite-plugin-pwa to v0.9.3 (#629)
|
||||
* Update dependency vite-plugin-vue2 to v1.7.3 (#613)
|
||||
* Update dependency vite-plugin-vue2 to v1.8.0 (#646)
|
||||
* Update dependency vite-plugin-vue2 to v1.8.1 (#656)
|
||||
* Update dependency vite to v2.4.3 (#611)
|
||||
* Update dependency vite to v2.4.4 (#619)
|
||||
* Update dependency vite to v2.5.0 (#658)
|
||||
* Update dependency vue-advanced-cropper to v1.6.0 (#516)
|
||||
* Update dependency vue-advanced-cropper to v1.7.0 (#543)
|
||||
* Update dependency vue-advanced-cropper to v1.8.0 (#641)
|
||||
* Update dependency vue-advanced-cropper to v1.8.1 (#642)
|
||||
* Update dependency vue-advanced-cropper to v1.8.2 (#645)
|
||||
* Update dependency vue-flatpickr-component to v8.1.7 (#572)
|
||||
* Update dependency vue-i18n to v8.24.5 (#564)
|
||||
* Update dependency vue-i18n to v8.25.0 (#595)
|
||||
* Update dependency vue-router to v3.5.2 (#557)
|
||||
* Update dependency wait-on to v6 (#568)
|
||||
* Update dependency workbox-cli to v6.1.5 (#609)
|
||||
* Update Font Awesome (#636)
|
||||
* Update Node.js (#549)
|
||||
* Update Node.js to v16.4.1 (#576)
|
||||
* Update Node.js to v16.4.2 (#578)
|
||||
* Update typescript-eslint monorepo to v4.28.4 (#600)
|
||||
* Update typescript-eslint monorepo to v4.28.5 (#618)
|
||||
* Update typescript-eslint monorepo to v4.29.0 (#631)
|
||||
* Update typescript-eslint monorepo to v4.29.1 (#647)
|
||||
* Update typescript-eslint monorepo to v4.29.2 (#659)
|
||||
* Update vue monorepo to v2.6.13 (#530)
|
||||
* Update vue monorepo to v2.6.14 (#540)
|
||||
* Update workbox monorepo to v6.2.0 (#639)
|
||||
* Update workbox monorepo to v6.2.2 (#640)
|
||||
* Update workbox monorepo to v6.2.4 (#649)
|
||||
* User account deletion (#651)
|
||||
* User Data Export and import (#699)
|
||||
|
||||
## [0.17.0 - 2021-05-14]
|
||||
|
||||
### Added
|
||||
|
@ -148,7 +489,8 @@ The releases aim at the api versions which is why there are missing versions.
|
|||
* Make sure all arm64 build steps run in parallel
|
||||
* Make sure all empty pages have a call to action
|
||||
* Make sure all popups & dropdowns are animated
|
||||
* Make sure attachements are only added once to the list after uploading + Make sure the attachment list shows up every time after adding an attachment
|
||||
* Make sure attachements are only added once to the list after uploading + Make sure the attachment list shows up every
|
||||
time after adding an attachment
|
||||
* Make sure no cta's are visible while the page is loading
|
||||
* Make sure the loading spinner is always visible at the end of the page
|
||||
* Make the button shadow lighter
|
||||
|
@ -675,7 +1017,7 @@ The releases aim at the api versions which is why there are missing versions.
|
|||
* Hide totp settings if it is disabled server side
|
||||
* Increase network timeout when building docker image
|
||||
* Make sure the version includes the tag when building docker images
|
||||
* #PrideMonth
|
||||
* # PrideMonth
|
||||
* Only renew user token on tab focus events
|
||||
* Redirect the user to login page if the token expired when the tab gets focus again
|
||||
* Remove title length restrictions
|
||||
|
@ -710,7 +1052,7 @@ The releases aim at the api versions which is why there are missing versions.
|
|||
|
||||
## [0.13] - 2020-05-12
|
||||
|
||||
#### Added
|
||||
#### Added
|
||||
|
||||
* Add docker run script to change api url on startup
|
||||
* Add github token for renovate (#89)
|
||||
|
@ -1055,6 +1397,7 @@ The releases aim at the api versions which is why there are missing versions.
|
|||
* Use email instead of username when resetting a password
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed trying to verify an email when there was none
|
||||
* Fixed loading tasks when the user was not authenticated
|
||||
|
||||
|
|
|
@ -24,12 +24,6 @@ RUN \
|
|||
# Stage 2: copy
|
||||
FROM nginx
|
||||
|
||||
RUN apt-get update && apt-get install -y apt-utils openssl && \
|
||||
mkdir -p /etc/nginx/ssl && \
|
||||
openssl genrsa -out /etc/nginx/ssl/dummy.key 2048 && \
|
||||
openssl req -new -key /etc/nginx/ssl/dummy.key -out /etc/nginx/ssl/dummy.csr -subj "/C=DE/L=Berlin/O=Vikunja/CN=Vikunja Snakeoil" && \
|
||||
openssl x509 -req -days 3650 -in /etc/nginx/ssl/dummy.csr -signkey /etc/nginx/ssl/dummy.key -out /etc/nginx/ssl/dummy.crt
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
COPY run.sh /run.sh
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
[![Build Status](https://drone.kolaente.de/api/badges/vikunja/frontend/status.svg)](https://drone.kolaente.de/vikunja/frontend)
|
||||
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](LICENSE)
|
||||
[![Download](https://img.shields.io/badge/download-v0.17.0-brightgreen.svg)](https://dl.vikunja.io)
|
||||
[![Translation](https://hosted.weblate.org/widgets/vikunja/-/frontend/svg-badge.svg)](https://hosted.weblate.org/engage/vikunja/)
|
||||
[![Download](https://img.shields.io/badge/download-v0.18.2-brightgreen.svg)](https://dl.vikunja.io)
|
||||
[![Translation](https://badges.crowdin.net/vikunja/localized.svg)](https://crowdin.com/project/vikunja)
|
||||
|
||||
This is the web frontend for Vikunja, written in Vue.js.
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app',
|
||||
],
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
"baseUrl": "http://localhost:5000",
|
||||
"env": {
|
||||
"API_URL": "http://localhost:3456/api/v1",
|
||||
"TEST_SECRET": "testingS3cr3et"
|
||||
"TEST_SECRET": "averyLongSecretToSe33dtheDB"
|
||||
},
|
||||
"video": false,
|
||||
"retries": {
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
## Fixtures
|
||||
|
||||
We're using the [test endpoint](https://vikunja.io/docs/config-options/#testingtoken) of the vikunja api to
|
||||
seed the database with test data before running the tests.
|
||||
We're using the [test endpoint](https://vikunja.io/docs/config-options/#testingtoken) of the vikunja api to
|
||||
seed the database with test data before running the tests.
|
||||
This ensures better reproducability of tests.
|
||||
|
||||
## Running The Tests Locally
|
||||
|
@ -22,20 +22,20 @@ It uses the same configuration as the CI.
|
|||
|
||||
To use it, run
|
||||
|
||||
```
|
||||
```shell
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Then, once all containers are started, run
|
||||
|
||||
```
|
||||
docker-composer run cypress bash
|
||||
```shell
|
||||
docker-compose run cypress bash
|
||||
```
|
||||
|
||||
to get a shell inside the cypress container.
|
||||
In that shell you can then execute the tests with
|
||||
|
||||
```
|
||||
```shell
|
||||
yarn test:frontend
|
||||
```
|
||||
|
||||
|
@ -43,6 +43,6 @@ yarn test:frontend
|
|||
|
||||
To open the Cypress Dashboard and run tests from there, run
|
||||
|
||||
```
|
||||
```shell
|
||||
yarn cypress:open
|
||||
```
|
||||
|
|
|
@ -2,10 +2,12 @@ version: '3'
|
|||
|
||||
services:
|
||||
api:
|
||||
image: vikunja/api
|
||||
image: vikunja/api:unstable
|
||||
environment:
|
||||
VIKUNJA_LOG_LEVEL: DEBUG
|
||||
VIKUNJA_SERVICE_TESTINGTOKEN: averyLongSecretToSe33dtheDB
|
||||
ports:
|
||||
- 3456:3456
|
||||
cypress:
|
||||
image: cypress/browsers:node12.18.3-chrome87-ff82
|
||||
volumes:
|
||||
|
|
|
@ -11,7 +11,7 @@ export class UserFactory extends Factory {
|
|||
|
||||
return {
|
||||
id: '{increment}',
|
||||
username: faker.lorem.word(10) + faker.random.uuid(),
|
||||
username: faker.lorem.word(10) + faker.datatype.uuid(),
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.', // 1234
|
||||
status: 0,
|
||||
created: formatISO(now),
|
||||
|
|
|
@ -31,15 +31,14 @@ describe('Lists', () => {
|
|||
cy.url()
|
||||
.should('contain', '/namespaces/1/list')
|
||||
cy.get('.card-header-title')
|
||||
.contains('Create a new list')
|
||||
.contains('New list')
|
||||
cy.get('input.input')
|
||||
.type('New List')
|
||||
cy.get('.button')
|
||||
.contains('Create')
|
||||
.click()
|
||||
|
||||
cy.wait(1000) // Waiting until the request to create the new list is done
|
||||
cy.get('.global-notification')
|
||||
cy.get('.global-notification', { timeout: 1000 }) // Waiting until the request to create the new list is done
|
||||
.should('contain', 'Success')
|
||||
cy.url()
|
||||
.should('contain', '/lists/')
|
||||
|
@ -102,7 +101,7 @@ describe('Lists', () => {
|
|||
.click()
|
||||
cy.url()
|
||||
.should('contain', '/settings/delete')
|
||||
cy.get('.modal-mask .modal-container .modal-content .actions a.button')
|
||||
cy.get('[data-cy="modalPrimary"]')
|
||||
.contains('Do it')
|
||||
.click()
|
||||
|
||||
|
@ -220,10 +219,10 @@ describe('Lists', () => {
|
|||
cy.get('.table-view .filter-container .items .button')
|
||||
.contains('Columns')
|
||||
.click()
|
||||
cy.get('.table-view .filter-container .card .card-content .fancycheckbox .check')
|
||||
cy.get('.table-view .filter-container .card.columns-filter .card-content .fancycheckbox .check')
|
||||
.contains('Priority')
|
||||
.click()
|
||||
cy.get('.table-view .filter-container .card .card-content .fancycheckbox .check')
|
||||
cy.get('.table-view .filter-container .card.columns-filter .card-content .fancycheckbox .check')
|
||||
.contains('Done')
|
||||
.click()
|
||||
|
||||
|
@ -393,7 +392,7 @@ describe('Lists', () => {
|
|||
cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item .field input.input')
|
||||
.first()
|
||||
.type(3)
|
||||
cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item .field a.button.is-primary')
|
||||
cy.get('[data-cy="setBucketLimit"]')
|
||||
.first()
|
||||
.click()
|
||||
|
||||
|
@ -446,7 +445,7 @@ describe('Lists', () => {
|
|||
cy.get('.kanban .bucket .tasks .task')
|
||||
.contains(tasks[0].title)
|
||||
.first()
|
||||
.drag('.kanban .bucket:nth-child(2) .tasks .dropper div')
|
||||
.drag('.kanban .bucket:nth-child(2) .tasks .dropper')
|
||||
|
||||
cy.get('.kanban .bucket:nth-child(2) .tasks')
|
||||
.should('contain', tasks[0].title)
|
||||
|
@ -501,7 +500,7 @@ describe('Lists', () => {
|
|||
.first()
|
||||
.click()
|
||||
|
||||
cy.get('.global-notification')
|
||||
cy.get('.global-notification', { timeout: 1000 })
|
||||
.should('contain', 'Success')
|
||||
cy.go('back')
|
||||
cy.get('.kanban .bucket')
|
||||
|
|
|
@ -15,7 +15,7 @@ describe('Namepaces', () => {
|
|||
|
||||
it('Should be all there', () => {
|
||||
cy.visit('/namespaces')
|
||||
cy.get('.namespace h1 span')
|
||||
cy.get('[data-cy="namespace-title"]')
|
||||
.should('contain', namespaces[0].title)
|
||||
})
|
||||
|
||||
|
@ -23,14 +23,14 @@ describe('Namepaces', () => {
|
|||
const newNamespaceTitle = 'New Namespace'
|
||||
|
||||
cy.visit('/namespaces')
|
||||
cy.get('a.button')
|
||||
.contains('Create a new namespace')
|
||||
cy.get('[data-cy="new-namespace"]')
|
||||
.should('contain', 'New namespace')
|
||||
.click()
|
||||
|
||||
cy.url()
|
||||
.should('contain', '/namespaces/new')
|
||||
cy.get('.card-header-title')
|
||||
.should('contain', 'Create a new namespace')
|
||||
.should('contain', 'New namespace')
|
||||
cy.get('input.input')
|
||||
.type(newNamespaceTitle)
|
||||
cy.get('.button')
|
||||
|
@ -67,12 +67,12 @@ describe('Namepaces', () => {
|
|||
.contains('Save')
|
||||
.click()
|
||||
|
||||
cy.get('.global-notification')
|
||||
cy.get('.global-notification', { timeout: 1000 })
|
||||
.should('contain', 'Success')
|
||||
cy.get('.namespace-container .menu.namespaces-lists')
|
||||
.should('contain', newNamespaceName)
|
||||
.should('not.contain', newNamespaces[0].title)
|
||||
cy.get('.content.namespaces-list')
|
||||
cy.get('[data-cy="namespaces-list"]')
|
||||
.should('contain', newNamespaceName)
|
||||
.should('not.contain', newNamespaces[0].title)
|
||||
})
|
||||
|
@ -89,7 +89,7 @@ describe('Namepaces', () => {
|
|||
.click()
|
||||
cy.url()
|
||||
.should('contain', '/settings/delete')
|
||||
cy.get('.modal-mask .modal-container .modal-content .actions a.button')
|
||||
cy.get('[data-cy="modalPrimary"]')
|
||||
.contains('Do it')
|
||||
.click()
|
||||
|
||||
|
@ -116,30 +116,30 @@ describe('Namepaces', () => {
|
|||
|
||||
// Initial
|
||||
cy.visit('/namespaces')
|
||||
cy.get('.namespaces-list .namespace')
|
||||
cy.get('.namespace')
|
||||
.should('not.contain', 'Archived')
|
||||
|
||||
// Show archived
|
||||
cy.get('.namespaces-list .fancycheckbox.show-archived-check label.check span')
|
||||
cy.get('[data-cy="show-archived-check"] label.check span')
|
||||
.should('be.visible')
|
||||
.click()
|
||||
cy.get('.namespaces-list .fancycheckbox.show-archived-check input')
|
||||
cy.get('[data-cy="show-archived-check"] input')
|
||||
.should('be.checked')
|
||||
cy.get('.namespaces-list .namespace')
|
||||
cy.get('.namespace')
|
||||
.should('contain', 'Archived')
|
||||
|
||||
// Don't show archived
|
||||
cy.get('.namespaces-list .fancycheckbox.show-archived-check label.check span')
|
||||
cy.get('[data-cy="show-archived-check"] label.check span')
|
||||
.should('be.visible')
|
||||
.click()
|
||||
cy.get('.namespaces-list .fancycheckbox.show-archived-check input')
|
||||
cy.get('[data-cy="show-archived-check"] input')
|
||||
.should('not.be.checked')
|
||||
|
||||
// Second time visiting after unchecking
|
||||
cy.visit('/namespaces')
|
||||
cy.get('.namespaces-list .fancycheckbox.show-archived-check input')
|
||||
cy.get('[data-cy="show-archived-check"] input')
|
||||
.should('not.be.checked')
|
||||
cy.get('.namespaces-list .namespace')
|
||||
cy.get('.namespace')
|
||||
.should('not.contain', 'Archived')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
import '../../support/authenticateUser'
|
||||
|
||||
const setHours = hours => {
|
||||
const date = new Date()
|
||||
date.setHours(hours)
|
||||
cy.clock(+date)
|
||||
}
|
||||
|
||||
describe('Home Page', () => {
|
||||
it('shows the right salutation in the night', () => {
|
||||
setHours(4)
|
||||
cy.visit('/')
|
||||
cy.get('h2').should('contain', 'Good Night')
|
||||
})
|
||||
it('shows the right salutation in the morning', () => {
|
||||
setHours(8)
|
||||
cy.visit('/')
|
||||
cy.get('h2').should('contain', 'Good Morning')
|
||||
})
|
||||
it('shows the right salutation in the day', () => {
|
||||
setHours(13)
|
||||
cy.visit('/')
|
||||
cy.get('h2').should('contain', 'Hi')
|
||||
})
|
||||
it('shows the right salutation in the night', () => {
|
||||
setHours(20)
|
||||
cy.visit('/')
|
||||
cy.get('h2').should('contain', 'Good Evening')
|
||||
})
|
||||
it('shows the right salutation in the night again', () => {
|
||||
setHours(23)
|
||||
cy.visit('/')
|
||||
cy.get('h2').should('contain', 'Good Night')
|
||||
})
|
||||
})
|
|
@ -7,7 +7,7 @@ describe('The Menu', () => {
|
|||
})
|
||||
|
||||
it('Can be hidden on desktop', () => {
|
||||
cy.get('a.menu-show-button:visible')
|
||||
cy.get('button.menu-show-button:visible')
|
||||
.click()
|
||||
cy.get('.namespace-container')
|
||||
.should('not.have.class', 'is-active')
|
||||
|
@ -21,7 +21,7 @@ describe('The Menu', () => {
|
|||
|
||||
it('Is can be shown on mobile', () => {
|
||||
cy.viewport('iphone-8')
|
||||
cy.get('a.menu-show-button:visible')
|
||||
cy.get('button.menu-show-button:visible')
|
||||
.click()
|
||||
cy.get('.namespace-container')
|
||||
.should('have.class', 'is-active')
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('Task', () => {
|
|||
|
||||
it('Should be created new', () => {
|
||||
cy.visit('/lists/1/list')
|
||||
cy.get('input.input[placeholder="Add a new task…"')
|
||||
cy.get('.input[placeholder="Add a new task…"')
|
||||
.type('New Task')
|
||||
cy.get('.button')
|
||||
.contains('Add')
|
||||
|
@ -43,7 +43,7 @@ describe('Task', () => {
|
|||
cy.visit('/lists/1/list')
|
||||
cy.get('.list-is-empty-notice')
|
||||
.should('not.exist')
|
||||
cy.get('input.input[placeholder="Add a new task…"')
|
||||
cy.get('.input[placeholder="Add a new task…"')
|
||||
.type('New Task')
|
||||
cy.get('.button')
|
||||
.contains('Add')
|
||||
|
@ -128,7 +128,7 @@ describe('Task', () => {
|
|||
cy.visit(`/tasks/${tasks[0].id}`)
|
||||
|
||||
cy.get('.task-view .action-buttons .button')
|
||||
.contains('Done!')
|
||||
.contains('Mark task done!')
|
||||
.click()
|
||||
|
||||
cy.get('.task-view .heading .is-done')
|
||||
|
@ -168,7 +168,7 @@ describe('Task', () => {
|
|||
.click()
|
||||
cy.get('.task-view .details.content.description .editor .vue-easymde .EasyMDEContainer .CodeMirror-scroll')
|
||||
.type('{selectall}New Description')
|
||||
cy.get('.task-view .details.content.description .editor a')
|
||||
cy.get('[data-cy="saveEditor"]')
|
||||
.contains('Save')
|
||||
.click()
|
||||
|
||||
|
@ -263,8 +263,7 @@ describe('Task', () => {
|
|||
|
||||
cy.visit(`/tasks/${tasks[0].id}`)
|
||||
|
||||
cy.get('.task-view .action-buttons .button')
|
||||
.contains('Assign this task to a user')
|
||||
cy.get('[data-cy="taskDetail.assign"]')
|
||||
.click()
|
||||
cy.get('.task-view .column.assignees .multiselect input')
|
||||
.type(users[1].username)
|
||||
|
@ -353,7 +352,7 @@ describe('Task', () => {
|
|||
.first()
|
||||
.click()
|
||||
|
||||
cy.get('.global-notification')
|
||||
cy.get('.global-notification', { timeout: 4000 })
|
||||
.should('contain', 'Success')
|
||||
cy.get('.task-view .details.labels-list .multiselect .input-wrapper span.tag')
|
||||
.should('exist')
|
||||
|
@ -405,7 +404,7 @@ describe('Task', () => {
|
|||
cy.get('.datepicker .datepicker-popup a')
|
||||
.contains('Tomorrow')
|
||||
.click()
|
||||
cy.get('.datepicker .datepicker-popup a.button')
|
||||
cy.get('[data-cy="closeDatepicker"]')
|
||||
.contains('Confirm')
|
||||
.click()
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ const testAndAssertFailed = fixture => {
|
|||
|
||||
cy.wait(5000) // It can take waaaayy too long to log the user in
|
||||
cy.url().should('include', '/')
|
||||
cy.get('div.notification.is-danger').contains('Wrong username or password.')
|
||||
cy.get('div.message.danger').contains('Wrong username or password.')
|
||||
}
|
||||
|
||||
context('Login', () => {
|
||||
|
|
|
@ -24,15 +24,15 @@ context('Registration', () => {
|
|||
cy.visit('/register')
|
||||
cy.get('#username').type(fixture.username)
|
||||
cy.get('#email').type(fixture.email)
|
||||
cy.get('#password1').type(fixture.password)
|
||||
cy.get('#password2').type(fixture.password)
|
||||
cy.get('#password').type(fixture.password)
|
||||
cy.get('#passwordValidation').type(fixture.password)
|
||||
cy.get('#register-submit').click()
|
||||
cy.url().should('include', '/')
|
||||
cy.clock(1625656161057) // 13:00
|
||||
cy.get('h2').should('contain', `Hi ${fixture.username}!`)
|
||||
})
|
||||
|
||||
it('Should fail', () => {
|
||||
it.only('Should fail', () => {
|
||||
const fixture = {
|
||||
username: 'test',
|
||||
password: '123456',
|
||||
|
@ -42,9 +42,9 @@ context('Registration', () => {
|
|||
cy.visit('/register')
|
||||
cy.get('#username').type(fixture.username)
|
||||
cy.get('#email').type(fixture.email)
|
||||
cy.get('#password1').type(fixture.password)
|
||||
cy.get('#password2').type(fixture.password)
|
||||
cy.get('#password').type(fixture.password)
|
||||
cy.get('#passwordValidation').type(fixture.password)
|
||||
cy.get('#register-submit').click()
|
||||
cy.get('div.notification.is-danger').contains('A user with this username already exists.')
|
||||
cy.get('div.message.danger').contains('A user with this username already exists.')
|
||||
})
|
||||
})
|
|
@ -8,17 +8,17 @@ describe('User Settings', () => {
|
|||
})
|
||||
|
||||
it('Changes the user avatar', () => {
|
||||
cy.visit('/user/settings')
|
||||
cy.visit('/user/settings/avatar')
|
||||
|
||||
cy.get('input[name=avatarProvider][value=upload]')
|
||||
.click()
|
||||
cy.get('input[type=file]')
|
||||
cy.get('input[type=file]', { timeout: 1000 })
|
||||
.attachFile('image.jpg')
|
||||
cy.get('.vue-handler-wrapper.vue-handler-wrapper--south .vue-simple-handler.vue-simple-handler--south')
|
||||
.trigger('mousedown', {which: 1})
|
||||
.trigger('mousemove', {clientY: 100})
|
||||
.trigger('mouseup')
|
||||
cy.get('a.button.is-primary')
|
||||
cy.get('[data-cy="uploadAvatar"]')
|
||||
.contains('Upload Avatar')
|
||||
.click()
|
||||
|
||||
|
@ -28,11 +28,12 @@ describe('User Settings', () => {
|
|||
})
|
||||
|
||||
it('Updates the name', () => {
|
||||
cy.visit('/user/settings')
|
||||
cy.visit('/user/settings/general')
|
||||
|
||||
cy.get('input#newName')
|
||||
cy.get('.general-settings .control input.input')
|
||||
.first()
|
||||
.type('Lorem Ipsum')
|
||||
cy.get('.card.general-settings .button.is-primary')
|
||||
cy.get('[data-cy="saveGeneralSettings"]')
|
||||
.contains('Save')
|
||||
.click()
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {seed} from './seed'
|
||||
import merge from 'lodash/merge'
|
||||
|
||||
/**
|
||||
* A factory makes it easy to seed the database with data.
|
||||
|
@ -25,7 +24,10 @@ export class Factory {
|
|||
const data = []
|
||||
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const entry = merge(this.factory(), override)
|
||||
const entry = {
|
||||
...this.factory(),
|
||||
...override,
|
||||
}
|
||||
for (const e in entry) {
|
||||
if(typeof entry[e] === 'function') {
|
||||
entry[e] = entry[e](i)
|
||||
|
|
|
@ -2,3 +2,10 @@
|
|||
import './commands'
|
||||
import 'cypress-file-upload'
|
||||
import '@4tw/cypress-drag-drop'
|
||||
|
||||
// see https://github.com/cypress-io/cypress/issues/702#issuecomment-587127275
|
||||
Cypress.on('window:before:load', (win) => {
|
||||
// disable service workers
|
||||
// @ts-ignore
|
||||
delete win.navigator.__proto__.ServiceWorker
|
||||
})
|
|
@ -1,17 +1,17 @@
|
|||
image: vikunja/frontend:latest
|
||||
image: vikunja/frontend:unstable
|
||||
manifests:
|
||||
-
|
||||
image: vikunja/frontend:latest-linux-amd64
|
||||
image: vikunja/frontend:unstable-linux-amd64
|
||||
platform:
|
||||
architecture: amd64
|
||||
os: linux
|
||||
-
|
||||
image: vikunja/frontend:latest-linux-arm64
|
||||
image: vikunja/frontend:unstable-linux-arm64
|
||||
platform:
|
||||
architecture: arm64
|
||||
os: linux
|
||||
-
|
||||
image: vikunja/frontend:latest-linux-arm
|
||||
image: vikunja/frontend:unstable-linux-arm
|
||||
platform:
|
||||
architecture: arm
|
||||
os: linux
|
|
@ -12,7 +12,6 @@
|
|||
<link rel="apple-touch-icon" href="/images/icons/apple-touch-icon-180x180.png"/>
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/open-sans-v15-latin-700italic.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/open-sans-v15-latin-italic.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/quicksand-v7-latin-300.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/quicksand-v7-latin-500.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/quicksand-v7-latin-700.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/open-sans-v15-latin-regular.woff2" as="font">
|
||||
|
@ -31,7 +30,10 @@
|
|||
// It has to be the full url, including the last /api/v1 part and port.
|
||||
// You can change this if your api is not reachable on the same port as the frontend.
|
||||
window.API_URL = 'http://localhost:3456/api/v1'
|
||||
//
|
||||
// Enable error tracking with sentry. If this is set to true, will send anonymized data to
|
||||
// our sentry instance to notify us of potential problems.
|
||||
window.SENTRY_ENABLED = false
|
||||
window.SENTRY_DSN = 'https://85694a2d757547cbbc90cd4b55c5a18d@o1047380.ingest.sentry.io/6024480'
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
[build]
|
||||
command = "yarn build"
|
||||
publish = "dist"
|
||||
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
X-Frame-Options = "DENY"
|
||||
X-XSS-Protection = "1; mode=block"
|
||||
X-Robots-Tag = "noindex"
|
13
nginx.conf
|
@ -34,7 +34,7 @@ http {
|
|||
gzip_buffers 16 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_min_length 256;
|
||||
gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml font/woff2 image/x-icon audio/wav;
|
||||
gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon audio/wav;
|
||||
|
||||
map_hash_max_size 128;
|
||||
map_hash_bucket_size 128;
|
||||
|
@ -60,19 +60,20 @@ http {
|
|||
server {
|
||||
listen 80;
|
||||
listen 81 default_server http2 proxy_protocol; ## Needed when behind HAProxy with SSL termination + HTTP/2 support
|
||||
listen 443 default_server ssl http2;
|
||||
|
||||
server_name _;
|
||||
|
||||
expires $expires;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/dummy.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/dummy.key;
|
||||
location ~* .(txt|webmanifest|css|js|mjs|map|svg|jpg|jpeg|png|ico|ttf|woff|woff2|wav)$ {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri/ /;
|
||||
index index.html index.htm;
|
||||
try_files $uri $uri/ /index.html;
|
||||
index index.html;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
|
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="16.000000pt" height="16.000000pt" viewBox="0 0 16.000000 16.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,16.000000) scale(0.000320,-0.000320)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M18 46618 c45 -75 122 -207 122 -211 0 -2 25 -45 55 -95 30 -50 55
|
||||
-96 55 -102 0 -5 5 -10 10 -10 6 0 10 -4 10 -9 0 -5 73 -135 161 -288 89 -153
|
||||
173 -298 187 -323 14 -25 32 -57 41 -72 88 -149 187 -324 189 -335 2 -7 8 -13
|
||||
13 -13 5 0 9 -4 9 -10 0 -5 46 -89 103 -187 175 -302 490 -846 507 -876 8 -16
|
||||
20 -36 25 -45 28 -46 290 -498 339 -585 13 -23 74 -129 136 -236 61 -107 123
|
||||
-215 137 -240 14 -25 29 -50 33 -56 5 -5 23 -37 40 -70 18 -33 38 -67 44 -75
|
||||
11 -16 21 -33 63 -109 14 -25 29 -50 33 -56 4 -5 21 -35 38 -65 55 -100 261
|
||||
-455 269 -465 4 -5 14 -21 20 -35 15 -29 41 -75 103 -180 24 -41 52 -88 60
|
||||
-105 9 -16 57 -100 107 -185 112 -193 362 -626 380 -660 8 -14 23 -38 33 -55
|
||||
11 -16 23 -37 27 -45 4 -8 26 -46 48 -85 23 -38 53 -90 67 -115 46 -81 64
|
||||
-113 178 -310 62 -107 121 -210 132 -227 37 -67 56 -99 85 -148 16 -27 32 -57
|
||||
36 -65 4 -8 15 -27 25 -42 9 -15 53 -89 96 -165 44 -76 177 -307 296 -513 120
|
||||
-206 268 -463 330 -570 131 -227 117 -203 200 -348 36 -62 73 -125 82 -140 10
|
||||
-15 21 -34 25 -42 4 -8 20 -37 36 -65 17 -27 38 -65 48 -82 49 -85 64 -111 87
|
||||
-153 13 -25 28 -49 32 -55 4 -5 78 -134 165 -285 87 -151 166 -288 176 -305
|
||||
10 -16 26 -43 35 -59 9 -17 125 -217 257 -445 132 -229 253 -441 270 -471 17
|
||||
-30 45 -79 64 -108 18 -29 33 -54 33 -57 0 -2 20 -37 44 -77 24 -40 123 -212
|
||||
221 -383 97 -170 190 -330 205 -355 16 -25 39 -65 53 -90 13 -25 81 -144 152
|
||||
-265 70 -121 137 -238 150 -260 12 -22 37 -65 55 -95 18 -30 43 -73 55 -95 12
|
||||
-22 48 -85 80 -140 77 -132 163 -280 190 -330 13 -22 71 -123 130 -225 59
|
||||
-102 116 -199 126 -217 10 -17 29 -50 43 -72 15 -22 26 -43 26 -45 0 -2 27
|
||||
-50 60 -106 33 -56 60 -103 60 -105 0 -2 55 -98 90 -155 8 -14 182 -316 239
|
||||
-414 13 -22 45 -79 72 -124 27 -46 49 -86 49 -89 0 -2 14 -24 30 -48 16 -24
|
||||
30 -46 30 -49 0 -5 74 -135 100 -176 5 -8 24 -42 43 -75 50 -88 58 -101 262
|
||||
-455 104 -179 199 -345 213 -370 14 -25 28 -49 32 -55 4 -5 17 -26 28 -45 10
|
||||
-19 62 -109 114 -200 114 -197 133 -230 170 -295 16 -27 33 -57 38 -65 17 -28
|
||||
96 -165 103 -180 4 -8 16 -28 26 -45 10 -16 77 -131 148 -255 72 -124 181
|
||||
-313 243 -420 62 -107 121 -209 131 -227 35 -62 323 -560 392 -678 38 -66 83
|
||||
-145 100 -175 16 -30 33 -59 37 -65 4 -5 17 -27 29 -47 34 -61 56 -100 90
|
||||
-156 17 -29 31 -55 31 -57 0 -2 17 -32 39 -67 21 -35 134 -229 251 -433 117
|
||||
-203 235 -407 261 -451 27 -45 49 -85 49 -88 0 -4 8 -19 19 -34 15 -21 200
|
||||
-341 309 -533 10 -19 33 -58 51 -87 17 -29 31 -54 31 -56 0 -2 25 -44 55 -94
|
||||
30 -50 55 -95 55 -98 0 -4 6 -15 14 -23 7 -9 27 -41 43 -71 17 -30 170 -297
|
||||
342 -594 171 -296 311 -542 311 -547 0 -5 5 -9 10 -9 6 0 10 -4 10 -10 0 -5
|
||||
22 -47 49 -92 27 -46 58 -99 68 -118 24 -43 81 -140 93 -160 5 -8 66 -114 135
|
||||
-235 69 -121 130 -227 135 -235 12 -21 259 -447 283 -490 10 -19 28 -47 38
|
||||
-62 11 -14 19 -29 19 -32 0 -3 37 -69 83 -148 99 -170 305 -526 337 -583 13
|
||||
-22 31 -53 41 -70 11 -16 22 -37 26 -45 7 -14 82 -146 103 -180 14 -24 181
|
||||
-311 205 -355 13 -22 46 -80 75 -130 29 -49 64 -110 78 -135 14 -25 51 -88 82
|
||||
-140 31 -52 59 -102 63 -110 4 -8 18 -33 31 -55 205 -353 284 -489 309 -535
|
||||
17 -30 45 -78 62 -106 18 -28 36 -60 39 -72 4 -12 12 -22 17 -22 5 0 9 -4 9
|
||||
-10 0 -5 109 -197 241 -427 133 -230 250 -431 259 -448 51 -90 222 -385 280
|
||||
-485 37 -63 78 -135 92 -160 14 -25 67 -117 118 -205 51 -88 101 -175 111
|
||||
-193 34 -58 55 -95 149 -257 51 -88 101 -173 110 -190 9 -16 76 -131 147 -255
|
||||
72 -124 140 -241 151 -260 61 -108 281 -489 355 -615 38 -66 77 -133 87 -150
|
||||
35 -63 91 -161 100 -175 14 -23 99 -169 128 -220 54 -97 135 -235 142 -245 4
|
||||
-5 20 -32 35 -60 26 -48 238 -416 276 -480 10 -16 26 -46 37 -65 30 -53 382
|
||||
-661 403 -695 10 -16 22 -37 26 -45 4 -8 26 -48 50 -88 24 -41 43 -75 43 -77
|
||||
0 -2 22 -40 50 -85 27 -45 50 -84 50 -86 0 -3 38 -69 83 -147 84 -142 302
|
||||
-520 340 -587 10 -19 34 -60 52 -90 18 -30 44 -75 57 -100 14 -25 45 -79 70
|
||||
-120 25 -41 56 -96 70 -121 14 -25 77 -133 138 -240 62 -107 122 -210 132
|
||||
-229 25 -43 310 -535 337 -581 11 -19 26 -45 34 -59 17 -32 238 -414 266 -460
|
||||
11 -19 24 -41 28 -49 3 -7 75 -133 160 -278 84 -146 153 -269 153 -274 0 -5 5
|
||||
-9 10 -9 6 0 10 -4 10 -10 0 -5 82 -150 181 -322 182 -314 201 -346 240 -415
|
||||
12 -21 80 -139 152 -263 71 -124 141 -245 155 -270 14 -25 28 -49 32 -55 6 -8
|
||||
145 -248 220 -380 37 -66 209 -362 229 -395 11 -19 24 -42 28 -49 4 -8 67
|
||||
-118 140 -243 73 -125 133 -230 133 -233 0 -2 15 -28 33 -57 19 -29 47 -78 64
|
||||
-108 17 -30 53 -93 79 -139 53 -90 82 -141 157 -272 82 -142 115 -199 381
|
||||
-659 142 -245 268 -463 281 -485 12 -22 71 -125 132 -230 60 -104 172 -298
|
||||
248 -430 76 -132 146 -253 156 -270 11 -16 22 -36 26 -44 3 -8 30 -54 60 -103
|
||||
29 -49 53 -91 53 -93 0 -3 18 -34 40 -70 22 -36 40 -67 40 -69 0 -2 37 -66 81
|
||||
-142 45 -77 98 -168 119 -204 20 -36 47 -81 58 -100 12 -19 27 -47 33 -62 6
|
||||
-16 15 -28 20 -28 5 0 9 -4 9 -9 0 -6 63 -118 140 -251 77 -133 140 -243 140
|
||||
-245 0 -2 18 -33 41 -70 22 -37 49 -83 60 -101 10 -19 29 -51 40 -71 25 -45
|
||||
109 -189 126 -218 7 -11 17 -29 22 -40 6 -11 22 -38 35 -60 14 -22 37 -62 52
|
||||
-90 14 -27 35 -62 45 -77 11 -14 19 -29 19 -32 0 -3 18 -35 40 -71 22 -36 40
|
||||
-67 40 -69 0 -2 19 -35 42 -72 23 -38 55 -94 72 -124 26 -47 139 -244 171
|
||||
-298 6 -9 21 -36 34 -60 28 -48 37 -51 51 -19 6 12 19 36 29 52 10 17 27 46
|
||||
38 65 11 19 104 181 208 360 103 179 199 345 213 370 14 25 42 74 64 109 21
|
||||
34 38 65 38 67 0 2 18 33 40 69 22 36 40 67 40 69 0 3 177 310 199 346 16 26
|
||||
136 234 140 244 2 5 25 44 52 88 27 44 49 81 49 84 0 2 18 34 40 70 22 36 40
|
||||
67 40 69 0 2 20 36 43 77 35 58 169 289 297 513 9 17 50 86 90 155 40 69 86
|
||||
150 103 180 16 30 35 62 41 70 6 8 16 24 22 35 35 64 72 129 167 293 59 100
|
||||
116 199 127 220 11 20 30 53 41 72 43 72 1070 1850 1121 1940 14 25 65 113
|
||||
113 195 48 83 96 166 107 185 10 19 28 50 38 68 11 18 73 124 137 235 64 111
|
||||
175 303 246 427 71 124 173 299 225 390 52 91 116 202 143 248 27 45 49 85 49
|
||||
89 0 4 6 14 14 22 7 9 28 43 46 76 26 47 251 436 378 655 11 19 29 51 40 70
|
||||
11 19 101 176 201 348 99 172 181 317 181 323 0 5 5 9 10 9 6 0 10 5 10 11 0
|
||||
6 8 23 18 37 11 15 32 52 49 82 16 30 130 228 253 440 122 212 234 405 248
|
||||
430 13 25 39 70 57 100 39 65 69 117 130 225 25 44 50 87 55 95 12 19 78 134
|
||||
220 380 61 107 129 224 150 260 161 277 222 382 246 425 15 28 47 83 71 123
|
||||
24 41 43 78 43 83 0 5 4 9 8 9 4 0 13 12 19 28 7 15 23 45 36 67 66 110 277
|
||||
478 277 483 0 3 6 13 14 21 7 9 27 41 43 71 17 30 45 80 63 110 34 57 375 649
|
||||
394 685 6 11 16 27 22 35 6 8 26 42 44 75 18 33 41 74 51 90 10 17 24 41 32
|
||||
55 54 97 72 128 88 152 11 14 19 28 19 30 0 3 79 141 175 308 96 167 175 305
|
||||
175 308 0 3 6 13 14 21 7 9 26 39 41 66 33 60 276 483 338 587 24 40 46 80 50
|
||||
88 4 8 13 24 20 35 14 23 95 163 125 215 11 19 52 91 92 160 40 69 80 139 90
|
||||
155 9 17 103 179 207 360 105 182 200 346 211 365 103 181 463 802 489 845 7
|
||||
11 15 27 19 35 4 8 29 51 55 95 64 110 828 1433 848 1470 9 17 24 41 33 55 9
|
||||
14 29 48 45 77 15 28 52 93 82 145 30 51 62 107 71 123 17 30 231 398 400 690
|
||||
51 88 103 179 115 202 12 23 26 48 32 55 6 7 24 38 40 68 17 30 61 107 98 170
|
||||
37 63 84 144 103 180 19 36 41 72 48 81 8 8 14 18 14 21 0 4 27 51 59 106 32
|
||||
55 72 124 89 154 16 29 71 125 122 213 51 88 104 180 118 205 13 25 28 50 32
|
||||
55 4 6 17 26 28 45 11 19 45 80 77 135 31 55 66 116 77 135 11 19 88 152 171
|
||||
295 401 694 620 1072 650 1125 11 19 87 152 170 295 83 143 158 273 166 288 9
|
||||
16 21 36 26 45 6 9 31 52 55 96 25 43 54 94 66 115 11 20 95 164 186 321 91
|
||||
157 173 299 182 315 9 17 26 46 37 65 12 19 66 114 121 210 56 96 108 186 117
|
||||
200 8 14 24 40 34 59 24 45 383 664 412 713 5 9 17 29 26 45 15 28 120 210
|
||||
241 419 36 61 68 117 72 125 4 8 12 23 19 34 35 57 245 420 262 453 11 20 35
|
||||
61 53 90 17 29 32 54 32 56 0 3 28 51 62 108 33 57 70 119 80 138 10 19 23 42
|
||||
28 50 5 8 32 53 59 100 27 47 149 258 271 470 122 212 234 405 248 430 30 53
|
||||
62 108 80 135 6 11 15 27 19 35 4 8 85 150 181 315 96 165 187 323 202 350 31
|
||||
56 116 202 130 225 5 8 25 42 43 75 19 33 92 159 162 280 149 257 157 271 202
|
||||
350 19 33 38 67 43 75 9 14 228 392 275 475 12 22 55 96 95 165 40 69 80 139
|
||||
90 155 24 42 202 350 221 383 9 15 27 47 41 72 14 25 75 131 136 236 61 106
|
||||
121 210 134 232 99 172 271 470 279 482 5 8 23 40 40 70 18 30 81 141 142 245
|
||||
60 105 121 210 135 235 14 25 71 124 127 220 56 96 143 247 194 335 51 88 96
|
||||
167 102 175 14 24 180 311 204 355 23 43 340 590 356 615 5 8 50 87 101 175
|
||||
171 301 517 898 582 1008 25 43 46 81 46 83 0 2 12 23 27 47 14 23 40 67 56
|
||||
97 16 30 35 62 42 70 7 8 15 22 18 30 4 8 20 38 37 65 16 28 33 57 37 65 6 12
|
||||
111 196 143 250 5 8 55 95 112 193 57 98 113 195 126 215 12 20 27 46 32 57 6
|
||||
11 14 27 20 35 5 8 76 130 156 270 80 140 165 287 187 325 23 39 52 90 66 115
|
||||
13 25 30 52 37 61 8 8 14 18 14 21 0 4 41 77 92 165 50 87 175 302 276 478
|
||||
101 176 208 360 236 408 28 49 67 117 86 152 19 35 41 70 48 77 6 6 12 15 12
|
||||
19 0 7 124 224 167 291 12 21 23 40 23 42 0 2 21 40 46 83 26 43 55 92 64 109
|
||||
54 95 327 568 354 614 19 30 45 75 59 100 71 128 82 145 89 148 4 2 8 8 8 13
|
||||
0 5 42 82 94 172 311 538 496 858 518 897 14 25 40 70 58 100 18 30 42 71 53
|
||||
90 10 19 79 139 152 265 73 127 142 246 153 265 10 19 43 76 72 125 29 50 63
|
||||
108 75 130 65 116 80 140 87 143 4 2 8 8 8 12 0 8 114 212 140 250 6 8 14 24
|
||||
20 35 5 11 54 97 108 190 l100 170 -9611 3 c-5286 1 -9614 -1 -9618 -5 -5 -6
|
||||
-419 -719 -619 -1068 -89 -155 -267 -463 -323 -560 -38 -66 -81 -140 -95 -165
|
||||
-31 -56 -263 -457 -526 -910 -110 -190 -224 -388 -254 -440 -29 -52 -61 -109
|
||||
-71 -125 -23 -39 -243 -420 -268 -465 -11 -19 -204 -352 -428 -740 -224 -388
|
||||
-477 -826 -563 -975 -85 -148 -185 -322 -222 -385 -37 -63 -120 -207 -185
|
||||
-320 -65 -113 -177 -306 -248 -430 -72 -124 -172 -297 -222 -385 -51 -88 -142
|
||||
-245 -202 -350 -131 -226 -247 -427 -408 -705 -65 -113 -249 -432 -410 -710
|
||||
-160 -278 -388 -673 -506 -877 -118 -205 -216 -373 -219 -373 -3 0 -52 82
|
||||
-109 183 -58 100 -144 250 -192 332 -95 164 -402 696 -647 1120 -85 149 -228
|
||||
396 -317 550 -212 365 -982 1700 -1008 1745 -10 19 -43 76 -72 125 -29 50 -64
|
||||
110 -77 135 -14 25 -63 110 -110 190 -47 80 -96 165 -110 190 -14 25 -99 171
|
||||
-188 325 -89 154 -174 300 -188 325 -13 25 -64 113 -112 195 -48 83 -140 242
|
||||
-205 355 -65 113 -183 317 -263 454 -79 137 -152 264 -163 282 -50 89 -335
|
||||
583 -354 614 -12 19 -34 58 -50 85 -15 28 -129 226 -253 440 -124 215 -235
|
||||
408 -247 430 -12 22 -69 121 -127 220 -58 99 -226 389 -373 645 -148 256 -324
|
||||
561 -392 678 -67 117 -134 232 -147 255 -13 23 -33 59 -46 80 l-22 37 -9615 0
|
||||
-9615 0 20 -32z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 10 KiB |
|
@ -49,7 +49,7 @@
|
|||
inkscape:label="ink_ext_XXXXXX 1"
|
||||
style="display:inline"
|
||||
transform="translate(-92.67749,-674.48297)"><circle
|
||||
style="fill:#5974d9;fill-opacity:1;stroke:none;stroke-width:2.88757133;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
style="fill:#196aff;fill-opacity:1;stroke:none;stroke-width:2.88757133;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
id="path920"
|
||||
cx="242.67749"
|
||||
cy="828.77881"
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1007.922 821.827"><defs><style>.a{fill:#fff;}.b{fill:url(#a);}.c{mask:url(#b);}.d{fill:url(#c);}.e{mask:url(#d);}.f{fill:url(#e);}.g{fill:url(#f);}.h{mask:url(#g);}.i{fill:url(#h);}.j{fill:#195abd;}.k{fill:url(#i);}</style><linearGradient id="a" x1="700.766" y1="597.024" x2="749.765" y2="597.024" gradientTransform="translate(86.603 -142.296) scale(0.867 1.307)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-opacity="0.13"/><stop offset="0.994" stop-opacity="0"/></linearGradient><mask id="b" x="317.137" y="651.827" width="170" height="205.208" maskUnits="userSpaceOnUse"><g transform="translate(-8.064 -116.521)"><rect class="a" x="367.701" y="870.953" width="85" height="85" transform="translate(766.054 -22.512) rotate(45)"/></g></mask><radialGradient id="c" cx="410.201" cy="853.349" r="85" gradientTransform="translate(715.49 -156.637) rotate(45)" gradientUnits="userSpaceOnUse"><stop offset="0.5" stop-opacity="0.13"/><stop offset="0.994" stop-opacity="0"/></radialGradient><mask id="d" x="837.922" y="95.835" width="205.208" height="205.208" maskUnits="userSpaceOnUse"><g transform="translate(-8.064 -116.521)"><rect class="a" x="876.038" y="260.012" width="170" height="85" transform="translate(1426.685 1195.977) rotate(-135)"/></g></mask><radialGradient id="e" cx="1051.126" cy="1265.852" r="85" gradientTransform="translate(771.087 1854.394) rotate(-135)" xlink:href="#c"/><linearGradient id="f" x1="1880.8" y1="34.286" x2="1929.799" y2="34.286" gradientTransform="matrix(0.867, 0, 0, -0.796, -1446.031, 767.147)" xlink:href="#a"/><mask id="g" x="-35.208" y="299.482" width="205.208" height="205.208" maskUnits="userSpaceOnUse"><g transform="translate(-8.064 -116.521)"><rect class="a" x="-21.988" y="463.659" width="170" height="85" transform="translate(-339.453 192.807) rotate(-45)"/></g></mask><radialGradient id="h" cx="27.608" cy="2001.37" r="85" gradientTransform="matrix(0.707, -0.707, -0.707, -0.707, 1480.66, 1854.394)" xlink:href="#c"/><linearGradient id="i" x1="308.378" y1="811.629" x2="919.318" y2="200.689" gradientTransform="translate(-178.117 582.307) rotate(-45)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2987e6"/><stop offset="0.994" stop-color="#58c1f5"/></linearGradient></defs><title>Todo</title><rect class="b" x="694.422" y="269.785" width="42.5" height="736.5" transform="translate(652.71 -435.701) rotate(45)"/><g class="c"><circle class="d" cx="402.137" cy="736.827" r="85"/></g><g class="e"><circle class="f" cx="922.922" cy="216.043" r="85"/></g><rect class="g" x="185.305" y="515.608" width="42.5" height="448.5" transform="translate(867.705 1000.439) rotate(135)"/><g class="h"><circle class="i" cx="85" cy="419.69" r="85"/></g><rect class="j" x="164.378" y="319.982" width="288" height="576" rx="42.5" transform="translate(-347.651 279.609) rotate(-45)"/><rect class="k" x="469.848" y="74.159" width="288" height="864" rx="42.5" transform="translate(529.636 -402.327) rotate(45)"/></svg>
|
After Width: | Height: | Size: 3.0 KiB |
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M224.001997,0 L31.9980026,0 C14.3579381,0.0394964443 0.0614809418,14.336846 0,32 L0,224 C0,241.6 14.3971038,256 31.9980026,256 L224.001997,256 C241.602896,256 256,241.6 256,224 L256,32 C256,14.4 241.602896,0 224.001997,0" fill="#E44332"></path>
|
||||
<path d="M54.132778,120.802491 C58.5960224,118.196275 154.476075,62.477451 156.667847,61.1862981 C158.859619,59.9110855 158.97917,55.9898065 156.508446,54.5711324 C154.053661,53.1604284 149.391165,50.4824817 147.661658,49.4543415 C145.192242,48.0957707 142.191169,48.132074 139.755339,49.5499825 C138.527947,50.2672896 56.6035026,97.8486625 53.8697654,99.4107981 C50.5781227,101.291737 46.5372925,101.323617 43.2695601,99.4107981 L0,74.0181257 L0,95.6011002 C10.5205046,101.801822 36.7181549,117.200015 43.062338,120.826401 C46.8481256,122.978322 50.4745117,122.930502 54.1407481,120.802491" fill="#FFFFFF"></path>
|
||||
<path d="M54.132778,161.609296 C58.5960224,159.00308 154.476075,103.284257 156.667847,101.993104 C158.859619,100.717891 158.97917,96.7966121 156.508446,95.377938 C154.053661,93.9672339 149.391165,91.2892873 147.661658,90.2611471 C145.192242,88.9025763 142.191169,88.9388796 139.755339,90.3567881 C138.527947,91.0740952 56.6035026,138.655468 53.8697654,140.217604 C50.5781227,142.098542 46.5372925,142.130423 43.2695601,140.217604 L0,114.824931 L0,136.407906 C10.5205046,142.608627 36.7181549,158.00682 43.062338,161.633206 C46.8481256,163.785128 50.4745117,163.737307 54.1407481,161.609296" fill="#FFFFFF"></path>
|
||||
<path d="M54.132778,204.966527 C58.5960224,202.360311 154.476075,146.641487 156.667847,145.350335 C158.859619,144.075122 158.97917,140.153843 156.508446,138.735169 C154.053661,137.324465 149.391165,134.646518 147.661658,133.618378 C145.192242,132.259807 142.191169,132.29611 139.755339,133.714019 C138.527947,134.431326 56.6035026,182.012699 53.8697654,183.574835 C50.5781227,185.455773 46.5372925,185.487654 43.2695601,183.574835 L0,158.182162 L0,179.765137 C10.5205046,185.965858 36.7181549,201.364051 43.062338,204.990437 C46.8481256,207.142359 50.4745117,207.094538 54.1407481,204.966527" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<defs>
|
||||
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
|
||||
<stop stop-color="#0091E6" offset="0%"></stop>
|
||||
<stop stop-color="#0079BF" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g>
|
||||
<g>
|
||||
<rect fill="url(#linearGradient-1)" x="0" y="0" width="256" height="256" rx="25"></rect>
|
||||
<rect fill="#FFFFFF" x="144.64" y="33.28" width="78.08" height="112" rx="12"></rect>
|
||||
<rect fill="#FFFFFF" x="33.28" y="33.28" width="78.08" height="176" rx="12"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 829 B |
After Width: | Height: | Size: 85 KiB |
161
package.json
|
@ -7,81 +7,103 @@
|
|||
"serve:dist-dev": "node scripts/serve-dist.js",
|
||||
"serve:dist": "vite preview",
|
||||
"build": "vite build && workbox copyLibraries dist/",
|
||||
"build:modern-only": "BUILD_MODERN_ONLY=true vite build && workbox copyLibraries dist/",
|
||||
"build:dev": "vite build -m development --outDir dist-dev/",
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
"lint": "eslint --ignore-pattern '*.test.*' ./src --ext .vue,.js,.ts",
|
||||
"cypress:open": "cypress open",
|
||||
"test:unit": "jest",
|
||||
"test:frontend": "cypress run"
|
||||
"test:unit": "vitest run",
|
||||
"test:frontend": "cypress run",
|
||||
"browserslist:update": "npx browserslist@latest --update-db"
|
||||
},
|
||||
"dependencies": {
|
||||
"browserslist": "4.16.8",
|
||||
"bulma": "0.9.3",
|
||||
"@github/hotkey": "1.6.1",
|
||||
"@kyvg/vue3-notification": "2.3.4",
|
||||
"@sentry/tracing": "6.16.1",
|
||||
"@sentry/vue": "6.16.1",
|
||||
"@types/is-touch-device": "1.0.0",
|
||||
"@vue/compat": "3.2.26",
|
||||
"@vueuse/core": "7.5.2",
|
||||
"@vueuse/router": "7.5.3",
|
||||
"bulma-css-variables": "0.9.33",
|
||||
"camel-case": "4.1.2",
|
||||
"codemirror": "5.65.0",
|
||||
"copy-to-clipboard": "3.3.1",
|
||||
"date-fns": "2.23.0",
|
||||
"dompurify": "2.3.1",
|
||||
"highlight.js": "11.2.0",
|
||||
"date-fns": "2.28.0",
|
||||
"dompurify": "2.3.4",
|
||||
"easymde": "2.15.0",
|
||||
"flatpickr": "4.6.9",
|
||||
"flexsearch": "0.7.21",
|
||||
"highlight.js": "11.4.0",
|
||||
"is-touch-device": "1.0.1",
|
||||
"lodash": "4.17.21",
|
||||
"marked": "3.0.2",
|
||||
"lodash.clonedeep": "4.5.0",
|
||||
"lodash.debounce": "4.0.8",
|
||||
"marked": "4.0.9",
|
||||
"register-service-worker": "1.7.2",
|
||||
"snake-case": "3.0.4",
|
||||
"verte": "0.0.12",
|
||||
"vue": "2.6.14",
|
||||
"vue-advanced-cropper": "1.8.2",
|
||||
"vue-drag-resize": "1.5.4",
|
||||
"vue-easymde": "1.4.0",
|
||||
"vue-i18n": "8.25.0",
|
||||
"vue-shortkey": "3.1.7",
|
||||
"vuedraggable": "2.24.3",
|
||||
"vuex": "3.6.2",
|
||||
"workbox-precaching": "6.2.4"
|
||||
"ufo": "0.7.9",
|
||||
"v-tooltip": "4.0.0-beta.13",
|
||||
"vue": "3.2.26",
|
||||
"vue-advanced-cropper": "2.7.1",
|
||||
"vue-drag-resize": "2.0.3",
|
||||
"vue-flatpickr-component": "9.0.5",
|
||||
"vue-i18n": "9.2.0-beta.26",
|
||||
"vue-router": "4.0.12",
|
||||
"vuedraggable": "4.1.0",
|
||||
"vuex": "4.0.2",
|
||||
"workbox-precaching": "6.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@4tw/cypress-drag-drop": "1.8.1",
|
||||
"@4tw/cypress-drag-drop": "2.1.0",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@fortawesome/vue-fontawesome": "2.0.2",
|
||||
"@types/jest": "27.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "4.30.0",
|
||||
"@typescript-eslint/parser": "4.30.0",
|
||||
"@vue/babel-preset-app": "4.5.13",
|
||||
"@vue/eslint-config-typescript": "7.0.0",
|
||||
"autoprefixer": "10.3.4",
|
||||
"axios": "0.21.3",
|
||||
"babel-eslint": "10.1.0",
|
||||
"cypress": "8.3.1",
|
||||
"@fortawesome/vue-fontawesome": "3.0.0-5",
|
||||
"@types/flexsearch": "0.7.2",
|
||||
"@typescript-eslint/eslint-plugin": "5.9.0",
|
||||
"@typescript-eslint/parser": "5.9.0",
|
||||
"@vitejs/plugin-legacy": "1.6.4",
|
||||
"@vitejs/plugin-vue": "2.0.1",
|
||||
"@vue/eslint-config-typescript": "10.0.0",
|
||||
"autoprefixer": "10.4.2",
|
||||
"axios": "0.24.0",
|
||||
"browserslist": "4.19.1",
|
||||
"caniuse-lite": "1.0.30001298",
|
||||
"cypress": "9.2.0",
|
||||
"cypress-file-upload": "5.0.8",
|
||||
"esbuild": "0.12.25",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-plugin-vue": "7.17.0",
|
||||
"express": "4.17.1",
|
||||
"esbuild": "0.14.10",
|
||||
"eslint": "8.6.0",
|
||||
"eslint-plugin-vue": "8.2.0",
|
||||
"express": "4.17.2",
|
||||
"faker": "5.5.3",
|
||||
"jest": "27.1.0",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"netlify-cli": "8.6.15",
|
||||
"happy-dom": "2.25.1",
|
||||
"postcss": "8.4.5",
|
||||
"postcss-preset-env": "7.2.0",
|
||||
"rollup": "2.63.0",
|
||||
"rollup-plugin-visualizer": "5.5.2",
|
||||
"sass": "1.39.0",
|
||||
"ts-jest": "27.0.5",
|
||||
"typescript": "4.4.2",
|
||||
"vite": "2.5.3",
|
||||
"vite-plugin-pwa": "0.11.2",
|
||||
"vite-plugin-vue2": "1.8.1",
|
||||
"vue-flatpickr-component": "8.1.7",
|
||||
"vue-notification": "1.3.20",
|
||||
"vue-router": "3.5.2",
|
||||
"vue-template-compiler": "2.6.14",
|
||||
"sass": "1.47.0",
|
||||
"slugify": "1.6.5",
|
||||
"typescript": "4.5.4",
|
||||
"vite": "2.7.10",
|
||||
"vite-plugin-pwa": "0.11.12",
|
||||
"vite-svg-loader": "3.1.1",
|
||||
"vitest": "0.0.139",
|
||||
"vue-tsc": "0.30.2",
|
||||
"wait-on": "6.0.0",
|
||||
"workbox-cli": "6.2.4"
|
||||
"workbox-cli": "6.4.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
"browser": true,
|
||||
"es2021": true,
|
||||
"node": true,
|
||||
"vue/setup-compiler-macros": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended",
|
||||
"plugin:vue/vue3-essential",
|
||||
"@vue/typescript"
|
||||
],
|
||||
"rules": {
|
||||
|
@ -100,45 +122,28 @@
|
|||
"semi": [
|
||||
"error",
|
||||
"never"
|
||||
]
|
||||
],
|
||||
"vue/script-setup-uses-vars": "error",
|
||||
"vue/multi-word-component-names": 0
|
||||
},
|
||||
"parser": "vue-eslint-parser",
|
||||
"parserOptions": {
|
||||
"parser": "@typescript-eslint/parser"
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"ecmaVersion": 2021
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"*.test.*",
|
||||
"cypress/*"
|
||||
]
|
||||
],
|
||||
"globals": {
|
||||
"defineProps": "readonly"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie > 0",
|
||||
"not dead",
|
||||
"Firefox ESR"
|
||||
],
|
||||
"jest": {
|
||||
"testPathIgnorePatterns": [
|
||||
"cypress"
|
||||
],
|
||||
"testEnvironment": "jsdom",
|
||||
"preset": "ts-jest",
|
||||
"roots": [
|
||||
"<rootDir>/src"
|
||||
],
|
||||
"transform": {
|
||||
"^.+\\.(js|tsx?)$": "ts-jest"
|
||||
},
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"js",
|
||||
"json"
|
||||
]
|
||||
},
|
||||
"license": "AGPL-3.0-or-later"
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"packageManager": "yarn@1.22.17"
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# Shell script because yaml doesn't understand the header is a string literal and not a yaml symbol
|
||||
|
||||
curl -d operation=pull -H "Authorization: Token $WEBLATE_TOKEN" https://hosted.weblate.org/api/projects/vikunja/repository/
|
||||
curl -d operation=push -H "Authorization: Token $WEBLATE_TOKEN" https://hosted.weblate.org/api/projects/vikunja/repository/
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 616 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 26 KiB |
18
run.sh
|
@ -2,14 +2,24 @@
|
|||
|
||||
# This shell script sets the api url based on an environment variable and starts nginx in foreground.
|
||||
|
||||
if [ -z "$VIKUNJA_API_URL" ]; then
|
||||
VIKUNJA_API_URL="/api/v1"
|
||||
fi
|
||||
VIKUNJA_API_URL="${VIKUNJA_API_URL:-"/api/v1"}"
|
||||
VIKUNJA_SENTRY_ENABLED="${VIKUNJA_SENTRY_ENABLED:-"false"}"
|
||||
VIKUNJA_SENTRY_DSN="${VIKUNJA_SENTRY_DSN:-"https://85694a2d757547cbbc90cd4b55c5a18d@o1047380.ingest.sentry.io/6024480"}"
|
||||
VIKUNJA_HTTP_PORT="${VIKUNJA_HTTP_PORT:-80}"
|
||||
VIKUNJA_HTTPS_PORT="${VIKUNJA_HTTPS_PORT:-443}"
|
||||
|
||||
echo "Using $VIKUNJA_API_URL as default api url"
|
||||
|
||||
# Escape the variable to prevent sed from complaining
|
||||
VIKUNJA_API_URL=$(echo $VIKUNJA_API_URL |sed 's/\//\\\//g')
|
||||
|
||||
sed -i "s/http\:\/\/localhost\:3456\/api\/v1/$VIKUNJA_API_URL/g" /usr/share/nginx/html/index.html
|
||||
sed -i "s/http\:\/\/localhost\:3456//g" /usr/share/nginx/html/index.html # replacing in two steps to make sure api urls from releases are properly replaced as well
|
||||
sed -i "s/'\/api\/v1/'$VIKUNJA_API_URL/g" /usr/share/nginx/html/index.html
|
||||
sed -i "s/\.SENTRY_ENABLED = false/\.SENTRY_ENABLED = $VIKUNJA_SENTRY_ENABLED/g" /usr/share/nginx/html/index.html
|
||||
sed -i "s/\.SENTRY_DSN = '.*'/\.SENTRY_DSN = '$VIKUNJA_SENTRY_DSN'/g" /usr/share/nginx/html/index.html
|
||||
|
||||
sed -i "s/listen 80/listen $VIKUNJA_HTTP_PORT/g" /etc/nginx/nginx.conf
|
||||
sed -i "s/listen 443/listen $VIKUNJA_HTTPS_PORT/g" /etc/nginx/nginx.conf
|
||||
|
||||
# Set the uid and gid of the nginx run user
|
||||
usermod --non-unique --uid ${PUID} nginx
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
const slugify = require('slugify')
|
||||
const {exec} = require('child_process')
|
||||
const axios = require('axios')
|
||||
|
||||
const BOT_USER_ID = 513
|
||||
const giteaToken = process.env.GITEA_TOKEN
|
||||
const siteId = process.env.NETLIFY_SITE_ID
|
||||
const branchSlug = slugify(process.env.DRONE_SOURCE_BRANCH)
|
||||
const prNumber = process.env.DRONE_PULL_REQUEST
|
||||
|
||||
const prIssueCommentsUrl = `https://kolaente.dev/api/v1/repos/vikunja/frontend/issues/${prNumber}/comments`
|
||||
const alias = `${prNumber}-${branchSlug}`
|
||||
const fullPreviewUrl = `https://${alias}--vikunja-frontend-preview.netlify.app`
|
||||
|
||||
const promiseExec = cmd => {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(cmd, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
return
|
||||
}
|
||||
|
||||
resolve(stdout)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
(async function () {
|
||||
let stdout = await promiseExec(`./node_modules/.bin/netlify link --id ${siteId}`)
|
||||
console.log(stdout)
|
||||
stdout = await promiseExec(`./node_modules/.bin/netlify deploy --alias ${alias}`)
|
||||
console.log(stdout)
|
||||
|
||||
const {data} = await axios.get(prIssueCommentsUrl)
|
||||
const hasComment = data.some(c => c.user.id === BOT_USER_ID)
|
||||
|
||||
if (hasComment) {
|
||||
console.log(`PR #${prNumber} already has a comment with a link, not sending another comment.`)
|
||||
return
|
||||
}
|
||||
|
||||
await axios.post(prIssueCommentsUrl, {
|
||||
body: `
|
||||
Hi ${process.env.DRONE_COMMIT_AUTHOR}!
|
||||
|
||||
Thank you for creating a PR!
|
||||
|
||||
I've deployed the changes of this PR on a preview environment under this URL: ${fullPreviewUrl}
|
||||
|
||||
You can use this url to view the changes live and test them out.
|
||||
You will need to manually connect this to an api running somehwere. The easiest to use is https://try.vikunja.io/.
|
||||
|
||||
Have a nice day!
|
||||
|
||||
> Beep boop, I'm a bot.
|
||||
`,
|
||||
}, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'accept': 'application/json',
|
||||
'Authorization': `token ${giteaToken}`,
|
||||
},
|
||||
})
|
||||
|
||||
console.log(`Preview comment sent successfully to PR #${prNumber}!`)
|
||||
})()
|
|
@ -0,0 +1 @@
|
|||
55ce0faaa2c1919341617ccfaeccbb6029ac12107964ff488985cff13dd952f1a991df3ab0d4b0705deb761e508e6434 ./scripts/deploy-preview-netlify.js
|
182
src/App.vue
|
@ -1,116 +1,94 @@
|
|||
<template>
|
||||
<div :class="{'is-touch': isTouch}">
|
||||
<div :class="{'is-hidden': !online}">
|
||||
<!-- This is a workaround to get the sw to "see" the to-be-cached version of the offline background image -->
|
||||
<div class="offline" style="height: 0;width: 0;"></div>
|
||||
<top-navigation v-if="authUser"/>
|
||||
<content-auth v-if="authUser"/>
|
||||
<content-link-share v-else-if="authLinkShare"/>
|
||||
<content-no-auth v-else/>
|
||||
<notification/>
|
||||
</div>
|
||||
<div class="app offline" v-if="!online">
|
||||
<div class="offline-message">
|
||||
<h1>You are offline.</h1>
|
||||
<p>Please check your network connection and try again.</p>
|
||||
</div>
|
||||
</div>
|
||||
<ready>
|
||||
<template v-if="authUser">
|
||||
<top-navigation/>
|
||||
<content-auth/>
|
||||
</template>
|
||||
<content-link-share v-else-if="authLinkShare"/>
|
||||
<no-auth-wrapper v-else>
|
||||
<router-view/>
|
||||
</no-auth-wrapper>
|
||||
<Notification/>
|
||||
|
||||
<transition name="fade">
|
||||
<keyboard-shortcuts v-if="keyboardShortcutsActive"/>
|
||||
</transition>
|
||||
</div>
|
||||
</ready>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
<script lang="ts" setup>
|
||||
import {computed, watch, Ref} from 'vue'
|
||||
import {useRouter} from 'vue-router'
|
||||
import {useRouteQuery} from '@vueuse/router'
|
||||
import {useStore} from 'vuex'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import isTouchDevice from 'is-touch-device'
|
||||
import {success} from '@/message'
|
||||
|
||||
import authTypes from './models/authTypes'
|
||||
import Notification from '@/components/misc/notification.vue'
|
||||
import KeyboardShortcuts from './components/misc/keyboard-shortcuts/index.vue'
|
||||
import TopNavigation from './components/home/topNavigation.vue'
|
||||
import ContentAuth from './components/home/contentAuth.vue'
|
||||
import ContentLinkShare from './components/home/contentLinkShare.vue'
|
||||
import NoAuthWrapper from '@/components/misc/no-auth-wrapper.vue'
|
||||
import Ready from '@/components/misc/ready.vue'
|
||||
|
||||
import Notification from './components/misc/notification'
|
||||
import {KEYBOARD_SHORTCUTS_ACTIVE, ONLINE} from './store/mutation-types'
|
||||
import KeyboardShortcuts from './components/misc/keyboard-shortcuts'
|
||||
import TopNavigation from './components/home/topNavigation'
|
||||
import ContentAuth from './components/home/contentAuth'
|
||||
import ContentLinkShare from './components/home/contentLinkShare'
|
||||
import ContentNoAuth from './components/home/contentNoAuth'
|
||||
import {setLanguage} from './i18n/setup'
|
||||
import {setLanguage} from './i18n'
|
||||
import AccountDeleteService from '@/services/accountDelete'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
ContentNoAuth,
|
||||
ContentLinkShare,
|
||||
ContentAuth,
|
||||
TopNavigation,
|
||||
KeyboardShortcuts,
|
||||
Notification,
|
||||
},
|
||||
beforeMount() {
|
||||
this.setupOnlineStatus()
|
||||
this.setupPasswortResetRedirect()
|
||||
this.setupEmailVerificationRedirect()
|
||||
this.setupAccountDeletionVerification()
|
||||
},
|
||||
beforeCreate() {
|
||||
this.$store.dispatch('config/update')
|
||||
.then(() => {
|
||||
this.$store.dispatch('auth/checkAuth')
|
||||
})
|
||||
this.$store.dispatch('auth/checkAuth')
|
||||
import {useColorScheme} from '@/composables/useColorScheme'
|
||||
import {useBodyClass} from '@/composables/useBodyClass'
|
||||
|
||||
setLanguage()
|
||||
},
|
||||
created() {
|
||||
// Make sure to always load the home route when running with electron
|
||||
if (this.$route.fullPath.endsWith('frontend/index.html')) {
|
||||
this.$router.push({name: 'home'})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isTouch() {
|
||||
return isTouchDevice()
|
||||
},
|
||||
...mapState({
|
||||
authUser: state => state.auth.authenticated && (state.auth.info && state.auth.info.type === authTypes.USER),
|
||||
authLinkShare: state => state.auth.authenticated && (state.auth.info && state.auth.info.type === authTypes.LINK_SHARE),
|
||||
online: ONLINE,
|
||||
keyboardShortcutsActive: KEYBOARD_SHORTCUTS_ACTIVE,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
setupOnlineStatus() {
|
||||
this.$store.commit(ONLINE, navigator.onLine)
|
||||
window.addEventListener('online', () => this.$store.commit(ONLINE, navigator.onLine))
|
||||
window.addEventListener('offline', () => this.$store.commit(ONLINE, navigator.onLine))
|
||||
},
|
||||
setupPasswortResetRedirect() {
|
||||
if (typeof this.$route.query.userPasswordReset !== 'undefined') {
|
||||
localStorage.removeItem('passwordResetToken') // Delete an eventually preexisting old token
|
||||
localStorage.setItem('passwordResetToken', this.$route.query.userPasswordReset)
|
||||
this.$router.push({name: 'user.password-reset.reset'})
|
||||
}
|
||||
},
|
||||
setupEmailVerificationRedirect() {
|
||||
if (typeof this.$route.query.userEmailConfirm !== 'undefined') {
|
||||
localStorage.removeItem('emailConfirmToken') // Delete an eventually preexisting old token
|
||||
localStorage.setItem('emailConfirmToken', this.$route.query.userEmailConfirm)
|
||||
this.$router.push({name: 'user.login'})
|
||||
}
|
||||
},
|
||||
setupAccountDeletionVerification() {
|
||||
if (typeof this.$route.query.accountDeletionConfirm !== 'undefined') {
|
||||
const accountDeletionService = new AccountDeleteService()
|
||||
accountDeletionService.confirm(this.$route.query.accountDeletionConfirm)
|
||||
.then(() => {
|
||||
this.success({message: this.$t('user.deletion.confirmSuccess')})
|
||||
this.$store.dispatch('auth/refreshUserInfo')
|
||||
})
|
||||
.catch(e => this.error(e))
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
const store = useStore()
|
||||
const router = useRouter()
|
||||
|
||||
useBodyClass('is-touch', isTouchDevice)
|
||||
const keyboardShortcutsActive = computed(() => store.state.keyboardShortcutsActive)
|
||||
|
||||
const authUser = computed(() => store.getters['auth/authUser'])
|
||||
const authLinkShare = computed(() => store.getters['auth/authLinkShare'])
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
// setup account deletion verification
|
||||
const accountDeletionConfirm = useRouteQuery('accountDeletionConfirm') as Ref<null | string>
|
||||
watch(accountDeletionConfirm, async (accountDeletionConfirm) => {
|
||||
if (accountDeletionConfirm === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const accountDeletionService = new AccountDeleteService()
|
||||
await accountDeletionService.confirm(accountDeletionConfirm)
|
||||
success({message: t('user.deletion.confirmSuccess')})
|
||||
store.dispatch('auth/refreshUserInfo')
|
||||
}, { immediate: true })
|
||||
|
||||
// setup passwort reset redirect
|
||||
const userPasswordReset = useRouteQuery('userPasswordReset') as Ref<null | string>
|
||||
watch(userPasswordReset, (userPasswordReset) => {
|
||||
if (userPasswordReset === null) {
|
||||
return
|
||||
}
|
||||
|
||||
localStorage.setItem('passwordResetToken', userPasswordReset)
|
||||
router.push({name: 'user.password-reset.reset'})
|
||||
}, { immediate: true })
|
||||
|
||||
// setup email verification redirect
|
||||
const userEmailConfirm = useRouteQuery('userEmailConfirm') as Ref<null | string>
|
||||
watch(userEmailConfirm, (userEmailConfirm) => {
|
||||
if (userEmailConfirm === null) {
|
||||
return
|
||||
}
|
||||
|
||||
localStorage.setItem('emailConfirmToken', userEmailConfirm)
|
||||
router.push({name: 'user.login'})
|
||||
}, { immediate: true })
|
||||
|
||||
setLanguage()
|
||||
useColorScheme()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/styles/global.scss';
|
||||
</style>
|
||||
|
|
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 49 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="145.4" height="204.5" xml:space="preserve"><defs><clipPath id="a" clipPathUnits="userSpaceOnUse"><path d="M5210 5148.5c-111.4 0-201.8 62.7-201.8 140s90.4 140 201.8 140c111.5 0 201.9-62.7 201.9-140s-90.4-140-201.9-140"/></clipPath></defs><path fill="#fff" d="M145 129.8c-1.5 11.7-6.3 15-6.3 15 8.2 4.3 6.9 16.5 4.5 21-1.5 3-3.6 3-3.6 3 7.4 11-1.4 18.7-1.4 18.7a39 39 0 0 1 1.7 17h-109c-.7-1.7-1.4-4.8-.5-10.3 1.8-11.5 5.5-16.1 6.3-17 0 0-7-10.2-6.3-19.4 1-14.6 4.9-16.7 4.9-16.7-7.4-10-2.4-20.4.4-23.8 0-1.3-3.9-14.8-1.1-27 1-4 3-15.3 3.5-15.9-.5-1.4-3-6.4 1-16.3 1.8-4.2 4.2-7.6 5.9-9.7l1.2-2.8C39.2 23 43-.3 46.9 0c7.2.6 17.2 27.3 18 29.1.2.7 7.8 1.3 16.2 1.9 7.8-.6 15.8-1 20-.4 5.2.9 9.6 2.4 13.3 4.1 5 .7 6.9.9 7.2.3 1.6-3.3 6.9-26.7 16.3-32.5 5.1-3 11.5 36.4-1 48.7 0 0-1 3.7-1.5 6.7 3.6 8 .3 18.7.3 18.7 15 6.2 1.7 28.3 1.7 28.3 3.3 3.6 9.7 8 7.5 25"/><path fill="#fef2e2" d="M136.5 11.6c3.1-5.3 9.9 20-3.2 32.3-3.2 3-3.3-2.1-1-17 .7-5.2 2-11.4 4.2-15.3M50 9c-3.4-5.1-8.8 20.5 5 32.1C58.2 44 58 38.8 55 24c-1-5.1-2.7-11.3-5-15M53.3 60.4c8.4-8.7 33.6-6.6 33.6-6.6s25-3 33.7 5.5c0 0 27.6 61.4-32.7 62.8-60.2.5-34.6-61.7-34.6-61.7"/><g clip-path="url(#a)" transform="matrix(.04413 0 0 .04413 -169.3 -148)"><path fill="#fee8de" d="M5008.2 5148.5h403.7v280h-403.7Z"/></g><path fill="#fee8de" d="M112.6 80.2c-4.9 0-8.9 2.8-8.9 6.2 0 3.4 4 6.2 9 6.2 4.9 0 8.9-2.8 8.9-6.2 0-3.4-4-6.2-9-6.2"/><path fill="#231f20" d="M68.3 74.4a3 3 0 1 0 6-.1c0-1.7-1.4-4.2-3-4.2-1.7 0-3 2.6-3 4.3M100.4 75a3 3 0 1 0 5.9 0c0-1.7-1.4-4.2-3-4.2-1.7 0-3 2.6-3 4.3"/><path fill="#eedbcc" d="M61.5 100.2c-.1-7.7 11.7-16.7 24.2-16.9 12.6-.2 24 8.2 24 15.9.1 4-3.5 6.1-7.9 9.1-4.3 3-9 9.8-15.9 10-7 0-11.7-6.7-16.2-9.6-4.4-2.7-8.1-4.5-8.2-8.5"/><path fill="#fff" d="M48.8 44.7c.3-2.6 2.3-4.8 5-4.7-1.4-2.2-2.3-7 2.2-9.3 2.8-1.3 6 1.1 6 1.1s.6-5.6 6.7-6.7c6.4-1.1 10 5.2 10 5.2-.2-5 8.5-8 13.2-7.2 5.9 1 8.7 5.3 8.7 5.3 11.6-7 16 4 16 4 2.5-6.2 11.7-4.3 14.6-.6 3.7 4.9-.7 9-.7 9s8 5.4 4.5 11.6c-4 7.1-11.5 2.7-11.5 2.7-3 15-14.6 2-14.6 2-.9 7-4 13-12.8 11-6-1.4-8-9.4-8-9.4-2 8.2-8.4 7-10.8 4.7a5.8 5.8 0 0 1-1.6-3.6C70 67.3 66 58.6 66 58.6c-4.9 3-9.7 2.8-12.2-.5-1.4-1.9-1.8-4-1-7.4-2.1-.6-4.4-2.3-4-6"/><path fill="#fef2e2" d="m128.1 42.8.7.3a1.8 1.8 0 0 1 .8 1l.1.6-.1 1.3a7.8 7.8 0 0 1-.5 1.3c-.4.8-.9 1.5-1.6 2l-.6.2h-.7c-.2 0-.4 0-.7-.2l-.6-.3-.6-.4.1.7.2 1.1-.1 1.2-.3 1-.5 1-.6.7-.4.4-.4.3-.8.5-1 .3c-.3 0-.6 0-1 .2h-2l-1.1-.2c-.4 0-.8-.2-1.1-.3-.4 0-.7-.2-1.1-.3l-1.1-.4-1.1-.5-.1.2.8.9 1 .8 1 .7 1.2.5 1.2.4 1.3.3h1.3l1.4-.3 1.3-.5 1.1-.8.5-.5.4-.6c.3-.3.5-.8.7-1.2l.3-1.3v-1.3c0-.4 0-.8-.2-1.2L125 49l-.5.4 1.5.8 1 .2h1c.6-.2 1.1-.5 1.6-1a5.2 5.2 0 0 0 1.1-1.5 6.2 6.2 0 0 0 .5-2.7l-.1-.9-.5-.9-.7-.7-1-.3h-.4l-.4.1v.2M89.5 33.5l.3-.4.2-.4v-1c0-.3 0-.6-.2-.9L89 30l-.7-.5-.9-.4-1.8-.3-1 .1-.8.3c-.6.3-1.2.7-1.5 1.2l-.5.9-.2.9.1 1.7.5-.3-1-.7-1-.7-1.2-.5-1.4-.2h-1.3l-.7.2-.7.2-1.2.7-1 1-.8 1-.6 1.3-.3 1.3-.1 1.3v1.3l.2 1.2.3 1.2.5 1.2h.2V42l.1-1.2c0-.3 0-.7.2-1 0-.5 0-.8.2-1.2l.3-1 .4-1 .4-1c.3-.2.4-.5.6-.8l.7-.7.8-.6.4-.2.5-.2 1-.2 1-.1c.4 0 .7 0 1.1.2.4 0 .7.2 1 .4l1 .6.6.3v-.6c-.1-.3-.2-.5-.1-.8v-.7l.4-.6.4-.4c.7-.5 1.6-.6 2.5-.7a6 6 0 0 1 1.4.1l1.2.5c.2 0 .4.2.5.3l.4.5.2.6v.8h.1M63.3 54.2l-.5.1a2 2 0 0 1-.6 0l-.3.1h-.4l-.9-.3c-.3 0-.6-.2-.9-.4-.3-.2-.6-.3-.8-.6l-.8-.7c-.2-.3-.5-.5-.6-.8l-.2-.5-.2-.4-.4-.8-.3-.7V49l-.1-.3v-1.2l-.2-.1-.5.4c-.2.1-.3.3-.4.6l-.4 1v1.1l.4 1.2.4.6.4.5 1 .9 1.1.7 1.2.5 1.1.2H62l.4-.1c.3 0 .5-.2.6-.3l.5-.2v-.2M111.8 40.1l.1-.5.2-.6v-.7c0-.3 0-.6-.2-1l-.3-.8-.5-1-.7-.8c-.2-.2-.5-.5-.8-.6l-.4-.3-.4-.2-.7-.5c-.3 0-.5-.2-.7-.3l-.3-.1h-.3l-.6-.2h-.6v-.2s0-.2.4-.5l.6-.3c.3-.2.6-.3 1-.3l1.1.1 1.2.5.5.4.5.5.8 1 .6 1.2.4 1.2.2 1.2-.1 1-.1.5-.2.4-.2.5-.4.5h-.1"/><path fill="#231f20" d="M85.3 88.8c4.2 0 12.3 0 10.8 3.3-.8 1.7-5.1 4-10.7 4.2-5.6 0-10-2.3-10.8-4C73 89 81 88.8 85.3 88.8"/><path fill="#231f20" d="M83.8 95.5c-.4 3.7.5 7.2 3.8 9.2 3.6 2.2 8.2.8 11.6-1 1.3-.7.1-2.6-1.1-2-2.7 1.5-5.6 2.4-8.6 1.4-3.3-1-3.8-4.6-3.5-7.6.2-1.4-2-1.3-2.2 0"/><path fill="#231f20" d="M83.3 96.3c0 2.5-1 5-3 6.4-3.2 2.2-6.3-.3-8.2-2.7-.9-1.1-2.4.4-1.6 1.5 2.3 3 6 5.5 9.9 3.6a9.5 9.5 0 0 0 5-8.8c0-1.4-2.2-1.4-2.1 0"/></svg>
|
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 5.9 KiB |
|
@ -0,0 +1,12 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 256 256" width="256" height="256">
|
||||
<path d="M2268.2 2512.3a953.7 953.7 0 0 1-50 57c-180.5 189.5-426.2 294-691.6 294A953.7 953.7 0 0 1 847.8 2582a952.7 952.7 0 0 1-281.2-678.8 953.8 953.8 0 0 1 281.2-678.9 953.7 953.7 0 0 1 678.8-281.1 953.7 953.7 0 0 1 678.8 281.1 953.7 953.7 0 0 1 281.2 678.9c0 219.2-78.9 437.2-218.4 609" style="fill:#196aff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1823.7 1650.9c35.7 104.2 94.7 136.1 102 297 2.6 56.5-14.7 236-14.7 236s28 72-25.8 152.3c-83.5 124.3-255.4 132.8-345.7 132.8-90.3 0-260.2-8.5-343.7-132.8C1142 2256 1170 2184 1170 2184s-9.5-92.4-16.7-173.8c-1.7-19.1.1-94.7 2.4-113a453 453 0 0 1 25.8-96.2c14.4-39.6 36.8-79.9 54-120.5 51.8-122.8 8.4-274.9 11.1-407.3 2.2-94-20-189.3-28.7-281.2a960.4 960.4 0 0 1 308.7-50.6 958.6 958.6 0 0 1 344.9 63.6c-20.4 115-44.1 224.2-47.8 265.9-10.6 125.9-41.3 259.4 0 380" style="fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36655635" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1162.9 2383.9c1.1-18.8 3-38 8.3-56.2 1.6-5.7 4-19.7 11.4-21.8 9-2.6 25.9 8.3 32.3 13 12.3 9 23.9 18.5 36.2 27.6 8 6 16.5 10.5 24.3 16.5 8.4 6.6 14.7 14.5 21.7 22.2 8.4 9.4 14.8 19 21.3 29.5 5.1 8.2 37.1 13.5 42.2 21 5.6 8.3 1 18.6 1 28.7 0 74.2 4.4 147.6 6.1 220.3 1.8 50 21.4 109.2-53.4 85.8-160.3-50-158.5-271.3-151.4-386.6M1869.1 2279.7c-1.6 1.8-4.2 3.2-6.3 4.8a208 208 0 0 0-25.1 21.5c-9.4 9.6-19.2 19-28.2 28.9-7.9 8.7-17.3 16.6-25 25.6-5.1 6-10 12.3-14.6 18.5-2.3 3.2-3.5 7-5.3 10.4-2.7 5-40 10.1-36.2 15 6.3 8.3 20.3 15.4 23.7 25 17.2 48.6 24.8 244.5 26.8 294.5 5.4 127.8 117.6-6.3 137.2-57.7 57-149.7 23.2-258.8-46.3-386.6" style="fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1716.5 1787.9c-.1 73.8-9.3 103.6-50.4 139.7-25.8 22.6-55.9 31.2-103.8 30-47.9 1.2-82.4-13.4-107.3-39.2-37.5-39-47.4-62-47.5-135.9 0-39.9 43-128.1 55.7-148.5 21.3-36 60.6-48.9 99.1-46.2 38.6-2.7 77.9 10.3 99.1 46.2 12.8 20.4 55.1 107 55 153.9" style="fill:#f1e6d3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1226.6 2316c-9.6 86.2-38.6 240 61.5 331.3 11 10.1 14-24.2 15.8-38 2.6-19 0-73.5.4-92.6.7-36.1 8.3-55 4.7-71.5-9.6-45-17.3-42.2-26.5-69.6-18.3-54.4-53.3-83-55.9-59.5M1851.7 2333c10.3-18.2 37 80.3 45.4 123.2 8 40.3 18 93.8 4 133.9-7.4 21.5-53 84.5-58.4 62.9-2-8.5-3.2-71.1-8.3-101.1-6.4-37.1-18-73.8-18-111.6-.2-84.5 25.3-88 35.3-107.2" style="fill:#f1d7d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1522 1319.7c-2.2-6.5-18.6-11.4-24.8-13.3-14.9-4.9-28.1 6.9-36.4 16.8-11.6 13.7-11.3 35.6-16.2 51.6-2.9 9.7-19.5 11-24.5 2-16.6-29.8-81.1 26.4-66.1 45.2 9.9 12.3-13.8 23.2-23.6 11-29-36.1 49-103.4 93.6-85.2 2-9 4-18 8-26.6 7.4-16.9 23.9-27.8 41-37 23.1-12.4 68.2 9.5 75 30.3 4.9 14.5-21.2 19.7-26 5.2M1727.6 1538.2c2.4-10 2.8-44-16-25.4-7.5 7.5-22.6 3-23.2-7-1.4-23.4-24.9-24-45.1-16.9-16 5.6-24.6-16.6-8.6-22.1 29.7-10.4 62-4.6 74.7 17.8 10.1-4.7 21.5-6 30.7 2.6 16 15 18.4 36.2 13.7 55.7-3.5 14.8-29.7 10.1-26.2-4.7M1775 1049.2c-7-14.3-19.8-13.4-33.6-7.4-10.1 4.4-22.6-2.8-19.6-13 6.2-20.6-19.7-26.6-37.3-19.3-15.4 6.5-28.8-13.8-13.2-20.3 31.6-13.2 71.7-1.6 77.5 26.2 20.4-3.3 39.8 2.4 49.4 22.3 6.7 13.6-16.4 25.4-23.2 11.5M1569.8 2153.3c-3.3-20.2-41.1 3.3-50.5 9.7-8.3 5.5-19 2.1-20-7.3-1.4-12.7-18.5-9-26.3-7.4-14.8 3-27.4 12.2-27.7 26-.4 13.6 8.2 27.7 12.6 40.4 2.9 8-8.7 17-17.2 11.5-15.2-9.7-88.7-18.5-59.4 13.6 9.3 10.2-7.1 24.8-16.6 14.5-13.5-14.8-22.6-48.7 6.6-56 15.5-3.7 37.8-3.5 56.8.8-8-25.5-9.6-48.8 23.2-65.1 22.1-11.1 52.5-11 65.4 6 27.2-14.5 69.7-28.7 75.6 7.8 2.1 13-20.4 18.5-22.5 5.5" style="fill:#faeee0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1443 1685.6c39.4-3.4 78.8-12.3 118.5-10.9 25.4 1 51.7 4.5 76.8 8.2 18.2 2.7 40.5 6 52.7 19.4 1-45-92.6-59.1-128.9-60-42.1-1-89.5 17.2-119 43.3" style="fill:#494949;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1549.4 1779.5a353.5 353.5 0 0 1-2.7-87.3c.7-7.6-1.3-25.7 8.8-29.5 8.2-3 18.3 2.7 19.7 10.1 2.2 12.5-3 28.2-3.5 41-.5 14.9 0 29.8 1.6 44.7 1 8.8 5.9 20.7-4.2 27-7.4 4.5-18.3 2.8-19.7-6" style="fill:#494949;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1626 1849.7c-23.7-1-45.7-14.2-63.4-27-16.1 10.7-40.5 20.5-60.7 14.8-12-3.4-1.1-7.1 4-10.3 9.2-6.2 16.8-14.2 23.7-22.4 10.3-12.6 19.6-25.8 30.7-38 7.6 5.6 15 11.1 21.6 17.6 3.1 3 28.5 37 32.4 42.7 2.4 3.6 5 7.4 7.8 10.8 2.9 3.5 11 9 3.9 11.8" style="fill:#494949;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1326.5 2010c11.7 30.3 24.3 68.4 56.3 62.4 24.2-5.2 56.7-86.2 36-78.2-11.3 4.4-20.3 41.1-41.4 46-13.4 3-32-43.6-50-48.4-8.7-2.3-4.3 10.4-.9 18.2M1670.6 2010c11.7 30.3 24.2 68.4 56.3 62.4 24.2-5.2 56.7-86.2 35.9-78.2-11.3 4.4-20.2 41.1-41.3 46-13.5 3-32-43.6-50-48.4-8.7-2.3-4.4 10.4-1 18.2" style="fill:#2c3844;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 519 KiB |
|
@ -0,0 +1,118 @@
|
|||
<template>
|
||||
<component
|
||||
:is="componentNodeName"
|
||||
class="base-button"
|
||||
:class="{ 'base-button--type-button': isButton }"
|
||||
v-bind="elementBindings"
|
||||
:disabled="disabled || undefined"
|
||||
>
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// see https://v3.vuejs.org/api/sfc-script-setup.html#usage-alongside-normal-script
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// this component removes styling differences between links / vue-router links and button elements
|
||||
// by doing so we make it easy abstract the functionality from style and enable easier and semantic
|
||||
// correct button and link usage. Also see: https://css-tricks.com/a-complete-guide-to-links-and-buttons/#accessibility-considerations
|
||||
|
||||
// the component tries to heuristically determine what it should be checking the props (see the
|
||||
// componentNodeName and elementBindings ref for this).
|
||||
|
||||
// NOTE: Do NOT use buttons with @click to push routes. => Use router-links instead!
|
||||
|
||||
import { ref, watchEffect, computed, useAttrs, PropType } from 'vue'
|
||||
|
||||
const BASE_BUTTON_TYPES_MAP = Object.freeze({
|
||||
button: 'button',
|
||||
submit: 'submit',
|
||||
})
|
||||
|
||||
type BaseButtonTypes = keyof typeof BASE_BUTTON_TYPES_MAP
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String as PropType<BaseButtonTypes>,
|
||||
default: 'button',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
const componentNodeName = ref<Node['nodeName']>('button')
|
||||
interface ElementBindings {
|
||||
type?: string;
|
||||
rel?: string,
|
||||
}
|
||||
|
||||
const elementBindings = ref({})
|
||||
|
||||
const attrs = useAttrs()
|
||||
watchEffect(() => {
|
||||
// by default this component is a button element with the attribute of the type "button" (default prop value)
|
||||
let nodeName = 'button'
|
||||
let bindings: ElementBindings = {type: props.type}
|
||||
|
||||
// if we find a "to" prop we set it as router-link
|
||||
if ('to' in attrs) {
|
||||
nodeName = 'router-link'
|
||||
bindings = {}
|
||||
}
|
||||
|
||||
// if there is a href we assume the user wants an external link via a link element
|
||||
// we also set the attribute rel to "noopener" but make it possible to overwrite this by the user.
|
||||
if ('href' in attrs) {
|
||||
nodeName = 'a'
|
||||
bindings = {rel: 'noopener'}
|
||||
}
|
||||
|
||||
componentNodeName.value = nodeName
|
||||
elementBindings.value = {
|
||||
...bindings,
|
||||
...attrs,
|
||||
}
|
||||
})
|
||||
|
||||
const isButton = computed(() => componentNodeName.value === 'button')
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// NOTE: we do not use scoped styles to reduce specifity and make it easy to overwrite
|
||||
|
||||
// We reset the default styles of a button element to enable easier styling
|
||||
:where(.base-button--type-button) {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
text-align: center;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
:where(.base-button) {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
user-select: none;
|
||||
pointer-events: auto; // disable possible resets
|
||||
|
||||
&:focus {
|
||||
outline: transparent;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,17 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import LogoFull from '@/assets/logo-full.svg?component'
|
||||
import LogoFullPride from '@/assets/logo-full-pride.svg?component'
|
||||
|
||||
const Logo = computed(() => new Date().getMonth() === 5 ? LogoFullPride : LogoFull)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Logo alt="Vikunja" class="logo" />
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.logo {
|
||||
color: var(--logo-text-color);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<button
|
||||
type="button"
|
||||
@click="$store.commit('toggleMenu')"
|
||||
class="menu-show-button"
|
||||
@shortkey="() => $store.commit('toggleMenu')"
|
||||
v-shortcut="'Control+e'"
|
||||
:title="$t('keyboardShortcuts.toggleMenu')"
|
||||
:aria-label="menuActive ? $t('misc.hideMenu') : $t('misc.showMenu')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue'
|
||||
import {store} from '@/store'
|
||||
|
||||
const menuActive = computed(() => store.menuActive)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$lineWidth: 2rem;
|
||||
$size: $lineWidth + 1rem;
|
||||
|
||||
.menu-show-button {
|
||||
// FIXME: create general button component
|
||||
appearance: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
|
||||
min-height: $size;
|
||||
width: $size;
|
||||
|
||||
position: relative;
|
||||
|
||||
$transformX: translateX(-50%);
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 3px;
|
||||
width: $lineWidth;
|
||||
left: 50%;
|
||||
transform: $transformX;
|
||||
background-color: var(--grey-400);
|
||||
border-radius: 2px;
|
||||
transition: all $transition;
|
||||
}
|
||||
|
||||
&::before {
|
||||
top: 50%;
|
||||
transform: $transformX translateY(-0.4rem)
|
||||
}
|
||||
|
||||
&::after {
|
||||
bottom: 50%;
|
||||
transform: $transformX translateY(0.4rem)
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
&::before,
|
||||
&::after {
|
||||
background-color: var(--grey-600);
|
||||
}
|
||||
|
||||
&::before {
|
||||
transform: $transformX translateY(-0.5rem);
|
||||
}
|
||||
|
||||
&::after {
|
||||
transform: $transformX translateY(0.5rem)
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<a class="menu-bottom-link" :href="poweredByUrl" target="_blank" rel="noreferrer noopener nofollow">
|
||||
{{ $t('misc.poweredBy') }}
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {POWERED_BY as poweredByUrl} from '@/urls'
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.menu-bottom-link {
|
||||
color: var(--grey-300);
|
||||
text-align: center;
|
||||
display: block;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
font-size: .8rem;
|
||||
}
|
||||
</style>
|
|
@ -1,19 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<a @click="$store.commit('menuActive', false)" class="menu-hide-button" v-if="menuActive">
|
||||
<icon icon="times"></icon>
|
||||
<icon icon="times" />
|
||||
</a>
|
||||
<div
|
||||
:class="{'has-background': background}"
|
||||
:style="{'background-image': `url(${background})`}"
|
||||
:style="{'background-image': background && `url(${background})`}"
|
||||
class="app-container"
|
||||
>
|
||||
<navigation/>
|
||||
<div
|
||||
:class="[
|
||||
{
|
||||
'is-menu-enabled': menuActive,
|
||||
},
|
||||
{ 'is-menu-enabled': menuActive },
|
||||
$route.name,
|
||||
]"
|
||||
class="app-content"
|
||||
|
@ -24,15 +22,16 @@
|
|||
|
||||
<router-view/>
|
||||
|
||||
<transition name="modal">
|
||||
<router-view name="popup"/>
|
||||
</transition>
|
||||
<router-view name="popup" v-slot="{ Component }">
|
||||
<transition name="modal">
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</router-view>
|
||||
|
||||
<a
|
||||
class="keyboard-shortcuts-button"
|
||||
@click="showKeyboardShortcuts()"
|
||||
@shortkey="showKeyboardShortcuts()"
|
||||
v-shortkey="['?']"
|
||||
v-shortcut="'?'"
|
||||
>
|
||||
<icon icon="keyboard"/>
|
||||
</a>
|
||||
|
@ -41,98 +40,187 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
<script lang="ts" setup>
|
||||
import {watch, computed} from 'vue'
|
||||
import {useStore} from 'vuex'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import {useEventListener} from '@vueuse/core'
|
||||
|
||||
import {CURRENT_LIST, KEYBOARD_SHORTCUTS_ACTIVE, MENU_ACTIVE} from '@/store/mutation-types'
|
||||
import Navigation from '@/components/home/navigation.vue'
|
||||
import QuickActions from '@/components/quick-actions/quick-actions.vue'
|
||||
|
||||
export default {
|
||||
name: 'contentAuth',
|
||||
components: {QuickActions, Navigation},
|
||||
watch: {
|
||||
'$route': 'doStuffAfterRoute',
|
||||
},
|
||||
created() {
|
||||
this.renewTokenOnFocus()
|
||||
this.loadLabels()
|
||||
},
|
||||
computed: mapState({
|
||||
namespaces(state) {
|
||||
return state.namespaces.namespaces.filter(n => !n.isArchived)
|
||||
},
|
||||
currentList: CURRENT_LIST,
|
||||
background: 'background', // FIXME: Return the full thing or nothing at all to prevent calls to /null
|
||||
menuActive: MENU_ACTIVE,
|
||||
userInfo: state => state.auth.info,
|
||||
authenticated: state => state.auth.authenticated,
|
||||
}),
|
||||
methods: {
|
||||
doStuffAfterRoute() {
|
||||
// this.setTitle('') // Reset the title if the page component does not set one itself
|
||||
this.hideMenuOnMobile()
|
||||
this.resetCurrentList()
|
||||
},
|
||||
resetCurrentList() {
|
||||
// Reset the current list highlight in menu if the current list is not list related.
|
||||
if (
|
||||
this.$route.name === 'home' ||
|
||||
this.$route.name === 'namespace.edit' ||
|
||||
this.$route.name === 'teams.index' ||
|
||||
this.$route.name === 'teams.edit' ||
|
||||
this.$route.name === 'tasks.range' ||
|
||||
this.$route.name === 'labels.index' ||
|
||||
this.$route.name === 'migrate.start' ||
|
||||
this.$route.name === 'migrate.wunderlist' ||
|
||||
this.$route.name === 'user.settings' ||
|
||||
this.$route.name === 'namespaces.index'
|
||||
) {
|
||||
this.$store.commit(CURRENT_LIST, null)
|
||||
}
|
||||
},
|
||||
renewTokenOnFocus() {
|
||||
// Try renewing the token every time vikunja is loaded initially
|
||||
// (When opening the browser the focus event is not fired)
|
||||
this.$store.dispatch('auth/renewToken')
|
||||
const store = useStore()
|
||||
|
||||
// Check if the token is still valid if the window gets focus again to maybe renew it
|
||||
window.addEventListener('focus', () => {
|
||||
const background = computed(() => store.state.background)
|
||||
const menuActive = computed(() => store.state.menuActive)
|
||||
|
||||
if (!this.authenticated) {
|
||||
return
|
||||
}
|
||||
|
||||
const expiresIn = (this.userInfo !== null ? this.userInfo.exp : 0) - +new Date() / 1000
|
||||
|
||||
// If the token expiry is negative, it is already expired and we have no choice but to redirect
|
||||
// the user to the login page
|
||||
if (expiresIn < 0) {
|
||||
this.$store.dispatch('auth/checkAuth')
|
||||
this.$router.push({name: 'user.login'})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the token is valid for less than 60 hours and renew if thats the case
|
||||
if (expiresIn < 60 * 3600) {
|
||||
this.$store.dispatch('auth/renewToken')
|
||||
console.debug('renewed token')
|
||||
}
|
||||
})
|
||||
},
|
||||
hideMenuOnMobile() {
|
||||
if (window.innerWidth < 769) {
|
||||
this.$store.commit(MENU_ACTIVE, false)
|
||||
}
|
||||
},
|
||||
showKeyboardShortcuts() {
|
||||
this.$store.commit(KEYBOARD_SHORTCUTS_ACTIVE, true)
|
||||
},
|
||||
loadLabels() {
|
||||
this.$store.dispatch('labels/loadAllLabels')
|
||||
.catch(e => {
|
||||
this.error(e)
|
||||
})
|
||||
},
|
||||
},
|
||||
function showKeyboardShortcuts() {
|
||||
store.commit(KEYBOARD_SHORTCUTS_ACTIVE, true)
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// hide menu on mobile
|
||||
watch(() => route.fullPath, () => window.innerWidth < 769 && store.commit(MENU_ACTIVE, false))
|
||||
|
||||
// FIXME: this is really error prone
|
||||
// Reset the current list highlight in menu if the current route is not list related.
|
||||
watch(() => route.name as string, (routeName) => {
|
||||
if (
|
||||
routeName &&
|
||||
(
|
||||
[
|
||||
'home',
|
||||
'namespace.edit',
|
||||
'teams.index',
|
||||
'teams.edit',
|
||||
'tasks.range',
|
||||
'labels.index',
|
||||
'migrate.start',
|
||||
'migrate.wunderlist',
|
||||
'namespaces.index',
|
||||
].includes(routeName) ||
|
||||
routeName.startsWith('user.settings')
|
||||
)
|
||||
) {
|
||||
store.dispatch(CURRENT_LIST, null)
|
||||
}
|
||||
})
|
||||
|
||||
// TODO: Reset the title if the page component does not set one itself
|
||||
|
||||
function useRenewTokenOnFocus() {
|
||||
const router = useRouter()
|
||||
|
||||
const userInfo = computed(() => store.state.auth.info)
|
||||
const authenticated = computed(() => store.state.auth.authenticated)
|
||||
|
||||
// Try renewing the token every time vikunja is loaded initially
|
||||
// (When opening the browser the focus event is not fired)
|
||||
store.dispatch('auth/renewToken')
|
||||
|
||||
// Check if the token is still valid if the window gets focus again to maybe renew it
|
||||
useEventListener('focus', () => {
|
||||
if (!authenticated.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const expiresIn = (userInfo.value !== null ? userInfo.value.exp : 0) - +new Date() / 1000
|
||||
|
||||
// If the token expiry is negative, it is already expired and we have no choice but to redirect
|
||||
// the user to the login page
|
||||
if (expiresIn < 0) {
|
||||
store.dispatch('auth/checkAuth')
|
||||
router.push({name: 'user.login'})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the token is valid for less than 60 hours and renew if thats the case
|
||||
if (expiresIn < 60 * 3600) {
|
||||
store.dispatch('auth/renewToken')
|
||||
console.debug('renewed token')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
useRenewTokenOnFocus()
|
||||
store.dispatch('labels/loadAllLabels')
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.menu-hide-button {
|
||||
position: fixed;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
z-index: 31;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 2rem;
|
||||
color: var(--grey-400);
|
||||
line-height: 1;
|
||||
transition: all $transition;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
height: 1rem;
|
||||
color: var(--grey-600);
|
||||
}
|
||||
}
|
||||
|
||||
.app-container {
|
||||
min-height: calc(100vh - 65px);
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
padding-top: $navbar-height;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
padding: $navbar-height + 1.5rem 1.5rem 1rem 1.5rem;
|
||||
z-index: 2;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
margin-left: 0;
|
||||
padding-top: 1.5rem;
|
||||
min-height: calc(100vh - 4rem);
|
||||
}
|
||||
|
||||
&.is-menu-enabled {
|
||||
margin-left: $navbar-width;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
min-width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.task\.detail {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--white);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(250, 250, 250, 0.8);
|
||||
z-index: 5;
|
||||
opacity: 0;
|
||||
transition: all $transition;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.keyboard-shortcuts-button {
|
||||
position: fixed;
|
||||
bottom: calc(1rem - 4px);
|
||||
right: 1rem;
|
||||
z-index: 4500; // The modal has a z-index of 4000
|
||||
|
||||
color: var(--grey-500);
|
||||
transition: color $transition;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<div
|
||||
:class="[background ? 'has-background' : '', $route.name+'-view']"
|
||||
:class="[background ? 'has-background' : '', $route.name as string +'-view']"
|
||||
:style="{'background-image': `url(${background})`}"
|
||||
class="link-share-container"
|
||||
>
|
||||
<div class="container has-text-centered link-share-view">
|
||||
<div class="column is-10 is-offset-1">
|
||||
<img alt="Vikunja" class="logo" src="/images/logo-full.svg"/>
|
||||
<Logo class="logo" />
|
||||
<h1
|
||||
:style="{ 'opacity': currentList.title === '' ? '0': '1' }"
|
||||
class="title">
|
||||
|
@ -14,30 +14,47 @@
|
|||
</h1>
|
||||
<div class="box has-text-left view">
|
||||
<router-view/>
|
||||
<a class="menu-bottom-link" href="https://vikunja.io" target="_blank" rel="noreferrer noopener nofollow">
|
||||
{{ $t('misc.poweredBy') }}
|
||||
</a>
|
||||
<PoweredByLink />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
import {CURRENT_LIST} from '@/store/mutation-types'
|
||||
<script lang="ts" setup>
|
||||
import {computed} from 'vue'
|
||||
import {useStore} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'contentLinkShare',
|
||||
computed: mapState({
|
||||
currentList: CURRENT_LIST,
|
||||
background: 'background',
|
||||
}),
|
||||
methods: {
|
||||
logout() {
|
||||
this.$store.dispatch('auth/logout')
|
||||
this.$router.push({name: 'user.login'})
|
||||
},
|
||||
},
|
||||
}
|
||||
import Logo from '@/components/home/Logo.vue'
|
||||
import PoweredByLink from './PoweredByLink.vue'
|
||||
|
||||
const store = useStore()
|
||||
const currentList = computed(() => store.state.currentList)
|
||||
const background = computed(() => store.state.background)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.link-share-container.has-background .view {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
max-width: 300px;
|
||||
width: 90%;
|
||||
margin: 2rem 0 1.5rem;
|
||||
}
|
||||
|
||||
.column {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-shadow: 0 0 1rem var(--white);
|
||||
}
|
||||
|
||||
// FIXME: this should be defined somewhere deep
|
||||
.link-share-view .card {
|
||||
background-color: var(--white);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
<template>
|
||||
<div class="no-auth-wrapper">
|
||||
<div class="noauth-container">
|
||||
<img alt="Vikunja" src="/images/logo-full.svg" width="400" height="117"/>
|
||||
<div class="message is-info" v-if="motd !== ''">
|
||||
<div class="message-header">
|
||||
<p>{{ $t('misc.info') }}</p>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
{{ motd }}
|
||||
</div>
|
||||
</div>
|
||||
<router-view/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'contentNoAuth',
|
||||
created() {
|
||||
this.redirectToHome()
|
||||
},
|
||||
computed: mapState({
|
||||
motd: state => state.config.motd,
|
||||
}),
|
||||
methods: {
|
||||
redirectToHome() {
|
||||
// Check if the user is already logged in and redirect them to the home page if not
|
||||
if (
|
||||
this.$route.name !== 'user.login' &&
|
||||
this.$route.name !== 'user.password-reset.request' &&
|
||||
this.$route.name !== 'user.password-reset.reset' &&
|
||||
this.$route.name !== 'user.register' &&
|
||||
this.$route.name !== 'link-share.auth' &&
|
||||
this.$route.name !== 'openid.auth' &&
|
||||
localStorage.getItem('passwordResetToken') === null &&
|
||||
localStorage.getItem('emailConfirmToken') === null
|
||||
) {
|
||||
this.$router.push({name: 'user.login'})
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -2,7 +2,7 @@
|
|||
<div :class="{'is-active': menuActive}" class="namespace-container">
|
||||
<div class="menu top-menu">
|
||||
<router-link :to="{name: 'home'}" class="logo">
|
||||
<img alt="Vikunja" src="/images/logo-full.svg" width="164" height="48"/>
|
||||
<Logo width="164" height="48" />
|
||||
</router-link>
|
||||
<ul class="menu-list">
|
||||
<li>
|
||||
|
@ -48,20 +48,20 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<aside class="menu namespaces-lists loader-container" :class="{'is-loading': loading}">
|
||||
<template v-for="(n, nk) in namespaces">
|
||||
<div :key="n.id" class="namespace-title" :class="{'has-menu': n.id > 0}">
|
||||
<aside class="menu namespaces-lists loader-container is-loading-small" :class="{'is-loading': loading}">
|
||||
<template v-for="(n, nk) in namespaces" :key="n.id" >
|
||||
<div class="namespace-title" :class="{'has-menu': n.id > 0}">
|
||||
<span
|
||||
@click="toggleLists(n.id)"
|
||||
class="menu-label"
|
||||
v-tooltip="getNamespaceTitle(n) + ' (' + n.lists.filter(l => !l.isArchived).length + ')'">
|
||||
v-tooltip="namespaceTitles[nk]">
|
||||
<span class="name">
|
||||
<span
|
||||
:style="{ backgroundColor: n.hexColor }"
|
||||
class="color-bubble"
|
||||
v-if="n.hexColor !== ''">
|
||||
</span>
|
||||
{{ getNamespaceTitle(n) }} ({{ n.lists.filter(l => !l.isArchived).length }})
|
||||
{{ namespaceTitles[nk] }}
|
||||
</span>
|
||||
</span>
|
||||
<a
|
||||
|
@ -74,86 +74,106 @@
|
|||
<namespace-settings-dropdown :namespace="n" v-if="n.id > 0"/>
|
||||
</div>
|
||||
<div
|
||||
v-if="listsVisible[n.id] ?? true"
|
||||
:key="n.id + 'child'"
|
||||
class="more-container"
|
||||
v-if="typeof listsVisible[n.id] !== 'undefined' ? listsVisible[n.id] : true"
|
||||
>
|
||||
<!--
|
||||
NOTE: a v-model / computed setter is not possible, since the updateActiveLists function
|
||||
triggered by the change needs to have access to the current namespace
|
||||
-->
|
||||
<draggable
|
||||
:value="activeLists[nk]"
|
||||
@input="(lists) => updateActiveLists(n, lists)"
|
||||
v-bind="dragOptions"
|
||||
:modelValue="activeLists[nk]"
|
||||
@update:modelValue="(lists) => updateActiveLists(n, lists)"
|
||||
:group="`namespace-${n.id}-lists`"
|
||||
@start="() => drag = true"
|
||||
@end="e => saveListPosition(e, nk)"
|
||||
v-bind="dragOptions"
|
||||
handle=".handle"
|
||||
:disabled="n.id < 0"
|
||||
:class="{'dragging-disabled': n.id < 0}"
|
||||
:disabled="n.id < 0 || null"
|
||||
tag="transition-group"
|
||||
item-key="id"
|
||||
:component-data="{
|
||||
type: 'transition',
|
||||
tag: 'ul',
|
||||
name: !drag ? 'flip-list' : null,
|
||||
class: [
|
||||
'menu-list can-be-hidden',
|
||||
{ 'dragging-disabled': n.id < 0 }
|
||||
]
|
||||
}"
|
||||
>
|
||||
<transition-group
|
||||
type="transition"
|
||||
:name="!drag ? 'flip-list' : null"
|
||||
tag="ul"
|
||||
class="menu-list can-be-hidden"
|
||||
>
|
||||
<template #item="{element: l}">
|
||||
<li
|
||||
v-for="l in activeLists[nk]"
|
||||
:key="l.id"
|
||||
class="loader-container"
|
||||
class="loader-container is-loading-small"
|
||||
:class="{'is-loading': listUpdating[l.id]}"
|
||||
>
|
||||
<router-link
|
||||
class="list-menu-link"
|
||||
:class="{'router-link-exact-active': currentList.id === l.id}"
|
||||
:to="{ name: 'list.index', params: { listId: l.id} }"
|
||||
tag="span"
|
||||
v-slot="{ href, navigate, isActive }"
|
||||
custom
|
||||
>
|
||||
<span class="icon handle">
|
||||
<icon icon="grip-lines"/>
|
||||
</span>
|
||||
<span
|
||||
:style="{ backgroundColor: l.hexColor }"
|
||||
class="color-bubble"
|
||||
v-if="l.hexColor !== ''">
|
||||
</span>
|
||||
<span class="list-menu-title">
|
||||
{{ getListTitle(l) }}
|
||||
</span>
|
||||
<span
|
||||
:class="{'is-favorite': l.isFavorite}"
|
||||
@click.stop="toggleFavoriteList(l)"
|
||||
class="favorite">
|
||||
<icon icon="star" v-if="l.isFavorite"/>
|
||||
<icon :icon="['far', 'star']" v-else/>
|
||||
</span>
|
||||
<a
|
||||
@click="navigate"
|
||||
:href="href"
|
||||
class="list-menu-link"
|
||||
:class="{'router-link-exact-active': isActive || currentList?.id === l.id}"
|
||||
>
|
||||
<span class="icon handle">
|
||||
<icon icon="grip-lines"/>
|
||||
</span>
|
||||
<span
|
||||
:style="{ backgroundColor: l.hexColor }"
|
||||
class="color-bubble"
|
||||
v-if="l.hexColor !== ''">
|
||||
</span>
|
||||
<span class="list-menu-title">
|
||||
{{ getListTitle(l) }}
|
||||
</span>
|
||||
<span
|
||||
:class="{'is-favorite': l.isFavorite}"
|
||||
@click.prevent.stop="toggleFavoriteList(l)"
|
||||
class="favorite">
|
||||
<icon :icon="l.isFavorite ? 'star' : ['far', 'star']" />
|
||||
</span>
|
||||
</a>
|
||||
</router-link>
|
||||
<list-settings-dropdown :list="l" v-if="l.id > 0"/>
|
||||
<span class="list-setting-spacer" v-else></span>
|
||||
</li>
|
||||
</transition-group>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
</template>
|
||||
</aside>
|
||||
<a class="menu-bottom-link" href="https://vikunja.io" target="_blank" rel="noreferrer noopener nofollow">
|
||||
{{ $t('misc.poweredBy') }}
|
||||
</a>
|
||||
<PoweredByLink />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
import {CURRENT_LIST, MENU_ACTIVE, LOADING, LOADING_MODULE} from '@/store/mutation-types'
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
|
||||
import NamespaceSettingsDropdown from '@/components/namespace/namespace-settings-dropdown.vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import PoweredByLink from '@/components/home/PoweredByLink.vue'
|
||||
import Logo from '@/components/home/Logo.vue'
|
||||
|
||||
import {CURRENT_LIST, MENU_ACTIVE, LOADING, LOADING_MODULE} from '@/store/mutation-types'
|
||||
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
|
||||
|
||||
|
||||
export default {
|
||||
name: 'navigation',
|
||||
|
||||
components: {
|
||||
ListSettingsDropdown,
|
||||
NamespaceSettingsDropdown,
|
||||
draggable,
|
||||
Logo,
|
||||
PoweredByLink,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
listsVisible: {},
|
||||
|
@ -165,11 +185,6 @@ export default {
|
|||
listUpdating: {},
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ListSettingsDropdown,
|
||||
NamespaceSettingsDropdown,
|
||||
draggable,
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
namespaces: state => state.namespaces.namespaces.filter(n => !n.isArchived),
|
||||
|
@ -179,15 +194,22 @@ export default {
|
|||
loading: state => state[LOADING] && state[LOADING_MODULE] === 'namespaces',
|
||||
}),
|
||||
activeLists() {
|
||||
return this.namespaces.map(({lists}) => lists.filter(item => !item.isArchived))
|
||||
return this.namespaces.map(({lists}) => lists?.filter(item => !item.isArchived))
|
||||
},
|
||||
namespaceTitles() {
|
||||
return this.namespaces.map((namespace, index) => {
|
||||
const title = this.getNamespaceTitle(namespace)
|
||||
return `${title} (${this.activeLists[index]?.length ?? 0})`
|
||||
})
|
||||
},
|
||||
},
|
||||
beforeCreate() {
|
||||
// FIXME: async action in beforeCreate, might be unfinished when component mounts
|
||||
this.$store.dispatch('namespaces/loadNamespaces')
|
||||
.then(namespaces => {
|
||||
namespaces.forEach(n => {
|
||||
if (typeof this.listsVisible[n.id] === 'undefined') {
|
||||
this.$set(this.listsVisible, n.id, true)
|
||||
this.listsVisible[n.id] = true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -206,18 +228,13 @@ export default {
|
|||
return
|
||||
}
|
||||
this.$store.dispatch('lists/toggleListFavorite', list)
|
||||
.catch(e => this.error(e))
|
||||
},
|
||||
resize() {
|
||||
// Hide the menu by default on mobile
|
||||
if (window.innerWidth < 770) {
|
||||
this.$store.commit(MENU_ACTIVE, false)
|
||||
} else {
|
||||
this.$store.commit(MENU_ACTIVE, true)
|
||||
}
|
||||
this.$store.commit(MENU_ACTIVE, window.innerWidth >= 770)
|
||||
},
|
||||
toggleLists(namespaceId) {
|
||||
this.$set(this.listsVisible, namespaceId, !this.listsVisible[namespaceId] ?? false)
|
||||
this.listsVisible[namespaceId] = !this.listsVisible[namespaceId]
|
||||
},
|
||||
updateActiveLists(namespace, activeLists) {
|
||||
// this is a bit hacky: since we do have to filter out the archived items from the list
|
||||
|
@ -237,34 +254,309 @@ export default {
|
|||
|
||||
this.$store.commit('namespaces/setNamespaceById', newNamespace)
|
||||
},
|
||||
saveListPosition(e, namespaceIndex) {
|
||||
|
||||
async saveListPosition(e, namespaceIndex) {
|
||||
const listsActive = this.activeLists[namespaceIndex]
|
||||
const list = listsActive[e.newIndex]
|
||||
const listBefore = listsActive[e.newIndex - 1] ?? null
|
||||
const listAfter = listsActive[e.newIndex + 1] ?? null
|
||||
this.$set(this.listUpdating, list.id, true)
|
||||
this.listUpdating[list.id] = true
|
||||
|
||||
const position = calculateItemPosition(listBefore !== null ? listBefore.position : null, listAfter !== null ? listAfter.position : null)
|
||||
|
||||
// create a copy of the list in order to not violate vuex mutations
|
||||
this.$store.dispatch('lists/updateList', {
|
||||
...list,
|
||||
position,
|
||||
})
|
||||
.catch(e => {
|
||||
this.error(e)
|
||||
})
|
||||
.finally(() => {
|
||||
this.$set(this.listUpdating, list.id, false)
|
||||
try {
|
||||
// create a copy of the list in order to not violate vuex mutations
|
||||
await this.$store.dispatch('lists/updateList', {
|
||||
...list,
|
||||
position,
|
||||
})
|
||||
} finally {
|
||||
this.listUpdating[list.id] = false
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
$navbar-padding: 2rem;
|
||||
$vikunja-nav-background: var(--site-background);
|
||||
$vikunja-nav-color: var(--grey-700);
|
||||
$vikunja-nav-selected-width: 0.4rem;
|
||||
|
||||
.namespace-container {
|
||||
z-index: 6;
|
||||
background: $vikunja-nav-background;
|
||||
color: $vikunja-nav-color;
|
||||
padding: 0 0 1rem;
|
||||
transition: transform $transition-duration ease-in;
|
||||
position: fixed;
|
||||
top: $navbar-height;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
overflow-x: auto;
|
||||
width: $navbar-width;
|
||||
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
top: 0;
|
||||
width: 70vw;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
transform: translateX(0);
|
||||
transition: transform $transition-duration ease-out;
|
||||
}
|
||||
|
||||
.menu {
|
||||
.menu-label {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
font-weight: bold;
|
||||
font-family: $vikunja-font;
|
||||
color: $vikunja-nav-color;
|
||||
font-weight: 500;
|
||||
min-height: 2.5rem;
|
||||
padding-top: 0;
|
||||
padding-left: $navbar-padding;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menu-label,
|
||||
.menu-list span.list-menu-link,
|
||||
.menu-list a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
|
||||
.list-menu-title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.color-bubble {
|
||||
height: 12px;
|
||||
flex: 0 0 12px;
|
||||
}
|
||||
|
||||
.favorite {
|
||||
margin-left: .25rem;
|
||||
transition: opacity $transition, color $transition;
|
||||
opacity: 0;
|
||||
|
||||
&:hover {
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
&.is-favorite {
|
||||
opacity: 1;
|
||||
color: var(--warning);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .favorite {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
.color-bubble {
|
||||
width: 14px !important;
|
||||
height: 14px !important;
|
||||
}
|
||||
|
||||
.is-archived {
|
||||
min-width: 85px;
|
||||
}
|
||||
}
|
||||
|
||||
.namespace-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.menu-label {
|
||||
margin-bottom: 0;
|
||||
flex: 1 1 auto;
|
||||
|
||||
.name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
a:not(.dropdown-item) {
|
||||
color: $vikunja-nav-color;
|
||||
padding: 0 .25rem;
|
||||
}
|
||||
|
||||
:deep(.dropdown-trigger) {
|
||||
padding: .5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.toggle-lists-icon {
|
||||
svg {
|
||||
transition: all $transition;
|
||||
transform: rotate(90deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.active svg {
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .toggle-lists-icon svg {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:not(.has-menu) .toggle-lists-icon {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-label,
|
||||
.nsettings,
|
||||
.menu-list span.list-menu-link,
|
||||
.menu-list a {
|
||||
color: $vikunja-nav-color;
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
li {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
background: var(--white);
|
||||
}
|
||||
|
||||
:deep(.dropdown-trigger) {
|
||||
opacity: 0;
|
||||
padding: .5rem;
|
||||
cursor: pointer;
|
||||
transition: $transition;
|
||||
}
|
||||
|
||||
&:hover :deep(.dropdown-trigger) {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.flip-list-move {
|
||||
transition: transform $transition-duration;
|
||||
}
|
||||
|
||||
.ghost {
|
||||
background: var(--grey-200);
|
||||
|
||||
* {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
span.list-menu-link, li > a {
|
||||
padding: 0.75rem .5rem 0.75rem ($navbar-padding * 1.5 - 1.75rem);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
border-radius: 0;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
border-left: $vikunja-nav-selected-width solid transparent;
|
||||
|
||||
.icon {
|
||||
height: 1rem;
|
||||
vertical-align: middle;
|
||||
padding-right: 0.5rem;
|
||||
|
||||
&.handle {
|
||||
opacity: 0;
|
||||
transition: opacity $transition;
|
||||
margin-right: .25rem;
|
||||
cursor: grab;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .icon.handle {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.router-link-exact-active {
|
||||
color: var(--primary);
|
||||
border-left: $vikunja-nav-selected-width solid var(--primary);
|
||||
|
||||
.icon {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-left: $vikunja-nav-selected-width solid var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: block;
|
||||
|
||||
padding-left: 2rem;
|
||||
margin-right: 1rem;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.namespaces-lists {
|
||||
padding-top: math.div($navbar-padding, 2);
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: var(--grey-400) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.top-menu {
|
||||
margin-top: math.div($navbar-padding, 2);
|
||||
|
||||
.menu-list {
|
||||
li {
|
||||
font-weight: 500;
|
||||
font-family: $vikunja-font;
|
||||
}
|
||||
|
||||
span.list-menu-link, li > a {
|
||||
padding-left: 2rem;
|
||||
display: inline-block;
|
||||
|
||||
.icon {
|
||||
padding-bottom: .25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-setting-spacer {
|
||||
width: 32px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.namespaces-list.loader-container.is-loading {
|
||||
min-height: calc(100vh - #{$navbar-height + 1.5rem + 1rem + 1.5rem});
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -5,25 +5,11 @@
|
|||
class="navbar main-theme is-fixed-top"
|
||||
role="navigation"
|
||||
>
|
||||
<div class="navbar-brand">
|
||||
<router-link :to="{name: 'home'}" class="navbar-item logo">
|
||||
<img width="164" height="48" alt="Vikunja" src="/images/logo-full-pride.svg" v-if="(new Date()).getMonth() === 5"/>
|
||||
<img width="164" height="48" alt="Vikunja" src="/images/logo-full.svg" v-else/>
|
||||
</router-link>
|
||||
<a
|
||||
@click="$store.commit('toggleMenu')"
|
||||
class="menu-show-button"
|
||||
@shortkey="() => $store.commit('toggleMenu')"
|
||||
v-shortkey="['ctrl', 'e']"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
<a
|
||||
@click="$store.commit('toggleMenu')"
|
||||
class="menu-show-button"
|
||||
>
|
||||
</a>
|
||||
<div class="list-title" ref="listTitle" :style="{'display': currentList.id ? '': 'none'}">
|
||||
<router-link :to="{name: 'home'}" class="logo-link">
|
||||
<Logo width="164" height="48"/>
|
||||
</router-link>
|
||||
<MenuButton class="menu-button"/>
|
||||
<div class="list-title" ref="listTitle" v-show="currentList.id">
|
||||
<template v-if="currentList.id">
|
||||
<h1
|
||||
:style="{ 'opacity': currentList.title === '' ? '0': '1' }"
|
||||
|
@ -40,8 +26,8 @@
|
|||
<a
|
||||
@click="openQuickActions"
|
||||
class="trigger-button pr-0"
|
||||
@shortkey="openQuickActions"
|
||||
v-shortkey="['ctrl', 'k']"
|
||||
v-shortcut="'Control+k'"
|
||||
:title="$t('keyboardShortcuts.quickSearch')"
|
||||
>
|
||||
<icon icon="search"/>
|
||||
</a>
|
||||
|
@ -49,9 +35,9 @@
|
|||
<div class="user">
|
||||
<img :src="userAvatar" alt="" class="avatar" width="40" height="40"/>
|
||||
<dropdown class="is-right" ref="usernameDropdown">
|
||||
<template v-slot:trigger>
|
||||
<template #trigger>
|
||||
<x-button
|
||||
type="secondary"
|
||||
variant="secondary"
|
||||
:shadow="false">
|
||||
<span class="username">{{ userInfo.name !== '' ? userInfo.name : userInfo.username }}</span>
|
||||
<span class="icon is-small">
|
||||
|
@ -97,11 +83,13 @@
|
|||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
import {CURRENT_LIST, QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
|
||||
import Rights from '@/models/rights.json'
|
||||
import Rights from '@/models/constants/rights.json'
|
||||
import Update from '@/components/home/update.vue'
|
||||
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
|
||||
import Dropdown from '@/components/misc/dropdown.vue'
|
||||
import Notifications from '@/components/notifications/notifications.vue'
|
||||
import Logo from '@/components/home/Logo.vue'
|
||||
import MenuButton from '@/components/home/MenuButton.vue'
|
||||
|
||||
export default {
|
||||
name: 'topNavigation',
|
||||
|
@ -110,17 +98,21 @@ export default {
|
|||
Dropdown,
|
||||
ListSettingsDropdown,
|
||||
Update,
|
||||
Logo,
|
||||
MenuButton,
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
userInfo: state => state.auth.info,
|
||||
userAvatar: state => state.auth.avatarUrl,
|
||||
userAuthenticated: state => state.auth.authenticated,
|
||||
currentList: CURRENT_LIST,
|
||||
background: 'background',
|
||||
imprintUrl: state => state.config.legal.imprintUrl,
|
||||
privacyPolicyUrl: state => state.config.legal.privacyPolicyUrl,
|
||||
canWriteCurrentList: state => state.currentList.maxRight > Rights.READ,
|
||||
}),
|
||||
},
|
||||
computed: mapState({
|
||||
userInfo: state => state.auth.info,
|
||||
userAvatar: state => state.auth.avatarUrl,
|
||||
userAuthenticated: state => state.auth.authenticated,
|
||||
currentList: CURRENT_LIST,
|
||||
background: 'background',
|
||||
imprintUrl: state => state.config.legal.imprintUrl,
|
||||
privacyPolicyUrl: state => state.config.legal.privacyPolicyUrl,
|
||||
canWriteCurrentList: state => state.currentList.maxRight > Rights.READ,
|
||||
}),
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
if (typeof this.$refs.usernameDropdown === 'undefined' || typeof this.$refs.listTitle === 'undefined') {
|
||||
|
@ -142,3 +134,160 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$vikunja-nav-logo-full-width: 164px;
|
||||
$user-dropdown-width-mobile: 5rem;
|
||||
|
||||
$hamburger-menu-icon-spacing: 1rem;
|
||||
$hamburger-menu-icon-width: 28px;
|
||||
|
||||
.navbar {
|
||||
z-index: 4 !important;
|
||||
}
|
||||
|
||||
.logo-link {
|
||||
display: none;
|
||||
padding: 0.5rem 0.75rem;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 2rem;
|
||||
margin-right: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-button {
|
||||
align-self: stretch;
|
||||
margin-right: auto;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
margin-left: $hamburger-menu-icon-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar.main-theme {
|
||||
background: var(--site-background);
|
||||
z-index: 5 !important;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
@media screen and (max-width: $desktop) {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
font-size: 1.75rem;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.navbar-end {
|
||||
margin-left: 0;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
.user {
|
||||
width: $user-dropdown-width-mobile;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
:deep(.dropdown-trigger) {
|
||||
line-height: 1;
|
||||
|
||||
.button {
|
||||
padding: 0 0.25rem;
|
||||
height: 1rem;
|
||||
|
||||
.icon {
|
||||
width: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.username {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar {
|
||||
// FIXME: notifications should provide a slot for the icon instead, so that we can style it as we want
|
||||
:deep() {
|
||||
.trigger-button {
|
||||
cursor: pointer;
|
||||
color: var(--grey-400);
|
||||
padding: .5rem;
|
||||
font-size: 1.25rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
> * > .trigger-button {
|
||||
width: $navbar-icon-width;
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-family: $vikunja-font;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 100%;
|
||||
vertical-align: middle;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
:deep(.dropdown-trigger .button) {
|
||||
background: none;
|
||||
|
||||
&:focus:not(:active), &:active {
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
$edit-icon-width: 1rem;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
// We need a fixed width for overflowing ellipsis to work
|
||||
--nav-username-width: 0;
|
||||
width: calc(100vw - #{$user-dropdown-width-mobile} - #{2 * $hamburger-menu-icon-spacing} - #{$hamburger-menu-icon-width} - #{$edit-icon-width} - #{2 * $navbar-icon-width} - #{$vikunja-nav-logo-full-width} - var(--nav-username-width));
|
||||
}
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
// We need a fixed width for overflowing ellipsis to work
|
||||
width: calc(100vw - #{$user-dropdown-width-mobile} - #{2 * $hamburger-menu-icon-spacing} - #{$hamburger-menu-icon-width} - #{$edit-icon-width} - #{2 * $navbar-icon-width});
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.dropdown-trigger) {
|
||||
color: var(--grey-400);
|
||||
margin-left: 1rem;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|