Compare commits

..

12 Commits

Author SHA1 Message Date
a66f6bbec8 🚀RELEASE v0.1.1 2021-01-10 12:24:29 +01:00
139b3294cd 🧪 move changelog generation to default 2021-01-10 12:24:19 +01:00
1aac783df3 🚀RELEASE v0.1.0 2021-01-10 12:21:35 +01:00
e361c89f6c add basic package script
ref #4
2021-01-10 12:18:22 +01:00
52a19c2036 added basic release-it config
ref #4
2021-01-10 12:18:00 +01:00
0023e22524 added release-it dev dependency
ref #4
2021-01-10 12:17:49 +01:00
8f25a874cb move serviceworker registration to separate module
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-10 11:42:30 +01:00
7cf2ffce2d 🐞 fix malfuntion in logout logic
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-09 18:39:13 +01:00
848fb2fb65 Merge branch 'feature/12-user-management' into dev
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-09 18:29:47 +01:00
6529907a13 display full user names in overview table
ref #12
2021-01-09 18:27:22 +01:00
e5ec98bf6f basic AddUserModal ui
ref #12
2021-01-09 18:26:14 +01:00
2048533fda actually perform user logout (recreate Cookies, invalidate token) 2021-01-09 18:24:57 +01:00
6 changed files with 197 additions and 64 deletions

View File

