feat(web): wire RowActionsMenu in requests + quarantine
Requests: primary Approve, secondary [Override, Reject]. Quarantine: primary Resolve, secondary [Play, Delete file]; the Delete-via-Lidarr conditional stays inline above md (preserves the disabled-with-tooltip semantics) and hides below md to avoid crowding — the operator can still trigger it from the desktop view. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
import { pageTitle } from '$lib/branding';
|
import { pageTitle } from '$lib/branding';
|
||||||
import { Music2, RotateCcw, Trash2, Cloud, Play, ChevronRight } from 'lucide-svelte';
|
import { Music2, RotateCcw, Trash2, Cloud, Play, ChevronRight } from 'lucide-svelte';
|
||||||
import { useQueryClient } from '@tanstack/svelte-query';
|
import { useQueryClient } from '@tanstack/svelte-query';
|
||||||
|
import RowActionsMenu, { type RowAction } from '$lib/components/RowActionsMenu.svelte';
|
||||||
import {
|
import {
|
||||||
createAdminQuarantineQuery,
|
createAdminQuarantineQuery,
|
||||||
resolveQuarantine,
|
resolveQuarantine,
|
||||||
@@ -258,41 +259,19 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Action cluster -->
|
<!-- Action cluster -->
|
||||||
|
{@const primary: RowAction = { icon: RotateCcw, label: 'Resolve', onclick: () => onResolve(r) }}
|
||||||
|
{@const secondary: RowAction[] = [
|
||||||
|
{ icon: Play, label: 'Play', onclick: () => onPlay(r) },
|
||||||
|
{ icon: Trash2, label: 'Delete file', onclick: () => openDeleteFile(r), danger: true }
|
||||||
|
]}
|
||||||
<div class="flex shrink-0 items-center gap-2">
|
<div class="flex shrink-0 items-center gap-2">
|
||||||
<button
|
<RowActionsMenu {primary} {secondary} />
|
||||||
type="button"
|
|
||||||
aria-label={`Play ${r.track_title}`}
|
|
||||||
class="inline-flex items-center justify-center rounded-md p-2 text-accent hover:bg-accent-tint"
|
|
||||||
onclick={() => onPlay(r)}
|
|
||||||
>
|
|
||||||
<Play size={16} strokeWidth={2} />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label={`Resolve ${r.track_title}`}
|
|
||||||
class="inline-flex items-center gap-1 rounded-md border border-border bg-transparent px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary hover:bg-surface-hover"
|
|
||||||
onclick={() => onResolve(r)}
|
|
||||||
>
|
|
||||||
<RotateCcw size={14} strokeWidth={1.5} />
|
|
||||||
Resolve
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label={`Delete file for ${r.track_title}`}
|
|
||||||
class="inline-flex items-center gap-1 rounded-md bg-action-secondary px-3 py-1.5 text-sm text-action-fg"
|
|
||||||
onclick={() => openDeleteFile(r)}
|
|
||||||
>
|
|
||||||
<Trash2 size={14} strokeWidth={2} />
|
|
||||||
Delete file
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{#if lidarrDisabled}
|
{#if lidarrDisabled}
|
||||||
<span
|
<span
|
||||||
aria-label={`Delete via Lidarr disabled for ${r.track_title}`}
|
aria-label={`Delete via Lidarr disabled for ${r.track_title}`}
|
||||||
title="Local-only track — no Lidarr album to remove."
|
title="Local-only track — no Lidarr album to remove."
|
||||||
class="inline-flex items-center gap-1 rounded-md bg-action-destructive px-3 py-1.5 text-sm text-action-fg opacity-50 cursor-not-allowed"
|
class="hidden md:inline-flex items-center gap-1 rounded-md bg-action-destructive px-3 py-1.5 text-sm text-action-fg opacity-50 cursor-not-allowed"
|
||||||
data-testid="delete-lidarr-disabled"
|
data-testid="delete-lidarr-disabled"
|
||||||
>
|
>
|
||||||
<Trash2 size={14} strokeWidth={2} />
|
<Trash2 size={14} strokeWidth={2} />
|
||||||
@@ -303,7 +282,7 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={`Delete via Lidarr for ${r.track_title}`}
|
aria-label={`Delete via Lidarr for ${r.track_title}`}
|
||||||
class="inline-flex items-center gap-1 rounded-md bg-action-destructive px-3 py-1.5 text-sm text-action-fg"
|
class="hidden md:inline-flex items-center gap-1 rounded-md bg-action-destructive px-3 py-1.5 text-sm text-action-fg"
|
||||||
onclick={() => openDeleteLidarr(r)}
|
onclick={() => openDeleteLidarr(r)}
|
||||||
>
|
>
|
||||||
<Trash2 size={14} strokeWidth={2} />
|
<Trash2 size={14} strokeWidth={2} />
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { pageTitle } from '$lib/branding';
|
import { pageTitle } from '$lib/branding';
|
||||||
import { Disc3, Album, Music2, Check, X, SlidersHorizontal } from 'lucide-svelte';
|
import { Disc3, Album, Music2, Check, X, SlidersHorizontal } from 'lucide-svelte';
|
||||||
import { useQueryClient } from '@tanstack/svelte-query';
|
import { useQueryClient } from '@tanstack/svelte-query';
|
||||||
|
import RowActionsMenu, { type RowAction } from '$lib/components/RowActionsMenu.svelte';
|
||||||
import {
|
import {
|
||||||
createAdminRequestsQuery,
|
createAdminRequestsQuery,
|
||||||
createQualityProfilesQuery,
|
createQualityProfilesQuery,
|
||||||
@@ -246,34 +247,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if r.status === 'pending'}
|
{#if r.status === 'pending'}
|
||||||
<div class="flex shrink-0 items-center gap-2">
|
{@const primary: RowAction = { icon: Check, label: 'Approve', onclick: () => onApprove(r) }}
|
||||||
<button
|
{@const secondary: RowAction[] = [
|
||||||
type="button"
|
{ icon: SlidersHorizontal, label: 'Override', onclick: () => openOverride(r) },
|
||||||
aria-label={`Override ${rowAccessibleName(r)}`}
|
{ icon: X, label: 'Reject', onclick: () => openReject(r), danger: true }
|
||||||
class="inline-flex items-center gap-1 rounded-md border border-border bg-transparent px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary hover:bg-surface-hover"
|
]}
|
||||||
onclick={() => openOverride(r)}
|
<div class="shrink-0">
|
||||||
>
|
<RowActionsMenu {primary} {secondary} />
|
||||||
<SlidersHorizontal size={14} strokeWidth={1.5} />
|
|
||||||
Override
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label={`Approve ${rowAccessibleName(r)}`}
|
|
||||||
class="inline-flex items-center gap-1 rounded-md bg-action-primary px-3 py-1.5 text-sm text-action-fg"
|
|
||||||
onclick={() => onApprove(r)}
|
|
||||||
>
|
|
||||||
<Check size={14} strokeWidth={2} />
|
|
||||||
Approve
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label={`Reject ${rowAccessibleName(r)}`}
|
|
||||||
class="inline-flex items-center gap-1 rounded-md bg-action-secondary px-3 py-1.5 text-sm text-action-fg"
|
|
||||||
onclick={() => openReject(r)}
|
|
||||||
>
|
|
||||||
<X size={14} strokeWidth={2} />
|
|
||||||
Reject
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user