Compare commits

..

25 Commits

Author SHA1 Message Date
7baaf2cff3 Merge branch 'feature/13-runner-management' of git.odit.services:lfk/frontend into feature/13-runner-management 2021-01-24 17:23:18 +01:00
9fbc1ba031 Added friles to ignore 2021-01-24 17:21:48 +01:00
6704c07db0 Deleted files to ignore 2021-01-24 17:21:39 +01:00
a87165148a 🧹 RunnerDetail cleanup + i18n 🌎
ref #13
2021-01-24 17:21:19 +01:00
ec4bcd093b 🐞 [bugfix] RunnerDetail update
ref #13
2021-01-24 17:16:49 +01:00
5552055b98 RunnerDetail - button text fixes
ref #13
2021-01-21 20:50:14 +01:00
03aa67034d basic RunnerDetail
ref #13
2021-01-21 19:07:43 +01:00
819b02a204 ImportRunnerModal - hide team when loading from TeamDetail
ref #13
2021-01-20 20:25:41 +01:00
de0bd5fd57 ImportRunnerModal usage in TeamDetail
ref #13
2021-01-20 20:21:59 +01:00
8aa1d94a1a use ImportRunnerModal in OrgDetail + Orgs
ref #13
2021-01-20 19:59:53 +01:00
f8a59133a2 ImportRunnerModal - compatibility for multi-component access
ref #13
2021-01-20 19:59:31 +01:00
c382f770dc 👀 basic ui interaction for ImportRunnerModal
ref #13
2021-01-20 18:31:23 +01:00
cde4ec13ef basic cancel event dispatch from ImportRunnerModal
ref #13
2021-01-20 18:15:47 +01:00
ecad1ea839 ↙ added default fallback parsing to ImportRunnerModal
ref #13
2021-01-20 17:56:32 +01:00
6b91b22713 🚀 ImportRunnerModal - working demo
ref #13
2021-01-20 17:46:18 +01:00
e34c91b2cc 🌎 i18n in ImportRunnerModal headers
ref #13
2021-01-20 17:33:10 +01:00
822759a688 😦 added missing dependencies
ref #13
2021-01-19 21:45:00 +01:00
b606037890 🌎 added locale based csv/xlsx header parsing
ref #13
2021-01-19 21:44:41 +01:00
74d9b94119 basic xlsx + csv parsing
ref #13
2021-01-19 21:44:13 +01:00
b1e9f955b0 basic ImportRunnerModal with CSV input
ref #13
2021-01-19 18:19:21 +01:00
e0356fa360 fixed runner permissions
ref #13
2021-01-19 18:18:51 +01:00
fbc67eeb98 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev 2021-01-18 20:34:50 +01:00
09fd73b130 🐞 improved version builder from template 2021-01-18 20:34:47 +01:00
259a76f46b 🧹 darkmode classes cleanup 2021-01-18 20:29:44 +01:00
c6504c2eaf new license file version [CI SKIP] 2021-01-17 18:46:15 +00:00
29 changed files with 780 additions and 90 deletions

3
.gitignore vendored
View File

@@ -7,4 +7,5 @@ public/env.js
public/sw.js
public/index.html
public/workbox-*.js
svelte.config.js
svelte.config.js
public/index.html

View File

@@ -14,7 +14,7 @@
</head>
<body>
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.3.1-RELEASE_INFO</span>
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.4.0-RELEASE_INFO</span>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script src="/env.js"></script>
<script defer type="module" src="/_dist_/index.js"></script>

View File