@@ -1,11 +1,13 @@
{ {
"name": "@odit/lfk-frontend", "name": "@odit/lfk-frontend",
"version": "0.0.0", "version": "0.1.1",
"scripts": { "scripts": {
"i18n-order": "node order.js", "i18n-order": "node order.js",
"dev": "snowpack dev", "dev": "snowpack dev",
"build": "snowpack build", "build": "snowpack build",
"build:sw": "workbox generateSW workbox-config.js", "build:sw": "workbox generateSW workbox-config.js",
"release": "release-it",
"changelog": "npx auto-changelog --commit-limit false --template https://raw.githubusercontent.com/release-it/release-it/master/templates/changelog-compact.hbs",
"licenses:export": "license-exporter --json -o public" "licenses:export": "license-exporter --json -o public"
}, },
"dependencies": { "dependencies": {
@@ -24,12 +26,28 @@
"devDependencies": { "devDependencies": {
"@odit/license-exporter": "0.0.9", "@odit/license-exporter": "0.0.9",
"@snowpack/plugin-svelte": "3.4.1", "@snowpack/plugin-svelte": "3.4.1",
"auto-changelog": "^2.2.1",
"autoprefixer": "10.2.1", "autoprefixer": "10.2.1",
"postcss": "8.2.4", "postcss": "8.2.4",
"postcss-load-config": "3.0.0", "postcss-load-config": "3.0.0",
"release-it": "^14.2.2",
"snowpack": "3.0.0-rc.2", "snowpack": "3.0.0-rc.2",
"svelte": "3.31.2", "svelte": "3.31.2",
"svelte-preprocess": "4.6.1", "svelte-preprocess": "4.6.1",
"workbox-cli": "6.0.2" "workbox-cli": "6.0.2"
},
"release-it": {
"git": {
"commit": true,
"requireCleanWorkingDir": false,
"commitMessage": "🚀RELEASE v${version}",
"push": false,
"tag": true,
"tagName": null,
"tagAnnotation": "v${version}"
},
"npm": {
"publish": false
}
} }
} }

View File

@@ -47,28 +47,11 @@
import { OpenAPI, AuthService } from "@odit/lfk-client-js"; import { OpenAPI, AuthService } from "@odit/lfk-client-js";
import UserDetail from "./components/UserDetail.svelte"; import UserDetail from "./components/UserDetail.svelte";
OpenAPI.BASE = config.baseurl; OpenAPI.BASE = config.baseurl;
import { register as registerSW } from "./swmodule";
store.init(); store.init();
// registerSW();
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("/sw.js").then(
(registration) => {
// console.log(`sw successful with scope: ${registration.scope}`);
},
(err) => {
// console.log(`sw failed: ${err}`);
}
);
});
}
</script> </script>
<style>
.bg-gray-900 {
background-color: #121317;
}
</style>
<Route> <Route>
{#if $router.path === '/forgot_password'} {#if $router.path === '/forgot_password'}
<Route path="/forgot_password"> <Route path="/forgot_password">

View File

@@ -3,23 +3,33 @@
import { clickOutside } from "./outsideclick"; import { clickOutside } from "./outsideclick";
import { focusTrap } from "svelte-focus-trap"; import { focusTrap } from "svelte-focus-trap";
import { tracks as tracksstore } from "../store.js"; import { tracks as tracksstore } from "../store.js";
import { TrackService } from "@odit/lfk-client-js"; import { TrackService, UserService } from "@odit/lfk-client-js";
import isEmail from "validator/es/lib/isEmail";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import "toastify-js/src/toastify.css"; import "toastify-js/src/toastify.css";
import About from "./About.svelte";
export let modal_open; export let modal_open;
let trackname_input; let firstname_input;
let lastname_input;
let middlename_input;
let password_input;
let email_input;
function focus(el) { function focus(el) {
el.focus(); el.focus();
} }
$: trackname_input_value = ""; $: middlename_input_value = "";
$: password_input_value = "";
$: email_input_value = "";
$: lastname_input_value = "";
$: firstname_input_value = "";
$: track_min_duration = 0; $: track_min_duration = 0;
$: tracklength = 0; $: tracklength = 0;
$: processed_last_submit = true; $: processed_last_submit = true;
$: smart_track_min_duration_placeholder = parseInt(tracklength || 0) * 0.369; $: isPasswordValid = password_input_value.trim().length === 0;
$: isFirstnameValid = trackname_input_value.trim().length === 0; $: isEmailValid = isEmail(email_input_value);
$: isTracklengthValid = tracklength <= 0; $: isLastnameValid = lastname_input_value.trim().length === 0;
$: trackMintimevalid = track_min_duration >= 0; $: isFirstnameValid = firstname_input_value.trim().length === 0;
$: createbtnenabled = !isFirstnameValid && !isTracklengthValid; $: createbtnenabled = !isFirstnameValid && !isLastnameValid;
(function () { (function () {
document.onkeydown = function (e) { document.onkeydown = function (e) {
e = e || window.event; e = e || window.event;
@@ -38,22 +48,23 @@
if (processed_last_submit === true) { if (processed_last_submit === true) {
processed_last_submit = false; processed_last_submit = false;
const toast = Toastify({ const toast = Toastify({
text: $_("track-is-being-added"), text: "User is being added...",
duration: -1, duration: -1,
}).showToast(); }).showToast();
TrackService.trackControllerPost({ UserService.userControllerPost({
distance: parseInt(tracklength), firstname: firstname_input_value,
name: trackname_input_value, lastname: lastname_input_value,
minimumLapTime: track_min_duration, middlename: middlename_input_value,
email:email_input_value,password:password_input_value
}) })
.then((result) => { .then((result) => {
trackname_input_value = ""; firstname_input_value = "";
track_min_duration = 0; lastname_input_value = "";
tracklength = 0; middlename_input_value = "";
modal_open = false; modal_open = false;
// //
Toastify({ Toastify({
text: $_("track-added"), text: "User added",
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@@ -125,7 +136,7 @@
<div class="grid grid-cols-6 gap-6"> <div class="grid grid-cols-6 gap-6">
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="trackname" for="firstname"
class="block text-sm font-medium text-gray-700">First Name</label> class="block text-sm font-medium text-gray-700">First Name</label>
<input <input
use:focus use:focus
@@ -134,10 +145,10 @@
class:border-red-500={isFirstnameValid} class:border-red-500={isFirstnameValid}
class:focus:border-red-500={isFirstnameValid} class:focus:border-red-500={isFirstnameValid}
class:focus:ring-red-500={isFirstnameValid} class:focus:ring-red-500={isFirstnameValid}
bind:value={trackname_input_value} bind:value={firstname_input_value}
bind:this={trackname_input} bind:this={firstname_input}
type="text" type="text"
name="trackname" 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" /> 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} {#if isFirstnameValid}
<span <span
@@ -146,6 +157,85 @@
</span> </span>
{/if} {/if}
</div> </div>
<div class="col-span-6">
<label
for="trackname"
class="block text-sm font-medium text-gray-700">Middle Name</label>
<input
autocomplete="off"
placeholder="Middle Name"
bind:value={middlename_input_value}
bind:this={middlename_input}
type="text"
name="trackname"
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="col-span-6">
<label
for="lastname"
class="block text-sm font-medium text-gray-700">Last Name</label>
<input
autocomplete="off"
placeholder="Last Name"
class:border-red-500={isLastnameValid}
class:focus:border-red-500={isLastnameValid}
class:focus:ring-red-500={isLastnameValid}
bind:value={lastname_input_value}
bind:this={lastname_input}
type="text"
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="col-span-6">
<label
for="password"
class="block text-sm font-medium text-gray-700">Password</label>
<input
autocomplete="off"
placeholder="Password"
class:border-red-500={isPasswordValid}
class:focus:border-red-500={isPasswordValid}
class:focus:ring-red-500={isPasswordValid}
bind:value={password_input_value}
bind:this={password_input}
type="password"
name="password"
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 isPasswordValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
Password is required
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="email"
class="block text-sm font-medium text-gray-700">E-Mail</label>
<input
autocomplete="off"
placeholder="E-Mail"
class:border-red-500={!isEmailValid}
class:focus:border-red-500={!isEmailValid}
class:focus:ring-red-500={!isEmailValid}
bind:value={email_input_value}
bind:this={email_input}
type="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 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> </div>
</div> </div>
</div> </div>

View File

@@ -6,6 +6,7 @@
import store from "../store"; import store from "../store";
import NoComponentLoaded from "./NoComponentLoaded.svelte"; import NoComponentLoaded from "./NoComponentLoaded.svelte";
import { AuthService, OpenAPI } from "@odit/lfk-client-js";
let activePage = "dashboard"; let activePage = "dashboard";
let dropdown1 = false; let dropdown1 = false;
@@ -273,6 +274,7 @@
tabindex="0" tabindex="0"
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
on:click={() => { on:click={() => {
AuthService.authControllerLogout();
logout(); logout();
}}> }}>
<svg <svg

View File

@@ -78,8 +78,11 @@
</div> </div>
{/if} {/if}
<div class="ml-4"> <div class="ml-4">
<div class="text-sm font-medium text-gray-900 dark:text-gray-100"> <div
class="text-sm font-medium text-gray-900 dark:text-gray-100">
{u.firstname} {u.firstname}
{u.middlename || ''}
{u.lastname}
</div> </div>
<div class="text-sm text-gray-500"> <div class="text-sm text-gray-500">
{u.email || u.username} {u.email || u.username}
@@ -104,7 +107,8 @@
</td> </td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{#each u.groups as g} {#each u.groups as g}
<a href="../groups/{g.id}" <a
href="../groups/{g.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{g.name}</a> class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{g.name}</a>
{/each} {/each}
</td> </td>
@@ -113,65 +117,87 @@
<a <a
href="./{u.id}" href="./{u.id}"
class="text-indigo-600 hover:text-indigo-900">Edit</a> class="text-indigo-600 hover:text-indigo-900">Edit</a>
<span tabindex="0" href="#" class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</span> <span
tabindex="0"
href="#"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">Delete</span>
</td> </td>
</tr> </tr>
{/each} {/each}
</tbody> </tbody>
</table> </table>
<div class="grid px-4 py-3 text-xs font-semibold tracking-wide text-gray-500 uppercase border-t dark:border-gray-700 bg-gray-50 sm:grid-cols-9 dark:text-gray-400 dark:bg-gray-900"> <div
<span class="flex items-center col-span-3"> class="grid px-4 py-3 text-xs font-semibold tracking-wide text-gray-500 uppercase border-t dark:border-gray-700 bg-gray-50 sm:grid-cols-9 dark:text-gray-400 dark:bg-gray-900">
Showing 21-30 of 100 <span class="flex items-center col-span-3"> Showing 21-30 of 100 </span>
</span> <span class="col-span-2" />
<span class="col-span-2"></span>
<!-- Pagination --> <!-- Pagination -->
<span class="flex col-span-4 mt-2 sm:mt-auto sm:justify-end"> <span class="flex col-span-4 mt-2 sm:mt-auto sm:justify-end">
<nav aria-label="Table navigation"> <nav aria-label="Table navigation">
<ul class="inline-flex items-center"> <ul class="inline-flex items-center">
<li> <li>
<button class="px-3 py-1 rounded-md rounded-l-lg focus:outline-none focus:shadow-outline-purple" aria-label="Previous"> <button
<svg aria-hidden="true" class="w-4 h-4 fill-current" viewBox="0 0 20 20"> class="px-3 py-1 rounded-md rounded-l-lg focus:outline-none focus:shadow-outline-purple"
<path d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" fill-rule="evenodd"></path> aria-label="Previous">
<svg
aria-hidden="true"
class="w-4 h-4 fill-current"
viewBox="0 0 20 20">
<path
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
clip-rule="evenodd"
fill-rule="evenodd" />
</svg> </svg>
</button> </button>
</li> </li>
<li> <li>
<button class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple"> <button
class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple">
1 1
</button> </button>
</li> </li>
<li> <li>
<button class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple"> <button
class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple">
2 2
</button> </button>
</li> </li>
<li> <li>
<button class="px-3 py-1 text-white transition-colors duration-150 bg-purple-600 border border-r-0 border-purple-600 rounded-md focus:outline-none focus:shadow-outline-purple"> <button
class="px-3 py-1 text-white transition-colors duration-150 bg-purple-600 border border-r-0 border-purple-600 rounded-md focus:outline-none focus:shadow-outline-purple">
3 3
</button> </button>
</li> </li>
<li> <li>
<button class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple"> <button
class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple">
4 4
</button> </button>
</li> </li>
<li><span class="px-3 py-1">...</span></li>
<li> <li>
<span class="px-3 py-1">...</span> <button
</li> class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple">
<li>
<button class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple">
8 8
</button> </button>
</li> </li>
<li> <li>
<button class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple"> <button
class="px-3 py-1 rounded-md focus:outline-none focus:shadow-outline-purple">
9 9
</button> </button>
</li> </li>
<li> <li>
<button class="px-3 py-1 rounded-md rounded-r-lg focus:outline-none focus:shadow-outline-purple" aria-label="Next"> <button
<svg class="w-4 h-4 fill-current" aria-hidden="true" viewBox="0 0 20 20"> class="px-3 py-1 rounded-md rounded-r-lg focus:outline-none focus:shadow-outline-purple"
<path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" fill-rule="evenodd"></path> aria-label="Next">
<svg
class="w-4 h-4 fill-current"
aria-hidden="true"
viewBox="0 0 20 20">
<path
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
fill-rule="evenodd" />
</svg> </svg>
</button> </button>
</li> </li>

14
src/swmodule.js Normal file
View File

@@ -0,0 +1,14 @@
export const register = () => {
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').then(
(registration) => {
// console.log(`sw successful with scope: ${registration.scope}`);
},
(err) => {
// console.log(`sw failed: ${err}`);
}
);
});
}
};