Compare commits
69 Commits
0.16.5
...
845737ee8e
| Author | SHA1 | Date | |
|---|---|---|---|
|
845737ee8e
|
|||
|
6993511c67
|
|||
|
9111ad147c
|
|||
|
333214aa8f
|
|||
|
c0cde02fec
|
|||
|
070a20a2e5
|
|||
|
c5e8409079
|
|||
|
67eff0eda9
|
|||
|
3de7b632e0
|
|||
|
842248e4c4
|
|||
|
c5d7ec25b5
|
|||
|
a9a965d698
|
|||
|
dc866dd540
|
|||
|
89252619b1
|
|||
|
2699b06d7c
|
|||
|
fd0d45f721
|
|||
|
5ecf838dd2
|
|||
|
45a7a90cb8
|
|||
|
cac851f2b1
|
|||
|
238082b657
|
|||
|
aecbabe522
|
|||
|
a9cdac4f74
|
|||
|
a59dbbe50e
|
|||
|
9bec95ede8
|
|||
|
70307a9e82
|
|||
|
ef077b4e6a
|
|||
|
dcabed4e93
|
|||
|
1af047f66e
|
|||
|
ee91748b3c
|
|||
|
e5241d619b
|
|||
|
d79608edbb
|
|||
|
4cbd26580e
|
|||
|
fe62ad5539
|
|||
|
eb13f038a1
|
|||
| 9505c2b030 | |||
| 008835c24f | |||
| 7083b3d8d2 | |||
| 754931b2f6 | |||
| 2dc8ffba32 | |||
| d0fe6a2e85 | |||
| 85705b6e68 | |||
| 3ea7a015a9 | |||
| 44329413ed | |||
| 46db68ab22 | |||
| dc9d7f22a2 | |||
| f917018fd9 | |||
| 7b420c430d | |||
| 00359d25c1 | |||
| d8a3063735 | |||
|
6491af19e3
|
|||
| 61328d20ed | |||
|
0a6d92a1f3
|
|||
|
3a576d1073
|
|||
|
b30b98b521
|
|||
|
43d82a2af0
|
|||
| 6a4495b813 | |||
|
e8a0ad6647
|
|||
|
92b89cc4d8
|
|||
|
268b1b1d98
|
|||
|
75bc89ca30
|
|||
| 0625937068 | |||
|
32a9074963
|
|||
|
b869b5fd2a
|
|||
| 3a3e2f7157 | |||
| bea57aa03a | |||
| 30991d5364 | |||
| 5cc8b0811c | |||
| 2c73b9862d | |||
| 732b2f061e |
@@ -1 +1,2 @@
|
||||
public/env.sample.js
|
||||
.pnpm-store
|
||||
29
.drone.yml
29
.drone.yml
@@ -19,6 +19,13 @@ get:
|
||||
path: odit-git-bot
|
||||
name: sshkey
|
||||
|
||||
---
|
||||
kind: secret
|
||||
name: npm_url
|
||||
get:
|
||||
path: odit-npm-cache
|
||||
name: url
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: kubernetes
|
||||
@@ -27,10 +34,14 @@ name: build:dev
|
||||
steps:
|
||||
- name: run full license export
|
||||
depends_on: ["clone"]
|
||||
image: registry.odit.services/hub/library/node:alpine
|
||||
image: registry.odit.services/hub/library/node:19.7.0-alpine3.16
|
||||
commands:
|
||||
- yarn
|
||||
- yarn licenses:export
|
||||
- npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8
|
||||
- pnpm i
|
||||
- pnpm licenses:export
|
||||
environment:
|
||||
NPM_REGISTRY_URL:
|
||||
from_secret: npm_url
|
||||
- name: push new licenses file to repo
|
||||
depends_on: ["run full license export"]
|
||||
image: appleboy/drone-git-push
|
||||
@@ -51,10 +62,8 @@ steps:
|
||||
password:
|
||||
from_secret: docker_password
|
||||
build_args:
|
||||
- NPM_REGISTRY_DOMAIN:
|
||||
from_secret: npmjs_domain
|
||||
- NPM_REGISTRY_TOKEN:
|
||||
from_secret: npmjs_token
|
||||
- NPM_REGISTRY_URL:
|
||||
from_secret: npm_url
|
||||
repo: lfk/frontend
|
||||
tags:
|
||||
- dev
|
||||
@@ -80,10 +89,8 @@ steps:
|
||||
password:
|
||||
from_secret: docker_password
|
||||
build_args:
|
||||
- NPM_REGISTRY_DOMAIN:
|
||||
from_secret: npmjs_domain
|
||||
- NPM_REGISTRY_TOKEN:
|
||||
from_secret: npmjs_token
|
||||
- NPM_REGISTRY_URL:
|
||||
from_secret: npm_url
|
||||
repo: lfk/frontend
|
||||
tags:
|
||||
- "${DRONE_TAG}"
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,11 +1,6 @@
|
||||
node_modules
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
*.map
|
||||
public/env.js
|
||||
public/index.html
|
||||
/dist
|
||||
.yarn
|
||||
.pnp.js
|
||||
.yarnrc.yml
|
||||
pnpm-lock.yaml
|
||||
.pnpm-store
|
||||
48
CHANGELOG.md
48
CHANGELOG.md
@@ -2,8 +2,56 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
||||
|
||||
#### [0.17.3](https://git.odit.services/lfk/frontend/compare/0.17.2...0.17.3)
|
||||
|
||||
- dependency fixes [`3ea7a01`](https://git.odit.services/lfk/frontend/commit/3ea7a015a9beba3c2e4d3eb966f24ff6d4ac786e)
|
||||
- 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)
|
||||
|
||||
> 15 March 2023
|
||||
|
||||
- new license file version [CI SKIP] [`00359d2`](https://git.odit.services/lfk/frontend/commit/00359d25c1bd3efdd6365bf284b3c07634049399)
|
||||
- 🚀RELEASE v0.17.2 [`46db68a`](https://git.odit.services/lfk/frontend/commit/46db68ab229dc740dfff8835ef916f2c2e629b27)
|
||||
- improved ThFilterGroup style [`f917018`](https://git.odit.services/lfk/frontend/commit/f917018fd92a8a5b034f735ac8b6e41995044317)
|
||||
|
||||
#### [0.17.1](https://git.odit.services/lfk/frontend/compare/0.17.0...0.17.1)
|
||||
|
||||
> 15 March 2023
|
||||
|
||||
- Revert "package dependency fixes, bumps, lockfile update" [`d8a3063`](https://git.odit.services/lfk/frontend/commit/d8a30637351e164599e07a6473d9a1d2b08d245d)
|
||||
- 🚀RELEASE v0.17.1 [`7b420c4`](https://git.odit.services/lfk/frontend/commit/7b420c430d27bf0fc85a4297780164a593fc1be3)
|
||||
|
||||
#### [0.17.0](https://git.odit.services/lfk/frontend/compare/0.16.5...0.17.0)
|
||||
|
||||
> 15 March 2023
|
||||
|
||||
- new license file version [CI SKIP] [`61328d2`](https://git.odit.services/lfk/frontend/commit/61328d20ed2cfd1df7d3c32767f9c64154879d6d)
|
||||
- wip: pnpm + node version [`732b2f0`](https://git.odit.services/lfk/frontend/commit/732b2f061e465bd08cf34c58d8cd6b021ba25dce)
|
||||
- package dependency fixes, bumps, lockfile update [`2c73b98`](https://git.odit.services/lfk/frontend/commit/2c73b9862d401dac15021eed3f7847d46132a8ed)
|
||||
- Fixed runners not showing up [`75bc89c`](https://git.odit.services/lfk/frontend/commit/75bc89ca3020c48f490c7602374616bd9461e78f)
|
||||
- add ThFilterRunner [`3a3e2f7`](https://git.odit.services/lfk/frontend/commit/3a3e2f71575d3a0e39a5e13b05cff932b8683ac9)
|
||||
- fix styling for table filters th border [`bea57aa`](https://git.odit.services/lfk/frontend/commit/bea57aa03acaaaa4b1860b30228dd5d1298317f8)
|
||||
- You can now create cards from runners by searching via #runnerid [`e8a0ad6`](https://git.odit.services/lfk/frontend/commit/e8a0ad6647ab39252865f62b755f27c34ac2d243)
|
||||
- remodelled for early return [`b869b5f`](https://git.odit.services/lfk/frontend/commit/b869b5fd2a01955fb21f936fa38eb5a9648e7de3)
|
||||
- 🚀RELEASE v0.17.0 [`6491af1`](https://git.odit.services/lfk/frontend/commit/6491af19e375cbeba7ddd94e463b4dfe308a70a8)
|
||||
- Wow this api is fun [`32a9074`](https://git.odit.services/lfk/frontend/commit/32a9074963cce3328f14b1f981ddd5ee49df0008)
|
||||
- Fixed double space in label [`92b89cc`](https://git.odit.services/lfk/frontend/commit/92b89cc4d88c9d5625c2ddf7c81c98494f7f5271)
|
||||
- UsersOverview: drop pfp [`30991d5`](https://git.odit.services/lfk/frontend/commit/30991d5364a09d517b2115a7e9ea3fbf1fe2e57d)
|
||||
- Switched license generation to cache registry and pnpm [`0a6d92a`](https://git.odit.services/lfk/frontend/commit/0a6d92a1f3c5562f11562c433b3a04e3eaae3da4)
|
||||
- Pinned pnpm in dockerfile, thx @philipp [`3a576d1`](https://git.odit.services/lfk/frontend/commit/3a576d1073ee503b68100e01054a1756bab62805)
|
||||
- Pinned ci node version [`b30b98b`](https://git.odit.services/lfk/frontend/commit/b30b98b521eda2bc7fc055097546f716e90d92ef)
|
||||
- Fixed pnpm being called without being installed [`43d82a2`](https://git.odit.services/lfk/frontend/commit/43d82a2af04af49c2169f78a0d0f27ef7e4d7558)
|
||||
- Merge pull request 'bugfix/162-create_card_modal' (#163) from bugfix/162-create_card_modal into dev [`6a4495b`](https://git.odit.services/lfk/frontend/commit/6a4495b8131a31cd48a608c2275e80494d0a0fb4)
|
||||
- Removed unused log [`268b1b1`](https://git.odit.services/lfk/frontend/commit/268b1b1d9830de196d1d95345d7a2467bbf19eb6)
|
||||
- Merge pull request 'filter by runner full names + "#<ID>"' (#160) from feature/159-cardsoverview-filter-for-runner-full-names-and-id into dev [`0625937`](https://git.odit.services/lfk/frontend/commit/0625937068f0786078ffd29b9c8bb54949350b6c)
|
||||
- UsersOverview: change profilepic scaling [`5cc8b08`](https://git.odit.services/lfk/frontend/commit/5cc8b0811cf290f97a4399b23c5ea4d961a5a91c)
|
||||
|
||||
#### [0.16.5](https://git.odit.services/lfk/frontend/compare/0.16.4...0.16.5)
|
||||
|
||||
> 14 March 2023
|
||||
|
||||
- 🚀RELEASE v0.16.5 [`3680533`](https://git.odit.services/lfk/frontend/commit/3680533eefef042fc77246dd3d374aafe10c428f)
|
||||
- new license file version [CI SKIP] [`405dfa0`](https://git.odit.services/lfk/frontend/commit/405dfa0c34ba87fc450c22e0e9974f92c4cdeffe)
|
||||
|
||||
#### [0.16.4](https://git.odit.services/lfk/frontend/compare/0.16.3...0.16.4)
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@@ -1,11 +1,14 @@
|
||||
FROM registry.odit.services/hub/library/node:19.5.0-alpine3.16 as build
|
||||
FROM registry.odit.services/hub/library/node:19.7.0-alpine3.16 as build
|
||||
ARG NPM_REGISTRY_URL=https://registry.npmjs.org
|
||||
WORKDIR /app
|
||||
COPY package.json ./
|
||||
RUN npx pnpm i
|
||||
COPY package.json *.config.js postcss.config.cjs tailwind.config.js vite.config.js index.html ./
|
||||
|
||||
COPY package.json pnpm-lock.yaml *.config.js *.config.cjs index.html ./
|
||||
RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8 && pnpm i
|
||||
|
||||
COPY src ./src
|
||||
COPY public ./public
|
||||
RUN yarn build
|
||||
RUN pnpm build
|
||||
|
||||
# final image
|
||||
FROM registry.odit.services/library/nginx-brotli:3.15 as final
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.16.5-RELEASE_INFO</span>
|
||||
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.17.3-RELEASE_INFO</span>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<script src="/env.js"></script>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
|
||||
56
package.json
56
package.json
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "@odit/lfk-frontend",
|
||||
"version": "0.16.5",
|
||||
"version": "0.17.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"i18n-order": "node order.js",
|
||||
"dev": "vite",
|
||||
@@ -10,32 +11,17 @@
|
||||
},
|
||||
"license": "CC-BY-NC-SA-4.0",
|
||||
"devDependencies": {
|
||||
"@odit/lfk-client-js": "0.13.1",
|
||||
"@odit/license-exporter": "0.0.11",
|
||||
"@sveltejs/vite-plugin-svelte": "1.0.0-next.6",
|
||||
"@types/html-minifier": "4.0.0",
|
||||
"@vincjo/datatables": "^1.1.0",
|
||||
"auto-changelog": "2.2.1",
|
||||
"autoprefixer": "10.2.5",
|
||||
"check-password-strength": "2.0.2",
|
||||
"csvtojson": "2.0.10",
|
||||
"gridjs": "3.4.0",
|
||||
"@odit/license-exporter": "0.0.12",
|
||||
"@sveltejs/vite-plugin-svelte": "2.0.4",
|
||||
"@types/html-minifier": "4.0.2",
|
||||
"auto-changelog": "2.4.0",
|
||||
"autoprefixer": "10.4.14",
|
||||
"html-minifier": "4.0.0",
|
||||
"localforage": "1.9.0",
|
||||
"marked": "2.0.3",
|
||||
"postcss": "8.2.10",
|
||||
"release-it": "14.6.1",
|
||||
"svelte": "3.37.0",
|
||||
"svelte-focus-trap": "1.2.0",
|
||||
"svelte-i18n": "3.3.9",
|
||||
"svelte-preprocess": "4.7.0",
|
||||
"postcss": "8.4.21",
|
||||
"release-it": "15.10.1",
|
||||
"svelte-select": "3.17.0",
|
||||
"tailwindcss": "3.2.7",
|
||||
"tinro": "0.6.1",
|
||||
"toastify-js": "1.10.0",
|
||||
"validator": "13.5.2",
|
||||
"vite": "2.1.5",
|
||||
"xlsx": "0.16.9"
|
||||
"tailwindcss": "3.3.1",
|
||||
"vite": "4.2.1"
|
||||
},
|
||||
"release-it": {
|
||||
"git": {
|
||||
@@ -55,6 +41,24 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@paralleldrive/cuid2": "^2.2.0"
|
||||
"@odit/lfk-client-js": "0.14.3",
|
||||
"@paralleldrive/cuid2": "^2.2.0",
|
||||
"@tanstack/svelte-table": "^8.8.5",
|
||||
"@tanstack/table-core": "^8.8.5",
|
||||
"@vincjo/datatables": "^1.5.2",
|
||||
"check-password-strength": "2.0.7",
|
||||
"csvtojson": "2.0.10",
|
||||
"gridjs": "3.4.0",
|
||||
"localforage": "1.10.0",
|
||||
"marked": "2.0.3",
|
||||
"svelte": "3.58.0",
|
||||
"svelte-i18n": "3.6.0",
|
||||
"tinro": "0.6.12",
|
||||
"toastify-js": "1.12.0",
|
||||
"validator": "13.9.0",
|
||||
"xlsx": "0.18.5"
|
||||
},
|
||||
"volta": {
|
||||
"node": "19.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
4047
pnpm-lock.yaml
generated
Normal file
4047
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { RunnerCardService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
export let bulk_modal_open;
|
||||
@@ -133,7 +133,7 @@
|
||||
{#if bulk_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
bulk_modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import {
|
||||
RunnerCardService,
|
||||
RunnerService,
|
||||
@@ -11,22 +11,37 @@
|
||||
import Toastify from "toastify-js";
|
||||
export let modal_open;
|
||||
export let current_cards;
|
||||
const getRunnerLabel = (option) =>
|
||||
option.firstname + " " + (option.middlename || "") + " " + option.lastname;
|
||||
const filterRunners = (label, filterText, option) =>
|
||||
|
||||
const getRunnerLabel = (option) => {
|
||||
if (option.middlename) {
|
||||
return option.firstname + " " + option.middlename + " " + option.lastname;
|
||||
}
|
||||
return option.firstname + " " + option.lastname;
|
||||
};
|
||||
|
||||
const filterRunners = (label, filterText, option) => {
|
||||
if (filterText.startsWith("#")) {
|
||||
return option.value.id == parseInt(filterText.replace("#",""))
|
||||
}
|
||||
return (
|
||||
label.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
option.value.toString().startsWith(filterText.toLowerCase());
|
||||
option.value.toString().startsWith(filterText.toLowerCase())
|
||||
);
|
||||
};
|
||||
function focus(el) {
|
||||
el.focus();
|
||||
}
|
||||
$: runner = 0;
|
||||
$: runners = [];
|
||||
$: enabled = true;
|
||||
$: processed_last_submit = true;
|
||||
|
||||
let loading = true;
|
||||
let runners = [];
|
||||
RunnerService.runnerControllerGetAll().then((val) => {
|
||||
runners = val.map((r) => {
|
||||
return { label: getRunnerLabel(r), value: r };
|
||||
});
|
||||
loading = false;
|
||||
});
|
||||
$: createbtnenabled = true;
|
||||
(() => {
|
||||
@@ -82,65 +97,82 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
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">
|
||||
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" />
|
||||
data-id="modal_backdrop"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span>
|
||||
aria-hidden="true">​</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">
|
||||
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">
|
||||
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" />
|
||||
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>
|
||||
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">
|
||||
{$_('create-a-new-card')}
|
||||
{$_("create-a-new-card")}
|
||||
</h3>
|
||||
<div class="mt-2 mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_('you-can-provide-a-runner-but-you-dont-have-to')}
|
||||
{$_('if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button')}
|
||||
{$_("you-can-provide-a-runner-but-you-dont-have-to")}
|
||||
{$_(
|
||||
"if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-6 gap-6">
|
||||
<div class="col-span-6">
|
||||
<label
|
||||
for="donor"
|
||||
class="block text-sm font-medium text-gray-700">{$_('runner')}</label>
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>{$_("runner")}</label
|
||||
>
|
||||
<Select
|
||||
containerClasses="rounded-l-md 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"
|
||||
itemFilter={(label, filterText, option) => filterRunners(label, filterText, option)}
|
||||
itemFilter={(label, filterText, option) =>
|
||||
filterRunners(label, filterText, option)}
|
||||
items={runners}
|
||||
showChevron={true}
|
||||
placeholder={$_('search-for-runner-by-name-or-id')}
|
||||
noOptionsMessage={$_('no-runners-found')}
|
||||
on:select={(selectedValue) => (runner = selectedValue.detail.value.id)}
|
||||
on:clear={() => (runner = null)} />
|
||||
bind:loading
|
||||
showChevron={!loading}
|
||||
placeholder={$_("search-for-runner-by-name-or-id")}
|
||||
noOptionsMessage={$_("no-runners-found")}
|
||||
on:select={(selectedValue) =>
|
||||
(runner = selectedValue.detail.value.id)}
|
||||
on:clear={() => (runner = null)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -152,16 +184,18 @@
|
||||
class:opacity-50={!createbtnenabled}
|
||||
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">
|
||||
{$_('create')}
|
||||
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")}
|
||||
</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')}
|
||||
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>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { RunnerCardService, RunnerService } from "@odit/lfk-client-js";
|
||||
import Select from "svelte-select";
|
||||
import Toastify from "toastify-js";
|
||||
@@ -13,9 +13,16 @@
|
||||
export let original_data = {};
|
||||
const getRunnerLabel = (option) =>
|
||||
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()) ||
|
||||
option.value.toString().startsWith(filterText.toLowerCase());
|
||||
option.value.toString().startsWith(filterText.toLowerCase())
|
||||
);
|
||||
};
|
||||
|
||||
function focus(el) {
|
||||
el.focus();
|
||||
}
|
||||
@@ -87,7 +94,7 @@
|
||||
{#if edit_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
edit_modal_open = false;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import CardDetailModal from "./CardDetailModal.svelte";
|
||||
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
|
||||
import ThFilterStatus from "./ThFilterStatus.svelte";
|
||||
import ThFilterRunner from "./ThFilterRunner.svelte";
|
||||
export let edit_modal_open = false;
|
||||
export let runner = {};
|
||||
export let editable = {};
|
||||
@@ -54,7 +55,7 @@
|
||||
bind:runner
|
||||
bind:editable
|
||||
bind:original_data
|
||||
on:dataUpdated={(handler.setRows(current_cards))}
|
||||
on:dataUpdated={handler.setRows(current_cards)}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -71,14 +72,53 @@
|
||||
{#if current_cards.length === 0}
|
||||
<CardsEmptyState />
|
||||
{:else}
|
||||
<div class="h-12">
|
||||
<div class="h-12 mt-1">
|
||||
{#if cards_show}
|
||||
<button
|
||||
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 inline-flex"
|
||||
id="options-menu"
|
||||
on:click={async () => {
|
||||
const prom = [];
|
||||
for (const card of generate_cards) {
|
||||
prom.push(
|
||||
RunnerCardService.runnerCardControllerRemove(card.id, true)
|
||||
);
|
||||
}
|
||||
await Promise.all(prom);
|
||||
Toastify({
|
||||
text: $_("cards-deleted"),
|
||||
duration: 3500,
|
||||
backgroundColor:
|
||||
"linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
//TODO: Delete cards from table
|
||||
}}
|
||||
>
|
||||
{$_("delete-cards")}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-5 h-5"
|
||||
>
|
||||
<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}
|
||||
<GenerateRunnerCards bind:cards_show bind:generate_cards />
|
||||
</div>
|
||||
<Datatable {handler}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<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"
|
||||
@@ -95,14 +135,14 @@
|
||||
<Th {handler} orderBy="code">{$_("code")}</Th>
|
||||
<Th {handler} orderBy="runner">{$_("runner")}</Th>
|
||||
<Th {handler} orderBy="status">{$_("status")}</Th>
|
||||
<th>{$_("action")}</th>
|
||||
<th style="border-bottom: 1px solid #ddd;">{$_("action")}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th />
|
||||
<th style="border-bottom: 1px solid #ddd;" />
|
||||
<ThFilter {handler} filterBy="code" />
|
||||
<ThFilter {handler} filterBy="runner" />
|
||||
<ThFilterRunner {handler} />
|
||||
<ThFilterStatus {handler} />
|
||||
<th />
|
||||
<th style="border-bottom: 1px solid #ddd;" />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
57
src/components/cards/ThFilterRunner.svelte
Normal file
57
src/components/cards/ThFilterRunner.svelte
Normal file
@@ -0,0 +1,57 @@
|
||||
<script>
|
||||
export let handler;
|
||||
let filterValue = "";
|
||||
</script>
|
||||
|
||||
<th>
|
||||
<input
|
||||
on:input={() => {
|
||||
setTimeout(() => {
|
||||
const v = filterValue.toLowerCase();
|
||||
handler.filter(v, (c) => {
|
||||
// if (v === "") {
|
||||
// return c;
|
||||
// }
|
||||
|
||||
if (!c.runner && v === "blanko") {
|
||||
return "blanko";
|
||||
}
|
||||
|
||||
if (v.startsWith("#")) {
|
||||
return `#${c.runner?.id}`;
|
||||
}
|
||||
if (c.runner) {
|
||||
let runnerName = `${c.runner.firstname} ${c.runner.lastname}`;
|
||||
if (c.runner.middlename) {
|
||||
runnerName = `${c.runner.firstname} ${c.runner.middlename} ${c.runner.lastname}`;
|
||||
}
|
||||
runnerName = runnerName.toLowerCase();
|
||||
return runnerName;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
}, 150);
|
||||
}}
|
||||
bind:value={filterValue}
|
||||
type="text"
|
||||
name="runnerfilter"
|
||||
id="runnerfilter"
|
||||
/>
|
||||
</th>
|
||||
|
||||
<style>
|
||||
th {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
input {
|
||||
margin: -1px 0 0 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
border: none;
|
||||
text-align: left;
|
||||
background: inherit;
|
||||
outline: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
@@ -10,10 +10,9 @@
|
||||
setTimeout(() => {
|
||||
if (`${selected}`.trim()) {
|
||||
if (selected === "all") {
|
||||
handler.filter('', 'enabled')
|
||||
}
|
||||
else{
|
||||
handler.filter(selected, 'enabled')
|
||||
handler.filter("", "enabled");
|
||||
} else {
|
||||
handler.filter(selected, "enabled");
|
||||
}
|
||||
}
|
||||
}, 50);
|
||||
@@ -22,8 +21,25 @@
|
||||
name="statusfilter"
|
||||
id="statusfilter"
|
||||
>
|
||||
<option value="all">{$_('all')}</option>
|
||||
<option value="all">{$_("all")}</option>
|
||||
<option value="true">{$_("enabled")}</option>
|
||||
<option value="false">{$_("disabled")}</option>
|
||||
</select>
|
||||
</th>
|
||||
|
||||
<style>
|
||||
th {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
select {
|
||||
margin: -1px 0 0 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
border: none;
|
||||
text-align: left;
|
||||
background: inherit;
|
||||
outline: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import {
|
||||
GroupContactService,
|
||||
RunnerTeamService,
|
||||
@@ -145,7 +145,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import {
|
||||
DonationService,
|
||||
DonorService,
|
||||
@@ -156,7 +156,7 @@ import { is_promise } from "svelte/internal";
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { DonationService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
export let payment_modal_open = false;
|
||||
@@ -96,7 +96,7 @@
|
||||
{#if payment_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
payment_modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import {
|
||||
DonorService
|
||||
} from "@odit/lfk-client-js";
|
||||
@@ -134,7 +134,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { DonorService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
@@ -32,7 +32,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={cancelDelete}>
|
||||
<div
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
export let modal_open;
|
||||
(function () {
|
||||
document.onkeydown = function (e) {
|
||||
@@ -25,7 +25,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { _, getLocaleFromNavigator } from "svelte-i18n";
|
||||
import marked from "marked";
|
||||
import Footer from "./Footer.svelte";
|
||||
import * as css from "../base/simple.css";
|
||||
// import * as css from "../base/simple.css?inline";
|
||||
let html = "";
|
||||
async function load() {
|
||||
let md = await fetch("/privacy_" + getLocaleFromNavigator() + ".md");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import Toastify from "toastify-js";
|
||||
import { UserGroupService } from "@odit/lfk-client-js";
|
||||
export let modal_open;
|
||||
@@ -69,7 +69,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { RunnerOrganizationService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
export let modal_open;
|
||||
@@ -89,7 +89,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { RunnerOrganizationService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
@@ -32,7 +32,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={cancelDelete}>
|
||||
<div
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import {
|
||||
RunnerService,
|
||||
RunnerTeamService,
|
||||
@@ -125,7 +125,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { read as readXlsx, utils as xlsx_utils } from "xlsx";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import Toastify from "toastify-js";
|
||||
import {
|
||||
ImportService,
|
||||
@@ -228,7 +228,7 @@
|
||||
{#if import_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
cancelModal();
|
||||
|
||||
@@ -1,22 +1,72 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
let tablePageCount = [50, 100, 250, 500];
|
||||
import { writable } from "svelte/store";
|
||||
import {
|
||||
createSvelteTable,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
} from "@tanstack/svelte-table";
|
||||
|
||||
$: selected =
|
||||
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
|
||||
|
||||
const columns = [
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: () => "id",
|
||||
filterFn: `equalsString`,
|
||||
},
|
||||
{
|
||||
accessorKey: "firstname",
|
||||
header: () => $_('first-name'),
|
||||
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: `includesString`,
|
||||
},
|
||||
{
|
||||
accessorKey: "distance",
|
||||
header: () => $_('distance'),
|
||||
cell: (info) => {
|
||||
if(info.getValue() < 1000){return `${info.getValue()} m`}
|
||||
return `${(info.getValue() / 1000).toFixed(1)} km`
|
||||
},
|
||||
enableColumnFilter: false,
|
||||
},
|
||||
];
|
||||
|
||||
//
|
||||
|
||||
import {
|
||||
RunnerService,
|
||||
RunnerTeamService,
|
||||
RunnerOrganizationService,
|
||||
} from "@odit/lfk-client-js";
|
||||
import ThFilterGroup from "./ThFilterGroup.svelte";
|
||||
import { DataHandler, Datatable, Th, ThFilter } from "@vincjo/datatables";
|
||||
import store from "../../store";
|
||||
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
|
||||
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
|
||||
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import InputElement from "../shared/InputElement.svelte";
|
||||
$: active_deletes = [];
|
||||
let dataLoaded = false;
|
||||
let current_runners = [];
|
||||
const handler = new DataHandler(current_runners, { rowsPerPage: 50 });
|
||||
const rows = handler.getRows();
|
||||
export let current_runners = [];
|
||||
$: sponsoring_contracts_show = generate_runners.length > 0;
|
||||
$: cards_show = generate_runners.length > 0;
|
||||
$: certificates_show = generate_runners.length > 0;
|
||||
@@ -31,11 +81,30 @@
|
||||
return { value: g.id, label: g.name };
|
||||
})
|
||||
.concat(mappedteams);
|
||||
const options = writable({
|
||||
data: [],
|
||||
columns: columns,
|
||||
initialState: {
|
||||
pagination: {
|
||||
pageSize: tablePageCount[0],
|
||||
},
|
||||
},
|
||||
enableRowSelection: true,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
});
|
||||
const table = createSvelteTable(options);
|
||||
onMount(() => {
|
||||
RunnerService.runnerControllerGetAll().then((val) => {
|
||||
current_runners = val;
|
||||
dataLoaded = true;
|
||||
handler.setRows(val);
|
||||
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_runners,
|
||||
}));
|
||||
});
|
||||
RunnerTeamService.runnerTeamControllerGetAll().then((val) => {
|
||||
teams = val;
|
||||
@@ -69,134 +138,161 @@
|
||||
bind:generate_runners
|
||||
/>
|
||||
</div>
|
||||
<Datatable {handler}>
|
||||
<table>
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input
|
||||
{#each $table.getHeaderGroups() as headerGroup}
|
||||
<tr class="select-none">
|
||||
<th class="inset-y-0 left-0 px-4 py-2 text-left bg-stone-100 w-px">
|
||||
<InputElement
|
||||
type="checkbox"
|
||||
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
||||
checked={generate_runners.length == current_runners.length}
|
||||
on:click={() => {
|
||||
if (generate_runners.length != current_runners.length) {
|
||||
generate_runners = current_runners;
|
||||
} else {
|
||||
generate_runners = [];
|
||||
}
|
||||
}}
|
||||
checked={$table.getIsAllRowsSelected()}
|
||||
indeterminate={$table.getIsSomeRowsSelected()}
|
||||
on:change={() => $table.toggleAllRowsSelected()}
|
||||
/>
|
||||
</th>
|
||||
<Th {handler} orderBy="id">ID</Th>
|
||||
<Th {handler} orderBy="firstname">First Name</Th>
|
||||
<Th {handler} orderBy="middlename">Middle Name</Th>
|
||||
<Th {handler} orderBy="lastname">Last Name</Th>
|
||||
<th>Gruppe</th>
|
||||
<Th {handler} orderBy="distance">Distanz</Th>
|
||||
<th>{$_("action")}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th />
|
||||
<ThFilter {handler} filterBy="id" />
|
||||
<ThFilter {handler} filterBy="firstname" />
|
||||
<ThFilter {handler} filterBy="middlename" />
|
||||
<ThFilter {handler} filterBy="lastname" />
|
||||
<ThFilterGroup groups={selectgroups} {handler} />
|
||||
<th />
|
||||
<th />
|
||||
{#each headerGroup.headers as header}
|
||||
<th class="cursor-pointer">
|
||||
{#if !header.isPlaceholder}
|
||||
<div on:click={header.column.getToggleSortingHandler()}>
|
||||
<svelte:component
|
||||
this={flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
/>
|
||||
{#if header.column.getIsSorted().toString() == "asc"}
|
||||
🔼
|
||||
{:else if header.column.getIsSorted().toString() == "desc"}
|
||||
🔽
|
||||
{/if}
|
||||
</div>
|
||||
{/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 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>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each $rows as row}
|
||||
{#each $table.getRowModel().rows as row}
|
||||
<tr>
|
||||
<td>
|
||||
<input
|
||||
<td class="inset-y-0 left-0 px-4 py-2">
|
||||
<InputElement
|
||||
type="checkbox"
|
||||
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
||||
checked={generate_runners.filter((i)=>i.id == row.id).length > 0}
|
||||
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)
|
||||
}}
|
||||
checked={row.getIsSelected()}
|
||||
on:change={() => row.toggleSelected()}
|
||||
/>
|
||||
</td>
|
||||
<td>{row.id}</td>
|
||||
<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} > {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>
|
||||
{#each row.getVisibleCells() as cell}
|
||||
<td>
|
||||
{#if active_deletes[row.id] === true}
|
||||
<button
|
||||
on:click={() => {
|
||||
active_deletes[row.id] = false;
|
||||
}}
|
||||
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}
|
||||
<svelte:component
|
||||
this={flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
/>
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</Datatable>
|
||||
<div class="h-2" />
|
||||
<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:change={(e) => {
|
||||
const ps = Number(e.target.value);
|
||||
console.log({ ps });
|
||||
$table.setPageSize(Number(e.target.value));
|
||||
}}
|
||||
>
|
||||
{#each tablePageCount 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>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
let selected = "all";
|
||||
</script>
|
||||
|
||||
<th>
|
||||
<th style="border-bottom: 1px solid #ddd;">
|
||||
<select
|
||||
on:input={() => {
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import {
|
||||
RunnerService,
|
||||
ScanService,
|
||||
@@ -81,7 +81,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,125 +1,147 @@
|
||||
<script>
|
||||
import { getLocaleFromNavigator, _ } from "svelte-i18n";
|
||||
import {
|
||||
ScanService,
|
||||
} from "@odit/lfk-client-js";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { DataHandler, Datatable, Th, ThFilter } from "@vincjo/datatables";
|
||||
import { ScanService, TrackService } from "@odit/lfk-client-js";
|
||||
import store from "../../store";
|
||||
import Toastify from "toastify-js";
|
||||
import ScansEmptyState from "./ScansEmptyState.svelte";
|
||||
$: searchvalue = "";
|
||||
import ThFilterRunner from "./ThFilterRunner.svelte";
|
||||
import ThFilterTrack from "./ThFilterTrack.svelte";
|
||||
$: active_deletes = [];
|
||||
export let current_scans = [];
|
||||
const handler = new DataHandler(current_scans, { rowsPerPage: 20 });
|
||||
const rows = handler.getRows();
|
||||
const scans_promise = ScanService.scanControllerGetAll().then((val) => {
|
||||
current_scans = val;
|
||||
handler.setRows(val);
|
||||
});
|
||||
$: allTracks = [];
|
||||
TrackService.trackControllerGetAll().then((val) => {
|
||||
allTracks = val;
|
||||
});
|
||||
function should_display_based_on_id(id) {
|
||||
if (searchvalue.toString().slice(-1) === "*") {
|
||||
return id.toString().startsWith(searchvalue.replace("*", ""));
|
||||
}
|
||||
return id.toString() === searchvalue;
|
||||
}
|
||||
function format_laptime(laptime) {
|
||||
if(laptime == 0 || laptime == null){return $_('first-scan-of-the-day')}
|
||||
if(laptime < 60){return `${laptime}s`}
|
||||
if(laptime < 3600){return `${Math.floor(laptime / 60)}min ${laptime - (Math.floor(laptime / 60)*60)}s`}
|
||||
return `${Math.floor(laptime / 3600)}h ${laptime - (Math.floor(laptime / 3600)*3600)}min ${laptime - (Math.floor(laptime / 3600)*3600) - (Math.floor(laptime / 60)*60)}`
|
||||
if (laptime == 0 || laptime == null) {
|
||||
return $_("first-scan-of-the-day");
|
||||
}
|
||||
if (laptime < 60) {
|
||||
return `${laptime}s`;
|
||||
}
|
||||
if (laptime < 3600) {
|
||||
return `${Math.floor(laptime / 60)}min ${
|
||||
laptime - Math.floor(laptime / 60) * 60
|
||||
}s`;
|
||||
}
|
||||
return `${Math.floor(laptime / 3600)}h ${
|
||||
laptime - Math.floor(laptime / 3600) * 3600
|
||||
}min ${
|
||||
laptime -
|
||||
Math.floor(laptime / 3600) * 3600 -
|
||||
Math.floor(laptime / 60) * 60
|
||||
}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes('SCAN:GET')}
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:GET")}
|
||||
{#await scans_promise}
|
||||
<div
|
||||
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
|
||||
role="alert">
|
||||
<p class="font-bold">{$_('scans-are-being-loaded')}</p>
|
||||
<p class="text-sm">{$_('this-might-take-a-moment')}</p>
|
||||
role="alert"
|
||||
>
|
||||
<p class="font-bold">{$_("scans-are-being-loaded")}</p>
|
||||
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
|
||||
</div>
|
||||
{:then}
|
||||
{#if current_scans.length === 0}
|
||||
<ScansEmptyState />
|
||||
{:else}
|
||||
<input
|
||||
type="search"
|
||||
bind:value={searchvalue}
|
||||
placeholder={$_('datatable.search')}
|
||||
aria-label={$_('datatable.search')}
|
||||
class="gridjs-input gridjs-search-input mb-4" />
|
||||
<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"
|
||||
>
|
||||
<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="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{$_('runner')}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{$_('distance-track')}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{$_('laptime')}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{$_('status')}
|
||||
</th>
|
||||
<th scope="col" class="relative px-6 py-3">
|
||||
<span class="sr-only">{$_('action')}</span>
|
||||
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 current_scans as scan}
|
||||
{#if scan.track?.name
|
||||
.toLowerCase()
|
||||
.includes(
|
||||
searchvalue.toLowerCase()
|
||||
) || scan.runner?.firstname
|
||||
.toLowerCase()
|
||||
.includes(
|
||||
searchvalue.toLowerCase()
|
||||
) || scan.runner?.lastname
|
||||
.toLowerCase()
|
||||
.includes(
|
||||
searchvalue.toLowerCase()
|
||||
) || should_display_based_on_id(scan.id)}
|
||||
{#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>
|
||||
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">
|
||||
<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}
|
||||
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">
|
||||
<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')}
|
||||
{$_("scan-with-fixed-distance")}
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
@@ -127,23 +149,30 @@
|
||||
<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>
|
||||
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>
|
||||
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">
|
||||
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
|
||||
>
|
||||
<button
|
||||
on:click={() => {
|
||||
active_deletes[scan.id] = false;
|
||||
}}
|
||||
tabindex="0"
|
||||
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button>
|
||||
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer"
|
||||
>{$_("cancel-delete")}</button
|
||||
>
|
||||
<button
|
||||
on:click={() => {
|
||||
ScanService.scanControllerRemove(scan.id, false).then(
|
||||
@@ -152,44 +181,51 @@
|
||||
(obj) => obj.id !== scan.id
|
||||
);
|
||||
Toastify({
|
||||
text: 'Scan deleted',
|
||||
text: "Scan deleted",
|
||||
duration: 500,
|
||||
backgroundColor:
|
||||
'linear-gradient(to right, #00b09b, #96c93d)',
|
||||
"linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
}
|
||||
);
|
||||
}}
|
||||
tabindex="0"
|
||||
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button>
|
||||
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
|
||||
>{$_("confirm-delete")}</button
|
||||
>
|
||||
</td>
|
||||
{:else}
|
||||
<td
|
||||
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
|
||||
>
|
||||
<a
|
||||
href="./{scan.id}"
|
||||
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a>
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes('SCAN:DELETE')}
|
||||
class="text-indigo-600 hover:text-indigo-900"
|
||||
>{$_("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>
|
||||
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
|
||||
>{$_("delete")}</button
|
||||
>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</Datatable>
|
||||
</div>
|
||||
{/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>
|
||||
<b class="capitalize">{$_("general_promise_error")}</b>
|
||||
{error}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
50
src/components/scans/ThFilterRunner.svelte
Normal file
50
src/components/scans/ThFilterRunner.svelte
Normal file
@@ -0,0 +1,50 @@
|
||||
<script>
|
||||
export let handler;
|
||||
let filterValue = "";
|
||||
</script>
|
||||
|
||||
<th>
|
||||
<input
|
||||
on:input={() => {
|
||||
setTimeout(() => {
|
||||
const v = filterValue.toLowerCase();
|
||||
handler.filter(v, (c) => {
|
||||
if (v.startsWith("#")) {
|
||||
return `#${c.runner?.id}`;
|
||||
}
|
||||
if (c.runner) {
|
||||
let runnerName = `${c.runner.firstname} ${c.runner.lastname}`;
|
||||
if (c.runner.middlename) {
|
||||
runnerName = `${c.runner.firstname} ${c.runner.middlename} ${c.runner.lastname}`;
|
||||
}
|
||||
runnerName = runnerName.toLowerCase();
|
||||
return runnerName;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
}, 150);
|
||||
}}
|
||||
placeholder="Filter"
|
||||
bind:value={filterValue}
|
||||
type="text"
|
||||
name="runnerfilter"
|
||||
id="runnerfilter"
|
||||
/>
|
||||
</th>
|
||||
|
||||
<style>
|
||||
th {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
input {
|
||||
margin: -1px 0 0 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
border: none;
|
||||
text-align: left;
|
||||
background: inherit;
|
||||
outline: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
31
src/components/scans/ThFilterTrack.svelte
Normal file
31
src/components/scans/ThFilterTrack.svelte
Normal file
@@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
export let tracks;
|
||||
export let handler;
|
||||
let selected = "all";
|
||||
</script>
|
||||
|
||||
<th style="border-bottom: 1px solid #ddd;">
|
||||
<select
|
||||
on:input={() => {
|
||||
setTimeout(() => {
|
||||
if (`${selected}`.trim()) {
|
||||
const value = selected;
|
||||
handler.filter(value, (scan) => {
|
||||
// TODO: fix filter
|
||||
if (scan.track.id === value || value === "all") return scan.track.id;
|
||||
return "";
|
||||
});
|
||||
}
|
||||
}, 50);
|
||||
}}
|
||||
bind:value={selected}
|
||||
name="trackfilter"
|
||||
id="trackfilter"
|
||||
>
|
||||
<option value="all">{$_("all")}</option>
|
||||
{#each tracks as track}
|
||||
<option value={track.id}>{track.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</th>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { ScanStationService, TrackService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import Select from "svelte-select";
|
||||
@@ -81,7 +81,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { ScanStationService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
@@ -32,7 +32,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={cancelDelete}>
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import Toastify from "toastify-js";
|
||||
import { tick, createEventDispatcher } from "svelte";
|
||||
export let copy_modal_open;
|
||||
@@ -46,7 +46,7 @@
|
||||
{#if valueCopy != null}
|
||||
<textarea bind:this={areaDom}>{valueCopy}</textarea>
|
||||
{/if}
|
||||
<div class="fixed z-10 inset-0 overflow-y-auto" use:focusTrap>
|
||||
<div class="fixed z-10 inset-0 overflow-y-auto" >
|
||||
<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">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { MeService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
@@ -30,7 +30,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={cancelDelete}>
|
||||
<div
|
||||
|
||||
20
src/components/shared/InputElement.svelte
Normal file
20
src/components/shared/InputElement.svelte
Normal 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
|
||||
/>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { StatsClientService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
export let modal_open;
|
||||
@@ -66,7 +66,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { ScanStationService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
@@ -32,7 +32,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={cancelDelete}>
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import Toastify from "toastify-js";
|
||||
import { tick, createEventDispatcher } from "svelte";
|
||||
export let copy_modal_open;
|
||||
@@ -46,7 +46,7 @@
|
||||
{#if valueCopy != null}
|
||||
<textarea bind:this={areaDom}>{valueCopy}</textarea>
|
||||
{/if}
|
||||
<div class="fixed z-10 inset-0 overflow-y-auto" use:focusTrap>
|
||||
<div class="fixed z-10 inset-0 overflow-y-auto" >
|
||||
<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">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import {
|
||||
RunnerOrganizationService,
|
||||
RunnerTeamService,
|
||||
@@ -77,7 +77,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { RunnerTeamService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
@@ -29,7 +29,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={cancelDelete}>
|
||||
<div
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { tracks as tracksstore } from "../../store.js";
|
||||
import { TrackService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
@@ -75,7 +75,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { focusTrap } from "svelte-focus-trap";
|
||||
|
||||
import { UserService } from "@odit/lfk-client-js";
|
||||
import isEmail from "validator/es/lib/isEmail";
|
||||
import Toastify from "toastify-js";
|
||||
@@ -92,7 +92,7 @@
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:focusTrap
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
|
||||
@@ -82,14 +82,6 @@
|
||||
<tr data-rowid="user_{u.id}">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
{#if u.profilePic}
|
||||
<div class="flex-shrink-0 h-10 w-10">
|
||||
<img
|
||||
class="h-10 w-10 rounded-full"
|
||||
src={u.profilePic}
|
||||
alt="" />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="ml-4">
|
||||
<div class="text-sm font-medium text-gray-900">
|
||||
{u.firstname}
|
||||
|
||||
@@ -473,5 +473,7 @@
|
||||
"you-have-to-provide-an-organization": "Du musst eine Organisation angeben",
|
||||
"you-have-to-save-your-changes-to-generate-a-link": "Du musst deine Änderungen speichern, um einen Link zu generieren.",
|
||||
"you-must-create-at-least-one-card-or-cancel": "Du musst mindestens eine Blankokarte erstellen (oder abbrechen).",
|
||||
"zip-postal-code": "Postleitzahl"
|
||||
"zip-postal-code": "Postleitzahl",
|
||||
"delete-cards": "Karten löschen",
|
||||
"cards-deleted": "Karten gelöscht"
|
||||
}
|
||||
@@ -473,5 +473,7 @@
|
||||
"you-have-to-provide-an-organization": "You have to provide an organization",
|
||||
"you-have-to-save-your-changes-to-generate-a-link": "You have to save your changes to generate a link.",
|
||||
"you-must-create-at-least-one-card-or-cancel": "You must create at least one card (or cancel).",
|
||||
"zip-postal-code": "ZIP/ postal code"
|
||||
"zip-postal-code": "ZIP/ postal code",
|
||||
"delete-cards": "Delete cards",
|
||||
"cards-deleted": "Cards deleted"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
mode: 'jit',
|
||||
purge: [ './src/**/*.svelte' ],
|
||||
content: [ './src/**/*.svelte' ],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
|
||||
@@ -1,39 +1,11 @@
|
||||
import svelte from '@sveltejs/vite-plugin-svelte';
|
||||
import { minify } from 'html-minifier';
|
||||
// vite.config.js
|
||||
import { defineConfig } from 'vite';
|
||||
//
|
||||
const indexReplace = () => {
|
||||
return {
|
||||
name: 'html-transform',
|
||||
transformIndexHtml(html) {
|
||||
return minify(html, {
|
||||
collapseWhitespace: true
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
const isProduction = mode === 'production';
|
||||
return {
|
||||
// base: './',
|
||||
build: {
|
||||
polyfillDynamicImport: false,
|
||||
cssCodeSplit: false,
|
||||
minify: isProduction,
|
||||
target: ["es2020", "esnext", "edge88", "chrome87", "safari14"]
|
||||
},
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
svelte({
|
||||
//@ts-ignore
|
||||
hot: !isProduction,
|
||||
emitCss: true,
|
||||
extensions: ['.md', '.svx', '.svelte'],
|
||||
preprocess: [
|
||||
//
|
||||
/* plugin options */
|
||||
})
|
||||
]
|
||||
}),
|
||||
indexReplace()
|
||||
]
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user