feat(views): "Venter på andre", and a project you share stays yours
`assignee_id` has been on tasks since sharing was built and delegating has been possible from the drawer since yesterday. What was missing was anywhere to see it: work handed to somebody else left your lists and appeared in nothing. GET /delegated returns everything assigned to somebody who is not you, in the projects you can see, grouped by the person. Grouped on the server rather than flat, because the question is about people — "what is Anders sitting on" — and a client cannot group it itself: it would need the name behind an assignee id from a project it does not happen to have open, and there is no way to ask for that. The names come back with the tasks, so one request is one screen. The filter is a field of its own rather than a sentinel in AssigneeID. "What is on my plate" and "what have I handed over" are different questions, and one string that means an id most of the time and a magic word the rest is a field somebody eventually passes a real id to. An assignee whose account is gone is named "Ukendt" rather than dropped. Losing the row would make work disappear from the one view that exists to stop work disappearing. The sidebar entry only appears where delegating is possible at all. On an instance with one person it could never have anything in it, and a permanent empty entry is a question the sidebar keeps asking and answering "no". Building it turned up a bug in the split above it. "Projekter" and "Delt med mig" were divided on `shared`, which only means the project has more than one member — so inviting somebody to a project of your own moved it under "Delt med mig", where it lost its place in the order, stopped being draggable, and could not be filed under a group. It is divided on ownership now, which is what the two headings have always said. Sharing your own project is not the same event as somebody sharing theirs with you. The smoke test now follows the whole loop in one go: invite, accept in a second browser, assign a task to the person who just joined, and find it under their name — with the shared project still under "Projekter" on the way past. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
34b718529c
commit
6b6b838167
@@ -0,0 +1,126 @@
|
||||
<script>
|
||||
/**
|
||||
* Venter på andre: what you have handed to somebody else and are waiting for.
|
||||
*
|
||||
* Grouped by person, because that is the question — "what is Anders sitting
|
||||
* on" — rather than by date. The server groups it and sends the names with it;
|
||||
* a client has no way to ask for the name behind an assignee id it has not met
|
||||
* in a project it happens to have open.
|
||||
*/
|
||||
import { api } from '$lib/api.js';
|
||||
import { app } from '$lib/stores.svelte.js';
|
||||
import TaskRow from '$lib/components/TaskRow.svelte';
|
||||
|
||||
let people = $state([]);
|
||||
let loaded = $state(false);
|
||||
|
||||
$effect(() => {
|
||||
api.delegated().then((data) => {
|
||||
people = data.people;
|
||||
app.tasks = data.people.flatMap((p) => p.tasks);
|
||||
loaded = true;
|
||||
});
|
||||
});
|
||||
|
||||
// Read back out of the store, so a task that is closed or reassigned from the
|
||||
// drawer leaves the list at once rather than on the next load. Reassigning to
|
||||
// yourself is the interesting one: it stops being delegated the moment it
|
||||
// happens, which is exactly what this view should show.
|
||||
const live = (person) =>
|
||||
app.tasks.filter((t) => t.assignee_id === person.user_id && !t.completed);
|
||||
</script>
|
||||
|
||||
<div class="view">
|
||||
<header><h1>Venter på andre</h1></header>
|
||||
|
||||
{#each people as person (person.user_id)}
|
||||
{@const tasks = live(person)}
|
||||
{#if tasks.length}
|
||||
<section>
|
||||
<h2>
|
||||
<span class="avatar" style="background: {person.avatar_color}">
|
||||
{person.name[0]?.toUpperCase() ?? '?'}
|
||||
</span>
|
||||
{person.name}
|
||||
<span class="count">{tasks.length}</span>
|
||||
</h2>
|
||||
{#each tasks as task (task.id)}
|
||||
<TaskRow {task} />
|
||||
{/each}
|
||||
</section>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
{#if loaded && !people.some((p) => live(p).length)}
|
||||
<p class="clear">
|
||||
<span class="rune" aria-hidden="true">ᚹ</span>
|
||||
Du venter ikke på nogen.
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.view {
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
padding: var(--s6) var(--s4) var(--s8);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--text-2xl);
|
||||
margin-bottom: var(--s5);
|
||||
}
|
||||
|
||||
section {
|
||||
margin-top: var(--s5);
|
||||
}
|
||||
|
||||
/* The person is the heading, so their face is part of it rather than a
|
||||
decoration beside it. */
|
||||
h2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s2);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 560;
|
||||
color: var(--ink-muted);
|
||||
padding: 0 var(--s2) var(--s2);
|
||||
border-bottom: 1px solid var(--line);
|
||||
margin-bottom: var(--s2);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: var(--radius-full);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 560;
|
||||
color: #fff;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.count {
|
||||
margin-left: auto;
|
||||
font-size: var(--text-xs);
|
||||
color: var(--ink-faint);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.clear {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--s3);
|
||||
padding: var(--s8) var(--s4);
|
||||
color: var(--ink-faint);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.rune {
|
||||
font-size: var(--text-2xl);
|
||||
color: var(--accent);
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user