feat: steadier live updates and notices for public proposals
- The web pings the live connection, reconnects when it goes quiet and reloads what each screen shows after reconnecting. - Dropping a card on a column it cannot go to puts it back. - Owners and admins get a notice when a proposal arrives. - The proposal limit lives in Redis, so it holds across instances. - REST tells whether I voted; pasted images leave the attachment list. - Deleting a project removes its Git integration; no lint warnings left. - Reactions and the blocked badge are components of their own. - Docs: what is done and what is left (chapter 10), Word and PDF. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
54
libs/web/tracker/presenters/src/lib/ui/blocked.ts
Normal file
54
libs/web/tracker/presenters/src/lib/ui/blocked.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { PiIconComponent } from '@pi/ui';
|
||||
import { IssueParent } from '@task-stream/web/tracker/domain';
|
||||
|
||||
/**
|
||||
* 🔒 «Bloqueado»: the ticket waits for others still open. `compact` for
|
||||
* cards and rows (the keys go in the tooltip); in full, they link.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ts-blocked',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [PiIconComponent, RouterLink],
|
||||
host: { role: 'status', '[title]': 'tooltip()' },
|
||||
template: `
|
||||
<pi-icon icon="lock" size="x-small" aria-hidden="true" />
|
||||
@if (compact()) {
|
||||
Bloqueado
|
||||
} @else {
|
||||
Bloqueado por
|
||||
@for (blocker of blockers(); track blocker.id) {
|
||||
<a class="ts-key" [routerLink]="['..', blocker.key]">{{
|
||||
blocker.key
|
||||
}}</a>
|
||||
}
|
||||
}
|
||||
`,
|
||||
styles: `
|
||||
:host {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem 0.375rem;
|
||||
align-items: center;
|
||||
padding: 0.0625rem 0.5rem;
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--ts-c-red, #d33) 12%, transparent);
|
||||
color: var(--ts-c-red, var(--ts-ink));
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.ts-key {
|
||||
color: inherit;
|
||||
}
|
||||
`,
|
||||
})
|
||||
export class BlockedComponent {
|
||||
readonly blockers = input.required<IssueParent[]>();
|
||||
readonly compact = input(false);
|
||||
protected tooltip(): string {
|
||||
return this.blockers()
|
||||
.map((b) => `${b.key}: ${b.title}`)
|
||||
.join('\n');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user