add ability to remove user and add task depndencies closes #69
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Notifications from './lib/Notifications.svelte';
|
||||
import { userStore } from './routes/UserStore.svelte';
|
||||
</script>
|
||||
|
||||
@@ -26,6 +27,8 @@
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<Notifications />
|
||||
|
||||
<style class="scss">
|
||||
nav {
|
||||
background: #ececec;
|
||||
|
||||
42
webpage/src/lib/Notifications.svelte
Normal file
42
webpage/src/lib/Notifications.svelte
Normal file
@@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import { fly, fade } from 'svelte/transition';
|
||||
import { notificationStore } from './NotificationsStore.svelte';
|
||||
</script>
|
||||
|
||||
<div class="notifications">
|
||||
{#each notificationStore.notifications as noti}
|
||||
<div
|
||||
class="notification"
|
||||
class:noti-success={noti.type === 'success'}
|
||||
class:noti-danger={noti.type === 'danger'}
|
||||
class:noti-info={noti.type === 'info'}
|
||||
in:fly|global={{ duration: 300, y: -120, opacity: 0 }}
|
||||
out:fly|global={{ duration: 300, y: -120, opacity: 1 }}
|
||||
>
|
||||
{noti.message}
|
||||
{@html noti.html ?? ''}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.notifications {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: max(300px, 30%);
|
||||
|
||||
.notification {
|
||||
border: 1px solid black;
|
||||
padding: 20px;
|
||||
background: #ffffff;
|
||||
margin: 15px 0;
|
||||
border-radius: 20px;
|
||||
|
||||
&.noti-danger {
|
||||
background: var(--danger-ligther);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
68
webpage/src/lib/NotificationsStore.svelte.ts
Normal file
68
webpage/src/lib/NotificationsStore.svelte.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
type NotificationType = 'danger' | 'success' | 'info';
|
||||
type Notification = {
|
||||
type?: NotificationType;
|
||||
timeToLive?: number;
|
||||
message: string;
|
||||
html?: string;
|
||||
};
|
||||
|
||||
export function createNotificationStore(defaultTimetoLive: number) {
|
||||
type InternalNotifications = {
|
||||
notification: Notification;
|
||||
endDate: Date;
|
||||
};
|
||||
let notifications = $state<InternalNotifications[]>([]);
|
||||
let timeout = $state<number | undefined>();
|
||||
|
||||
function clearNotifications() {
|
||||
const now = new Date().getTime();
|
||||
let min: number | undefined = undefined;
|
||||
notifications = notifications.filter((a) => {
|
||||
const t = a.endDate.getTime();
|
||||
if (t <= now) {
|
||||
return false;
|
||||
}
|
||||
if (min == undefined) {
|
||||
min = t;
|
||||
} else if (min > t) {
|
||||
min = t;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (min != undefined) {
|
||||
timeout = setTimeout(clearNotifications, now - min);
|
||||
} else {
|
||||
timeout = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function add(noti: Notification) {
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(clearNotifications, noti.timeToLive ?? defaultTimetoLive);
|
||||
}
|
||||
const now = new Date();
|
||||
notifications.push({
|
||||
notification: noti,
|
||||
endDate: new Date(now.getTime() + (noti.timeToLive ?? defaultTimetoLive))
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
get notifications() {
|
||||
return notifications.map((a) => a.notification);
|
||||
},
|
||||
clear() {
|
||||
notifications.forEach((a) => clearInterval(a.timeout));
|
||||
notifications = [];
|
||||
},
|
||||
add,
|
||||
notify(message: string, type: NotificationType = 'danger') {
|
||||
add({ message, type });
|
||||
},
|
||||
display(message: string) {
|
||||
add({ message, type: 'danger' });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const notificationStore = createNotificationStore(5000);
|
||||
@@ -108,7 +108,11 @@ export async function showMessage(
|
||||
if (e == null) {
|
||||
return false;
|
||||
} else if (e instanceof Response) {
|
||||
messages.display(await e.json());
|
||||
try {
|
||||
messages.display(await e.json());
|
||||
} catch (ex) {
|
||||
showMessage(ex, messages, message);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
console.error(e);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
|
||||
import BaseModelInfo from './BaseModelInfo.svelte';
|
||||
import DeleteModel from './DeleteModel.svelte';
|
||||
@@ -50,16 +50,22 @@
|
||||
|
||||
let id: string | undefined = $state();
|
||||
|
||||
let re_query_timeout: number | undefined = undefined;
|
||||
|
||||
async function getModel() {
|
||||
if (re_query_timeout) {
|
||||
clearTimeout(re_query_timeout);
|
||||
re_query_timeout = undefined;
|
||||
}
|
||||
try {
|
||||
let temp_model: Model = await get(`models/edit?id=${id}`);
|
||||
|
||||
if ([3, 7, 6].includes(temp_model.status)) {
|
||||
setTimeout(getModel, 2000);
|
||||
re_query_timeout = setTimeout(getModel, 2000);
|
||||
}
|
||||
|
||||
if (temp_model.status == 4) {
|
||||
setTimeout(getModel, 5000);
|
||||
re_query_timeout = setTimeout(getModel, 5000);
|
||||
|
||||
definitions = await get(`models/edit/definitions?id=${id}`);
|
||||
}
|
||||
@@ -108,6 +114,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (re_query_timeout) {
|
||||
clearTimeout(re_query_timeout);
|
||||
}
|
||||
});
|
||||
|
||||
// Auto reload after 2s when model.status 3,4
|
||||
</script>
|
||||
|
||||
|
||||
8
webpage/src/routes/user-deleted/+page.svelte
Normal file
8
webpage/src/routes/user-deleted/+page.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<h1>Your User has been deleted</h1>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 40px;
|
||||
}
|
||||
</style>
|
||||
@@ -7,6 +7,7 @@
|
||||
import { post } from 'src/lib/requests.svelte';
|
||||
import MessageSimple, { type DisplayFn } from 'src/lib/MessageSimple.svelte';
|
||||
import TokenTable from './TokenTable.svelte';
|
||||
import DeleteUser from './DeleteUser.svelte';
|
||||
|
||||
onMount(() => {
|
||||
if (!userStore.isLogin()) {
|
||||
@@ -110,8 +111,8 @@
|
||||
<button> Update </button>
|
||||
</div>
|
||||
</form>
|
||||
<!-- TODO Delete -->
|
||||
<TokenTable />
|
||||
<DeleteUser />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
34
webpage/src/routes/user/info/DeleteUser.svelte
Normal file
34
webpage/src/routes/user/info/DeleteUser.svelte
Normal file
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||
import { rdelete, showMessage } from 'src/lib/requests.svelte';
|
||||
import { userStore } from 'src/routes/UserStore.svelte';
|
||||
|
||||
let data = $state({ password: '' });
|
||||
|
||||
async function deleteUser() {
|
||||
if (!userStore.user) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await rdelete('user/delete', {
|
||||
id: userStore.user?.id,
|
||||
password: data.password
|
||||
});
|
||||
userStore.user = undefined;
|
||||
goto('/user-deleted');
|
||||
} catch (e) {
|
||||
showMessage(e, notificationStore);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form class="danger-bg" on:submit|preventDefault={deleteUser}>
|
||||
<h2 class="no-top-margin">Delete user</h2>
|
||||
Deleting the user will delete all your data stored in the service including the images.
|
||||
<fieldset>
|
||||
To confirm please type your password
|
||||
<input name="password" type="password" required bind:value={data.password} />
|
||||
</fieldset>
|
||||
<button> Delete </button>
|
||||
</form>
|
||||
@@ -13,6 +13,7 @@
|
||||
--warning: #fca311;
|
||||
--warning-transparent: #fca31144;
|
||||
|
||||
--danger-ligther: #ffe0de;
|
||||
--danger: #ff8282;
|
||||
--danger-transparent: #ff828244;
|
||||
|
||||
@@ -171,3 +172,20 @@ a.button {
|
||||
background-color: var(--danger-transparent);
|
||||
border: 1px solid var(--danger);
|
||||
}
|
||||
|
||||
.box {
|
||||
padding: 30px;
|
||||
margin: 20px 0;
|
||||
border-radius: 10px;
|
||||
box-shadow: 2px 5px 8px 2px #66666655;
|
||||
}
|
||||
|
||||
.no-top-margin {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.box.danger-bg,
|
||||
form.danger-bg {
|
||||
background-color: var(--danger-transparent);
|
||||
border: 1px solid var(--danger);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user