mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-26 17:54:14 +00:00
fix: resolve i18n no-restricted-imports lint warnings (#8704)
## Summary
Fix all i18n `no-restricted-imports` lint warnings and upgrade rules
from `warn` to `error`.
## Changes
- **What**: Migrate Vue components from `import { t/d } from '@/i18n'`
to `const { t } = useI18n()`. Migrate non-component `.ts` files from
`useI18n()` to `import { t/d } from '@/i18n'`. Allow `st` import from
`@/i18n` in Vue components (it wraps `te`/`t` for safe fallback
translation). Remove `@deprecated` tag from `i18n.ts` global exports
(still used by `st` and non-component code). Upgrade both lint rules
from `warn` to `error`.
## Review Focus
- The `st` helper is intentionally excluded from the Vue component
restriction since it provides safe fallback translation needed for
custom node definitions.
Fixes #8701
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8704-fix-resolve-i18n-no-restricted-imports-lint-warnings-2ff6d73d365081ae84d8eb0dfef24323)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -3,11 +3,11 @@ import { useEventListener, useTimeout } from '@vueuse/core'
|
||||
import { partition } from 'es-toolkit'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, ref, shallowRef } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Popover from '@/components/ui/Popover.vue'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import { extractVueNodeData } from '@/composables/graph/useGraphNodeManager'
|
||||
import { t } from '@/i18n'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
|
||||
import { useBillingContext } from '@/composables/billing/useBillingContext'
|
||||
import SubscribeToRunButton from '@/platform/cloud/subscription/components/SubscribeToRun.vue'
|
||||
@@ -26,6 +26,7 @@ import { useQueueSettingsStore } from '@/stores/queueStore'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
|
||||
const { t } = useI18n()
|
||||
const commandStore = useCommandStore()
|
||||
const executionStore = useExecutionStore()
|
||||
const { batchCount } = storeToRefs(useQueueSettingsStore())
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { downloadFile } from '@/base/common/downloadUtil'
|
||||
import Popover from '@/components/ui/Popover.vue'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import { d, t } from '@/i18n'
|
||||
import { useMediaAssetActions } from '@/platform/assets/composables/useMediaAssetActions'
|
||||
import { getOutputAssetMetadata } from '@/platform/assets/schemas/assetMetadataSchema'
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
@@ -26,6 +26,7 @@ import { formatDuration } from '@/utils/dateTimeUtil'
|
||||
import { collectAllNodes } from '@/utils/graphTraversalUtil'
|
||||
import { executeWidgetsCallback } from '@/utils/litegraphUtil'
|
||||
|
||||
const { t, d } = useI18n()
|
||||
const mediaActions = useMediaAssetActions()
|
||||
|
||||
const { runButtonClick, selectedItem, selectedOutput } = defineProps<{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { t } from '@/i18n'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -4,13 +4,15 @@ import {
|
||||
CollapsibleTrigger,
|
||||
CollapsibleContent
|
||||
} from 'reka-ui'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import WorkflowsSidebarTab from '@/components/sidebar/tabs/WorkflowsSidebarTab.vue'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import Popover from '@/components/ui/Popover.vue'
|
||||
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
|
||||
import { t } from '@/i18n'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
<template>
|
||||
<CollapsibleRoot class="flex flex-col">
|
||||
|
||||
@@ -85,8 +85,8 @@
|
||||
import { useIntervalFn } from '@vueuse/core'
|
||||
import { Button } from 'primevue'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { t } from '@/i18n'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
|
||||
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
@@ -98,6 +98,8 @@ import { useAudioRecorder } from '../composables/audio/useAudioRecorder'
|
||||
import { useAudioWaveform } from '../composables/audio/useAudioWaveform'
|
||||
import { formatTime } from '../utils/audioUtils'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
readonly?: boolean
|
||||
nodeId: string
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import Popover from 'primevue/popover'
|
||||
import { computed, ref, useTemplateRef } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { t } from '@/i18n'
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
|
||||
import type {
|
||||
@@ -46,16 +46,28 @@ interface Props {
|
||||
) => Promise<FormDropdownItem[]>
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
placeholder: t('widgets.uploadSelect.placeholder'),
|
||||
multiple: false,
|
||||
uploadable: false,
|
||||
disabled: false,
|
||||
filterOptions: () => [],
|
||||
sortOptions: () => getDefaultSortOptions(),
|
||||
isSelected: (selected, item, _index) => selected.has(item.id),
|
||||
searcher: defaultSearcher
|
||||
})
|
||||
const { t } = useI18n()
|
||||
|
||||
const {
|
||||
placeholder,
|
||||
multiple = false,
|
||||
uploadable = false,
|
||||
disabled = false,
|
||||
accept,
|
||||
filterOptions = [],
|
||||
sortOptions = getDefaultSortOptions(),
|
||||
showOwnershipFilter,
|
||||
ownershipOptions,
|
||||
showBaseModelFilter,
|
||||
baseModelOptions,
|
||||
isSelected = (selected, item, _index) => selected.has(item.id),
|
||||
searcher = defaultSearcher,
|
||||
items
|
||||
} = defineProps<Props>()
|
||||
|
||||
const placeholderText = computed(
|
||||
() => placeholder ?? t('widgets.uploadSelect.placeholder')
|
||||
)
|
||||
|
||||
const selected = defineModel<Set<string>>('selected', {
|
||||
default: () => new Set()
|
||||
@@ -82,24 +94,22 @@ const triggerRef = useTemplateRef('triggerRef')
|
||||
const isOpen = ref(false)
|
||||
|
||||
const maxSelectable = computed(() => {
|
||||
if (props.multiple === true) return Infinity
|
||||
if (typeof props.multiple === 'number') return props.multiple
|
||||
if (multiple === true) return Infinity
|
||||
if (typeof multiple === 'number') return multiple
|
||||
return 1
|
||||
})
|
||||
|
||||
const itemsKey = computed(() => props.items.map((item) => item.id).join('|'))
|
||||
const itemsKey = computed(() => items.map((item) => item.id).join('|'))
|
||||
|
||||
const filteredItems = ref<FormDropdownItem[]>([])
|
||||
|
||||
const defaultSorter = computed<SortOption['sorter']>(() => {
|
||||
const sorter = props.sortOptions.find(
|
||||
(option) => option.id === 'default'
|
||||
)?.sorter
|
||||
return sorter || (({ items }) => items.slice())
|
||||
const sorter = sortOptions.find((option) => option.id === 'default')?.sorter
|
||||
return sorter || (({ items: i }) => i.slice())
|
||||
})
|
||||
const selectedSorter = computed<SortOption['sorter']>(() => {
|
||||
if (sortSelected.value === 'default') return defaultSorter.value
|
||||
const sorter = props.sortOptions.find(
|
||||
const sorter = sortOptions.find(
|
||||
(option) => option.id === sortSelected.value
|
||||
)?.sorter
|
||||
return sorter || defaultSorter.value
|
||||
@@ -109,11 +119,11 @@ const sortedItems = computed(() => {
|
||||
})
|
||||
|
||||
function internalIsSelected(item: FormDropdownItem, index: number): boolean {
|
||||
return props.isSelected?.(selected.value, item, index) ?? false
|
||||
return isSelected(selected.value, item, index)
|
||||
}
|
||||
|
||||
const toggleDropdown = (event: Event) => {
|
||||
if (props.disabled) return
|
||||
if (disabled) return
|
||||
if (popoverRef.value && triggerRef.value) {
|
||||
popoverRef.value.toggle(event, triggerRef.value)
|
||||
isOpen.value = !isOpen.value
|
||||
@@ -128,7 +138,7 @@ const closeDropdown = () => {
|
||||
}
|
||||
|
||||
function handleFileChange(event: Event) {
|
||||
if (props.disabled) return
|
||||
if (disabled) return
|
||||
const target = event.target
|
||||
if (!(target instanceof HTMLInputElement)) return
|
||||
if (target.files) {
|
||||
@@ -138,7 +148,7 @@ function handleFileChange(event: Event) {
|
||||
}
|
||||
|
||||
function handleSelection(item: FormDropdownItem, index: number) {
|
||||
if (props.disabled) return
|
||||
if (disabled) return
|
||||
const sel = selected.value
|
||||
if (internalIsSelected(item, index)) {
|
||||
sel.delete(item.id)
|
||||
@@ -170,11 +180,9 @@ async function customSearcher(
|
||||
isCleanup = true
|
||||
cleanupFn?.()
|
||||
})
|
||||
await props
|
||||
.searcher(query, props.items, (cb) => (cleanupFn = cb))
|
||||
.then((results) => {
|
||||
if (!isCleanup) filteredItems.value = results
|
||||
})
|
||||
await searcher(query, items, (cb) => (cleanupFn = cb)).then((results) => {
|
||||
if (!isCleanup) filteredItems.value = results
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -183,7 +191,7 @@ async function customSearcher(
|
||||
<FormDropdownInput
|
||||
:files
|
||||
:is-open
|
||||
:placeholder
|
||||
:placeholder="placeholderText"
|
||||
:items
|
||||
:max-selectable
|
||||
:selected
|
||||
|
||||
Reference in New Issue
Block a user