mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 15:15:44 -03:00
fix: Show all tags in LoRA Pool without limit (#819)
- Backend: Support limit=0 to return all tags in top-tags API - Frontend: Remove tags limit setting and fetch all tags by default - UI: Implement virtual scrolling in TagsModal for performance - Initial display 200 tags, load more on scroll - Show all results when searching - Remove lora_pool_tags_limit setting to simplify UX Fixes #819
This commit is contained in:
@@ -648,7 +648,7 @@ class ModelQueryHandler:
|
|||||||
async def get_top_tags(self, request: web.Request) -> web.Response:
|
async def get_top_tags(self, request: web.Request) -> web.Response:
|
||||||
try:
|
try:
|
||||||
limit = int(request.query.get("limit", "20"))
|
limit = int(request.query.get("limit", "20"))
|
||||||
if limit < 1 or limit > 100:
|
if limit < 0:
|
||||||
limit = 20
|
limit = 20
|
||||||
top_tags = await self._service.get_top_tags(limit)
|
top_tags = await self._service.get_top_tags(limit)
|
||||||
return web.json_response({"success": True, "tags": top_tags})
|
return web.json_response({"success": True, "tags": top_tags})
|
||||||
|
|||||||
@@ -1448,7 +1448,7 @@ class ModelScanner:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_top_tags(self, limit: int = 20) -> List[Dict[str, any]]:
|
async def get_top_tags(self, limit: int = 20) -> List[Dict[str, any]]:
|
||||||
"""Get top tags sorted by count"""
|
"""Get top tags sorted by count. If limit is 0, return all tags."""
|
||||||
await self.get_cached_data()
|
await self.get_cached_data()
|
||||||
|
|
||||||
sorted_tags = sorted(
|
sorted_tags = sorted(
|
||||||
@@ -1457,6 +1457,8 @@ class ModelScanner:
|
|||||||
reverse=True
|
reverse=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if limit == 0:
|
||||||
|
return sorted_tags
|
||||||
return sorted_tags[:limit]
|
return sorted_tags[:limit]
|
||||||
|
|
||||||
async def get_base_models(self, limit: int = 20) -> List[Dict[str, any]]:
|
async def get_base_models(self, limit: int = 20) -> List[Dict[str, any]]:
|
||||||
|
|||||||
@@ -31,9 +31,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="tags-container">
|
<div ref="tagsContainerRef" class="tags-container" @scroll="handleScroll">
|
||||||
<button
|
<button
|
||||||
v-for="tag in filteredTags"
|
v-for="tag in visibleTags"
|
||||||
:key="tag.tag"
|
:key="tag.tag"
|
||||||
type="button"
|
type="button"
|
||||||
class="tag-chip"
|
class="tag-chip"
|
||||||
@@ -42,9 +42,12 @@
|
|||||||
>
|
>
|
||||||
{{ tag.tag }}
|
{{ tag.tag }}
|
||||||
</button>
|
</button>
|
||||||
<div v-if="filteredTags.length === 0" class="no-results">
|
<div v-if="visibleTags.length === 0" class="no-results">
|
||||||
No tags found
|
No tags found
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="hasMoreTags" class="load-more-hint">
|
||||||
|
Scroll to load more...
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ModalWrapper>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
@@ -78,6 +81,11 @@ const subtitle = computed(() =>
|
|||||||
|
|
||||||
const searchQuery = ref('')
|
const searchQuery = ref('')
|
||||||
const searchInputRef = ref<HTMLInputElement | null>(null)
|
const searchInputRef = ref<HTMLInputElement | null>(null)
|
||||||
|
const tagsContainerRef = ref<HTMLElement | null>(null)
|
||||||
|
const displayedCount = ref(200)
|
||||||
|
|
||||||
|
const BATCH_SIZE = 200
|
||||||
|
const SCROLL_THRESHOLD = 100
|
||||||
|
|
||||||
const filteredTags = computed(() => {
|
const filteredTags = computed(() => {
|
||||||
if (!searchQuery.value) {
|
if (!searchQuery.value) {
|
||||||
@@ -87,6 +95,20 @@ const filteredTags = computed(() => {
|
|||||||
return props.tags.filter(t => t.tag.toLowerCase().includes(query))
|
return props.tags.filter(t => t.tag.toLowerCase().includes(query))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const visibleTags = computed(() => {
|
||||||
|
// When searching, show all filtered results
|
||||||
|
if (searchQuery.value) {
|
||||||
|
return filteredTags.value
|
||||||
|
}
|
||||||
|
// Otherwise, use virtual scrolling
|
||||||
|
return filteredTags.value.slice(0, displayedCount.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const hasMoreTags = computed(() => {
|
||||||
|
if (searchQuery.value) return false
|
||||||
|
return displayedCount.value < filteredTags.value.length
|
||||||
|
})
|
||||||
|
|
||||||
const isSelected = (tag: string) => {
|
const isSelected = (tag: string) => {
|
||||||
return props.selected.includes(tag)
|
return props.selected.includes(tag)
|
||||||
}
|
}
|
||||||
@@ -100,16 +122,40 @@ const toggleTag = (tag: string) => {
|
|||||||
|
|
||||||
const clearSearch = () => {
|
const clearSearch = () => {
|
||||||
searchQuery.value = ''
|
searchQuery.value = ''
|
||||||
|
displayedCount.value = BATCH_SIZE
|
||||||
searchInputRef.value?.focus()
|
searchInputRef.value?.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (searchQuery.value) return
|
||||||
|
|
||||||
|
const container = tagsContainerRef.value
|
||||||
|
if (!container) return
|
||||||
|
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = container
|
||||||
|
const scrollBottom = scrollHeight - scrollTop - clientHeight
|
||||||
|
|
||||||
|
// Load more tags when user scrolls near bottom
|
||||||
|
if (scrollBottom < SCROLL_THRESHOLD && hasMoreTags.value) {
|
||||||
|
displayedCount.value = Math.min(
|
||||||
|
displayedCount.value + BATCH_SIZE,
|
||||||
|
filteredTags.value.length
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(() => props.visible, (isVisible) => {
|
watch(() => props.visible, (isVisible) => {
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
|
displayedCount.value = BATCH_SIZE
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
searchInputRef.value?.focus()
|
searchInputRef.value?.focus()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(() => props.tags, () => {
|
||||||
|
displayedCount.value = BATCH_SIZE
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -245,4 +291,14 @@ watch(() => props.visible, (isVisible) => {
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.load-more-hint {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--fg-color, #fff);
|
||||||
|
opacity: 0.4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function useLoraPoolApi() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchTags = async (limit = 100): Promise<TagOption[]> => {
|
const fetchTags = async (limit = 0): Promise<TagOption[]> => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/lm/loras/top-tags?limit=${limit}`)
|
const response = await fetch(`/api/lm/loras/top-tags?limit=${limit}`)
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
|||||||
@@ -708,10 +708,10 @@ to { transform: rotate(360deg);
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-container[data-v-110d6f7d] {
|
.search-container[data-v-48c2535d] {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.search-icon[data-v-110d6f7d] {
|
.search-icon[data-v-48c2535d] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 10px;
|
left: 10px;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -721,7 +721,7 @@ to { transform: rotate(360deg);
|
|||||||
color: var(--fg-color, #fff);
|
color: var(--fg-color, #fff);
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
.search-input[data-v-110d6f7d] {
|
.search-input[data-v-48c2535d] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 8px 12px 8px 32px;
|
padding: 8px 12px 8px 32px;
|
||||||
background: var(--comfy-input-bg, #333);
|
background: var(--comfy-input-bg, #333);
|
||||||
@@ -731,14 +731,14 @@ to { transform: rotate(360deg);
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
.search-input[data-v-110d6f7d]:focus {
|
.search-input[data-v-48c2535d]:focus {
|
||||||
border-color: var(--fg-color, #fff);
|
border-color: var(--fg-color, #fff);
|
||||||
}
|
}
|
||||||
.search-input[data-v-110d6f7d]::placeholder {
|
.search-input[data-v-48c2535d]::placeholder {
|
||||||
color: var(--fg-color, #fff);
|
color: var(--fg-color, #fff);
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
.clear-button[data-v-110d6f7d] {
|
.clear-button[data-v-48c2535d] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -755,20 +755,20 @@ to { transform: rotate(360deg);
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
transition: opacity 0.15s;
|
transition: opacity 0.15s;
|
||||||
}
|
}
|
||||||
.clear-button[data-v-110d6f7d]:hover {
|
.clear-button[data-v-48c2535d]:hover {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
.clear-button svg[data-v-110d6f7d] {
|
.clear-button svg[data-v-48c2535d] {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
color: var(--fg-color, #fff);
|
color: var(--fg-color, #fff);
|
||||||
}
|
}
|
||||||
.tags-container[data-v-110d6f7d] {
|
.tags-container[data-v-48c2535d] {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
.tag-chip[data-v-110d6f7d] {
|
.tag-chip[data-v-48c2535d] {
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
background: var(--comfy-input-bg, #333);
|
background: var(--comfy-input-bg, #333);
|
||||||
border: 1px solid var(--border-color, #555);
|
border: 1px solid var(--border-color, #555);
|
||||||
@@ -780,48 +780,48 @@ to { transform: rotate(360deg);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Default hover (gray for neutral) */
|
/* Default hover (gray for neutral) */
|
||||||
.tag-chip[data-v-110d6f7d]:hover:not(.tag-chip--selected) {
|
.tag-chip[data-v-48c2535d]:hover:not(.tag-chip--selected) {
|
||||||
border-color: rgba(226, 232, 240, 0.5);
|
border-color: rgba(226, 232, 240, 0.5);
|
||||||
background: rgba(255, 255, 255, 0.05);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Include variant hover - blue tint */
|
/* Include variant hover - blue tint */
|
||||||
.tags-modal--include .tag-chip[data-v-110d6f7d]:hover:not(.tag-chip--selected) {
|
.tags-modal--include .tag-chip[data-v-48c2535d]:hover:not(.tag-chip--selected) {
|
||||||
border-color: rgba(66, 153, 225, 0.4);
|
border-color: rgba(66, 153, 225, 0.4);
|
||||||
background: rgba(66, 153, 225, 0.08);
|
background: rgba(66, 153, 225, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exclude variant hover - red tint */
|
/* Exclude variant hover - red tint */
|
||||||
.tags-modal--exclude .tag-chip[data-v-110d6f7d]:hover:not(.tag-chip--selected) {
|
.tags-modal--exclude .tag-chip[data-v-48c2535d]:hover:not(.tag-chip--selected) {
|
||||||
border-color: rgba(239, 68, 68, 0.4);
|
border-color: rgba(239, 68, 68, 0.4);
|
||||||
background: rgba(239, 68, 68, 0.08);
|
background: rgba(239, 68, 68, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Selected chips hover - slightly deepen the color */
|
/* Selected chips hover - slightly deepen the color */
|
||||||
.tags-modal--include .tag-chip--selected[data-v-110d6f7d]:hover {
|
.tags-modal--include .tag-chip--selected[data-v-48c2535d]:hover {
|
||||||
background: rgba(66, 153, 225, 0.25);
|
background: rgba(66, 153, 225, 0.25);
|
||||||
border-color: rgba(66, 153, 225, 0.7);
|
border-color: rgba(66, 153, 225, 0.7);
|
||||||
}
|
}
|
||||||
.tags-modal--exclude .tag-chip--selected[data-v-110d6f7d]:hover {
|
.tags-modal--exclude .tag-chip--selected[data-v-48c2535d]:hover {
|
||||||
background: rgba(239, 68, 68, 0.25);
|
background: rgba(239, 68, 68, 0.25);
|
||||||
border-color: rgba(239, 68, 68, 0.7);
|
border-color: rgba(239, 68, 68, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Include variant - blue when selected */
|
/* Include variant - blue when selected */
|
||||||
.tags-modal--include .tag-chip--selected[data-v-110d6f7d],
|
.tags-modal--include .tag-chip--selected[data-v-48c2535d],
|
||||||
.tag-chip--selected[data-v-110d6f7d] {
|
.tag-chip--selected[data-v-48c2535d] {
|
||||||
background: rgba(66, 153, 225, 0.2);
|
background: rgba(66, 153, 225, 0.2);
|
||||||
border-color: rgba(66, 153, 225, 0.6);
|
border-color: rgba(66, 153, 225, 0.6);
|
||||||
color: #4299e1;
|
color: #4299e1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exclude variant - red when selected */
|
/* Exclude variant - red when selected */
|
||||||
.tags-modal--exclude .tag-chip--selected[data-v-110d6f7d] {
|
.tags-modal--exclude .tag-chip--selected[data-v-48c2535d] {
|
||||||
background: rgba(239, 68, 68, 0.2);
|
background: rgba(239, 68, 68, 0.2);
|
||||||
border-color: rgba(239, 68, 68, 0.6);
|
border-color: rgba(239, 68, 68, 0.6);
|
||||||
color: #ef4444;
|
color: #ef4444;
|
||||||
}
|
}
|
||||||
.no-results[data-v-110d6f7d] {
|
.no-results[data-v-48c2535d] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -829,6 +829,15 @@ to { transform: rotate(360deg);
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
.load-more-hint[data-v-48c2535d] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--fg-color, #fff);
|
||||||
|
opacity: 0.4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.tree-node__item[data-v-90187dd4] {
|
.tree-node__item[data-v-90187dd4] {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -11219,12 +11228,17 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|||||||
});
|
});
|
||||||
const BaseModelModal = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-e02ca44a"]]);
|
const BaseModelModal = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-e02ca44a"]]);
|
||||||
const _hoisted_1$d = { class: "search-container" };
|
const _hoisted_1$d = { class: "search-container" };
|
||||||
const _hoisted_2$9 = { class: "tags-container" };
|
const _hoisted_2$9 = ["onClick"];
|
||||||
const _hoisted_3$8 = ["onClick"];
|
const _hoisted_3$8 = {
|
||||||
const _hoisted_4$6 = {
|
|
||||||
key: 0,
|
key: 0,
|
||||||
class: "no-results"
|
class: "no-results"
|
||||||
};
|
};
|
||||||
|
const _hoisted_4$6 = {
|
||||||
|
key: 1,
|
||||||
|
class: "load-more-hint"
|
||||||
|
};
|
||||||
|
const BATCH_SIZE = 200;
|
||||||
|
const SCROLL_THRESHOLD = 100;
|
||||||
const _sfc_main$d = /* @__PURE__ */ defineComponent({
|
const _sfc_main$d = /* @__PURE__ */ defineComponent({
|
||||||
__name: "TagsModal",
|
__name: "TagsModal",
|
||||||
props: {
|
props: {
|
||||||
@@ -11245,6 +11259,8 @@ const _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|||||||
);
|
);
|
||||||
const searchQuery = ref("");
|
const searchQuery = ref("");
|
||||||
const searchInputRef = ref(null);
|
const searchInputRef = ref(null);
|
||||||
|
const tagsContainerRef = ref(null);
|
||||||
|
const displayedCount = ref(200);
|
||||||
const filteredTags = computed(() => {
|
const filteredTags = computed(() => {
|
||||||
if (!searchQuery.value) {
|
if (!searchQuery.value) {
|
||||||
return props.tags;
|
return props.tags;
|
||||||
@@ -11252,6 +11268,16 @@ const _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|||||||
const query = searchQuery.value.toLowerCase();
|
const query = searchQuery.value.toLowerCase();
|
||||||
return props.tags.filter((t) => t.tag.toLowerCase().includes(query));
|
return props.tags.filter((t) => t.tag.toLowerCase().includes(query));
|
||||||
});
|
});
|
||||||
|
const visibleTags = computed(() => {
|
||||||
|
if (searchQuery.value) {
|
||||||
|
return filteredTags.value;
|
||||||
|
}
|
||||||
|
return filteredTags.value.slice(0, displayedCount.value);
|
||||||
|
});
|
||||||
|
const hasMoreTags = computed(() => {
|
||||||
|
if (searchQuery.value) return false;
|
||||||
|
return displayedCount.value < filteredTags.value.length;
|
||||||
|
});
|
||||||
const isSelected = (tag) => {
|
const isSelected = (tag) => {
|
||||||
return props.selected.includes(tag);
|
return props.selected.includes(tag);
|
||||||
};
|
};
|
||||||
@@ -11262,16 +11288,34 @@ const _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|||||||
const clearSearch = () => {
|
const clearSearch = () => {
|
||||||
var _a2;
|
var _a2;
|
||||||
searchQuery.value = "";
|
searchQuery.value = "";
|
||||||
|
displayedCount.value = BATCH_SIZE;
|
||||||
(_a2 = searchInputRef.value) == null ? void 0 : _a2.focus();
|
(_a2 = searchInputRef.value) == null ? void 0 : _a2.focus();
|
||||||
};
|
};
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (searchQuery.value) return;
|
||||||
|
const container = tagsContainerRef.value;
|
||||||
|
if (!container) return;
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = container;
|
||||||
|
const scrollBottom = scrollHeight - scrollTop - clientHeight;
|
||||||
|
if (scrollBottom < SCROLL_THRESHOLD && hasMoreTags.value) {
|
||||||
|
displayedCount.value = Math.min(
|
||||||
|
displayedCount.value + BATCH_SIZE,
|
||||||
|
filteredTags.value.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
watch(() => props.visible, (isVisible) => {
|
watch(() => props.visible, (isVisible) => {
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
|
displayedCount.value = BATCH_SIZE;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
var _a2;
|
var _a2;
|
||||||
(_a2 = searchInputRef.value) == null ? void 0 : _a2.focus();
|
(_a2 = searchInputRef.value) == null ? void 0 : _a2.focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
watch(() => props.tags, () => {
|
||||||
|
displayedCount.value = BATCH_SIZE;
|
||||||
|
});
|
||||||
return (_ctx, _cache) => {
|
return (_ctx, _cache) => {
|
||||||
return openBlock(), createBlock(ModalWrapper, {
|
return openBlock(), createBlock(ModalWrapper, {
|
||||||
visible: __props.visible,
|
visible: __props.visible,
|
||||||
@@ -11315,24 +11359,30 @@ const _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
default: withCtx(() => [
|
default: withCtx(() => [
|
||||||
createBaseVNode("div", _hoisted_2$9, [
|
createBaseVNode("div", {
|
||||||
(openBlock(true), createElementBlock(Fragment, null, renderList(filteredTags.value, (tag) => {
|
ref_key: "tagsContainerRef",
|
||||||
|
ref: tagsContainerRef,
|
||||||
|
class: "tags-container",
|
||||||
|
onScroll: handleScroll
|
||||||
|
}, [
|
||||||
|
(openBlock(true), createElementBlock(Fragment, null, renderList(visibleTags.value, (tag) => {
|
||||||
return openBlock(), createElementBlock("button", {
|
return openBlock(), createElementBlock("button", {
|
||||||
key: tag.tag,
|
key: tag.tag,
|
||||||
type: "button",
|
type: "button",
|
||||||
class: normalizeClass(["tag-chip", { "tag-chip--selected": isSelected(tag.tag) }]),
|
class: normalizeClass(["tag-chip", { "tag-chip--selected": isSelected(tag.tag) }]),
|
||||||
onClick: ($event) => toggleTag(tag.tag)
|
onClick: ($event) => toggleTag(tag.tag)
|
||||||
}, toDisplayString(tag.tag), 11, _hoisted_3$8);
|
}, toDisplayString(tag.tag), 11, _hoisted_2$9);
|
||||||
}), 128)),
|
}), 128)),
|
||||||
filteredTags.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_4$6, " No tags found ")) : createCommentVNode("", true)
|
visibleTags.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_3$8, " No tags found ")) : createCommentVNode("", true),
|
||||||
])
|
hasMoreTags.value ? (openBlock(), createElementBlock("div", _hoisted_4$6, " Scroll to load more... ")) : createCommentVNode("", true)
|
||||||
|
], 544)
|
||||||
]),
|
]),
|
||||||
_: 1
|
_: 1
|
||||||
}, 8, ["visible", "title", "subtitle", "modal-class"]);
|
}, 8, ["visible", "title", "subtitle", "modal-class"]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const TagsModal = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-110d6f7d"]]);
|
const TagsModal = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-48c2535d"]]);
|
||||||
const _hoisted_1$c = { class: "tree-node" };
|
const _hoisted_1$c = { class: "tree-node" };
|
||||||
const _hoisted_2$8 = {
|
const _hoisted_2$8 = {
|
||||||
key: 1,
|
key: 1,
|
||||||
@@ -11565,7 +11615,7 @@ function useLoraPoolApi() {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const fetchTags = async (limit = 100) => {
|
const fetchTags = async (limit = 0) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/lm/loras/top-tags?limit=${limit}`);
|
const response = await fetch(`/api/lm/loras/top-tags?limit=${limit}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user