@@ -13,6 +13,7 @@
},
"dependencies": {
"@odit/lfk-client-js": "0.1.1",
"csvtojson": "^2.0.10",
"filepond": "4.25.1",
"gridjs": "3.2.2",
"localforage": "1.9.0",
@@ -23,7 +24,8 @@
"tailwindcss": "2.0.2",
"tinro": "0.5.7",
"toastify-js": "1.9.3",
"validator": "13.5.2"
"validator": "13.5.2",
"xlsx": "^0.16.9"
},
"devDependencies": {
"@odit/license-exporter": "0.0.9",

View File

@@ -1 +0,0 @@
<!-- this is configured with dev scripts -->

File diff suppressed because one or more lines are too long

View File

@@ -48,6 +48,7 @@
OpenAPI.BASE = config.baseurl;
import { register as registerSW } from "./swmodule";
import TeamDetail from "./components/TeamDetail.svelte";
import RunnerDetail from "./components/RunnerDetail.svelte";
store.init();
registerSW();
</script>
@@ -81,8 +82,13 @@
</Route>
<Route path="/:trackid" let:params />
</Route>
<Route path="/runners">
<Runners />
<Route path="/runners/*">
<Route path="/">
<Runners />
</Route>
<Route path="/:runnerid" let:params>
<RunnerDetail {params} />
</Route>
</Route>
<Route path="/teams/*">
<Route path="/">

View File

@@ -28,7 +28,13 @@
$: firstname_input_value = "";
$: processed_last_submit = true;
$: isPhoneValidOrEmpty =
isMobilePhone(phone_input_value) || phone_input_value === "";
isMobilePhone(
phone_input_value
.replaceAll("(", "")
.replaceAll(")", "")
.replaceAll("-", "")
.replaceAll(" ", "")
) || phone_input_value === "";
$: isEmailValidOrEmpty =
isEmail(email_input_value) || email_input_value === "";
$: isLastnameValid = lastname_input_value.trim().length !== 0;
@@ -213,7 +219,7 @@
<select
name="team"
bind:value={selected_team}
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2">
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2">
{#each groups as g}
<option value={g.id}>{g.name}</option>
{/each}

View File

@@ -147,7 +147,7 @@
class="block text-sm font-medium text-gray-700">{$_('organization')}</label>
<select
bind:value={parentGroup}
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2">
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2">
{#each orgs as t}
<option value={t.id}>{t.name}</option>
{/each}

View File

@@ -30,7 +30,7 @@
<Table />
</div>
<div
class="widget w-full p-4 mb-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
class="widget w-full p-4 mb-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">Regular</div>

View File

@@ -1,4 +1,4 @@
<div class="w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">Conversions</div>
@@ -18,16 +18,16 @@
<div class="flex flex-col w-full">
<ul class="list-none">
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">Today</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This week</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This month</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This year</a></li>
</ul>
</div>

View File

@@ -323,7 +323,7 @@
</li>
</ul>
</div>
<div class="main w-full bg-grey-50 text-grey-900 dark:bg-grey-900 dark:text-white">
<div class="main w-full bg-grey-50 text-grey-900">
<div class="navbar navbar-1 border-b">
<div class="navbar-inner w-full flex items-center justify-start"><button class="mx-4"><svg stroke="currentColor"
fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" size="20"
@@ -733,7 +733,7 @@
<div class="flex flex-col lg:flex-row w-full lg:space-x-2 space-y-2 lg:space-y-0 mb-2 lg:mb-4">
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">Users</div>
@@ -751,7 +751,7 @@
</div>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">Sessions</div>
@@ -766,7 +766,7 @@
</div>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">Bounce rate</div>
@@ -783,7 +783,7 @@
</div>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">Session duration</div>
@@ -803,7 +803,7 @@
<ConversionsChart />
</div>
<div class="w-full lg:w-1/3">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">Sessions</div>
@@ -823,16 +823,16 @@
<div class="flex flex-col w-full">
<ul class="list-none">
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">Today</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This week</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This month</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This year</a></li>
</ul>
</div>
@@ -923,7 +923,7 @@
</div>
</div>
<div class="w-full lg:space-x-2 space-y-2 lg:space-y-0 mb-2 lg:mb-4">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">Users</div>
@@ -1211,15 +1211,15 @@
</table>
<div class="flex flex-row w-full items-center justify-around lg:justify-between my-4">
<div class="flex flex-wrap items-center justify-start space-x-2 pagination"><button
class="btn btn-default bg-transparent hover:bg-grey-200 text-grey-900 dark:text-white">Next</button><button
class="btn btn-default bg-transparent hover:bg-grey-200 text-grey-900 dark:text-white">Last</button>
class="btn btn-default bg-transparent hover:bg-grey-200 text-grey-900">Next</button><button
class="btn btn-default bg-transparent hover:bg-grey-200 text-grey-900">Last</button>
</div><span class="hidden lg:block">Page
<!-- --> <b>1
<!-- --> of
<!-- -->11
</b>
</span><select
class="hidden lg:block form-select text-sm bg-white dark:bg-grey-800 dark:border-grey-800 outline-none shadow-none focus:shadow-none">
class="hidden lg:block form-select text-sm bg-white outline-none shadow-none focus:shadow-none">
<option selected="" value="10">Show 10</option>
<option value="25">Show 25</option>
<option value="50">Show 50</option>
@@ -1232,7 +1232,7 @@
</div>
<div class="flex flex-col lg:flex-row w-full lg:space-x-2 space-y-2 lg:space-y-0 mb-2 lg:mb-4">
<div class="w-full lg:w-1/2">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">Project status</div>
@@ -1252,16 +1252,16 @@
<div class="flex flex-col w-full">
<ul class="list-none">
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">Today</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This week</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This month</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This year</a></li>
</ul>
</div>
@@ -1336,7 +1336,7 @@
</div>
</div>
<div class="w-full lg:w-1/2">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">Sales</div>
@@ -1356,16 +1356,16 @@
<div class="flex flex-col w-full">
<ul class="list-none">
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">Today</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This week</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This month</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This year</a></li>
</ul>
</div>
@@ -1578,7 +1578,7 @@
</div>
<div class="flex flex-col lg:flex-row w-full lg:space-x-2 space-y-2 lg:space-y-0 mb-2 lg:mb-4">
<div class="w-full lg:w-1/3">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">Activities</div>
@@ -1598,16 +1598,16 @@
<div class="flex flex-col w-full">
<ul class="list-none">
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">Today</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This week</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This month</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This year</a></li>
</ul>
</div>
@@ -1619,7 +1619,7 @@
<div class="flex flex-col w-full">
<div class="flex relative justify-start items-start">
<div class="h-full w-6 absolute inset-0 flex items-center justify-center">
<div class="h-full w-1 bg-grey-200 dark:bg-grey-800 pointer-events-none"></div>
<div class="h-full w-1 bg-grey-200 pointer-events-none"></div>
</div>
<div
class="flex-shrink-0 w-6 h-6 rounded-full inline-flex items-center justify-center bg-blue-500 text-white relative z-10 font-medium text-sm">
@@ -1636,7 +1636,7 @@
</div>
<div class="flex relative justify-start items-start">
<div class="h-full w-6 absolute inset-0 flex items-center justify-center">
<div class="h-full w-1 bg-grey-200 dark:bg-grey-800 pointer-events-none"></div>
<div class="h-full w-1 bg-grey-200 pointer-events-none"></div>
</div>
<div
class="flex-shrink-0 w-6 h-6 rounded-full inline-flex items-center justify-center bg-blue-500 text-white relative z-10 font-medium text-sm">
@@ -1653,7 +1653,7 @@
</div>
<div class="flex relative justify-start items-start">
<div class="h-full w-6 absolute inset-0 flex items-center justify-center">
<div class="h-full w-1 bg-grey-200 dark:bg-grey-800 pointer-events-none"></div>
<div class="h-full w-1 bg-grey-200 pointer-events-none"></div>
</div>
<div
class="flex-shrink-0 w-6 h-6 rounded-full inline-flex items-center justify-center bg-blue-500 text-white relative z-10 font-medium text-sm">
@@ -1670,7 +1670,7 @@
</div>
<div class="flex relative justify-start items-start">
<div class="h-full w-6 absolute inset-0 flex items-center justify-center">
<div class="h-full w-1 bg-grey-200 dark:bg-grey-800 pointer-events-none"></div>
<div class="h-full w-1 bg-grey-200 pointer-events-none"></div>
</div>
<div
class="flex-shrink-0 w-6 h-6 rounded-full inline-flex items-center justify-center bg-blue-500 text-white relative z-10 font-medium text-sm">
@@ -1690,7 +1690,7 @@
</div>
</div>
<div class="w-full lg:w-2/3">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
<div class="w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">To do</div>
@@ -1710,16 +1710,16 @@
<div class="flex flex-col w-full">
<ul class="list-none">
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">Today</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This week</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This month</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100"
href="/">This year</a></li>
</ul>
</div>
@@ -1831,7 +1831,7 @@
</div>
<form>
<div class="form-element"><input type="text" value="" name="todo"
class="form-input text-sm bg-white dark:bg-grey-800 dark:border-grey-800"
class="form-input text-sm bg-white"
placeholder="Add new..."></div>
</form>
<div class="flex flex-row items-center justify-between">

View File

@@ -0,0 +1,281 @@
<script>
import csv from "csvtojson";
import { read as readXlsx, utils as xlsx_utils } from "xlsx";
import { _ } from "svelte-i18n";
import { clickOutside } from "./outsideclick";
import { focusTrap } from "svelte-focus-trap";
import Toastify from "toastify-js";
import { ImportService } from "@odit/lfk-client-js";
import { createEventDispatcher } from "svelte";
export let opened_from;
export let passed_orgs;
export let passed_team;
export let import_modal_open;
$: searchvalue = "";
const dispatch = createEventDispatcher();
function cancelModal() {
import_modal_open = false;
dispatch("cancel");
}
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
import_modal_open = false;
}
if (e.keyCode === 13) {
//
}
};
})();
let selected_org;
let files;
let recent_processed = true;
$: json_output = [];
$: {
if (files) {
if (
files[0].type ===
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
) {
const reader = new FileReader();
reader.addEventListener("load", async (e) => {
const data = new Uint8Array(e.target.result);
const out = readXlsx(data, { type: "array" });
json_output = xlsx_utils.sheet_to_json(
out.Sheets[Object.keys(out.Sheets)[0]]
);
});
reader.readAsArrayBuffer(files[0]);
} else {
const reader = new FileReader();
reader.addEventListener("load", async (e) => {
json_output = await csv({
delimiter: [";", ","],
trim: true,
}).fromString(e.target.result);
});
reader.readAsText(files[0]);
}
}
}
function importAction() {
if (recent_processed === true) {
const toast = Toastify({
text: "Runners are being imported...",
duration: -1,
}).showToast();
recent_processed = false;
const mapped = json_output.map(function (runner) {
return {
firstname: runner[`${$_("csv_import__firstname")}`],
middlename: runner[`${$_("csv_import__middlename")}`],
lastname: runner[`${$_("csv_import__lastname")}`],
team:
runner[`${$_("csv_import__team")}`] ||
runner[`${$_("csv_import__class")}`],
};
});
let org = 0;
if (opened_from === "OrgDetail") {
org = passed_org.id;
}
if (opened_from === "OrgOverview") {
org = parseInt(selected_org);
}
if (opened_from === "OrgOverview" || opened_from === "OrgDetail") {
ImportService.importControllerPostOrgsJson(org, mapped)
.then((resp) => {
toast.hideToast();
recent_processed = true;
Toastify({
text: "Import finished",
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
cancelModal();
})
.catch((err) => {
toast.hideToast();
recent_processed = true;
});
}
if (opened_from === "TeamDetail") {
ImportService.importControllerPostTeamsJson(passed_team.id, mapped)
.then((resp) => {
toast.hideToast();
recent_processed = true;
Toastify({
text: "Import finished",
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
cancelModal();
})
.catch((err) => {
toast.hideToast();
recent_processed = true;
});
}
}
}
</script>
{#if import_modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside
on:click_outside={() => {
import_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 overflow-hidden 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 w-full">
<h3 class="text-lg leading-6 font-medium text-gray-900">
Runner Import
</h3>
{#if json_output.length === 0}
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
Please provide the required csv/ xlsx file
</p>
</div>
<div class="overflow-hidden relative mt-4 mb-4">
<input
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
bind:files
type="file" />
</div>
{/if}
{#if json_output.length > 0}
{#if opened_from === 'OrgOverview'}
<p>{$_('import__target-organization')}</p>
<select
name="team"
bind:value={selected_org}
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2">
{#each passed_orgs as o}
<option value={o.id}>{o.name}</option>
{/each}
</select>
<p>Bitte bestätige diese Läufer für den Import</p>
{/if}
{#if opened_from === 'OrgDetail'}
<p>
Bitte bestätige diese Läufer für den Import in die
Organisation "{passed_org.name}"
</p>
{/if}
<input
type="search"
bind:value={searchvalue}
placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')}
class="p-2 w-full" />
<div class="relative w-full mt-4 mb-4">
<table
class="divide-y divide-gray-200 w-full overflow-x-scroll">
<thead class="bg-gray-50">
<tr>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('csv_import__firstname')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('csv_import__middlename')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('csv_import__lastname')}
</th>
{#if opened_from !== 'TeamDetail'}
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('csv_import__team')}
</th>
{/if}
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
{#each json_output as runner}
{#if Object.values(runner)
.toString()
.toLowerCase()
.includes(searchvalue)}
<tr>
<td class="px-6 py-4 whitespace-nowrap">
{runner[`${$_('csv_import__firstname')}`]}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{runner[`${$_('csv_import__middlename')}`] || ''}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{runner[`${$_('csv_import__lastname')}`]}
</td>
{#if opened_from !== 'TeamDetail'}
<td class="px-6 py-4 whitespace-nowrap">
{runner[`${$_('csv_import__team')}`] || runner[`${$_('csv_import__class')}`] || '---'}
</td>
{/if}
</tr>
{/if}
{/each}
</tbody>
</table>
<button
on:click={importAction}
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">
{$_('import-runners')}
</button>
<button
on:click={() => {
json_output = [];
cancelModal();
}}
type="button"
class="w-full inline-flex 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">
{$_('cancel')}
</button>
</div>
{/if}
</div>
</div>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -4,6 +4,7 @@
import Toastify from "toastify-js";
import store from "../store";
import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte";
import ImportRunnerModal from "./ImportRunnerModal.svelte";
import PromiseError from "./PromiseError.svelte";
$: delete_triggered = false;
$: save_enabled = !data_changed;
@@ -64,14 +65,33 @@
} else {
}
}
export let import_modal_open = false;
</script>
<ImportRunnerModal
on:cancelDelete={(event) => {
import_modal_open = false;
}}
passed_orgs={[]}
passed_org={orgdata}
opened_from="OrgDetail"
bind:import_modal_open />
<ConfirmOrgDeletion bind:modal_open bind:delete_org />
{#if data_loaded}
<section class="container p-5">
<div class="mb-8 text-3xl font-extrabold leading-tight">
{original.name}
<span data-id="org_actions_${orgdata.id}">
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')}
<button
on:click={() => {
import_modal_open = true;
}}
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">
{$_('import-runners')}
</button>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')}
{#if delete_triggered}
<button
@@ -181,7 +201,7 @@
type="text"
bind:value={orgdata.name}
name="name"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
@@ -193,7 +213,7 @@
type="text"
bind:value={orgdata.contact}
name="contact"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
@@ -205,7 +225,7 @@
type="text"
bind:value={orgdata.address}
name="address"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
</section>
{:else}

View File

@@ -79,7 +79,7 @@
<div class="flex items-center">
<div class="ml-4">
<div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
class="text-sm font-medium text-gray-900">
{o.name}
</div>
</div>
@@ -89,7 +89,7 @@
<div class="flex items-center">
<div class="ml-4">
<div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
class="text-sm font-medium text-gray-900">
{#if o.address}
{JSON.stringify(o.address)}
{:else}no address specified{/if}
@@ -101,7 +101,7 @@
<div class="flex items-center">
<div class="ml-4">
<div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
class="text-sm font-medium text-gray-900">
{#if o.contact}
{JSON.stringify(o.contact)}
{:else}no contact specified{/if}

View File

@@ -4,8 +4,9 @@
import AddOrgModal from "./AddOrgModal.svelte";
export let modal_open = false;
import OrgOverview from "./OrgOverview.svelte";
console.log(store.state.jwtinfo.userdetails.permissions);
import ImportRunnerModal from "./ImportRunnerModal.svelte";
let current_organizations = [];
export let import_modal_open = false;
</script>
<section class="container p-5">
@@ -21,6 +22,16 @@
{$_('create-organization')}
</button>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')}
<button
on:click={() => {
import_modal_open = true;
}}
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">
{$_('import-runners')}
</button>
{/if}
</span>
<p class="mb-8 text-lg text-gray-500">manage runner organizations</p>
<OrgOverview bind:current_organizations />
@@ -28,4 +39,12 @@
{#if store.state.jwtinfo.userdetails.permissions.includes('ORGANISATION:CREATE')}
<AddOrgModal bind:current_organizations bind:modal_open />
<ImportRunnerModal
on:cancelDelete={(event) => {
import_modal_open = false;
}}
passed_org={{}}
passed_orgs={current_organizations}
opened_from="OrgOverview"
bind:import_modal_open />
{/if}

View File

@@ -8,7 +8,7 @@
</div>
</div>
<div
class="w-full p-4 mb-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
class="w-full p-4 mb-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-start p-4">
<div class="flex-shrink-0 w-24">
<img

View File

@@ -0,0 +1,235 @@
<script>
import { _ } from "svelte-i18n";
import lodashIsEqual from "lodash.isequal";
import store from "../store";
import { RunnerService } from "@odit/lfk-client-js";
import Toastify from "toastify-js";
import PromiseError from "./PromiseError.svelte";
import isEmail from "validator/es/lib/isEmail";
const runner_promise = RunnerService.runnerControllerGetOne(params.runnerid);
let data_loaded = false;
export let params;
$: delete_triggered = false;
$: original_data = {};
$: editable = {};
$: changes_performed = !lodashIsEqual(original_data, editable);
$: isEmailValid =
(editable.email || "") === "" ||
(editable.email && isEmail(editable.email || ""));
$: isFirstnameValid = editable.firstname !== "";
$: isLastnameValid = editable.lastname !== "";
$: save_enabled =
changes_performed && isFirstnameValid && isLastnameValid && isEmailValid;
runner_promise.then((data) => {
data_loaded = true;
original_data = Object.assign(original_data, data);
editable = data;
});
function submit() {
if (data_loaded === true && save_enabled) {
Toastify({
text: "Updating runner...",
duration: 2500,
}).showToast();
editable.group = editable.group.id;
RunnerService.runnerControllerPut(original_data.id, editable)
.then((resp) => {
Object.assign(original_data, editable);
original_data = editable;
Object.assign(original_data, editable);
//
Toastify({
text: "Runner updated!",
duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
})
.catch((err) => {});
} else {
}
}
function deleteRunner() {
RunnerService.runnerControllerRemove(original_data.id, true)
.then((resp) => {
location.replace("./");
})
.catch((err) => {});
}
</script>
{#await runner_promise}
<!-- -->
{:then}
<section class="container p-5 select-none">
<div class="flex flex-row mb-4">
<div class="w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="flex-shrink-0 w-5 h-5 mr-2"
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>
</li>
<li class="flex items-center">
<a class="mr-2" href="./">{$_('runners')}</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
</li>
<li class="flex items-center">
<span class="mr-2">{original_data.firstname}
{original_data.middlename || ''}
{original_data.lastname}</span>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-8 text-3xl font-extrabold leading-tight">
{original_data.firstname}
{original_data.middlename || ''}
{original_data.lastname}
<span data-id="runner_actions_${editable.id}">
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:DELETE')}
{#if delete_triggered}
<button
on:click={deleteRunner}
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">{$_('confirm-deletion')}</button>
<button
on:click={() => {
delete_triggered = !delete_triggered;
}}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button>
{/if}
{#if !delete_triggered}
<button
on:click={() => {
delete_triggered = true;
}}
type="button"
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">{$_('delete-runner')}</button>
{/if}
{/if}
{#if !delete_triggered}
<button
disabled={!save_enabled}
class:opacity-50={!save_enabled}
type="button"
on:click={submit}
class="w-full 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">{$_('save-changes')}</button>
{/if}
</span>
</div>
<!-- -->
<div class="text-sm w-full">
<label
for="firstname"
class="font-medium text-gray-700">{$_('first-name')}</label>
<input
autocomplete="off"
placeholder={$_('first-name')}
type="text"
class:border-red-500={!isFirstnameValid}
class:focus:border-red-500={!isFirstnameValid}
class:focus:ring-red-500={!isFirstnameValid}
bind:value={editable.firstname}
name="firstname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isFirstnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
{$_('first-name-is-required')}
</span>
{/if}
</div>
<div class="text-sm w-full">
<label
for="middlename"
class="font-medium text-gray-700">{$_('middle-name')}</label>
<input
autocomplete="off"
placeholder={$_('middle-name')}
type="text"
bind:value={editable.middlename}
name="middlename"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
for="lastname"
class="font-medium text-gray-700">{$_('last-name')}</label>
<input
autocomplete="off"
placeholder={$_('last-name')}
type="text"
bind:value={editable.lastname}
class:border-red-500={!isLastnameValid}
class:focus:border-red-500={!isLastnameValid}
class:focus:ring-red-500={!isLastnameValid}
name="lastname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isLastnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
{$_('last-name-is-required')}
</span>
{/if}
</div>
<div class="text-sm w-full">
<label
for="email"
class="font-medium text-gray-700">{$_('e-mail-adress')}</label>
<input
autocomplete="off"
placeholder={$_('e-mail-adress')}
type="email"
bind:value={editable.email}
class:border-red-500={!isEmailValid}
class:focus:border-red-500={!isEmailValid}
class:focus:ring-red-500={!isEmailValid}
name="email"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isEmailValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
{$_('valid-email-is-required')}
</span>
{/if}
</div>
<div class="text-sm w-full">
<label for="phone" class="font-medium text-gray-700">{$_('phone')}</label>
<input
autocomplete="off"
placeholder={$_('phone')}
type="tel"
bind:value={editable.phone}
name="phone"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<span class="font-medium text-gray-700">{$_('distance')}</span>
<br />
<span class="text-gray-700">{original_data.distance} km</span>
</div>
</section>
{:catch error}
<PromiseError {error} />
{/await}

View File

@@ -0,0 +1,75 @@
<script>
import "filepond/dist/filepond.css";
import FilePond from "svelte-filepond";
import { _ } from "svelte-i18n";
let pond;
// pond.getFiles() will return the active files
// the name to use for the internal file input
let name = "filepond";
function handleInit() {
// console.log("FilePond has initialised");
}
function handleAddFile(err, fileItem) {
// console.log("A file has been added", fileItem);
}
const labelInvalidField = $_("filepond__field-contains-invalid-files");
const labelFileWaitingForSize = $_("filepond__waiting-for-size");
const labelFileSizeNotAvailable = $_("filepond__size-not-available");
const labelFileLoading = $_("filepond__loading");
const labelFileLoadError = $_("filepond__error-during-load");
const labelFileProcessing = $_("filepond__uploading");
const labelFileProcessingComplete = $_("filepond__upload-complete");
const labelFileProcessingAborted = $_("filepond__upload-cancelled");
const labelFileProcessingError = $_("filepond__error-during-upload");
const labelFileProcessingRevertError = $_("filepond__error-during-revert");
const labelFileRemoveError = $_("filepond__error-during-remove");
const labelTapToCancel = $_("filepond__tap-to-cancel");
const labelTapToRetry = $_("filepond__tap-to-retry");
const labelTapToUndo = $_("filepond__tap-to-undo");
const labelButtonRemoveItem = $_("filepond__remove");
const labelButtonAbortItemLoad = $_("filepond__abort");
const labelButtonRetryItemLoad = $_("filepond__retry");
const labelButtonAbortItemProcessing = $_("filepond__cancel");
const labelButtonUndoItemProcessing = $_("filepond__undo");
const labelButtonRetryItemProcessing = $_("filepond__retry");
const labelButtonProcessItem = $_("filepond__upload");
const labelIdle =
$_("drag-and-drop-your-files-or") +
` <span class="filepond--label-action"> ` +
$_("browse") +
` </span>`;
</script>
<div class="col-span-6">
<FilePond
class="col-span-6"
bind:this={pond}
{name}
{labelFileWaitingForSize}
{labelFileSizeNotAvailable}
{labelFileLoading}
{labelFileLoadError}
{labelFileProcessing}
{labelFileProcessingComplete}
{labelFileProcessingAborted}
{labelFileProcessingError}
{labelFileProcessingRevertError}
{labelFileRemoveError}
{labelTapToCancel}
{labelTapToRetry}
{labelTapToUndo}
{labelButtonRemoveItem}
{labelButtonAbortItemLoad}
{labelButtonRetryItemLoad}
{labelButtonAbortItemProcessing}
{labelButtonUndoItemProcessing}
{labelButtonRetryItemProcessing}
{labelButtonProcessItem}
{labelIdle}
{labelInvalidField}
server="/api"
allowMultiple={false}
credits={false}
oninit={handleInit}
onaddfile={handleAddFile} />
</div>

View File

@@ -2,15 +2,17 @@
import { _ } from "svelte-i18n";
import store from "../store";
import AddRunnerModal from "./AddRunnerModal.svelte";
// import ImportRunnerModal from "./ImportRunnerModal.svelte";
import RunnersOverview from "./RunnersOverview.svelte";
export let modal_open = false;
// export let import_modal_open = false;
let current_runners = [];
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('runners')}
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')}
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:CREATE')}
<button
on:click={() => {
modal_open = true;
@@ -19,12 +21,21 @@
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">
Läufer hinzufügen
</button>
<!-- <button
on:click={() => {
import_modal_open = true;
}}
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">
Läufer importieren
</button> -->
{/if}
</span>
<p class="mb-8 text-lg text-gray-500">läuft bei ihnen</p>
<RunnersOverview bind:current_runners />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')}
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:CREATE')}
<AddRunnerModal bind:current_runners bind:modal_open />
<!-- <ImportRunnerModal bind:import_modal_open /> -->
{/if}

View File

@@ -70,7 +70,7 @@
<div class="flex items-center">
<div class="ml-4">
<div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
class="text-sm font-medium text-gray-900">
{runner.firstname}
{runner.middlename || ''}
{runner.lastname}

View File

@@ -18,7 +18,7 @@
class="flex flex-col lg:flex-row w-full lg:space-x-2 space-y-2 lg:space-y-0 mb-2 lg:mb-4">
<a href="/runners/" class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
@@ -39,7 +39,7 @@
</a>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
@@ -64,7 +64,7 @@
</div>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
@@ -83,7 +83,7 @@
</div>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
@@ -106,7 +106,7 @@
</div>
<a href="/teams/" class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
@@ -135,7 +135,7 @@
</a>
<a href="/orgs/" class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
class="widget w-full p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">

View File

@@ -6,6 +6,7 @@
import { _ } from "svelte-i18n";
import Toastify from "toastify-js";
import store from "../store";
import ImportRunnerModal from "./ImportRunnerModal.svelte";
import PromiseError from "./PromiseError.svelte";
import ConfirmTeamDeletion from "./ConfirmTeamDeletion.svelte";
export let params;
@@ -16,6 +17,7 @@
[],
false,
];
export let import_modal_open = false;
$: delete_triggered = false;
$: save_enabled = !data_changed;
$: data_loaded = false;
@@ -71,12 +73,31 @@
}
</script>
<ImportRunnerModal
on:cancelDelete={(event) => {
import_modal_open = false;
}}
passed_team={teamdata}
passed_orgs={[]}
passed_org={{}}
opened_from="TeamDetail"
bind:import_modal_open />
<ConfirmTeamDeletion bind:modal_open bind:delete_team />
{#if data_loaded}
<section class="container p-5">
<div class="mb-8 text-3xl font-extrabold leading-tight">
{original.name}
<span data-id="org_actions_${teamdata.id}">
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')}
<button
on:click={() => {
import_modal_open = true;
}}
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">
{$_('import-runners')}
</button>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:DELETE')}
{#if delete_triggered}
<button
@@ -188,7 +209,7 @@
type="text"
bind:value={teamdata.name}
name="name"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
@@ -200,14 +221,14 @@
type="text"
bind:value={teamdata.contact}
name="contact"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label for="org" class="font-medium text-gray-700">Parent Organization</label>
<select
name="org"
bind:value={teamdata.parentGroup}
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2">
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2">
{#each orgs as o}
<option value={o.id}>{o.name}</option>
{/each}

View File

@@ -81,7 +81,7 @@
<div class="flex items-center">
<div class="ml-4">
<div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
class="text-sm font-medium text-gray-900">
{t.name}
</div>
</div>
@@ -91,7 +91,7 @@
<div class="flex items-center">
<div class="ml-4">
<div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
class="text-sm font-medium text-gray-900">
{#if t.parentGroup}
{t.parentGroup.name}
{:else}no organization specified{/if}
@@ -103,7 +103,7 @@
<div class="flex items-center">
<div class="ml-4">
<div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
class="text-sm font-medium text-gray-900">
{#if t.contact}
{JSON.stringify(t.contact)}
{:else}no contact specified{/if}

View File

@@ -206,7 +206,7 @@
type="text"
bind:value={editable_userdata.firstname}
name="firstname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
@@ -218,7 +218,7 @@
type="text"
bind:value={editable_userdata.middlename}
name="middlename"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
@@ -230,7 +230,7 @@
type="text"
bind:value={editable_userdata.lastname}
name="lastname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
@@ -242,7 +242,7 @@
type="email"
bind:value={editable_userdata.email}
name="email"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
@@ -254,14 +254,14 @@
type="text"
bind:value={editable_userdata.username}
name="username"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<span class="font-medium">{$_('groups')}</span>
<!-- svelte-ignore a11y-no-onchange -->
<select
bind:value={usergroups_array}
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2"
multiple>
{#each allgroups as g}
{#if usergroups_array.includes(g.id)}
@@ -291,7 +291,7 @@
{#each allpermissions as p}
{#if !editable_userdata.permissions.includes(p)}
<p
class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input">
class="block w-full mt-1 text-sm bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple form-input">
{p}
<button
on:click={() => {
@@ -311,7 +311,7 @@
{#each allpermissions as p}
{#if editable_userdata.permissions.includes(p)}
<p
class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input">
class="block w-full mt-1 text-sm bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple form-input">
{p}
<button
on:click={() => {

View File

@@ -93,7 +93,7 @@
{/if}
<div class="ml-4">
<div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
class="text-sm font-medium text-gray-900">
{u.firstname}
{u.middlename || ''}
{u.lastname}

View File

@@ -4,8 +4,11 @@
"about": "Über",
"application_name": "Lauf für Kaya! \n- Admin",
"by": "von",
"cancel": "Abbrechen",
"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.",
"credits": "",
"csv_import__firstname": "Vorname",
"csv_import__middlename": "Mittelname",
"dashboard-greeting": "Moin",
"datatable": {
"search": "🔍 Suche ...",
@@ -27,6 +30,7 @@
"goback": "Zur Startseite",
"hallo": "hallo",
"icon-image-credits": "Wir möchten uns außerdem für die verwendeten Icons und Bilder bedanken bei:",
"import-runners": "Läufer importieren",
"invalid-mail-reset": "Das ist keine gültige E-Mail",
"lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.",
"log_in": "Anmelden",

View File

@@ -14,6 +14,7 @@
"changelog": "Changelog",
"close": "Close",
"confirm-delete": "Confirm Delete",
"confirm-deletion": "Confirm Deletion",
"contact": "Contact",
"count_organizations": "# Organizations",
"count_teams": "# Teams",
@@ -22,6 +23,11 @@
"create-organization": "Create Organization",
"create-user": "Create User",
"credits": "Credits",
"csv_import__class": "Klasse",
"csv_import__firstname": "First Name",
"csv_import__lastname": "Nachname",
"csv_import__middlename": "Middlename",
"csv_import__team": "Team",
"dashboard-greeting": "hello there",
"dashboard-title": "Dashboard",
"datatable": {
@@ -40,9 +46,11 @@
"an_error_happened_while_fetching_the_data": "An error happened while fetching the data"
},
"delete-organization": "Delete Organization",
"delete-runner": "Delete Runner",
"delete-team": "Delete Team",
"delete-user": "Delete User",
"dependency_name": "Name",
"distance": "Distance",
"dont-have-your-email-connected": "Don't have your email connected?",
"dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌",
"drag-and-drop-your-files-or": "Drag & Drop your files or",
@@ -79,6 +87,8 @@
"groups": "Groups",
"hallo": "hello",
"icon-image-credits": "We also want to thank these projects for illustrations and icons:",
"import-runners": "Import runners",
"import__target-organization": "Target Organization",
"installed-version": "Installed version",
"invalid-mail-reset": "the provided email is invalid",
"last-name": "Last name",
@@ -102,6 +112,7 @@
"oss_credit_description": "We use a lot of open source software on these projects, and would like to thank the following projects and contributors who help make open source great!",
"password": "Password",
"password-is-required": "Password is required",
"phone": "Phone",
"please-provide-the-required-information-to-add-a-new-track": "Please provide the required information to add a new track.",
"profile-picture": "Profile Picture",
"read-license": "Read License",

View File

@@ -1 +0,0 @@
// this is configured with dev scripts

View File

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