-
Notifications
You must be signed in to change notification settings - Fork 490
Updates: Model Management #8248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fe5406d
028e0ee
b851b00
2d1222f
c82445d
96377e0
9d0dc30
ae2ad6f
cdd65fa
e7d6330
ba6b114
60406a6
8ae3902
05429ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,17 +10,29 @@ | |||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||
| </template> | ||||||||||||||||||||||||||||||||||||||
| <ModelInfoField :label="t('assetBrowser.modelInfo.displayName')"> | ||||||||||||||||||||||||||||||||||||||
| <EditableText | ||||||||||||||||||||||||||||||||||||||
| :model-value="displayName" | ||||||||||||||||||||||||||||||||||||||
| :is-editing="isEditingDisplayName" | ||||||||||||||||||||||||||||||||||||||
| :class="cn('break-all', !isImmutable && 'text-base-foreground')" | ||||||||||||||||||||||||||||||||||||||
| @dblclick="isEditingDisplayName = !isImmutable" | ||||||||||||||||||||||||||||||||||||||
| @edit="handleDisplayNameEdit" | ||||||||||||||||||||||||||||||||||||||
| @cancel="isEditingDisplayName = false" | ||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||
| <div class="group flex justify-between"> | ||||||||||||||||||||||||||||||||||||||
| <EditableText | ||||||||||||||||||||||||||||||||||||||
| :model-value="displayName" | ||||||||||||||||||||||||||||||||||||||
| :is-editing="isEditingDisplayName" | ||||||||||||||||||||||||||||||||||||||
| :class="cn('break-all text-muted-foreground flex-auto')" | ||||||||||||||||||||||||||||||||||||||
| @dblclick="isEditingDisplayName = !isImmutable" | ||||||||||||||||||||||||||||||||||||||
| @edit="handleDisplayNameEdit" | ||||||||||||||||||||||||||||||||||||||
| @cancel="isEditingDisplayName = false" | ||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||
| v-if="!isImmutable && !isEditingDisplayName" | ||||||||||||||||||||||||||||||||||||||
| size="icon-sm" | ||||||||||||||||||||||||||||||||||||||
| variant="muted-textonly" | ||||||||||||||||||||||||||||||||||||||
| class="transition-opacity opacity-0 group-hover:opacity-100" | ||||||||||||||||||||||||||||||||||||||
| :aria-label="t('assetBrowser.modelInfo.editDisplayName')" | ||||||||||||||||||||||||||||||||||||||
| @click="isEditingDisplayName = !isImmutable" | ||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||
| <i class="icon-[lucide--square-pen] self-center size-4" /> | ||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| </ModelInfoField> | ||||||||||||||||||||||||||||||||||||||
| <ModelInfoField :label="t('assetBrowser.modelInfo.fileName')"> | ||||||||||||||||||||||||||||||||||||||
| <span class="break-all">{{ asset.name }}</span> | ||||||||||||||||||||||||||||||||||||||
| <span class="break-all text-muted-foreground">{{ asset.name }}</span> | ||||||||||||||||||||||||||||||||||||||
| </ModelInfoField> | ||||||||||||||||||||||||||||||||||||||
| <ModelInfoField | ||||||||||||||||||||||||||||||||||||||
| v-if="sourceUrl" | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -51,7 +63,7 @@ | |||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||
| </template> | ||||||||||||||||||||||||||||||||||||||
| <ModelInfoField :label="t('assetBrowser.modelInfo.modelType')"> | ||||||||||||||||||||||||||||||||||||||
| <Select v-model="selectedModelType" :disabled="isImmutable"> | ||||||||||||||||||||||||||||||||||||||
| <Select v-if="!isImmutable" v-model="selectedModelType"> | ||||||||||||||||||||||||||||||||||||||
| <SelectTrigger class="w-full"> | ||||||||||||||||||||||||||||||||||||||
| <SelectValue | ||||||||||||||||||||||||||||||||||||||
| :placeholder="t('assetBrowser.modelInfo.selectModelType')" | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -67,6 +79,12 @@ | |||||||||||||||||||||||||||||||||||||
| </SelectItem> | ||||||||||||||||||||||||||||||||||||||
| </SelectContent> | ||||||||||||||||||||||||||||||||||||||
| </Select> | ||||||||||||||||||||||||||||||||||||||
| <div v-else class="p-2 text-sm text-muted-foreground"> | ||||||||||||||||||||||||||||||||||||||
| {{ | ||||||||||||||||||||||||||||||||||||||
| modelTypes.find((o) => o.value === selectedModelType)?.name ?? | ||||||||||||||||||||||||||||||||||||||
| t('assetBrowser.unknown') | ||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||
DrJKL marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| </ModelInfoField> | ||||||||||||||||||||||||||||||||||||||
| <ModelInfoField :label="t('assetBrowser.modelInfo.compatibleBaseModels')"> | ||||||||||||||||||||||||||||||||||||||
| <TagsInput | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -124,14 +142,31 @@ | |||||||||||||||||||||||||||||||||||||
| v-if="triggerPhrases.length > 0" | ||||||||||||||||||||||||||||||||||||||
| :label="t('assetBrowser.modelInfo.triggerPhrases')" | ||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||
| <div class="flex flex-wrap gap-1"> | ||||||||||||||||||||||||||||||||||||||
| <span | ||||||||||||||||||||||||||||||||||||||
| <template #label-action> | ||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||
| variant="muted-textonly" | ||||||||||||||||||||||||||||||||||||||
| size="icon-sm" | ||||||||||||||||||||||||||||||||||||||
| :title="t('g.copyAll')" | ||||||||||||||||||||||||||||||||||||||
| :aria-label="t('g.copyAll')" | ||||||||||||||||||||||||||||||||||||||
| class="p-0" | ||||||||||||||||||||||||||||||||||||||
| @click="copyToClipboard(triggerPhrases.join(', '))" | ||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||
| <i class="icon-[lucide--copy] size-4 min-w-4 min-h-4 opacity-60" /> | ||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
| </template> | ||||||||||||||||||||||||||||||||||||||
| <div class="flex flex-wrap gap-1 pt-1"> | ||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||
| v-for="phrase in triggerPhrases" | ||||||||||||||||||||||||||||||||||||||
| :key="phrase" | ||||||||||||||||||||||||||||||||||||||
| class="rounded px-2 py-0.5 text-xs" | ||||||||||||||||||||||||||||||||||||||
| variant="muted-textonly" | ||||||||||||||||||||||||||||||||||||||
| size="unset" | ||||||||||||||||||||||||||||||||||||||
| :title="t('g.copyToClipboard')" | ||||||||||||||||||||||||||||||||||||||
| class="text-pretty whitespace-normal text-left text-xs" | ||||||||||||||||||||||||||||||||||||||
| @click="copyToClipboard(phrase)" | ||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||
| {{ phrase }} | ||||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||
| <i class="icon-[lucide--copy] size-4 min-w-4 min-h-4 opacity-60" /> | ||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| </ModelInfoField> | ||||||||||||||||||||||||||||||||||||||
| <ModelInfoField | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -170,7 +205,9 @@ import { computed, ref, useTemplateRef, watch } from 'vue' | |||||||||||||||||||||||||||||||||||||
| import { useI18n } from 'vue-i18n' | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import EditableText from '@/components/common/EditableText.vue' | ||||||||||||||||||||||||||||||||||||||
| import { useCopyToClipboard } from '@/composables/useCopyToClipboard' | ||||||||||||||||||||||||||||||||||||||
| import PropertiesAccordionItem from '@/components/rightSidePanel/layout/PropertiesAccordionItem.vue' | ||||||||||||||||||||||||||||||||||||||
| import Button from '@/components/ui/button/Button.vue' | ||||||||||||||||||||||||||||||||||||||
| import Select from '@/components/ui/select/Select.vue' | ||||||||||||||||||||||||||||||||||||||
| import SelectContent from '@/components/ui/select/SelectContent.vue' | ||||||||||||||||||||||||||||||||||||||
| import SelectItem from '@/components/ui/select/SelectItem.vue' | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -201,6 +238,7 @@ import { cn } from '@/utils/tailwindUtil' | |||||||||||||||||||||||||||||||||||||
| import ModelInfoField from './ModelInfoField.vue' | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const { t } = useI18n() | ||||||||||||||||||||||||||||||||||||||
| const { copyToClipboard } = useCopyToClipboard() | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const descriptionTextarea = useTemplateRef<HTMLTextAreaElement>( | ||||||||||||||||||||||||||||||||||||||
| 'descriptionTextarea' | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -219,6 +257,7 @@ const assetsStore = useAssetsStore() | |||||||||||||||||||||||||||||||||||||
| const { modelTypes } = useModelTypes() | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const pendingUpdates = ref<AssetUserMetadata>({}) | ||||||||||||||||||||||||||||||||||||||
| const pendingModelType = ref<string | undefined>(undefined) | ||||||||||||||||||||||||||||||||||||||
| const isEditingDisplayName = ref(false) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const isImmutable = computed(() => asset.is_immutable ?? true) | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -239,10 +278,17 @@ watch( | |||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| watch( | ||||||||||||||||||||||||||||||||||||||
| () => asset.tags, | ||||||||||||||||||||||||||||||||||||||
| () => { | ||||||||||||||||||||||||||||||||||||||
| pendingModelType.value = undefined | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const debouncedFlushMetadata = useDebounceFn(() => { | ||||||||||||||||||||||||||||||||||||||
| if (isImmutable.value) return | ||||||||||||||||||||||||||||||||||||||
| assetsStore.updateAssetMetadata( | ||||||||||||||||||||||||||||||||||||||
| asset.id, | ||||||||||||||||||||||||||||||||||||||
| asset, | ||||||||||||||||||||||||||||||||||||||
| { ...(asset.user_metadata ?? {}), ...pendingUpdates.value }, | ||||||||||||||||||||||||||||||||||||||
| cacheKey | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -267,7 +313,7 @@ const debouncedSaveModelType = useDebounceFn((newModelType: string) => { | |||||||||||||||||||||||||||||||||||||
| const newTags = asset.tags | ||||||||||||||||||||||||||||||||||||||
| .filter((tag) => tag !== currentModelType) | ||||||||||||||||||||||||||||||||||||||
| .concat(newModelType) | ||||||||||||||||||||||||||||||||||||||
| assetsStore.updateAssetTags(asset.id, newTags, cacheKey) | ||||||||||||||||||||||||||||||||||||||
| assetsStore.updateAssetTags(asset, newTags, cacheKey) | ||||||||||||||||||||||||||||||||||||||
| }, 500) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const baseModels = computed({ | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -288,9 +334,11 @@ const userDescription = computed({ | |||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const selectedModelType = computed({ | ||||||||||||||||||||||||||||||||||||||
| get: () => getAssetModelType(asset) ?? undefined, | ||||||||||||||||||||||||||||||||||||||
| get: () => pendingModelType.value ?? getAssetModelType(asset) ?? undefined, | ||||||||||||||||||||||||||||||||||||||
| set: (value: string | undefined) => { | ||||||||||||||||||||||||||||||||||||||
| if (value) debouncedSaveModelType(value) | ||||||||||||||||||||||||||||||||||||||
| if (!value) return | ||||||||||||||||||||||||||||||||||||||
| pendingModelType.value = value | ||||||||||||||||||||||||||||||||||||||
| debouncedSaveModelType(value) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
336
to
343
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Remove redundant The trailing Proposed fix const selectedModelType = computed({
- get: () => pendingModelType.value ?? getAssetModelType(asset) ?? undefined,
+ get: () => pendingModelType.value ?? getAssetModelType(asset),
set: (value: string | undefined) => {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| </script> | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider using
vi.hoisted()to enable assertions on clipboard calls.The current mock prevents runtime errors but doesn't expose
copyToClipboardfor test assertions. Since the PR adds click-to-copy functionality, tests should verify the behavior works correctly.♻️ Proposed refactor to enable per-test assertions
Then add tests for the copy functionality:
Based on learnings, using
vi.hoisted()allows per-test manipulation of mock state, which is essential for verifying clipboard interactions.Would you like me to generate complete test cases for the new copy-to-clipboard functionality?
📝 Committable suggestion
🤖 Prompt for AI Agents