mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 16:03:47 +00:00
feat(drafts): drop the authed user's circle, mark own drafts with a '*' suffix
Three tweaks to the home-page Draft badge: 1. Filter the authed user out of `draft_users` before rendering circles. The row already signals 'this user has a draft' via the asterisk (below), so a circle for them would be redundant noise. New `currentUsername` prop on DraftBadge — pass `$userStore?.username` from each row. The tooltip still lists every user (with `(you)` next to the authed one) so the full picture is one hover away. 2. The badge already showed whenever `is_draft || draft_users.length > 0` (per-user OR any-user). Spelled the rationale out in a comment — no logic change. 3. Append '*' to the displayed summary when `is_draft` is true. Falls back to `draft_path`/`path` when summary is empty so the marker never decorates an empty string. Threaded the same expression into ScriptRow / FlowRow / AppRow. Slice/overflow math now keys on the post-filter `otherUsers` list, so dropping the authed user doesn't silently shrink the visible count (e.g. 3 users incl. self → 2 circles, not 1 circle + a '+1' bubble).
This commit is contained in:
@@ -23,9 +23,26 @@
|
||||
is_draft?: boolean
|
||||
draft_only?: boolean
|
||||
draft_users?: DraftUser[]
|
||||
/** Authed user's workspace username — circles for THIS user are
|
||||
* omitted because the row already signals their own draft via
|
||||
* the asterisk appended to the displayed summary. Pass
|
||||
* `$userStore?.username` from the row. */
|
||||
currentUsername?: string | null
|
||||
}
|
||||
|
||||
let { is_draft = false, draft_only = false, draft_users = [] }: Props = $props()
|
||||
let {
|
||||
is_draft = false,
|
||||
draft_only = false,
|
||||
draft_users = [],
|
||||
currentUsername = undefined
|
||||
}: Props = $props()
|
||||
|
||||
// Drop the authed user from the circle row — their own draft is
|
||||
// signalled by the asterisk on the row's summary, so showing both
|
||||
// would be visual noise. Keep the legacy NULL-username row.
|
||||
const otherUsers = $derived(
|
||||
currentUsername ? draft_users.filter((u) => u.username !== currentUsername) : draft_users
|
||||
)
|
||||
|
||||
/** Two-letter uppercase initials from a username — `john.doe`/`john_doe` →
|
||||
* `JD`, `alice` → `AL`, the legacy NULL-email row (no username) → `?`. */
|
||||
@@ -60,15 +77,22 @@
|
||||
return PALETTE[hash % PALETTE.length]
|
||||
}
|
||||
|
||||
// First 3 circles when ≤3 users; first 2 + a "+N" overflow when 4+.
|
||||
// First 3 circles when ≤3 OTHER users; first 2 + a "+N" overflow
|
||||
// when 4+. The slice/overflow math applies to `otherUsers` (post
|
||||
// current-user filter), not the raw `draft_users` — otherwise
|
||||
// dropping the authed user would silently change the visible count.
|
||||
const MAX_CIRCLES = 3
|
||||
const visibleUsers = $derived(
|
||||
draft_users.length <= MAX_CIRCLES ? draft_users : draft_users.slice(0, MAX_CIRCLES - 1)
|
||||
otherUsers.length <= MAX_CIRCLES ? otherUsers : otherUsers.slice(0, MAX_CIRCLES - 1)
|
||||
)
|
||||
const overflowCount = $derived(
|
||||
draft_users.length > MAX_CIRCLES ? draft_users.length - (MAX_CIRCLES - 1) : 0
|
||||
otherUsers.length > MAX_CIRCLES ? otherUsers.length - (MAX_CIRCLES - 1) : 0
|
||||
)
|
||||
|
||||
// Show the badge whenever ANY draft exists (`draft_users` non-empty)
|
||||
// OR when the authed user has a draft (`is_draft` true — the list
|
||||
// endpoint sets this even for paths the user has a draft on but no
|
||||
// one else does).
|
||||
const showBadge = $derived(is_draft || draft_users.length > 0)
|
||||
</script>
|
||||
|
||||
@@ -79,7 +103,7 @@
|
||||
{draft_only ? 'Never deployed — only a draft exists.' : 'Deployed with drafts pending.'}
|
||||
<div class="mt-1 flex flex-col gap-0.5">
|
||||
{#each draft_users as u}
|
||||
<span>• {fullLabel(u)}</span>
|
||||
<span>• {fullLabel(u)}{u.username === currentUsername ? ' (you)' : ''}</span>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if draft_only}
|
||||
@@ -89,11 +113,13 @@
|
||||
{/if}
|
||||
{/snippet}
|
||||
<Badge small color="indigo">
|
||||
{#if draft_users.length > 0}
|
||||
{#if otherUsers.length > 0}
|
||||
<!-- Circles sit inside the Badge, before the label. `-space-x-1`
|
||||
overlaps them slightly; each circle's ring uses the badge's
|
||||
indigo tint instead of plain white so the overlap reads as
|
||||
intentional rather than a stack-of-floating-dots. -->
|
||||
intentional rather than a stack-of-floating-dots. Only OTHER
|
||||
users get a circle — the authed user's own draft is
|
||||
signalled by the row's asterisk. -->
|
||||
<span class="flex -space-x-1">
|
||||
{#each visibleUsers as u}
|
||||
<span
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
kind="app"
|
||||
{marked}
|
||||
path={(app as any).draft_path ?? app.path}
|
||||
summary={app.summary}
|
||||
summary={app.is_draft ? `${app.summary || (app as any).draft_path || app.path}*` : app.summary}
|
||||
workspaceId={app.workspace_id ?? $workspaceStore ?? ''}
|
||||
canFavorite={!app.draft_only}
|
||||
{depth}
|
||||
@@ -119,7 +119,12 @@
|
||||
<Badge small icon={{ icon: FileJson }}>Raw</Badge>
|
||||
{/if}
|
||||
<SharedBadge canWrite={app.canWrite} extraPerms={app.extra_perms} />
|
||||
<DraftBadge is_draft={app.is_draft} draft_only={app.draft_only} draft_users={app.draft_users} />
|
||||
<DraftBadge
|
||||
is_draft={app.is_draft}
|
||||
draft_only={app.draft_only}
|
||||
draft_users={app.draft_users}
|
||||
currentUsername={$userStore?.username}
|
||||
/>
|
||||
{#if app.labels?.length}
|
||||
<div class="flex items-center gap-0.5">
|
||||
{#each app.labels.slice(0, 3) as label}
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
workspaceId={flow.workspace_id ?? $workspaceStore ?? ''}
|
||||
{marked}
|
||||
path={flow.draft_path ?? flow.path}
|
||||
summary={flow.summary}
|
||||
summary={flow.is_draft ? `${flow.summary || flow.draft_path || flow.path}*` : flow.summary}
|
||||
{errorHandlerMuted}
|
||||
canFavorite={!flow.draft_only}
|
||||
{depth}
|
||||
@@ -145,6 +145,7 @@
|
||||
is_draft={flow.is_draft}
|
||||
draft_only={flow.draft_only}
|
||||
draft_users={flow.draft_users}
|
||||
currentUsername={$userStore?.username}
|
||||
/>
|
||||
{#if flow.labels?.length}
|
||||
<div class="flex items-center gap-0.5">
|
||||
|
||||
@@ -147,7 +147,9 @@
|
||||
kind="script"
|
||||
{marked}
|
||||
path={script.draft_path ?? script.path}
|
||||
summary={script.summary}
|
||||
summary={script.is_draft
|
||||
? `${script.summary || script.draft_path || script.path}*`
|
||||
: script.summary}
|
||||
{errorHandlerMuted}
|
||||
workspaceId={$workspaceStore ?? ''}
|
||||
canFavorite={!script.draft_only}
|
||||
@@ -192,6 +194,7 @@
|
||||
is_draft={script.is_draft}
|
||||
draft_only={script.draft_only}
|
||||
draft_users={script.draft_users}
|
||||
currentUsername={$userStore?.username}
|
||||
/>
|
||||
{#if script.labels?.length}
|
||||
<div class="flex items-center gap-0.5">
|
||||
|
||||
Reference in New Issue
Block a user