feat: mark already-added images as disabled in EntityPicker
This commit is contained in:
@@ -104,7 +104,7 @@
|
||||
case 'Enter': {
|
||||
event.preventDefault();
|
||||
const item = flatFiltered[highlightIndex];
|
||||
if (item) {
|
||||
if (item && !item.disabled) {
|
||||
onselect(item.value);
|
||||
}
|
||||
break;
|
||||
@@ -121,8 +121,9 @@
|
||||
onclose();
|
||||
}
|
||||
|
||||
function handleItemClick(value: string) {
|
||||
onselect(value);
|
||||
function handleItemClick(item: EntityPickerItem) {
|
||||
if (item.disabled) return;
|
||||
onselect(item.value);
|
||||
}
|
||||
|
||||
/** Track the flat index across groups for highlight matching. */
|
||||
@@ -204,18 +205,22 @@
|
||||
<button
|
||||
type="button"
|
||||
class="entity-picker-item"
|
||||
class:entity-picker-item--highlighted={isHighlighted}
|
||||
class:entity-picker-item--highlighted={isHighlighted && !item.disabled}
|
||||
class:entity-picker-item--current={isCurrent}
|
||||
class:entity-picker-item--disabled={item.disabled}
|
||||
data-highlighted={isHighlighted}
|
||||
onclick={() => handleItemClick(item.value)}
|
||||
onclick={() => handleItemClick(item)}
|
||||
onmouseenter={() => { highlightIndex = flatIdx; }}
|
||||
disabled={item.disabled}
|
||||
>
|
||||
{#if item.icon}
|
||||
<span class="entity-picker-item-icon">{@html item.icon}</span>
|
||||
{/if}
|
||||
<span class="entity-picker-item-content">
|
||||
<span class="entity-picker-item-label">{item.label}</span>
|
||||
{#if item.description}
|
||||
{#if item.disabledHint}
|
||||
<span class="entity-picker-item-hint">{item.disabledHint}</span>
|
||||
{:else if item.description}
|
||||
<span class="entity-picker-item-description">{item.description}</span>
|
||||
{/if}
|
||||
</span>
|
||||
@@ -422,4 +427,17 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.entity-picker-item--disabled {
|
||||
opacity: 0.45;
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.entity-picker-item-hint {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-tertiary);
|
||||
font-style: italic;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -144,6 +144,8 @@ export interface EntityPickerItem {
|
||||
description?: string;
|
||||
icon?: string;
|
||||
group?: string;
|
||||
disabled?: boolean;
|
||||
disabledHint?: string;
|
||||
}
|
||||
|
||||
/** Volume mount configuration for a project. */
|
||||
|
||||
@@ -33,17 +33,22 @@
|
||||
imagePickerLoading = true;
|
||||
try {
|
||||
const registries = await api.listRegistries();
|
||||
// Collect existing project images to mark as already added.
|
||||
const existingImages = new Set(projects.map(p => p.image.toLowerCase()));
|
||||
const items: EntityPickerItem[] = [];
|
||||
for (const reg of registries) {
|
||||
if (!reg.owner) continue;
|
||||
try {
|
||||
const images = await api.listRegistryImages(reg.id);
|
||||
for (const img of images) {
|
||||
const alreadyAdded = existingImages.has(img.full_ref.toLowerCase());
|
||||
items.push({
|
||||
value: JSON.stringify({ full_ref: img.full_ref, registryName: reg.name }),
|
||||
label: img.full_ref,
|
||||
description: reg.name,
|
||||
group: reg.name
|
||||
description: alreadyAdded ? undefined : reg.name,
|
||||
group: reg.name,
|
||||
disabled: alreadyAdded,
|
||||
disabledHint: alreadyAdded ? 'Already added' : undefined
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user