Compare commits

..

115 Commits

Author SHA1 Message Date
eb80406fdb 🚀RELEASE v0.18.0 2023-04-12 21:36:26 +02:00
9ae5e62e5d Module 2023-04-12 21:36:10 +02:00
1613ae7de6 Versionbuilder 2023-04-12 21:35:32 +02:00
ed1caa7be7 new license file version [CI SKIP] 2023-04-12 19:32:09 +00:00
d88f3a5a27 Merge pull request 'experiment/tanstack' (#172) from experiment/tanstack into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #172
2023-04-12 19:31:47 +00:00
c98eb49ae3 drop legacy dependencies 2023-04-12 21:31:25 +02:00
6d9d8a4724 Scans deletion 2023-04-12 21:25:33 +02:00
7d8c68a455 Scan deletion 2023-04-12 21:25:26 +02:00
8f33640bec Reactivated generate cards modal 2023-04-12 21:20:56 +02:00
f89023e24a Always load bulk created cards 2023-04-12 21:17:53 +02:00
f5d14f2e18 Scan reactive add 2023-04-12 21:14:37 +02:00
9811ede3b2 removed unused import 2023-04-12 21:11:56 +02:00
b2e51fea48 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 21:11:08 +02:00
2a915620c9 Import add to datatable 2023-04-12 21:11:06 +02:00
526688935f Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 21:10:51 +02:00
c7dcf7c66d scan delete working 2023-04-12 21:10:36 +02:00
06411dc147 Add runners reactivity 2023-04-12 21:09:40 +02:00
195d182cc9 Add Card appends current cards 2023-04-12 21:04:29 +02:00
17217dae76 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 20:54:33 +02:00
f105cc0a41 wip: delete scans 2023-04-12 20:54:09 +02:00
2f62c7ae89 Fixed killing of the dom 2023-04-12 20:54:00 +02:00
f6c1fea17c Added status filter function 2023-04-12 20:47:36 +02:00
178dc93319 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 20:43:09 +02:00
8ffe8eff06 Basic card delete modal 2023-04-12 20:43:08 +02:00
bd4952ee57 wip:ScanValid badge 2023-04-12 20:40:04 +02:00
4b171fd04f ScansOverview: use CardRunner link 2023-04-12 20:36:56 +02:00
2c198cfde8 Added custom filter to scan overview 2023-04-12 20:33:30 +02:00
7c6d39b5fa Added custom runner filter 2023-04-12 20:32:24 +02:00
9c13b2f9e9 fix(CardsOverview): table scroll + checkbox posititioning 2023-04-12 20:27:12 +02:00
1ec9556aa6 ScansOverview: fallback for manual scans 2023-04-12 20:22:59 +02:00
adec38b50b Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 20:20:31 +02:00
a35af6f020 Moved data loading to onmount 2023-04-12 20:20:30 +02:00
e74ff5e885 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 20:20:10 +02:00
c87561f63b wip: ScansOverview -> new datatable 2023-04-12 20:19:48 +02:00
c681570134 Fixed edit dispatch 2023-04-12 20:15:43 +02:00
53b945c72f Moved update card logic to overview 2023-04-12 20:14:04 +02:00
f6985daec7 Cards details modal 2023-04-12 20:07:46 +02:00
5662c3b6da Basic card table replace 2023-04-12 20:06:26 +02:00
9def0b27c9 fix: formatting 2023-04-12 19:56:29 +02:00
52a02c82d2 yeeted extra table styling 2023-04-12 19:47:48 +02:00
c241961d0a Extracted table header 2023-04-12 19:46:33 +02:00
8f50555a06 Extracted table bottom 2023-04-12 19:44:48 +02:00
b35375c929 fix min-w th 2023-04-12 19:43:15 +02:00
bf1e715261 RunnersOverview: table responsiveness 2023-04-12 19:41:41 +02:00
0240e1dca2 import 2023-04-12 19:36:35 +02:00
7cec2a00c5 Fixed id sorting 2023-04-12 19:34:54 +02:00
239f79fecb Moved code around 2023-04-12 19:28:10 +02:00
0265a59b82 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 19:26:56 +02:00
57dce34fc5 fix: table sort button + search style 2023-04-12 19:26:54 +02:00
d8110580e9 Added middle-name 2023-04-12 19:25:33 +02:00
03b7ada5ef Close modal on delete and import toastify 2023-04-12 19:23:27 +02:00
1df505ea00 fix(DeleteRunnerModal): ESC key 2023-04-12 19:22:52 +02:00
3e8dac3203 Reload table data on delete 2023-04-12 19:22:26 +02:00
95707a71a9 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 19:21:19 +02:00
fc2c2907c4 Disable sort for actions 2023-04-12 19:21:01 +02:00
ebdd1c2c0c quick cleanup 2023-04-12 19:20:03 +02:00
13254b24dd Fixed styling 2023-04-12 19:15:28 +02:00
e17eb64031 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 19:14:44 +02:00
a0727a0291 Extracted deletion into function of overview 2023-04-12 19:14:42 +02:00
f7f7926829 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 19:11:13 +02:00
9b7dca341b Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 19:11:08 +02:00
da3300562a Delete modal logic 2023-04-12 19:11:07 +02:00
e2ddb5a14c Added delete toast 2023-04-12 19:05:57 +02:00
fb9645aed6 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 19:05:02 +02:00
a4ebc7e126 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 19:04:22 +02:00
fd5db7d68a Added delete runner modal 2023-04-12 19:04:15 +02:00
e7eddb4f08 drop redundant button role 2023-04-12 19:03:49 +02:00
94155845f0 RunnersOverview: add filter keyboard support 2023-04-12 19:00:10 +02:00
3abf608b15 improved tablefilters/groupFilter 2023-04-12 18:56:55 +02:00
d31fe2363b ammendme 2023-04-12 18:51:48 +02:00
11a56f87e8 Implemented table buttons 2023-04-12 18:51:42 +02:00
19793cdcd4 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 18:47:52 +02:00
9363773fa1 Basic details and delete buttons 2023-04-12 18:47:47 +02:00
c7990882cf fix: TracksOverview 2023-04-12 18:46:31 +02:00
d4ab76ea1b RunnersOverview: pass selectedRunners to actions 2023-04-12 18:42:16 +02:00
2c992a0e63 RunnersOverview: disable debug log 2023-04-12 18:37:38 +02:00
88f96acc3c RunnersOverview: TopActionSection: add margin top 2023-04-12 18:37:26 +02:00
245db06173 updated default table row count 2023-04-12 18:37:02 +02:00
49c2cd5c4b show certificate, runnercard, sponsoring contract section 2023-04-12 18:36:49 +02:00
64db553185 fix: checkbox styling 2023-04-12 18:31:43 +02:00
a06a19ce9c Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 18:29:25 +02:00
592ddc1541 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 18:29:15 +02:00
cb5f2b73d0 drop old datatables 2023-04-12 18:29:06 +02:00
2304b12c1c Moved filter function to shared 2023-04-12 18:28:48 +02:00
38d3e1912c Unused filter function value 2023-04-12 18:26:36 +02:00
fbc14fd7b4 Make the linter happy 2023-04-12 16:31:56 +02:00
0283df22c8 Group filters 2023-04-12 16:30:00 +02:00
845737ee8e Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 16:18:55 +02:00
6993511c67 feat(RunnersOverview): row selection 2023-04-12 16:18:45 +02:00
9111ad147c Updated group name conversion 2023-04-12 16:14:06 +02:00
333214aa8f Added distance conversion 2023-04-12 16:09:57 +02:00
c0cde02fec Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 16:06:58 +02:00
070a20a2e5 Table header i18n 2023-04-12 16:06:55 +02:00
c5e8409079 add basic table styling 2023-04-12 16:05:42 +02:00
67eff0eda9 Dsable column filter for distance 2023-04-12 16:03:53 +02:00
3de7b632e0 Moved sort onclick to header only 2023-04-12 16:03:20 +02:00
842248e4c4 Added sort 2023-04-12 16:02:00 +02:00
c5d7ec25b5 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 15:58:33 +02:00
a9a965d698 Added filterfunctions 2023-04-12 15:58:31 +02:00
dc866dd540 default to 50 rows pagination 2023-04-12 15:58:13 +02:00
89252619b1 Yeeted old datatable references 2023-04-12 15:56:53 +02:00
2699b06d7c Filter id as equals 2023-04-12 15:54:36 +02:00
fd0d45f721 debug table 2023-04-12 15:52:19 +02:00
5ecf838dd2 cleanup headers 2023-04-12 15:52:13 +02:00
45a7a90cb8 pagination size 2023-04-12 15:52:05 +02:00
cac851f2b1 fix pagination next prev 2023-04-12 15:51:46 +02:00
238082b657 getPaginationRowModel 2023-04-12 15:48:08 +02:00
aecbabe522 -> onkeyup 2023-04-12 15:43:52 +02:00
a9cdac4f74 Added filter 2023-04-12 15:40:43 +02:00
a59dbbe50e wip: pagination 2023-04-12 15:36:45 +02:00
9bec95ede8 dependency update, drop focusTrap, first tanstack experiment in RunnersOverview 2023-04-12 15:20:38 +02:00
70307a9e82 Added delete cards button
All checks were successful
continuous-integration/drone/push Build is passing
ref #161
2023-04-12 14:34:06 +02:00
ef077b4e6a Cards deleted migrations
ref #161
2023-04-12 14:32:55 +02:00
dcabed4e93 Added translations
ref #161
2023-04-12 14:30:35 +02:00
1af047f66e Moved filter function to typed version
All checks were successful
continuous-integration/drone/push Build is passing
closes #171
2023-04-12 14:16:36 +02:00
65 changed files with 3596 additions and 1774 deletions

View File

@@ -2,9 +2,121 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [0.18.0](https://git.odit.services/lfk/frontend/compare/0.17.3...0.18.0)
- Moved filter function to typed version [`#171`](https://git.odit.services/lfk/frontend/issues/171)
- ScansOverview: migrate to datatable [`#168`](https://git.odit.services/lfk/frontend/issues/168)
- wip: ScansOverview -> new datatable [`c87561f`](https://git.odit.services/lfk/frontend/commit/c87561f63b90ab951daf91d9b8b54ba96a94cc7f)
- Basic card table replace [`5662c3b`](https://git.odit.services/lfk/frontend/commit/5662c3b6da67c00c94254bf39f8820e531fc93ef)
- RunnersOverview: table responsiveness [`bf1e715`](https://git.odit.services/lfk/frontend/commit/bf1e715261c0076fd8543dd1187c516209a73b16)
- Basic card delete modal [`8ffe8ef`](https://git.odit.services/lfk/frontend/commit/8ffe8eff0623767809cdc49ea15cf2d30b609285)
- wip: delete scans [`f105cc0`](https://git.odit.services/lfk/frontend/commit/f105cc0a41972261610d03015ecd5ee492dab8e2)
- Added delete runner modal [`fd5db7d`](https://git.odit.services/lfk/frontend/commit/fd5db7d68ab4b32f7bb14bd0275a447b749e1fd8)
- Extracted table bottom [`8f50555`](https://git.odit.services/lfk/frontend/commit/8f50555a06a35d0b11ac1d9201851d00d915c4b8)
- fix: formatting [`9def0b2`](https://git.odit.services/lfk/frontend/commit/9def0b27c9958c5c75466f56c17b6dc4d44d2b50)
- fix(CardsOverview): table scroll + checkbox posititioning [`9c13b2f`](https://git.odit.services/lfk/frontend/commit/9c13b2f9e938ad36cb74c66a8f91a5b872c8c2d1)
- Extracted table header [`c241961`](https://git.odit.services/lfk/frontend/commit/c241961d0ab0d6b8c3bf0453c1a21d84027ed62f)
- drop legacy dependencies [`c98eb49`](https://git.odit.services/lfk/frontend/commit/c98eb49ae31d1d28de79c7a9c945ade50828f07f)
- scan delete working [`c7dcf7c`](https://git.odit.services/lfk/frontend/commit/c7dcf7c66d7141117e08462ad05f6f441565d012)
- Add Card appends current cards [`195d182`](https://git.odit.services/lfk/frontend/commit/195d182cc977b4ac9f342f09a9ea69d461892a95)
- Moved data loading to onmount [`a35af6f`](https://git.odit.services/lfk/frontend/commit/a35af6f02055115d60d040baaf22dabbeda38498)
- Add runners reactivity [`06411dc`](https://git.odit.services/lfk/frontend/commit/06411dc14747fc9803da009a29688789c31dfc42)
- quick cleanup [`ebdd1c2`](https://git.odit.services/lfk/frontend/commit/ebdd1c2c0c2191c60dfacd0c4be989748628ca63)
- Extracted deletion into function of overview [`a0727a0`](https://git.odit.services/lfk/frontend/commit/a0727a02913708de06be8bf1b9f8cbae5489f080)
- Moved update card logic to overview [`53b945c`](https://git.odit.services/lfk/frontend/commit/53b945c72fa5b30f03eff8bb83f8f25d85d79b07)
- wip:ScanValid badge [`bd4952e`](https://git.odit.services/lfk/frontend/commit/bd4952ee575b4cd8caea3608b14d8c51b37a55eb)
- yeeted extra table styling [`52a02c8`](https://git.odit.services/lfk/frontend/commit/52a02c82d2bdabdf3e632910aa415c1ffb97fd7f)
- Added custom runner filter [`7c6d39b`](https://git.odit.services/lfk/frontend/commit/7c6d39b5fa60d1b834c9fb74dd26dfc2225161d6)
- Scan reactive add [`f5d14f2`](https://git.odit.services/lfk/frontend/commit/f5d14f2e1810462cba99b2482320746f0750d4a1)
- Moved code around [`239f79f`](https://git.odit.services/lfk/frontend/commit/239f79fecba732c807f4296cf524be15c1ccff1e)
- Scan deletion [`7d8c68a`](https://git.odit.services/lfk/frontend/commit/7d8c68a4550407e8c871545e7a0c5f622a1e3b9c)
- Added status filter function [`f6c1fea`](https://git.odit.services/lfk/frontend/commit/f6c1fea17ce64d890ac810d9dff058dd589c2989)
- Added delete toast [`e2ddb5a`](https://git.odit.services/lfk/frontend/commit/e2ddb5a14cc8b450c00129709bf5b933a47866dd)
- Fixed killing of the dom [`2f62c7a`](https://git.odit.services/lfk/frontend/commit/2f62c7ae89b7dda3bc0efd4d56e677898a3f197f)
- Cards details modal [`f6985da`](https://git.odit.services/lfk/frontend/commit/f6985daec71e4d922acd8a9b2673fd41317b075f)
- Reload table data on delete [`3e8dac3`](https://git.odit.services/lfk/frontend/commit/3e8dac3203f56723a3dad4a35887d60fc03d4ae3)
- Added middle-name [`d811058`](https://git.odit.services/lfk/frontend/commit/d8110580e9a33cfb0c6e9cbdce630262d5b5d4c1)
- Fixed id sorting [`7cec2a0`](https://git.odit.services/lfk/frontend/commit/7cec2a00c513678cae8643ef3905d566a538bde0)
- Import add to datatable [`2a91562`](https://git.odit.services/lfk/frontend/commit/2a915620c9adcb481be53e3c919bd5f14a5108ee)
- Scans deletion [`6d9d8a4`](https://git.odit.services/lfk/frontend/commit/6d9d8a4724135df98ed1bec74b0cc20a8bdbda53)
- fix(DeleteRunnerModal): ESC key [`1df505e`](https://git.odit.services/lfk/frontend/commit/1df505ea00968f65e7aff85baa80f8935fd2eb7b)
- Versionbuilder [`1613ae7`](https://git.odit.services/lfk/frontend/commit/1613ae7de6e84aa5f9df6774a8e820fcf515b14a)
- Fixed edit dispatch [`c681570`](https://git.odit.services/lfk/frontend/commit/c68157013431eeb1150e37fea87da02d5f7b032e)
- ScansOverview: use CardRunner link [`4b171fd`](https://git.odit.services/lfk/frontend/commit/4b171fd04f4fc895f9919294858e546686504c65)
- Added custom filter to scan overview [`2c198cf`](https://git.odit.services/lfk/frontend/commit/2c198cfde89363142c1c958e6961b7823196e04e)
- Disable sort for actions [`fc2c290`](https://git.odit.services/lfk/frontend/commit/fc2c2907c43e5b1fa192b571cf93b2f2e492158f)
- Delete modal logic [`da33005`](https://git.odit.services/lfk/frontend/commit/da3300562a25cf39945a94f873ec27f0d5fb9dc0)
- Module [`9ae5e62`](https://git.odit.services/lfk/frontend/commit/9ae5e62e5d84097082bc29fe20b329f6e614f6ed)
- new license file version [CI SKIP] [`ed1caa7`](https://git.odit.services/lfk/frontend/commit/ed1caa7be7673ef08f9c0074101f3cfb52963ab7)
- Merge pull request 'experiment/tanstack' (#172) from experiment/tanstack into dev [`d88f3a5`](https://git.odit.services/lfk/frontend/commit/d88f3a5a2737921536c5eb109734abafd7609e51)
- Removed pnpm store [`eb13f03`](https://git.odit.services/lfk/frontend/commit/eb13f038a1990ed2966552ab1d36df4a76e5a99a)
- dependency update, drop focusTrap, first tanstack experiment in RunnersOverview [`9bec95e`](https://git.odit.services/lfk/frontend/commit/9bec95ede80908e45ad0f18a66dbb45784f7e33e)
- Added translations [`dcabed4`](https://git.odit.services/lfk/frontend/commit/dcabed4e93134a1f04305c47536f1cc93b0cfb31)
- new license file version [CI SKIP] [`d0fe6a2`](https://git.odit.services/lfk/frontend/commit/d0fe6a2e8513638c4d8e2b3dafd48b91490eab3b)
- Bumped pnpm to 8 [`ee91748`](https://git.odit.services/lfk/frontend/commit/ee91748b3c7c2fb4f196d76121713ac42465b9dd)
- drop old datatables [`cb5f2b7`](https://git.odit.services/lfk/frontend/commit/cb5f2b73d0a5f71875f48d381382919f9bee364e)
- wip: pagination [`a59dbbe`](https://git.odit.services/lfk/frontend/commit/a59dbbe50ede47e0dada906d10887cc6b1ae3264)
- Added sort [`842248e`](https://git.odit.services/lfk/frontend/commit/842248e4c43bb94a0e73981d2d848e0723687932)
- cleanup headers [`5ecf838`](https://git.odit.services/lfk/frontend/commit/5ecf838dd231269c3c4f0d1e3376ff157457b04a)
- Moved filter function to shared [`2304b12`](https://git.odit.services/lfk/frontend/commit/2304b12c1cca6a64573223906ab0561ba9050ec5)
- Group filters [`0283df2`](https://git.odit.services/lfk/frontend/commit/0283df22c84740dd978e09120985215b65d7a12a)
- feat(RunnersOverview): row selection [`6993511`](https://git.odit.services/lfk/frontend/commit/6993511c67cc81303a1eece7fc2a4218dc818afc)
- Basic details and delete buttons [`9363773`](https://git.odit.services/lfk/frontend/commit/9363773fa1910975d48746572fe166363986c6ab)
- Added delete cards button [`70307a9`](https://git.odit.services/lfk/frontend/commit/70307a9e8272f22801c6765c947f8576cc1d1102)
- ScansOverview: add ThFilterTrack [`008835c`](https://git.odit.services/lfk/frontend/commit/008835c24f833aebbecc53921b0901a76f25bf06)
- Yeeted old datatable references [`8925261`](https://git.odit.services/lfk/frontend/commit/89252619b1f6d478c287178bfffc573cf574a8fa)
- Added filter [`a9cdac4`](https://git.odit.services/lfk/frontend/commit/a9cdac4f74a80afe3d0ce677ed5256201b75b29b)
- Moved sort onclick to header only [`3de7b63`](https://git.odit.services/lfk/frontend/commit/3de7b632e058e9ca9ab951de9e86cc2a40eceb68)
- Switched drone to pnpm cache [`d79608e`](https://git.odit.services/lfk/frontend/commit/d79608edbb7ca68b0a26f6c021a141373308081f)
- pagination size [`45a7a90`](https://git.odit.services/lfk/frontend/commit/45a7a90cb8ee933d064c5891b3532cb1ece38d38)
- RunnersOverview: add filter keyboard support [`9415584`](https://git.odit.services/lfk/frontend/commit/94155845f020679e8765d198b5ab4735e1d1142c)
- RunnersOverview: pass selectedRunners to actions [`d4ab76e`](https://git.odit.services/lfk/frontend/commit/d4ab76ea1be1789aaa53ca57d33b2356c6804ffd)
- fix pagination next prev [`cac851f`](https://git.odit.services/lfk/frontend/commit/cac851f2b19dafa01b08d1da612e34cbe3eb4133)
- Moved docker to pnpm with cache [`4cbd265`](https://git.odit.services/lfk/frontend/commit/4cbd26580e51b854fdfd369056f24a30b04100a1)
- fix: TracksOverview [`c799088`](https://git.odit.services/lfk/frontend/commit/c7990882cfa4ac6c3a2ffa696dcbf3b62790c1fe)
- Table header i18n [`070a20a`](https://git.odit.services/lfk/frontend/commit/070a20a2e599e9f00b1bd0e944f9d68d08dc1cba)
- default to 50 rows pagination [`dc866dd`](https://git.odit.services/lfk/frontend/commit/dc866dd5403ae681193c5e325b1f6d4068f80b61)
- improved tablefilters/groupFilter [`3abf608`](https://git.odit.services/lfk/frontend/commit/3abf608b15fcfc2cf65b705d28d394917e7ac333)
- Updated group name conversion [`9111ad1`](https://git.odit.services/lfk/frontend/commit/9111ad147c7537036de834f80db6e557d8d6f0d9)
- show certificate, runnercard, sponsoring contract section [`49c2cd5`](https://git.odit.services/lfk/frontend/commit/49c2cd5c4b32e1b75fe0dae48c1b470608936704)
- add basic table styling [`c5e8409`](https://git.odit.services/lfk/frontend/commit/c5e84090795636c7a80d6cabe46168e436d40f50)
- Cards deleted migrations [`ef077b4`](https://git.odit.services/lfk/frontend/commit/ef077b4e6ad722e6d1c9efd5060165f649fd94c9)
- ignore pnpm store from now on [`fe62ad5`](https://git.odit.services/lfk/frontend/commit/fe62ad5539bc94b242c30c2952bf4c115cc9abfd)
- ammendme [`d31fe23`](https://git.odit.services/lfk/frontend/commit/d31fe2363b0f167b937f7d67908e75c709b324d8)
- updated default table row count [`245db06`](https://git.odit.services/lfk/frontend/commit/245db0617306bab23993caf00dc5ba0405e95625)
- fix: checkbox styling [`64db553`](https://git.odit.services/lfk/frontend/commit/64db5531858b2275d27c53a347da6c0416a278e8)
- Added distance conversion [`333214a`](https://git.odit.services/lfk/frontend/commit/333214aa8f945975ee2dcbd1cfa285e5e75c9d02)
- Added filterfunctions [`a9a965d`](https://git.odit.services/lfk/frontend/commit/a9a965d6981b07b02e3f752e65e1e5c4e9df7147)
- card/ThFilterRunner: text align left [`7083b3d`](https://git.odit.services/lfk/frontend/commit/7083b3d8d2c81fa4ab14f21d379befbb2dab5b6c)
- import [`0240e1d`](https://git.odit.services/lfk/frontend/commit/0240e1dca2e162b8c79f294f5c651b4a38455235)
- fix: table sort button + search style [`57dce34`](https://git.odit.services/lfk/frontend/commit/57dce34fc5b04c297c5341db24ec47c2f1d39595)
- No longer switching pnpm store path [`e5241d6`](https://git.odit.services/lfk/frontend/commit/e5241d619beda90d271485b6c09142b1e7b9b5f1)
- Reactivated generate cards modal [`8f33640`](https://git.odit.services/lfk/frontend/commit/8f33640bec8f79987b1319fb0765535fe493d496)
- Always load bulk created cards [`f89023e`](https://git.odit.services/lfk/frontend/commit/f89023e24ab30c90a8cacf2e9590d1dfa1a743d5)
- ScansOverview: fallback for manual scans [`1ec9556`](https://git.odit.services/lfk/frontend/commit/1ec9556aa64b996d0bdd9cd3ee50a767a154f5f6)
- fix min-w th [`b35375c`](https://git.odit.services/lfk/frontend/commit/b35375c929ad8d525b2761c321ecef0399917828)
- Close modal on delete and import toastify [`03b7ada`](https://git.odit.services/lfk/frontend/commit/03b7ada5ef3cbf64f178d3d0d88c448d76a42885)
- Fixed styling [`13254b2`](https://git.odit.services/lfk/frontend/commit/13254b24dd75ca3eb47fd53d5368f047545e8420)
- Implemented table buttons [`11a56f8`](https://git.odit.services/lfk/frontend/commit/11a56f87e89866bd9b2f7029ef683fd139d60aa4)
- RunnersOverview: disable debug log [`2c992a0`](https://git.odit.services/lfk/frontend/commit/2c992a0e63fa72055d28785fe7f5c21fd26f1fea)
- RunnersOverview: TopActionSection: add margin top [`88f96ac`](https://git.odit.services/lfk/frontend/commit/88f96acc3c31c748d3da29b4564dd681a89208b9)
- Unused filter function value [`38d3e19`](https://git.odit.services/lfk/frontend/commit/38d3e1912cd6d5362db236c34e0c602b52060b73)
- Make the linter happy [`fbc14fd`](https://git.odit.services/lfk/frontend/commit/fbc14fd7b47009bf64a8824e7b60373eea031e3f)
- Dsable column filter for distance [`67eff0e`](https://git.odit.services/lfk/frontend/commit/67eff0eda9b7d49d1abe784247afdbfbd7a76b00)
- getPaginationRowModel [`238082b`](https://git.odit.services/lfk/frontend/commit/238082b657998f513111e832556926decbe84e21)
- -> onkeyup [`aecbabe`](https://git.odit.services/lfk/frontend/commit/aecbabe52221c0ab8d94a42dc8ac42f4f397fde8)
- removed unused import [`9811ede`](https://git.odit.services/lfk/frontend/commit/9811ede3b23a488a49962a43dae5abad60f93341)
- drop redundant button role [`e7eddb4`](https://git.odit.services/lfk/frontend/commit/e7eddb4f08632cc803b8752e3561319fab538843)
- Filter id as equals [`2699b06`](https://git.odit.services/lfk/frontend/commit/2699b06d7c42608b1b3ce2037908a78143038441)
- debug table [`fd0d45f`](https://git.odit.services/lfk/frontend/commit/fd0d45f721396787ad35fca2a7fd0f26d98b23e9)
- add TODO for ScansOverview status filter [`9505c2b`](https://git.odit.services/lfk/frontend/commit/9505c2b03005f4e667082cb4527fea863dbbf7fc)
#### [0.17.3](https://git.odit.services/lfk/frontend/compare/0.17.2...0.17.3) #### [0.17.3](https://git.odit.services/lfk/frontend/compare/0.17.2...0.17.3)
> 15 March 2023
- dependency fixes [`3ea7a01`](https://git.odit.services/lfk/frontend/commit/3ea7a015a9beba3c2e4d3eb966f24ff6d4ac786e) - dependency fixes [`3ea7a01`](https://git.odit.services/lfk/frontend/commit/3ea7a015a9beba3c2e4d3eb966f24ff6d4ac786e)
- 🚀RELEASE v0.17.3 [`85705b6`](https://git.odit.services/lfk/frontend/commit/85705b6e684d0c41d3dc770cef7bffb199101576)
- set pnpm to @7 [`4432941`](https://git.odit.services/lfk/frontend/commit/44329413ed2ca23f74e86db041b2c25b2b1c2a2b) - set pnpm to @7 [`4432941`](https://git.odit.services/lfk/frontend/commit/44329413ed2ca23f74e86db041b2c25b2b1c2a2b)
#### [0.17.2](https://git.odit.services/lfk/frontend/compare/0.17.1...0.17.2) #### [0.17.2](https://git.odit.services/lfk/frontend/compare/0.17.1...0.17.2)

View File

@@ -13,7 +13,7 @@
</head> </head>
<body> <body>
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.17.3-RELEASE_INFO</span> <span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.18.0-RELEASE_INFO</span>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<script src="/env.js"></script> <script src="/env.js"></script>
<script type="module" src="/src/main.js"></script> <script type="module" src="/src/main.js"></script>

View File

@@ -1,4 +1,4 @@
const fs = require('fs'); import fs from 'fs'
// get all language files // get all language files
const files = fs.readdirSync('./src/locales/'); const files = fs.readdirSync('./src/locales/');
files.forEach((f) => { files.forEach((f) => {

View File

@@ -1,6 +1,7 @@
{ {
"name": "@odit/lfk-frontend", "name": "@odit/lfk-frontend",
"version": "0.17.3", "version": "0.18.0",
"type": "module",
"scripts": { "scripts": {
"i18n-order": "node order.js", "i18n-order": "node order.js",
"dev": "vite", "dev": "vite",
@@ -10,18 +11,15 @@
}, },
"license": "CC-BY-NC-SA-4.0", "license": "CC-BY-NC-SA-4.0",
"devDependencies": { "devDependencies": {
"@sveltejs/vite-plugin-svelte": "1.0.0-next.6",
"@odit/license-exporter": "0.0.12", "@odit/license-exporter": "0.0.12",
"@types/html-minifier": "4.0.2", "@sveltejs/vite-plugin-svelte": "2.0.4",
"auto-changelog": "2.4.0", "auto-changelog": "2.4.0",
"autoprefixer": "10.4.14", "autoprefixer": "10.4.14",
"html-minifier": "4.0.0",
"postcss": "8.4.21", "postcss": "8.4.21",
"release-it": "14.6.1", "release-it": "15.10.1",
"svelte-preprocess": "4.7.0",
"svelte-select": "3.17.0", "svelte-select": "3.17.0",
"tailwindcss": "3.2.7", "tailwindcss": "3.3.1",
"vite": "2.1.5" "vite": "4.2.1"
}, },
"release-it": { "release-it": {
"git": { "git": {
@@ -41,21 +39,20 @@
} }
}, },
"dependencies": { "dependencies": {
"tinro": "0.6.12", "@odit/lfk-client-js": "0.14.3",
"toastify-js": "1.12.0", "@paralleldrive/cuid2": "^2.2.0",
"validator": "13.9.0", "@tanstack/svelte-table": "^8.8.5",
"xlsx": "0.16.9",
"@odit/lfk-client-js": "0.14.0",
"@vincjo/datatables": "^1.4.0",
"check-password-strength": "2.0.7", "check-password-strength": "2.0.7",
"csvtojson": "2.0.10", "csvtojson": "2.0.10",
"gridjs": "3.4.0", "gridjs": "3.4.0",
"localforage": "1.10.0", "localforage": "1.10.0",
"marked": "2.0.3", "marked": "2.0.3",
"svelte": "3.37.0", "svelte": "3.58.0",
"svelte-focus-trap": "1.2.0", "svelte-i18n": "3.6.0",
"svelte-i18n": "3.3.9", "tinro": "0.6.12",
"@paralleldrive/cuid2": "^2.2.0" "toastify-js": "1.12.0",
"validator": "13.9.0",
"xlsx": "0.18.5"
}, },
"volta": { "volta": {
"node": "19.7.0" "node": "19.7.0"

3070
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,14 +1,16 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { RunnerCardService } from "@odit/lfk-client-js"; import { RunnerCardService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte";
export let bulk_modal_open; export let bulk_modal_open;
export let current_cards;
function focus(el) { function focus(el) {
el.focus(); el.focus();
} }
const dispatch = createEventDispatcher();
$: card_count = 0; $: card_count = 0;
$: is_card_count_valid = card_count > 0; $: is_card_count_valid = card_count > 0;
$: processed_last_submit = true; $: processed_last_submit = true;
@@ -34,7 +36,7 @@
text: $_("creating-blanco-cards"), text: $_("creating-blanco-cards"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, false) RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, true)
.then((result) => { .then((result) => {
bulk_modal_open = false; bulk_modal_open = false;
// //
@@ -43,6 +45,7 @@
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
dispatch("created", {cards: result})
}) })
.catch((err) => { .catch((err) => {
// //
@@ -71,11 +74,11 @@
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_cards = current_cards.concat(result);
const toast = Toastify({ const toast = Toastify({
text: $_("generating-pdf"), text: $_("generating-pdf"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
dispatch("created", {cards: result})
fetch( fetch(
`${config.baseurl_documentserver}/cards?&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/cards?&download=true&key=${config.documentserver_key}`,
{ {
@@ -133,7 +136,7 @@
{#if bulk_modal_open} {#if bulk_modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
bulk_modal_open = false; bulk_modal_open = false;

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { import {
RunnerCardService, RunnerCardService,
RunnerService, RunnerService,
@@ -9,9 +9,10 @@
} from "@odit/lfk-client-js"; } from "@odit/lfk-client-js";
import Select from "svelte-select"; import Select from "svelte-select";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte";
export let modal_open; export let modal_open;
export let current_cards;
const dispatch = createEventDispatcher();
const getRunnerLabel = (option) => { const getRunnerLabel = (option) => {
if (option.middlename) { if (option.middlename) {
return option.firstname + " " + option.middlename + " " + option.lastname; return option.firstname + " " + option.middlename + " " + option.lastname;
@@ -21,7 +22,7 @@
const filterRunners = (label, filterText, option) => { const filterRunners = (label, filterText, option) => {
if (filterText.startsWith("#")) { if (filterText.startsWith("#")) {
return option.value.id == parseInt(filterText.replace("#","")) return option.value.id == parseInt(filterText.replace("#", ""));
} }
return ( return (
label.toLowerCase().includes(filterText.toLowerCase()) || label.toLowerCase().includes(filterText.toLowerCase()) ||
@@ -79,8 +80,7 @@
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_cards.push(result); dispatch("created", { cards: [result] });
current_cards = current_cards;
}) })
.catch((err) => { .catch((err) => {
// //
@@ -97,7 +97,6 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -1,21 +1,27 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { RunnerCardService, RunnerService } from "@odit/lfk-client-js"; import { RunnerCardService, RunnerService } from "@odit/lfk-client-js";
import Select from "svelte-select"; import Select from "svelte-select";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
export let edit_modal_open; export let edit_modal_open;
export let current_cards;
export let runner = {}; export let runner = {};
export let editable = {}; export let editable = {};
export let original_data = {}; export let original_data = {};
const getRunnerLabel = (option) => const getRunnerLabel = (option) =>
option.firstname + " " + (option.middlename || "") + " " + option.lastname; option.firstname + " " + (option.middlename || "") + " " + option.lastname;
const filterRunners = (label, filterText, option) => const filterRunners = (label, filterText, option) => {
if (filterText.startsWith("#")) {
return option.value.id == parseInt(filterText.replace("#",""))
}
return (
label.toLowerCase().includes(filterText.toLowerCase()) || label.toLowerCase().includes(filterText.toLowerCase()) ||
option.value.toString().startsWith(filterText.toLowerCase()); option.value.toString().startsWith(filterText.toLowerCase())
);
};
function focus(el) { function focus(el) {
el.focus(); el.focus();
} }
@@ -23,9 +29,6 @@
$: enabled = true; $: enabled = true;
$: processed_last_submit = true; $: processed_last_submit = true;
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
function dataUpdated() {
dispatch('dataUpdated',);
}
RunnerService.runnerControllerGetAll().then((val) => { RunnerService.runnerControllerGetAll().then((val) => {
runners = val.map((r) => { runners = val.map((r) => {
return { label: getRunnerLabel(r), value: r }; return { label: getRunnerLabel(r), value: r };
@@ -68,9 +71,7 @@
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_cards[current_cards.findIndex((c) => c.id === id)] = result; dispatch('dataUpdated', {card: result});
current_cards = current_cards;
dataUpdated();
}) })
.catch((err) => { .catch((err) => {
// //
@@ -87,7 +88,7 @@
{#if edit_modal_open} {#if edit_modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
edit_modal_open = false; edit_modal_open = false;

View File

@@ -0,0 +1,16 @@
<script>
import { _ } from "svelte-i18n";
export let runner;
</script>
{#if !runner}
{$_("non-blanko")}
{:else}
<a href={`/runners/${runner.id}`}>
{#if runner.middlename}
{runner.firstname} {runner.middlename} {runner.lastname}
{:else}
{runner.firstname} {runner.lastname}
{/if}
</a>
{/if}

View File

@@ -0,0 +1,16 @@
<script>
import { _ } from "svelte-i18n";
export let enabled = false;
</script>
{#if enabled}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
>{$_("enabled")}</span
>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800"
>{$_("disabled")}</span
>
{/if}

View File

@@ -7,34 +7,48 @@
$: current_cards = []; $: current_cards = [];
export let modal_open = false; export let modal_open = false;
export let bulk_modal_open = false; export let bulk_modal_open = false;
let addCards;
</script> </script>
<section class="container p-5"> <section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight"> <span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('cards')} {$_("cards")}
{#if store.state.jwtinfo.userdetails.permissions.includes('CARD:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")}
<button <button
on:click={() => { on:click={() => {
modal_open = true; modal_open = true;
}} }}
type="button" type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
{$_('add-card')} >
{$_("add-card")}
</button> </button>
<button <button
on:click={() => { on:click={() => {
bulk_modal_open = true; bulk_modal_open = true;
}} }}
type="button" type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
{$_('create-bulk-cards')} >
{$_("create-bulk-cards")}
</button> </button>
{/if} {/if}
</span> </span>
<CardsOverview bind:current_cards /> <CardsOverview bind:current_cards bind:addCards />
</section> </section>
{#if store.state.jwtinfo.userdetails.permissions.includes('CARD:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")}
<AddCardModal bind:current_cards bind:modal_open /> <AddCardModal
<AddCardBulkModal bind:current_cards bind:bulk_modal_open /> bind:modal_open
on:created={(event) => {
console.log(event)
addCards(event.detail.cards);
}}
/>
<AddCardBulkModal
bind:bulk_modal_open
on:created={(event) => {
addCards(event.detail.cards);
}}
/>
{/if} {/if}

View File

@@ -3,35 +3,129 @@
import { RunnerCardService } from "@odit/lfk-client-js"; import { RunnerCardService } from "@odit/lfk-client-js";
import store from "../../store"; import store from "../../store";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { DataHandler, Datatable, Th, ThFilter } from "@vincjo/datatables";
import CardsEmptyState from "./CardsEmptyState.svelte"; import CardsEmptyState from "./CardsEmptyState.svelte";
import CardDetailModal from "./CardDetailModal.svelte"; import CardDetailModal from "./CardDetailModal.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import ThFilterStatus from "./ThFilterStatus.svelte"; import InputElement from "../shared/InputElement.svelte";
import ThFilterRunner from "./ThFilterRunner.svelte"; import {
createSvelteTable,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
renderComponent,
} from "@tanstack/svelte-table";
import { writable } from "svelte/store";
import TableBottom from "../shared/TableBottom.svelte";
import TableActions from "../shared/TableActions.svelte";
import TableHeader from "../shared/TableHeader.svelte";
import CardStatus from "./CardStatus.svelte";
import CardRunner from "./CardRunner.svelte";
import { onMount } from "svelte";
import { runnerFilter, statusFilter } from "../shared/tablefilters";
import DeleteCardModal from "./DeleteCardModal.svelte";
export let edit_modal_open = false; export let edit_modal_open = false;
export let runner = {}; export let runner = {};
export let editable = {}; export let editable = {};
export let original_data = {}; export let original_data = {};
export let current_cards = []; export let current_cards = [];
const handler = new DataHandler(current_cards, { rowsPerPage: 50 }); export const addCards = (cards) => {
const rows = handler.getRows(); console.log(cards)
$: active_deletes = []; current_cards = current_cards.concat(...cards);
options.update((options) => ({
...options,
data: current_cards,
}));
};
$: dataLoaded = false;
$: selected =
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
$: selectedCards =
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
$: active_delete = undefined;
$: cards_show = generate_cards.length > 0; $: cards_show = generate_cards.length > 0;
$: generate_cards = []; $: generate_cards = [];
const cards_promise = RunnerCardService.runnerCardControllerGetAll().then(
(val) => { const columns = [
current_cards = val; {
handler.setRows(val); accessorKey: "code",
} header: () => $_("code"),
filterFn: `includesString`,
},
{
accessorKey: "runner",
header: () => $_("runner"),
cell: (info) => {
return renderComponent(CardRunner, { runner: info.getValue() });
},
filterFn: `runner`,
},
{
accessorKey: "enabled",
cell: (info) => {
return renderComponent(CardStatus, { enabled: info.getValue() });
},
header: () => $_("status"),
filterFn: `status`,
},
{
accessorKey: "actions",
header: () => $_("action"),
cell: (info) => {
return renderComponent(TableActions, {
detailsAction: () => {
open_edit_modal(
current_cards[
current_cards.findIndex((r) => r.id == info.row.original.id)
]
); );
const getRunnerLabel = (option) => },
option?.firstname + deleteAction: () => {
" " + active_delete =
(option?.middlename || "") + current_cards[
" " + current_cards.findIndex((r) => r.id == info.row.original.id)
(option?.lastname || "{$_('non-blanko')}"); ];
},
deleteEnabled:
store.state.jwtinfo.userdetails.permissions.includes("CARD:DELETE"),
});
},
enableColumnFilter: false,
enableSorting: false,
},
];
const options = writable({
data: [],
columns: columns,
initialState: {
pagination: {
pageSize: 50,
},
},
filterFns: {
runner: runnerFilter,
status: statusFilter,
},
enableRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});
const table = createSvelteTable(options);
function open_edit_modal(card) { function open_edit_modal(card) {
const getRunnerLabel = (option) =>
option.firstname +
" " +
(option.middlename || "") +
" " +
option.lastname;
if (card.runner?.id) { if (card.runner?.id) {
runner = Object.assign( runner = Object.assign(
{ runner }, { runner },
@@ -46,21 +140,61 @@
original_data = Object.assign(original_data, card); original_data = Object.assign(original_data, card);
edit_modal_open = true; edit_modal_open = true;
} }
async function deleteCard(delete_card_id) {
await RunnerCardService.runnerCardControllerRemove(delete_card_id, true);
current_cards = current_cards.filter((r) => r.id !== delete_card_id);
options.update((options) => ({
...options,
data: current_cards,
}));
Toastify({
text: $_("card-deleted"),
duration: 3500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
onMount(() => {
RunnerCardService.runnerCardControllerGetAll().then((val) => {
current_cards = val;
options.update((options) => ({
...options,
data: current_cards,
}));
dataLoaded = true;
});
});
</script> </script>
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:UPDATE")} {#if store.state.jwtinfo.userdetails.permissions.includes("CARD:UPDATE")}
<CardDetailModal <CardDetailModal
bind:current_cards
bind:edit_modal_open bind:edit_modal_open
bind:runner bind:runner
bind:editable bind:editable
bind:original_data bind:original_data
on:dataUpdated={handler.setRows(current_cards)} on:dataUpdated={(event) => {
current_cards[
current_cards.findIndex((c) => c.id === event.detail.card.id)
] = event.detail.card;
current_cards = current_cards;
options.update((options) => ({
...options,
data: current_cards,
}));
}}
/> />
{/if} {/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")} {#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")}
{#await cards_promise} <DeleteCardModal
delete_card={active_delete}
modal_open={active_delete != undefined}
on:delete={(event) => {
deleteCard(event.detail.id);
}}
/>
{#if !dataLoaded}
<div <div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert" role="alert"
@@ -68,166 +202,99 @@
<p class="font-bold">{$_("loading-cards")}</p> <p class="font-bold">{$_("loading-cards")}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p> <p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div> </div>
{:then} {:else if current_cards.length === 0}
{#if current_cards.length === 0}
<CardsEmptyState /> <CardsEmptyState />
{:else} {:else}
<div class="h-12"> <div class="h-12 mt-1">
<GenerateRunnerCards bind:cards_show bind:generate_cards /> {#if selected.length > 0}
</div>
<Datatable {handler}>
<table>
<thead>
<tr>
<th style="border-bottom: 1px solid #ddd;">
<input
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
checked={generate_cards.length == current_cards.length}
on:click={() => {
if (generate_cards.length != current_cards.length) {
generate_cards = current_cards;
} else {
generate_cards = [];
}
}}
/>
</th>
<Th {handler} orderBy="code">{$_("code")}</Th>
<Th {handler} orderBy="runner">{$_("runner")}</Th>
<Th {handler} orderBy="status">{$_("status")}</Th>
<th style="border-bottom: 1px solid #ddd;">{$_("action")}</th>
</tr>
<tr>
<th style="border-bottom: 1px solid #ddd;" />
<ThFilter {handler} filterBy="code" />
<ThFilterRunner {handler} />
<ThFilterStatus {handler} />
<th style="border-bottom: 1px solid #ddd;" />
</tr>
</thead>
<tbody>
{#each $rows as row}
<tr>
<td>
<input
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
checked={generate_cards.filter((i) => i.id == row.id)
.length > 0}
on:click={() => {
if (
generate_cards.findIndex((i) => i.id == row.id) == -1
) {
generate_cards.push(row);
generate_cards = generate_cards;
} else {
generate_cards = generate_cards.filter(
(r) => r.id != row.id
);
}
console.log(generate_cards);
}}
/>
</td>
<td>{row.code}</td>
<td>
{#if row.runner}
<a
href="../runners/{row.runner.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
>{row.runner.firstname}
{row.runner.middlename || ""}
{row.runner.lastname}</a
>
{:else}{$_("non-blanko")}{/if}
</td>
<td>
{#if row.enabled}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
>{$_("enabled")}</span
>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800"
>{$_("disabled")}</span
>
{/if}
</td>
<td>
{#if active_deletes[row.id] === true}
<button <button
on:click={() => { type="button"
active_deletes[row.id] = false; class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm inline-flex"
}} id="options-menu"
tabindex="0" on:click={async () => {
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer" const prom = [];
>{$_("cancel-delete")}</button for (const card of selectedCards) {
> prom.push(
<button await RunnerCardService.runnerCardControllerRemove(
on:click={() => { card.id,
RunnerCardService.runnerCardControllerRemove(
row.id,
true true
) )
.then((resp) => {
current_cards = current_cards.filter(
(obj) => obj.id !== row.id
); );
}) }
.catch((err) => {}); await Promise.all(prom);
for (const card of selectedCards) {
current_cards = current_cards.filter((r) => r.id !== card.id);
}
options.update((options) => ({
...options,
data: current_cards,
}));
$table.resetRowSelection()
}} }}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("confirm-delete")}</button
> >
{:else} {$_("delete-cards")}
<button <svg
on:click={() => { xmlns="http://www.w3.org/2000/svg"
open_edit_modal(row); fill="none"
}} viewBox="0 0 24 24"
class="text-indigo-600 hover:text-indigo-900" stroke-width="1.5"
>{$_("details")}</button stroke="currentColor"
> class="w-5 h-5"
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:DELETE")}
<button
on:click={() => {
active_deletes[row.id] = true;
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("delete")}</button
> >
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
{/if} {/if}
{/if} <GenerateRunnerCards cards_show={selected.length>0} bind:generate_cards={selectedCards} />
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead>
{#each $table.getHeaderGroups() as headerGroup}
<tr class="select-none">
<th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
<InputElement
type="checkbox"
checked={$table.getIsAllRowsSelected()}
indeterminate={$table.getIsSomeRowsSelected()}
on:change={() => $table.toggleAllRowsSelected()}
/>
</th>
{#each headerGroup.headers as header}
<TableHeader {header} />
{/each}
</tr>
{/each}
</thead>
<tbody>
{#each $table.getRowModel().rows as row}
<tr>
<td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
<InputElement
type="checkbox"
checked={row.getIsSelected()}
on:change={() => row.toggleSelected()}
/>
</td> </td>
{#each row.getVisibleCells() as cell}
<td>
<svelte:component
this={flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
/>
</td>
{/each}
</tr> </tr>
{/each} {/each}
</tbody> </tbody>
</table> </table>
</Datatable>
{/if}
{:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_("general_promise_error")}</b>
{error}
</span>
</div> </div>
{/await} <TableBottom {table} {selected} />
{/if}
{/if} {/if}
<style>
table tbody {
display: block;
overflow-y: scroll;
}
table thead,
table tbody tr {
display: table;
width: 100%;
table-layout: fixed;
}
</style>

View File

@@ -0,0 +1,128 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { createEventDispatcher, onMount } from "svelte";
export let modal_open;
export let delete_card = {
id: 0,
code: "",
runner: {
firstname: "",
lastname: "",
},
};
const dispatch = createEventDispatcher();
onMount(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
});
async function submit() {
dispatch("delete", { id: delete_card.id });
modal_open = false;
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("confirm-delete")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_("please-confirm-the-deletion-of-card")}
</p>
</div>
<div class="w-full">
{$_("card")} #{delete_card.code}<br />
<span class="inline-block">
{$_("runner")}:
{#if delete_card.runner}
<span class="inline-block"
>{delete_card.runner.firstname}
{delete_card.runner.lastname}</span
>
{:else}
{$_("non-blanko")}
{/if}</span
>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("delete")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { import {
GroupContactService, GroupContactService,
RunnerTeamService, RunnerTeamService,
@@ -145,7 +145,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -31,7 +31,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
<table class="divide-y divide-gray-200 w-full"> <table class="divide-y divide-gray-200 w-full">

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { import {
DonationService, DonationService,
DonorService, DonorService,
@@ -156,7 +156,7 @@ import { is_promise } from "svelte/internal";
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { DonationService } from "@odit/lfk-client-js"; import { DonationService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
export let payment_modal_open = false; export let payment_modal_open = false;
@@ -96,7 +96,7 @@
{#if payment_modal_open} {#if payment_modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
payment_modal_open = false; payment_modal_open = false;

View File

@@ -49,7 +49,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
<table class="divide-y divide-gray-200 w-full"> <table class="divide-y divide-gray-200 w-full">

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { import {
DonorService DonorService
} from "@odit/lfk-client-js"; } from "@odit/lfk-client-js";
@@ -134,7 +134,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { DonorService } from "@odit/lfk-client-js"; import { DonorService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
@@ -32,7 +32,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={cancelDelete}> on:click_outside={cancelDelete}>
<div <div

View File

@@ -51,7 +51,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
<table class="divide-y divide-gray-200 w-full"> <table class="divide-y divide-gray-200 w-full">

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
export let modal_open; export let modal_open;
(function () { (function () {
document.onkeydown = function (e) { document.onkeydown = function (e) {
@@ -25,7 +25,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -2,7 +2,7 @@
import { _, getLocaleFromNavigator } from "svelte-i18n"; import { _, getLocaleFromNavigator } from "svelte-i18n";
import marked from "marked"; import marked from "marked";
import Footer from "./Footer.svelte"; import Footer from "./Footer.svelte";
import * as css from "../base/simple.css"; // import * as css from "../base/simple.css?inline";
let html = ""; let html = "";
async function load() { async function load() {
let md = await fetch("/privacy_" + getLocaleFromNavigator() + ".md"); let md = await fetch("/privacy_" + getLocaleFromNavigator() + ".md");

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { UserGroupService } from "@odit/lfk-client-js"; import { UserGroupService } from "@odit/lfk-client-js";
export let modal_open; export let modal_open;
@@ -69,7 +69,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -30,7 +30,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
<table class="divide-y divide-gray-200 w-full"> <table class="divide-y divide-gray-200 w-full">

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { RunnerOrganizationService } from "@odit/lfk-client-js"; import { RunnerOrganizationService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
export let modal_open; export let modal_open;
@@ -89,7 +89,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { RunnerOrganizationService } from "@odit/lfk-client-js"; import { RunnerOrganizationService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
@@ -32,7 +32,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={cancelDelete}> on:click_outside={cancelDelete}>
<div <div

View File

@@ -51,7 +51,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<div class="h-12"> <div class="h-12">
<GenerateSponsoringContracts <GenerateSponsoringContracts
bind:sponsoring_contracts_show bind:sponsoring_contracts_show

View File

@@ -1,30 +0,0 @@
<script>
import { _, json } from "svelte-i18n";
import { getlang } from "./datatable_i18n";
import { Grid } from "gridjs";
//
let table;
const datatable = new Grid({
columns: ["Name", "Email", "Phone Number"],
language: getlang($json("datatable")),
sort: true,
search: { enabled: true },
data: [
["John", "john@example.com", "(353) 01 222 3333"],
["Mark", "mark@gmail.com", "(01) 22 888 4444"],
["Eoin", "eoin@gmail.com", "0097 22 654 00033"],
["Sarah", "sarahcdd@gmail.com", "+322 876 1233"],
["Afshin", "afshin@mail.com", "(353) 22 87 8356"],
],
pagination: {
enabled: true,
limit: 2,
summary: false,
},
});
setTimeout(() => {
datatable.render(table);
}, 0);
</script>
<div bind:this={table} />

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { import {
RunnerService, RunnerService,
RunnerTeamService, RunnerTeamService,
@@ -11,8 +11,10 @@
import isMobilePhone from "validator/es/lib/isMobilePhone"; import isMobilePhone from "validator/es/lib/isMobilePhone";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import Select from "svelte-select"; import Select from "svelte-select";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
export let modal_open; export let modal_open;
export let current_runners;
$: selected_team = undefined; $: selected_team = undefined;
let firstname_input; let firstname_input;
let lastname_input; let lastname_input;
@@ -107,8 +109,7 @@
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_runners.push(result); dispatch("created", { runners: [result] });
current_runners = current_runners;
}) })
.catch((err) => { .catch((err) => {
// //
@@ -125,7 +126,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -0,0 +1,115 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { createEventDispatcher, onMount } from "svelte";
export let modal_open;
export let delete_runner = {
id: 0,
firstname: "",
lastname: "",
};
const dispatch = createEventDispatcher();
onMount(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
});
async function submit() {
dispatch("delete", { id: delete_runner.id });
modal_open=false;
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="h-6 w-6 text-blue-600"
fill="currentColor"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("confirm-delete")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_("please-confirm-the-deletion-of-runner")}
</p>
</div>
<div class="w-full">
<span class="inline-block"
>{delete_runner.firstname} {delete_runner.lastname}</span
>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("delete")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -3,7 +3,7 @@
import { read as readXlsx, utils as xlsx_utils } from "xlsx"; import { read as readXlsx, utils as xlsx_utils } from "xlsx";
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { import {
ImportService, ImportService,
@@ -16,7 +16,6 @@
export let passed_org; export let passed_org;
export let passed_orgs; export let passed_orgs;
export let passed_team; export let passed_team;
export let current_runners;
export let import_modal_open; export let import_modal_open;
$: searchvalue = ""; $: searchvalue = "";
$: importButtonEnabled = $: importButtonEnabled =
@@ -169,7 +168,7 @@
mapped mapped
) )
.then((resp) => { .then((resp) => {
current_runners = current_runners.concat(resp); dispatch("created", { runners: resp });
toast.hideToast(); toast.hideToast();
recent_processed = true; recent_processed = true;
Toastify({ Toastify({
@@ -198,7 +197,7 @@
mapped mapped
) )
.then((resp) => { .then((resp) => {
current_runners = current_runners.concat(resp); dispatch("created", { runners: resp });
toast.hideToast(); toast.hideToast();
recent_processed = true; recent_processed = true;
Toastify({ Toastify({
@@ -228,7 +227,7 @@
{#if import_modal_open} {#if import_modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
cancelModal(); cancelModal();

View File

@@ -7,35 +7,43 @@
$: current_runners = []; $: current_runners = [];
export let modal_open = false; export let modal_open = false;
export let import_modal_open = false; export let import_modal_open = false;
let addRunners;
</script> </script>
<section class="container p-5"> <section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight"> <span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('runners')} {$_("runners")}
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:CREATE")}
<button <button
on:click={() => { on:click={() => {
modal_open = true; modal_open = true;
}} }}
type="button" type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
{$_('laeufer-hinzufuegen')} >
{$_("laeufer-hinzufuegen")}
</button> </button>
<button <button
on:click={() => { on:click={() => {
import_modal_open = true; import_modal_open = true;
}} }}
type="button" type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
{$_('import-runners')} >
{$_("import-runners")}
</button> </button>
{/if} {/if}
</span> </span>
<RunnersOverview bind:current_runners /> <RunnersOverview bind:current_runners bind:addRunners />
</section> </section>
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:CREATE")}
<AddRunnerModal bind:current_runners bind:modal_open /> <AddRunnerModal
bind:modal_open
on:created={(event) => {
addRunners(event.detail.runners);
}}
/>
<ImportRunnerModal <ImportRunnerModal
on:cancelDelete={(event) => { on:cancelDelete={(event) => {
import_modal_open = false; import_modal_open = false;
@@ -43,7 +51,10 @@
passed_team={{}} passed_team={{}}
passed_orgs={[]} passed_orgs={[]}
passed_org={{}} passed_org={{}}
bind:current_runners
opened_from="RunnerOverview" opened_from="RunnerOverview"
bind:import_modal_open /> bind:import_modal_open
on:created={(event) => {
addRunners(event.detail.runners);
}}
/>
{/if} {/if}

View File

@@ -1,41 +1,171 @@
<script> <script>
import { _ } from "svelte-i18n";
import { import {
RunnerOrganizationService,
RunnerService, RunnerService,
RunnerTeamService, RunnerTeamService,
RunnerOrganizationService,
} from "@odit/lfk-client-js"; } from "@odit/lfk-client-js";
import ThFilterGroup from "./ThFilterGroup.svelte"; import {
import { DataHandler, Datatable, Th, ThFilter } from "@vincjo/datatables"; createSvelteTable,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
renderComponent,
} from "@tanstack/svelte-table";
import { onMount } from "svelte";
import { _ } from "svelte-i18n";
import { writable } from "svelte/store";
import store from "../../store"; import store from "../../store";
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
import { onMount } from "svelte"; import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
$: active_deletes = []; import InputElement from "../shared/InputElement.svelte";
import TableActions from "../shared/TableActions.svelte";
import { groupFilter } from "../shared/tablefilters";
import DeleteRunnerModal from "./DeleteRunnerModal.svelte";
import Toastify from "toastify-js";
import TableBottom from "../shared/TableBottom.svelte";
import TableHeader from "../shared/TableHeader.svelte";
$: selectedRunners =
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
$: selected =
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
$: active_delete = undefined;
let dataLoaded = false; let dataLoaded = false;
let current_runners = []; export let current_runners = [];
const handler = new DataHandler(current_runners, { rowsPerPage: 50 }); $: sponsoring_contracts_show = selected.length > 0;
const rows = handler.getRows(); $: cards_show = selected.length > 0;
$: sponsoring_contracts_show = generate_runners.length > 0; $: certificates_show = selected.length > 0;
$: cards_show = generate_runners.length > 0;
$: certificates_show = generate_runners.length > 0;
$: generate_runners = []; //current_runners.filter((r) => r.selected === true);
$: teams = []; $: teams = [];
$: orgs = []; $: orgs = [];
$: mappedteams = teams.map(function (g) {
return { value: g.id, label: g.parentGroup.name + " > " + g.name }; export const addRunners = (runners) => {
current_runners = current_runners.concat(...runners);
options.update((options) => ({
...options,
data: current_runners,
}));
};
//Section table
const columns = [
{
accessorKey: "id",
header: () => "id",
filterFn: `equalsString`,
},
{
accessorKey: "firstname",
header: () => $_("first-name"),
filterFn: `includesString`,
},
{
accessorKey: "middlename",
header: () => $_("middle-name"),
cell: (info) => {
if (!info || !info.getValue()) {
return "";
}
return info.getValue();
},
filterFn: `includesString`,
},
{
accessorKey: "lastname",
header: () => $_("last-name"),
filterFn: `includesString`,
},
{
accessorKey: "group",
header: () => $_("group"),
cell: (info) => {
const group = info.getValue();
if (group.responseType === "RUNNERORGANIZATION") {
return group.name;
}
return `${group.parentGroup.name} > ${group.name}`;
},
filterFn: `group`,
},
{
accessorKey: "distance",
header: () => $_("distance"),
cell: (info) => {
if (info.getValue() < 1000) {
return `${info.getValue()} m`;
}
return `${(info.getValue() / 1000).toFixed(1)} km`;
},
enableColumnFilter: false,
},
{
accessorKey: "actions",
header: () => $_("action"),
cell: (info) => {
return renderComponent(TableActions, {
detailsLink: `./${info.row.original.id}`,
deleteAction: () => {
active_delete =
current_runners[
current_runners.findIndex((r) => r.id == info.row.original.id)
];
},
deleteEnabled:
store.state.jwtinfo.userdetails.permissions.includes(
"RUNNER:DELETE"
),
}); });
$: selectgroups = orgs },
.map(function (g) { enableColumnFilter: false,
return { value: g.id, label: g.name }; enableSorting: false,
}) },
.concat(mappedteams); ];
const options = writable({
data: [],
columns: columns,
filterFns: {
group: groupFilter,
},
initialState: {
pagination: {
pageSize: 50,
},
},
enableRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});
const table = createSvelteTable(options);
async function deleteRunner(delete_runner_id) {
await RunnerService.runnerControllerRemove(delete_runner_id, true);
current_runners = current_runners.filter((r) => r.id !== delete_runner_id);
options.update((options) => ({
...options,
data: current_runners,
}));
Toastify({
text: $_("runner-deleted"),
duration: 3500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
onMount(() => { onMount(() => {
RunnerService.runnerControllerGetAll().then((val) => { RunnerService.runnerControllerGetAll().then((val) => {
current_runners = val; current_runners = val;
dataLoaded = true; dataLoaded = true;
handler.setRows(val);
options.update((options) => ({
...options,
data: current_runners,
}));
}); });
RunnerTeamService.runnerTeamControllerGetAll().then((val) => { RunnerTeamService.runnerTeamControllerGetAll().then((val) => {
teams = val; teams = val;
@@ -48,6 +178,13 @@
}); });
</script> </script>
<DeleteRunnerModal
delete_runner={active_delete}
modal_open={active_delete != undefined}
on:delete={(event) => {
deleteRunner(event.detail.id);
}}
/>
{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET")} {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET")}
{#if !dataLoaded} {#if !dataLoaded}
<div <div
@@ -58,166 +195,65 @@
<p class="text-sm">{$_("this-might-take-a-moment")}</p> <p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div> </div>
{:else} {:else}
<div class="h-12"> <div class="h-12 mt-2">
<GenerateSponsoringContracts <GenerateSponsoringContracts
bind:sponsoring_contracts_show bind:sponsoring_contracts_show
bind:generate_runners bind:generate_runners={selectedRunners}
/>
<GenerateRunnerCards
bind:cards_show
bind:generate_runners={selectedRunners}
/> />
<GenerateRunnerCards bind:cards_show bind:generate_runners />
<GenerateRunnerCertificates <GenerateRunnerCertificates
bind:certificates_show bind:certificates_show
bind:generate_runners bind:generate_runners={selectedRunners}
/> />
</div> </div>
<Datatable {handler}> <div class="overflow-x-auto">
<table> <table class="w-full">
<thead> <thead>
<tr> {#each $table.getHeaderGroups() as headerGroup}
<th style="border-bottom: 1px solid #ddd;"> <tr class="select-none">
<input <th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
<InputElement
type="checkbox" type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" checked={$table.getIsAllRowsSelected()}
checked={generate_runners.length == current_runners.length} indeterminate={$table.getIsSomeRowsSelected()}
on:click={() => { on:change={() => $table.toggleAllRowsSelected()}
if (generate_runners.length != current_runners.length) {
generate_runners = current_runners;
} else {
generate_runners = [];
}
}}
/> />
</th> </th>
<Th {handler} orderBy="id">ID</Th> {#each headerGroup.headers as header}
<Th {handler} orderBy="firstname">First Name</Th> <TableHeader {header} />
<Th {handler} orderBy="middlename">Middle Name</Th> {/each}
<Th {handler} orderBy="lastname">Last Name</Th>
<th style="border-bottom: 1px solid #ddd;">Gruppe</th>
<Th {handler} orderBy="distance">Distanz</Th>
<th style="border-bottom: 1px solid #ddd;">{$_("action")}</th>
</tr>
<tr>
<th style="border-bottom: 1px solid #ddd;" />
<ThFilter {handler} filterBy="id" />
<ThFilter {handler} filterBy="firstname" />
<ThFilter {handler} filterBy="middlename" />
<ThFilter {handler} filterBy="lastname" />
<ThFilterGroup groups={selectgroups} {handler} />
<th style="border-bottom: 1px solid #ddd;" />
<th style="border-bottom: 1px solid #ddd;" />
</tr> </tr>
{/each}
</thead> </thead>
<tbody> <tbody>
{#each $rows as row} {#each $table.getRowModel().rows as row}
<tr> <tr>
<td> <td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
<input <InputElement
type="checkbox" type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" checked={row.getIsSelected()}
checked={generate_runners.filter((i)=>i.id == row.id).length > 0} on:change={() => row.toggleSelected()}
on:click={() => {
if (
generate_runners.findIndex((i) => i.id == row.id) == -1
) {
generate_runners.push(row);
generate_runners = generate_runners;
} else {
generate_runners = generate_runners.filter(
(r) => r.id != row.id
);
}
console.log(generate_runners)
}}
/> />
</td> </td>
<td>{row.id}</td> {#each row.getVisibleCells() as cell}
<td>{row.firstname}</td>
<td>{row.middlename || ""}</td>
<td>{row.lastname}</td>
<td
>{#if row.group.responseType === "RUNNERTEAM"}
<a
href="../teams/{row.group.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
>{row.group.parentGroup.name} &gt; {row.group.name}</a
>
{/if}
{#if row.group.responseType === "RUNNERORGANIZATION"}
<a
href="../orgs/{row.group.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
>{row.group.name}</a
>
{/if}</td
>
<td>{row.distance / 1000} km</td>
<td> <td>
{#if active_deletes[row.id] === true} <svelte:component
<button this={flexRender(
on:click={() => { cell.column.columnDef.cell,
active_deletes[row.id] = false; cell.getContext()
}} )}
tabindex="0" />
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer"
>{$_("cancel-delete")}</button
>
<button
on:click={() => {
RunnerService.runnerControllerRemove(row.id, true)
.then((resp) => {
current_runners = current_runners.filter(
(obj) => obj.id !== row.id
);
})
.catch((err) => {});
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("confirm-delete")}</button
>
{:else}
<a
href="./{row.id}"
class="text-indigo-600 hover:text-indigo-900"
>{$_("details")}</a
>
{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:DELETE")}
<button
on:click={() => {
active_deletes[row.id] = true;
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("delete")}</button
>
{/if}
{/if}
</td> </td>
{/each}
</tr> </tr>
{/each} {/each}
</tbody> </tbody>
</table> </table>
</Datatable> </div>
<div class="h-2" />
{/if} {/if}
{/if} {/if}
<TableBottom {table} {selected} />
<style>
thead {
background: #fff;
}
thead {
position: sticky;
inset-block-start: 0;
}
tbody td {
padding: 4px;
}
tbody tr:nth-child(even) {
background: #fafafa;
}
tbody tr {
transition: all, 0.2s;
}
tbody tr:hover {
background: #f5f5f5;
}
</style>

View File

@@ -1,15 +1,15 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { import {
RunnerService, RunnerService,
ScanService, ScanService,
} from "@odit/lfk-client-js"; } from "@odit/lfk-client-js";
import Select from "svelte-select"; import Select from "svelte-select";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte";
export let modal_open; export let modal_open;
export let current_scans;
const getRunnerLabel = (option) => const getRunnerLabel = (option) =>
option.firstname + " " + (option.middlename || "") + " " + option.lastname; option.firstname + " " + (option.middlename || "") + " " + option.lastname;
const filterRunners = (label, filterText, option) => const filterRunners = (label, filterText, option) =>
@@ -18,6 +18,7 @@
function focus(el) { function focus(el) {
el.focus(); el.focus();
} }
const dispatch = createEventDispatcher();
$: runner = 0; $: runner = 0;
$: runners = []; $: runners = [];
RunnerService.runnerControllerGetAll().then((val) => { RunnerService.runnerControllerGetAll().then((val) => {
@@ -63,8 +64,7 @@
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_scans.push(result); dispatch("created", { scans: [result] });
current_scans = current_scans;
}) })
.catch((err) => { .catch((err) => {
// //
@@ -81,7 +81,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -0,0 +1,110 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { createEventDispatcher, onMount } from "svelte";
export let modal_open;
export let delete_scan = {
id: 0,
runner: {
firstname: "",
lastname: "",
},
};
const dispatch = createEventDispatcher();
onMount(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
});
async function submit() {
dispatch("delete", { id: delete_scan.id });
modal_open = false;
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="h-6 w-6 text-blue-600"
fill="currentColor"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("confirm-delete")}
</h3>
<div class="mt-2 mb-6">
{$_("please-confirm-the-deletion-of-scan")} #{delete_scan.id}
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("delete")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -0,0 +1,16 @@
<script>
import { _ } from "svelte-i18n";
export let valid = false;
</script>
{#if valid}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
>{$_("valid")}</span
>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800"
>{$_("invalid")}</span
>
{/if}

View File

@@ -5,6 +5,7 @@
import ScansOverview from "./ScansOverview.svelte"; import ScansOverview from "./ScansOverview.svelte";
$: current_scans = []; $: current_scans = [];
export let modal_open = false; export let modal_open = false;
let addScans;
</script> </script>
<section class="container p-5"> <section class="container p-5">
@@ -21,9 +22,11 @@
</button> </button>
{/if} {/if}
</span> </span>
<ScansOverview bind:current_scans /> <ScansOverview bind:current_scans bind:addScans />
</section> </section>
{#if store.state.jwtinfo.userdetails.permissions.includes('SCAN:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes('SCAN:CREATE')}
<AddScanModal bind:current_scans bind:modal_open /> <AddScanModal bind:modal_open on:created={(event)=>{
addScans(event.detail.scans)
}} />
{/if} {/if}

View File

@@ -1,21 +1,54 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { DataHandler, Datatable, Th, ThFilter } from "@vincjo/datatables";
import { ScanService, TrackService } from "@odit/lfk-client-js"; import { ScanService, TrackService } from "@odit/lfk-client-js";
import store from "../../store"; import store from "../../store";
import {
createSvelteTable,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
renderComponent,
} from "@tanstack/svelte-table";
import { onMount } from "svelte";
import { writable } from "svelte/store";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import TableBottom from "../shared/TableBottom.svelte";
import TableHeader from "../shared/TableHeader.svelte";
import ScansEmptyState from "./ScansEmptyState.svelte"; import ScansEmptyState from "./ScansEmptyState.svelte";
import ThFilterRunner from "./ThFilterRunner.svelte"; import InputElement from "../shared/InputElement.svelte";
import ThFilterTrack from "./ThFilterTrack.svelte"; import TableActions from "../shared/TableActions.svelte";
$: active_deletes = []; import { runnerFilter, statusFilter } from "../shared/tablefilters";
import CardRunner from "../cards/CardRunner.svelte";
import ScanValid from "./ScanValid.svelte";
import DeleteScanModal from "./DeleteScanModal.svelte";
$: selectedScans =
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
$: selected =
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
$: active_delete = undefined;
export let current_scans = []; export let current_scans = [];
const handler = new DataHandler(current_scans, { rowsPerPage: 20 }); export const addScans = (scans) => {
const rows = handler.getRows(); current_scans = current_scans.concat(...scans);
options.update((options) => ({
...options,
data: current_scans,
}));
};
const scans_promise = ScanService.scanControllerGetAll().then((val) => { const scans_promise = ScanService.scanControllerGetAll().then((val) => {
current_scans = val; current_scans = val;
handler.setRows(val); // handler.setRows(val);
current_scans = val;
options.update((options) => ({
...options,
data: current_scans,
}));
}); });
$: allTracks = []; let allTracks = [];
TrackService.trackControllerGetAll().then((val) => { TrackService.trackControllerGetAll().then((val) => {
allTracks = val; allTracks = val;
}); });
@@ -39,8 +72,118 @@
Math.floor(laptime / 60) * 60 Math.floor(laptime / 60) * 60
}`; }`;
} }
const columns = [
{
accessorKey: "id",
header: () => "id",
filterFn: `equalsString`,
},
{
accessorKey: "runner",
header: () => $_("runner"),
cell: (info) => {
return renderComponent(CardRunner, { runner: info.getValue() });
},
filterFn: `runner`,
},
{
accessorKey: "lapTime",
header: () => $_("laptime"),
cell: (info) => {
return format_laptime(info.getValue());
},
enableColumnFilter: false,
},
{
accessorKey: "distance",
header: () => $_("distance"),
cell: (info) => {
if (info.getValue() < 1000) {
return `${info.getValue()}m`;
}
return `${(info.getValue() / 1000).toFixed(1)}km`;
},
enableColumnFilter: false,
},
{
accessorKey: "track",
header: () => $_("track"),
cell: (info) => {
const track = info.getValue();
return track?.name || "?";
},
enableColumnFilter: true,
},
{
accessorKey: "valid",
cell: (info) => {
return renderComponent(ScanValid, { valid: info.getValue() });
},
header: () => $_("status"),
filterFn: `status`,
},
{
accessorKey: "actions",
header: () => $_("action"),
cell: (info) => {
return renderComponent(TableActions, {
detailsLink: `./${info.row.original.id}`,
deleteAction: () => {
active_delete =
current_scans[
current_scans.findIndex((r) => r.id == info.row.original.id)
];
},
deleteEnabled:
store.state.jwtinfo.userdetails.permissions.includes("SCAN:DELETE"),
});
},
enableColumnFilter: false,
enableSorting: false,
},
];
const options = writable({
data: [],
columns: columns,
initialState: {
pagination: {
pageSize: 50,
},
},
filterFns: {
runner: runnerFilter,
status: statusFilter,
},
enableRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});
const table = createSvelteTable(options);
async function deleteScan(scan_id) {
await ScanService.scanControllerRemove(scan_id, true);
current_scans = current_scans.filter((r) => r.id !== scan_id);
options.update((options) => ({
...options,
data: current_scans,
}));
Toastify({
text: $_("scan-deleted"),
duration: 3500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
</script> </script>
<DeleteScanModal
delete_scan={active_delete}
modal_open={active_delete != undefined}
on:delete={(event) => {
deleteScan(event.detail.id);
}}
/>
{#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:GET")} {#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:GET")}
{#await scans_promise} {#await scans_promise}
<div <div
@@ -54,173 +197,94 @@
{#if current_scans.length === 0} {#if current_scans.length === 0}
<ScansEmptyState /> <ScansEmptyState />
{:else} {:else}
<div {#if selected.length > 0}
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"
>
<Datatable {handler}>
<table class="divide-y divide-gray-200 w-full">
<thead class="bg-gray-50">
<tr>
<Th {handler} orderBy="id">ID</Th>
<Th {handler}>
{$_("runner")}
</Th>
<Th {handler}>
{$_("distance")}
</Th>
<Th {handler}>
{$_("track")}
</Th>
<Th {handler}>
{$_("laptime")}
</Th>
<Th {handler}>
{$_("status")}
</Th>
<th
scope="col"
class="relative px-6 py-3"
style="border-bottom: 1px solid #ddd;"
>
{$_("action")}
</th>
</tr>
<tr>
<ThFilter {handler} filterBy="id" />
<ThFilterRunner {handler} />
<th style="border-bottom: 1px solid #ddd;" />
<ThFilterTrack tracks={allTracks} {handler} />
<!-- <th style="border-bottom: 1px solid #ddd;" /> -->
<th style="border-bottom: 1px solid #ddd;" />
<th style="border-bottom: 1px solid #ddd;" />
<!-- TODO: filter status -->
<th style="border-bottom: 1px solid #ddd;" />
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
{#each $rows as scan}
<tr data-rowid="scan_{scan.id}">
<td class="px-6 py-4 whitespace-nowrap text-left">
<div class="text-sm font-medium text-gray-900">
{scan.id}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<a
href="../runners/{scan.runner.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
>{scan.runner.firstname}
{scan.runner.middlename || ""}
{scan.runner.lastname}</a
>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-left">
<div class="text-sm font-medium text-gray-900">
{#if scan.distance < 1000}
{scan.distance}m
{:else}{scan.distance / 1000}km{/if}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-left">
<div class="text-sm font-medium text-gray-900">
{#if scan.track}
<a
href="../tracks"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
>{scan.track.name}
</a>
{/if}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-left">
{#if scan.responseType === "TRACKSCAN"}
<div class="text-sm font-medium text-gray-900">
{format_laptime(scan.lapTime)}
</div>
{:else}
<div class="text-sm font-medium text-gray-900">
{$_("scan-with-fixed-distance")}
</div>
{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
{#if scan.valid}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
>{$_("valid")}</span
>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800"
>{$_("invalid")}</span
>
{/if}
</div>
</td>
{#if active_deletes[scan.id] === true}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
>
<button <button
on:click={() => { type="button"
active_deletes[scan.id] = false; class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm inline-flex"
}} id="options-menu"
tabindex="0" on:click={async () => {
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer" const prom = [];
>{$_("cancel-delete")}</button for (const scan of selectedScans) {
> prom.push(ScanService.scanControllerRemove(scan.id, true));
<button
on:click={() => {
ScanService.scanControllerRemove(scan.id, false).then(
(resp) => {
current_scans = current_scans.filter(
(obj) => obj.id !== scan.id
);
Toastify({
text: "Scan deleted",
duration: 500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
} }
); await Promise.all(prom);
for (const scan of selectedScans) {
current_scans = current_scans.filter((r) => r.id !== scan.id);
}
options.update((options) => ({
...options,
data: current_scans,
}));
$table.resetRowSelection();
Toastify({
text: $_("scan-deleted"),
duration: 3500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}} }}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("confirm-delete")}</button
> >
</td> {$_("delete-scans")}
{:else} <svg
<td xmlns="http://www.w3.org/2000/svg"
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium" fill="none"
> viewBox="0 0 24 24"
<a stroke-width="1.5"
href="./{scan.id}" stroke="currentColor"
class="text-indigo-600 hover:text-indigo-900" class="w-5 h-5"
>{$_("details")}</a
>
{#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:DELETE")}
<button
on:click={() => {
active_deletes[scan.id] = true;
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("delete")}</button
> >
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
{/if} {/if}
<div class="overflow-x-auto">
<table class="w-full">
<thead>
{#each $table.getHeaderGroups() as headerGroup}
<tr class="select-none">
<th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
<InputElement
type="checkbox"
checked={$table.getIsAllRowsSelected()}
indeterminate={$table.getIsSomeRowsSelected()}
on:change={() => $table.toggleAllRowsSelected()}
/>
</th>
{#each headerGroup.headers as header}
<TableHeader {header} />
{/each}
</tr>
{/each}
</thead>
<tbody>
{#each $table.getRowModel().rows as row}
<tr>
<td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
<InputElement
type="checkbox"
checked={row.getIsSelected()}
on:change={() => row.toggleSelected()}
/>
</td> </td>
{/if} {#each row.getVisibleCells() as cell}
<td>
<svelte:component
this={flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
/>
</td>
{/each}
</tr> </tr>
{/each} {/each}
</tbody> </tbody>
</table> </table>
</Datatable>
</div> </div>
<TableBottom {table} {selected} />
{/if} {/if}
{:catch error} {:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { ScanStationService, TrackService } from "@odit/lfk-client-js"; import { ScanStationService, TrackService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import Select from "svelte-select"; import Select from "svelte-select";
@@ -81,7 +81,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { ScanStationService } from "@odit/lfk-client-js"; import { ScanStationService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
@@ -32,7 +32,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={cancelDelete}> on:click_outside={cancelDelete}>
<div <div

View File

@@ -1,6 +1,6 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { focusTrap } from "svelte-focus-trap";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { tick, createEventDispatcher } from "svelte"; import { tick, createEventDispatcher } from "svelte";
export let copy_modal_open; export let copy_modal_open;
@@ -46,7 +46,7 @@
{#if valueCopy != null} {#if valueCopy != null}
<textarea bind:this={areaDom}>{valueCopy}</textarea> <textarea bind:this={areaDom}>{valueCopy}</textarea>
{/if} {/if}
<div class="fixed z-10 inset-0 overflow-y-auto" use:focusTrap> <div class="fixed z-10 inset-0 overflow-y-auto" >
<div <div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true"> <div class="fixed inset-0 transition-opacity" aria-hidden="true">

View File

@@ -41,7 +41,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
<table class="divide-y divide-gray-200 w-full"> <table class="divide-y divide-gray-200 w-full">

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { MeService } from "@odit/lfk-client-js"; import { MeService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
@@ -30,7 +30,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={cancelDelete}> on:click_outside={cancelDelete}>
<div <div

View File

@@ -0,0 +1,20 @@
<script>
let className = "";
export { className as class };
export let type;
</script>
<input
class={`border-1 border-stone-300 border rounded-md shadow ${className} ${
type === "checkbox" && "w-5 h-5 text-orange-400"
}`}
{type}
{...$$restProps}
on:click
on:change
on:keydown
on:keyup
on:mouseenter
on:mouseleave
/>

View File

@@ -0,0 +1,26 @@
<script>
import { _ } from "svelte-i18n";
export let detailsLink;
export let detailsAction;
export let deleteEnabled;
export let deleteAction;
</script>
{#if detailsLink}
<a href={detailsLink} class="text-indigo-600 hover:text-indigo-900"
>{$_("details")}</a
>
{:else if detailsAction}
<button on:click={detailsAction} class="text-indigo-600 hover:text-indigo-900"
>{$_("details")}</button
>
{/if}
{#if deleteEnabled}
<button
tabindex="0"
on:click={deleteAction}
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("delete")}</button
>
{/if}

View File

@@ -0,0 +1,71 @@
<script>
export let table;
export let selected;
</script>
<div class="flex items-center gap-2">
<button
class="border rounded p-1"
on:click={() => $table.setPageIndex(0)}
disabled={!$table.getCanPreviousPage()}
>
{"<<"}
</button>
<button
class="border rounded p-1"
on:click={() => $table.previousPage()}
disabled={!$table.getCanPreviousPage()}
>
{"<"}
</button>
<button
class="border rounded p-1"
on:click={() => $table.nextPage()}
disabled={!$table.getCanNextPage()}
>
{">"}
</button>
<button
class="border rounded p-1"
on:click={() => $table.setPageIndex($table.getPageCount() - 1)}
disabled={!$table.getCanNextPage()}
>
{">>"}
</button>
<span class="flex items-center gap-1">
<div>Page</div>
<strong>
{$table.getState().pagination.pageIndex + 1} of{" "}
{$table.getPageCount()}
</strong>
</span>
<span class="flex items-center gap-1">
| Go to page:
<input
type="number"
defaultValue={$table.getState().pagination.pageIndex + 1}
on:change={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
$table.setPageIndex(page);
}}
class="border p-1 rounded w-16"
/>
</span>
<select
value={$table.getState().pagination.pageSize}
on:input={(e) => {
const ps = Number(e.target.value);
console.log({ ps });
$table.setPageSize(Number(e.target.value));
}}
>
{#each [25, 50, 100, 250, 500] as pageSize}
<option value={pageSize}>{pageSize}</option>
{/each}
</select>
</div>
<!-- <pre>{JSON.stringify($table.getState(), null, 2)}</pre> -->
<div>
{Object.keys(selected).length} of{" "}
{$table.getPreFilteredRowModel().rows.length} Total Rows Selected
</div>

View File

@@ -0,0 +1,57 @@
<script>
import { flexRender } from "@tanstack/svelte-table";
export let header;
</script>
<th class="cursor-pointer min-w-[5rem]">
{#if !header.isPlaceholder}
<button
class="w-full"
tabindex="0"
on:click={header.column.getToggleSortingHandler()}
>
<svelte:component
this={flexRender(header.column.columnDef.header, header.getContext())}
/>
{#if header.column
.getIsSorted()
.toString() == "asc" && header.column.getCanSort()}
🔼
{:else if header.column
.getIsSorted()
.toString() == "desc" && header.column.getCanSort()}
🔽
{/if}
</button>
{/if}
{#if header.column.getCanFilter()}
<div class="relative max-w-xs">
<input
title="name-search"
value={header.column.getFilterValue() || ""}
on:keyup={(e) => {
header.column.setFilterValue(e.target.value);
}}
type="text"
class="block w-full rounded-md border-gray-200 py-2 pl-8 text-xs focus:border-blue-500 focus:ring-blue-500"
placeholder=""
/>
<div
class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-2"
>
<svg
class="h-3.5 w-3.5 text-gray-400"
xmlns="http://www.w3.org/2000/svg"
width={16}
height={16}
fill="currentColor"
viewBox="0 0 16 16"
>
<path
d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"
/>
</svg>
</div>
</div>
{/if}
</th>

View File

@@ -0,0 +1,34 @@
export const groupFilter = (row, columnId, value) => {
const group = row.getValue(columnId);
if (group.responseType === "RUNNERORGANIZATION") {
return group.name.toLowerCase().includes(value.toLowerCase());
} else if (value.includes(">")) {
return (
`${group.parentGroup.name} > ${group.name}`.toLowerCase().includes(value.toLowerCase())
);
} else {
return (
group.name.toLowerCase().includes(value.toLowerCase()) ||
group.parentGroup.name.toLowerCase().includes(value.toLowerCase())
);
}
};
export const runnerFilter = (row, columnId, value) => {
const runner = row.getValue(columnId);
if(!runner && value == "blanko"){return true}
if(!runner){return false}
if(value.startsWith("#")){
return runner.id == value.replace("#","")
}
if(runner.middlename){
return `${runner.firstname} ${runner.middlename} ${runner.lastname}`.toLowerCase().includes(value.toLowerCase())
}
return `${runner.firstname} ${runner.lastname}`.toLowerCase().includes(value.toLowerCase())
};
export const statusFilter = (row, columnId, value) => {
const status = row.getValue(columnId);
return status.toString().includes(value);
};

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { StatsClientService } from "@odit/lfk-client-js"; import { StatsClientService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
export let modal_open; export let modal_open;
@@ -66,7 +66,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { ScanStationService } from "@odit/lfk-client-js"; import { ScanStationService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
@@ -32,7 +32,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={cancelDelete}> on:click_outside={cancelDelete}>
<div <div

View File

@@ -1,6 +1,6 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { focusTrap } from "svelte-focus-trap";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { tick, createEventDispatcher } from "svelte"; import { tick, createEventDispatcher } from "svelte";
export let copy_modal_open; export let copy_modal_open;
@@ -46,7 +46,7 @@
{#if valueCopy != null} {#if valueCopy != null}
<textarea bind:this={areaDom}>{valueCopy}</textarea> <textarea bind:this={areaDom}>{valueCopy}</textarea>
{/if} {/if}
<div class="fixed z-10 inset-0 overflow-y-auto" use:focusTrap> <div class="fixed z-10 inset-0 overflow-y-auto" >
<div <div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true"> <div class="fixed inset-0 transition-opacity" aria-hidden="true">

View File

@@ -41,7 +41,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
<table class="divide-y divide-gray-200 w-full"> <table class="divide-y divide-gray-200 w-full">

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { import {
RunnerOrganizationService, RunnerOrganizationService,
RunnerTeamService, RunnerTeamService,
@@ -77,7 +77,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { RunnerTeamService } from "@odit/lfk-client-js"; import { RunnerTeamService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
@@ -29,7 +29,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={cancelDelete}> on:click_outside={cancelDelete}>
<div <div

View File

@@ -57,7 +57,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<div class="h-12"> <div class="h-12">
<GenerateSponsoringContracts <GenerateSponsoringContracts
bind:sponsoring_contracts_show bind:sponsoring_contracts_show

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { tracks as tracksstore } from "../../store.js"; import { tracks as tracksstore } from "../../store.js";
import { TrackService } from "@odit/lfk-client-js"; import { TrackService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
@@ -75,7 +75,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { UserService } from "@odit/lfk-client-js"; import { UserService } from "@odit/lfk-client-js";
import isEmail from "validator/es/lib/isEmail"; import isEmail from "validator/es/lib/isEmail";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
@@ -92,7 +92,7 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;

View File

@@ -36,7 +36,7 @@
bind:value={searchvalue} bind:value={searchvalue}
placeholder={$_('datatable.search')} placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')} aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" /> class="mb-4" />
<!-- {/if} --> <!-- {/if} -->
<!-- <button <!-- <button
on:click={() => { on:click={() => {

View File

@@ -52,10 +52,12 @@
"cancel-keep-statsclient": "Abbrechen und Statsclient behalten", "cancel-keep-statsclient": "Abbrechen und Statsclient behalten",
"cancel-keep-team": "Abbrechen, Team behalten", "cancel-keep-team": "Abbrechen, Team behalten",
"cannot-reset-your-password-directly": "Schade. \nWir können das Passwort leider nicht direkt zurücksetzen.\nBitte sende uns eine Mail in der du deine Identität bestätigst.", "cannot-reset-your-password-directly": "Schade. \nWir können das Passwort leider nicht direkt zurücksetzen.\nBitte sende uns eine Mail in der du deine Identität bestätigst.",
"card": "Läuferkarte",
"card-added": "Karte wurde hinzugefügt", "card-added": "Karte wurde hinzugefügt",
"card-deleted": "Karte gelöscht", "card-deleted": "Karte gelöscht",
"card-updated": "Karte aktualisiert", "card-updated": "Karte aktualisiert",
"cards": "Läuferkarten", "cards": "Läuferkarten",
"cards-deleted": "Karten gelöscht",
"certificates": "Urkunden", "certificates": "Urkunden",
"change-your-password-here": "Hier kannst du dein Passwort ändern", "change-your-password-here": "Hier kannst du dein Passwort ändern",
"changing-your-password": "Passwort wird geändert", "changing-your-password": "Passwort wird geändert",
@@ -138,6 +140,7 @@
"sort_column_descending": "Spalte absteigend sortieren" "sort_column_descending": "Spalte absteigend sortieren"
}, },
"delete": "Löschen", "delete": "Löschen",
"delete-cards": "Karten löschen",
"delete-contact": "Kontakt löschen", "delete-contact": "Kontakt löschen",
"delete-donation": "Sponsoring löschen", "delete-donation": "Sponsoring löschen",
"delete-donor": "Sponsor:in löschen", "delete-donor": "Sponsor:in löschen",
@@ -146,6 +149,7 @@
"delete-profile": "Profil löschen", "delete-profile": "Profil löschen",
"delete-runner": "Läufer:in löschen", "delete-runner": "Läufer:in löschen",
"delete-scan": "Scan löschen", "delete-scan": "Scan löschen",
"delete-scans": "Scans löschen",
"delete-station": "Station löschen", "delete-station": "Station löschen",
"delete-statsclient": "Statsclient löschen", "delete-statsclient": "Statsclient löschen",
"delete-team": "Team Löschen", "delete-team": "Team Löschen",
@@ -314,6 +318,9 @@
"permissions": "Berechtigungen", "permissions": "Berechtigungen",
"permissions-updated": "Berechtigungen aktualisiert!", "permissions-updated": "Berechtigungen aktualisiert!",
"phone": "Telefon", "phone": "Telefon",
"please-confirm-the-deletion-of-card": "Bitte bestätige die Löschung der Karte",
"please-confirm-the-deletion-of-runner": "Bitte bestätige die Löschung der Läufer:in",
"please-confirm-the-deletion-of-scan": "Bitte bestätige die Löschung des Scans",
"please-copy-the-token-and-store-it-somewhere-save": "Bitte kopiere dir den Token und bewahre ihn gut auf.", "please-copy-the-token-and-store-it-somewhere-save": "Bitte kopiere dir den Token und bewahre ihn gut auf.",
"please-provide-a-password": "Bitte gebe ein Passwort an...", "please-provide-a-password": "Bitte gebe ein Passwort an...",
"please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen", "please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen",
@@ -346,6 +353,7 @@
"reset-password": "Passwort zurücksetzen", "reset-password": "Passwort zurücksetzen",
"runner": "Läufer:in", "runner": "Läufer:in",
"runner-added": "Läufer:in hinzugefügt", "runner-added": "Läufer:in hinzugefügt",
"runner-deleted": "Läufer:in gelöscht",
"runner-import": "Läufer:innen Import", "runner-import": "Läufer:innen Import",
"runner-is-being-added": "Läufer:in wird hinzugefügt...", "runner-is-being-added": "Läufer:in wird hinzugefügt...",
"runner-updated": "Läufer:in aktualisiert!", "runner-updated": "Läufer:in aktualisiert!",
@@ -357,6 +365,7 @@
"save": "Speichern", "save": "Speichern",
"save-changes": "Änderungen speichern", "save-changes": "Änderungen speichern",
"scan-added": "Scan hinzugefügt", "scan-added": "Scan hinzugefügt",
"scan-deleted": "Scan gelöscht",
"scan-is-being-updated": "Scan wird aktualisiert", "scan-is-being-updated": "Scan wird aktualisiert",
"scan-with-fixed-distance": "Scan mit Festdistanz", "scan-with-fixed-distance": "Scan mit Festdistanz",
"scans": "Scans", "scans": "Scans",

View File

@@ -52,10 +52,12 @@
"cancel-keep-statsclient": "Cancel and keep statsclient", "cancel-keep-statsclient": "Cancel and keep statsclient",
"cancel-keep-team": "Cancel, keep team", "cancel-keep-team": "Cancel, keep team",
"cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity", "cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity",
"card": "card",
"card-added": "Card added", "card-added": "Card added",
"card-deleted": "Card deleted", "card-deleted": "Card deleted",
"card-updated": "Card updated", "card-updated": "Card updated",
"cards": "Cards", "cards": "Cards",
"cards-deleted": "Cards deleted",
"certificates": "Certificates", "certificates": "Certificates",
"change-your-password-here": "Change your password here", "change-your-password-here": "Change your password here",
"changing-your-password": "Changing your password", "changing-your-password": "Changing your password",
@@ -138,6 +140,7 @@
"an_error_happened_while_fetching_the_data": "An error happened while fetching the data" "an_error_happened_while_fetching_the_data": "An error happened while fetching the data"
}, },
"delete": "Delete", "delete": "Delete",
"delete-cards": "Delete cards",
"delete-contact": "Delete Contact", "delete-contact": "Delete Contact",
"delete-donation": "Delete Donation", "delete-donation": "Delete Donation",
"delete-donor": "Delete donor", "delete-donor": "Delete donor",
@@ -146,6 +149,7 @@
"delete-profile": "Delete Profile", "delete-profile": "Delete Profile",
"delete-runner": "Delete Runner", "delete-runner": "Delete Runner",
"delete-scan": "Delete scan", "delete-scan": "Delete scan",
"delete-scans": "Delete scans",
"delete-station": "Delete station", "delete-station": "Delete station",
"delete-statsclient": "Delete statsclient", "delete-statsclient": "Delete statsclient",
"delete-team": "Delete Team", "delete-team": "Delete Team",
@@ -314,6 +318,9 @@
"permissions": "Permissions", "permissions": "Permissions",
"permissions-updated": "Permissions updated!", "permissions-updated": "Permissions updated!",
"phone": "Phone", "phone": "Phone",
"please-confirm-the-deletion-of-card": "Please confirm the deletion of this card",
"please-confirm-the-deletion-of-runner": "Please confirm the deletion of this runner",
"please-confirm-the-deletion-of-scan": "Please confirm the deletion of scan",
"please-copy-the-token-and-store-it-somewhere-save": "Please copy the token and store it somewhere safe.", "please-copy-the-token-and-store-it-somewhere-save": "Please copy the token and store it somewhere safe.",
"please-provide-a-password": "Please provide a password...", "please-provide-a-password": "Please provide a password...",
"please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor", "please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor",
@@ -346,6 +353,7 @@
"reset-password": "Reset your password", "reset-password": "Reset your password",
"runner": "Runner", "runner": "Runner",
"runner-added": "Runner added", "runner-added": "Runner added",
"runner-deleted": "runner deleted",
"runner-import": "Runner Import", "runner-import": "Runner Import",
"runner-is-being-added": "Runner is being added...", "runner-is-being-added": "Runner is being added...",
"runner-updated": "Runner updated!", "runner-updated": "Runner updated!",
@@ -357,6 +365,7 @@
"save": "Save", "save": "Save",
"save-changes": "Save Changes", "save-changes": "Save Changes",
"scan-added": "Scan added", "scan-added": "Scan added",
"scan-deleted": "scan deleted",
"scan-is-being-updated": "Scan is being updated", "scan-is-being-updated": "Scan is being updated",
"scan-with-fixed-distance": "Scan with fixed distance", "scan-with-fixed-distance": "Scan with fixed distance",
"scans": "Scans", "scans": "Scans",

View File

@@ -1,6 +1,6 @@
module.exports = { module.exports = {
mode: 'jit', mode: 'jit',
purge: [ './src/**/*.svelte' ], content: [ './src/**/*.svelte' ],
theme: { theme: {
extend: { extend: {
colors: { colors: {

View File

@@ -1,5 +1,5 @@
const fs = require('fs'); import fs from 'fs';
const package = JSON.parse(fs.readFileSync(`./package.json`, { encoding: 'utf-8' })); const packagejson = JSON.parse(fs.readFileSync(`./package.json`, { encoding: 'utf-8' }));
const original = fs.readFileSync(`./index.html`, { encoding: 'utf-8' }); const original = fs.readFileSync(`./index.html`, { encoding: 'utf-8' });
let out = original.replace(/RELEASE_INFO-(\S)+-RELEASE_INFO/gi, 'RELEASE_INFO-' + package.version + '-RELEASE_INFO'); let out = original.replace(/RELEASE_INFO-(\S)+-RELEASE_INFO/gi, 'RELEASE_INFO-' + packagejson.version + '-RELEASE_INFO');
fs.writeFileSync(`./index.html`, out); fs.writeFileSync(`./index.html`, out);

View File

@@ -1,39 +1,11 @@
import svelte from '@sveltejs/vite-plugin-svelte'; // vite.config.js
import { minify } from 'html-minifier';
import { defineConfig } from 'vite'; import { defineConfig } from 'vite';
// import { svelte } from '@sveltejs/vite-plugin-svelte';
const indexReplace = () => {
return {
name: 'html-transform',
transformIndexHtml(html) {
return minify(html, {
collapseWhitespace: true
});
}
};
};
export default defineConfig(({ command, mode }) => { export default defineConfig({
const isProduction = mode === 'production';
return {
// base: './',
build: {
polyfillDynamicImport: false,
cssCodeSplit: false,
minify: isProduction,
target: ["es2020", "esnext", "edge88", "chrome87", "safari14"]
},
plugins: [ plugins: [
svelte({ svelte({
//@ts-ignore /* plugin options */
hot: !isProduction, })
emitCss: true,
extensions: ['.md', '.svx', '.svelte'],
preprocess: [
//
] ]
}),
indexReplace()
]
};
}); });