tighten frontend types

This commit is contained in:
0nikod
2026-05-14 08:52:07 +08:00
parent b71f32857a
commit 96d0713684
18 changed files with 255 additions and 79 deletions
+6 -2
View File
@@ -10,13 +10,17 @@
},
"devDependencies": {
"@comfyorg/comfyui-frontend-types": "^1.45.6",
"@types/node": "^25.7.0",
"@vitejs/plugin-vue": "^6.0.6",
"typescript": "^5.9.3",
"vite": "^8.0.12",
"vite-plugin-vue-devtools": "^8.1.2"
"vite-plugin-vue-devtools": "^8.1.2",
"vue-tsc": "^3.2.8"
},
"scripts": {
"dev": "vite",
"build": "vite build"
"build": "vite build",
"typecheck": "vue-tsc --noEmit"
},
"dependencies": {
"@iconify/vue": "^5.0.1"
+142 -31
View File
@@ -10,29 +10,38 @@ importers:
dependencies:
'@iconify/vue':
specifier: ^5.0.1
version: 5.0.1(vue@3.5.34)
version: 5.0.1(vue@3.5.34(typescript@5.9.3))
primevue:
specifier: ^4.5.5
version: 4.5.5(vue@3.5.34)
vue:
specifier: ^3.5.34
version: 3.5.34
version: 3.5.34(typescript@5.9.3)
vue-i18n:
specifier: ^11.4.2
version: 11.4.2(vue@3.5.34)
devDependencies:
'@comfyorg/comfyui-frontend-types':
specifier: ^1.45.6
version: 1.45.6(vue@3.5.34)(zod@3.25.76)
version: 1.45.6(vue@3.5.34(typescript@5.9.3))(zod@3.25.76)
'@types/node':
specifier: ^25.7.0
version: 25.7.0
'@vitejs/plugin-vue':
specifier: ^6.0.6
version: 6.0.6(vite@8.0.12)(vue@3.5.34)
version: 6.0.6(vite@8.0.12(@types/node@25.7.0))(vue@3.5.34(typescript@5.9.3))
typescript:
specifier: ^5.9.3
version: 5.9.3
vite:
specifier: ^8.0.12
version: 8.0.12
version: 8.0.12(@types/node@25.7.0)
vite-plugin-vue-devtools:
specifier: ^8.1.2
version: 8.1.2(vite@8.0.12)(vue@3.5.34)
version: 8.1.2(vite@8.0.12(@types/node@25.7.0))(vue@3.5.34(typescript@5.9.3))
vue-tsc:
specifier: ^3.2.8
version: 3.2.8(typescript@5.9.3)
packages:
@@ -368,6 +377,9 @@ packages:
'@tybys/wasm-util@0.10.2':
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
'@types/node@25.7.0':
resolution: {integrity: sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==}
'@vitejs/plugin-vue@6.0.6':
resolution: {integrity: sha512-u9HHgfrq3AjXlysn0eINFnWQOJQLO9WN6VprZ8FXl7A2bYisv3Hui9Ij+7QZ41F/WYWarHjwBbXtD7dKg3uxbg==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -375,6 +387,15 @@ packages:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
vue: ^3.2.25
'@volar/language-core@2.4.28':
resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==}
'@volar/source-map@2.4.28':
resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==}
'@volar/typescript@2.4.28':
resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==}
'@vue/babel-helper-vue-transform-on@1.5.0':
resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==}
@@ -417,6 +438,9 @@ packages:
'@vue/devtools-shared@8.1.2':
resolution: {integrity: sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==}
'@vue/language-core@3.2.8':
resolution: {integrity: sha512-9OiSPQFiAAWNVnXb0d2dcTmcKnFQamhuNES6ayyISrb/mwPWVgoGdAqSfCWqKhQpa3D5gDTcYD+w7ObiheZ81g==}
'@vue/reactivity@3.5.34':
resolution: {integrity: sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==}
@@ -434,6 +458,9 @@ packages:
'@vue/shared@3.5.34':
resolution: {integrity: sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==}
alien-signals@3.2.0:
resolution: {integrity: sha512-5J9+NpCLHgic4xnZtI8SznvNagwJsZSvRFsAwoLlLw+Edaqa4upCiOC19P8Vx2DqmEvqK2qJBMtI8+9eXOEb/A==}
ansis@4.3.0:
resolution: {integrity: sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg==}
engines: {node: '>=14'}
@@ -647,6 +674,9 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
nanoid@3.3.12:
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -662,6 +692,9 @@ packages:
resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==}
engines: {node: '>=18'}
path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
@@ -715,6 +748,14 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
hasBin: true
undici-types@7.21.0:
resolution: {integrity: sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==}
unplugin-utils@0.3.1:
resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==}
engines: {node: '>=20.19.0'}
@@ -799,12 +840,21 @@ packages:
yaml:
optional: true
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
vue-i18n@11.4.2:
resolution: {integrity: sha512-sADDeKXqAGsPX6tK3t3y2ZiMpbVWN12tG+MhTiJ06rVoh58eGtM4wFyw3uWGbVkXByVp9Ne/AP+nSSzI+J9OAQ==}
engines: {node: '>= 16'}
peerDependencies:
vue: ^3.0.0
vue-tsc@3.2.8:
resolution: {integrity: sha512-27vTLJ6Q2370obOd0PFYoYoKnmXJ521uUIedrs3Zhhhg/8YG10VOCMmwt+JQslatpAMTDbnWiitLnoD5VlIvog==}
hasBin: true
peerDependencies:
typescript: '>=5.0.0'
vue@3.5.34:
resolution: {integrity: sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==}
peerDependencies:
@@ -1016,9 +1066,9 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@comfyorg/comfyui-frontend-types@1.45.6(vue@3.5.34)(zod@3.25.76)':
'@comfyorg/comfyui-frontend-types@1.45.6(vue@3.5.34(typescript@5.9.3))(zod@3.25.76)':
dependencies:
vue: 3.5.34
vue: 3.5.34(typescript@5.9.3)
zod: 3.25.76
'@emnapi/core@1.10.0':
@@ -1039,10 +1089,10 @@ snapshots:
'@iconify/types@2.0.0': {}
'@iconify/vue@5.0.1(vue@3.5.34)':
'@iconify/vue@5.0.1(vue@3.5.34(typescript@5.9.3))':
dependencies:
'@iconify/types': 2.0.0
vue: 3.5.34
vue: 3.5.34(typescript@5.9.3)
'@intlify/core-base@11.4.2':
dependencies:
@@ -1173,11 +1223,27 @@ snapshots:
tslib: 2.8.1
optional: true
'@vitejs/plugin-vue@6.0.6(vite@8.0.12)(vue@3.5.34)':
'@types/node@25.7.0':
dependencies:
undici-types: 7.21.0
'@vitejs/plugin-vue@6.0.6(vite@8.0.12(@types/node@25.7.0))(vue@3.5.34(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-rc.13
vite: 8.0.12
vue: 3.5.34
vite: 8.0.12(@types/node@25.7.0)
vue: 3.5.34(typescript@5.9.3)
'@volar/language-core@2.4.28':
dependencies:
'@volar/source-map': 2.4.28
'@volar/source-map@2.4.28': {}
'@volar/typescript@2.4.28':
dependencies:
'@volar/language-core': 2.4.28
path-browserify: 1.0.1
vscode-uri: 3.1.0
'@vue/babel-helper-vue-transform-on@1.5.0': {}
@@ -1240,11 +1306,11 @@ snapshots:
'@vue/devtools-api@6.5.0': {}
'@vue/devtools-core@8.1.2(vue@3.5.34)':
'@vue/devtools-core@8.1.2(vue@3.5.34(typescript@5.9.3))':
dependencies:
'@vue/devtools-kit': 8.1.2
'@vue/devtools-shared': 8.1.2
vue: 3.5.34
vue: 3.5.34(typescript@5.9.3)
'@vue/devtools-kit@8.1.2':
dependencies:
@@ -1255,6 +1321,16 @@ snapshots:
'@vue/devtools-shared@8.1.2': {}
'@vue/language-core@3.2.8':
dependencies:
'@volar/language-core': 2.4.28
'@vue/compiler-dom': 3.5.34
'@vue/shared': 3.5.34
alien-signals: 3.2.0
muggle-string: 0.4.1
path-browserify: 1.0.1
picomatch: 4.0.4
'@vue/reactivity@3.5.34':
dependencies:
'@vue/shared': 3.5.34
@@ -1271,6 +1347,12 @@ snapshots:
'@vue/shared': 3.5.34
csstype: 3.2.3
'@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3))':
dependencies:
'@vue/compiler-ssr': 3.5.34
'@vue/shared': 3.5.34
vue: 3.5.34(typescript@5.9.3)
'@vue/server-renderer@3.5.34(vue@3.5.34)':
dependencies:
'@vue/compiler-ssr': 3.5.34
@@ -1279,6 +1361,8 @@ snapshots:
'@vue/shared@3.5.34': {}
alien-signals@3.2.0: {}
ansis@4.3.0: {}
baseline-browser-mapping@2.10.29: {}
@@ -1420,6 +1504,8 @@ snapshots:
ms@2.1.3: {}
muggle-string@0.4.1: {}
nanoid@3.3.12: {}
node-releases@2.0.44: {}
@@ -1433,6 +1519,8 @@ snapshots:
is-inside-container: 1.0.0
wsl-utils: 0.1.0
path-browserify@1.0.1: {}
pathe@2.0.3: {}
perfect-debounce@2.1.0: {}
@@ -1500,6 +1588,10 @@ snapshots:
tslib@2.8.1:
optional: true
typescript@5.9.3: {}
undici-types@7.21.0: {}
unplugin-utils@0.3.1:
dependencies:
pathe: 2.0.3
@@ -1511,17 +1603,17 @@ snapshots:
escalade: 3.2.0
picocolors: 1.1.1
vite-dev-rpc@1.1.0(vite@8.0.12):
vite-dev-rpc@1.1.0(vite@8.0.12(@types/node@25.7.0)):
dependencies:
birpc: 2.4.0
vite: 8.0.12
vite-hot-client: 2.2.0(vite@8.0.12)
vite: 8.0.12(@types/node@25.7.0)
vite-hot-client: 2.2.0(vite@8.0.12(@types/node@25.7.0))
vite-hot-client@2.2.0(vite@8.0.12):
vite-hot-client@2.2.0(vite@8.0.12(@types/node@25.7.0)):
dependencies:
vite: 8.0.12
vite: 8.0.12(@types/node@25.7.0)
vite-plugin-inspect@11.3.3(vite@8.0.12):
vite-plugin-inspect@11.3.3(vite@8.0.12(@types/node@25.7.0)):
dependencies:
ansis: 4.3.0
debug: 4.4.3
@@ -1531,26 +1623,26 @@ snapshots:
perfect-debounce: 2.1.0
sirv: 3.0.2
unplugin-utils: 0.3.1
vite: 8.0.12
vite-dev-rpc: 1.1.0(vite@8.0.12)
vite: 8.0.12(@types/node@25.7.0)
vite-dev-rpc: 1.1.0(vite@8.0.12(@types/node@25.7.0))
transitivePeerDependencies:
- supports-color
vite-plugin-vue-devtools@8.1.2(vite@8.0.12)(vue@3.5.34):
vite-plugin-vue-devtools@8.1.2(vite@8.0.12(@types/node@25.7.0))(vue@3.5.34(typescript@5.9.3)):
dependencies:
'@vue/devtools-core': 8.1.2(vue@3.5.34)
'@vue/devtools-core': 8.1.2(vue@3.5.34(typescript@5.9.3))
'@vue/devtools-kit': 8.1.2
'@vue/devtools-shared': 8.1.2
sirv: 3.0.2
vite: 8.0.12
vite-plugin-inspect: 11.3.3(vite@8.0.12)
vite-plugin-vue-inspector: 6.0.0(vite@8.0.12)
vite: 8.0.12(@types/node@25.7.0)
vite-plugin-inspect: 11.3.3(vite@8.0.12(@types/node@25.7.0))
vite-plugin-vue-inspector: 6.0.0(vite@8.0.12(@types/node@25.7.0))
transitivePeerDependencies:
- '@nuxt/kit'
- supports-color
- vue
vite-plugin-vue-inspector@6.0.0(vite@8.0.12):
vite-plugin-vue-inspector@6.0.0(vite@8.0.12(@types/node@25.7.0)):
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0)
@@ -1561,11 +1653,11 @@ snapshots:
'@vue/compiler-dom': 3.5.34
kolorist: 1.8.0
magic-string: 0.30.21
vite: 8.0.12
vite: 8.0.12(@types/node@25.7.0)
transitivePeerDependencies:
- supports-color
vite@8.0.12:
vite@8.0.12(@types/node@25.7.0):
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
@@ -1573,8 +1665,11 @@ snapshots:
rolldown: 1.0.0
tinyglobby: 0.2.16
optionalDependencies:
'@types/node': 25.7.0
fsevents: 2.3.3
vscode-uri@3.1.0: {}
vue-i18n@11.4.2(vue@3.5.34):
dependencies:
'@intlify/core-base': 11.4.2
@@ -1583,6 +1678,12 @@ snapshots:
'@vue/devtools-api': 6.5.0
vue: 3.5.34
vue-tsc@3.2.8(typescript@5.9.3):
dependencies:
'@volar/typescript': 2.4.28
'@vue/language-core': 3.2.8
typescript: 5.9.3
vue@3.5.34:
dependencies:
'@vue/compiler-dom': 3.5.34
@@ -1591,6 +1692,16 @@ snapshots:
'@vue/server-renderer': 3.5.34(vue@3.5.34)
'@vue/shared': 3.5.34
vue@3.5.34(typescript@5.9.3):
dependencies:
'@vue/compiler-dom': 3.5.34
'@vue/compiler-sfc': 3.5.34
'@vue/runtime-dom': 3.5.34
'@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@5.9.3))
'@vue/shared': 3.5.34
optionalDependencies:
typescript: 5.9.3
wsl-utils@0.1.0:
dependencies:
is-wsl: 3.1.1
+2 -5
View File
@@ -1,10 +1,9 @@
<script setup lang="ts">
import { ref, watch, onMounted } from 'vue';
import { ref, onMounted } from 'vue';
import ModalWrapper from './components/ModalWrapper.vue';
import TextEditor from './components/TextEditor.vue';
import { textToTags, tagsToText } from './utils/promptParser';
import type { TagItem } from './utils/types';
import { DuckDBService } from './utils/duckdbService';
import { useI18n } from 'vue-i18n';
const showModal = ref(false);
const promptText = ref('1girl, solo, (masterpiece:1.2), best quality');
@@ -46,8 +45,6 @@ const saveChanges = () => {
closeModal();
};
const { locale } = DuckDBService.getInstance() as any; // Mock logic or use i18n
import { useI18n } from 'vue-i18n';
const { locale: i18nLocale } = useI18n();
const toggleLanguage = () => {
+5 -4
View File
@@ -3,20 +3,21 @@ import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { CategoryService } from '../utils/categoryService';
import { Icon } from '@iconify/vue';
import type { TagRecord } from '../api/types';
const props = defineProps<{
items: any[];
items: TagRecord[];
selectedIndex: number;
loading?: boolean;
}>();
const emit = defineEmits<{
select: [item: any];
select: [item: TagRecord];
}>();
const { t } = useI18n();
const handleSelect = (item: any) => {
const handleSelect = (item: TagRecord) => {
emit('select', item);
};
@@ -59,7 +60,7 @@ const formatCount = (count: number | bigint) => {
:style="{ backgroundColor: getCategoryColor(item.category) }"
></div>
<span class="item-name">{{ item.name }}</span>
<span v-if="item.alias_match" class="item-alias">({{ item.alias_match }})</span>
<span v-if="item.matched_alias" class="item-alias">({{ item.matched_alias }})</span>
</div>
<div class="item-right">
+4 -3
View File
@@ -5,11 +5,12 @@ import { Icon } from '@iconify/vue';
import { categoryService } from '../utils/categoryService';
import { TagCategory } from '../utils/types';
import { simplePromptApi } from '../api/client';
import type { TagRecord } from '../api/types';
const props = defineProps<{
visible: boolean;
editMode?: boolean;
initialData?: any;
initialData?: TagRecord;
targetSource?: string;
}>();
@@ -95,9 +96,9 @@ const handleSave = async () => {
handleClose();
}, 1000);
} catch (error: any) {
} catch (error: unknown) {
console.error('Add tag error:', error);
errorMsg.value = error.message || t('customTag.errorGeneric');
errorMsg.value = error instanceof Error ? error.message : t('customTag.errorGeneric');
} finally {
isSubmitting.value = false;
}
+2 -1
View File
@@ -4,9 +4,10 @@ import { useI18n } from 'vue-i18n';
import { settings } from '../utils/settings';
import { CategoryService } from '../utils/categoryService';
import { Icon } from '@iconify/vue';
import type { TagItem as TagItemType } from '../utils/types';
const props = defineProps<{
tag: TagItem;
tag: TagItemType;
}>();
const emit = defineEmits<{
+7 -5
View File
@@ -52,8 +52,9 @@ const handleDelete = async (tag: TagRecord) => {
try {
await simplePromptApi.deleteTag(tag.name, activeTab.value);
fetchTags();
} catch (e: any) {
alert('Delete failed: ' + e.message);
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
alert('Delete failed: ' + message);
}
};
@@ -116,8 +117,9 @@ const handleInlineAdd = async () => {
newTagName.value = '';
fetchTags();
// Show toast or alert? Just clean input is standard.
} catch (e: any) {
alert('Add failed: ' + e.message);
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
alert('Add failed: ' + message);
} finally {
isAddingKey.value = false;
}
@@ -266,7 +268,7 @@ const getCategoryColor = (catId: number) => {
<CustomTagModal
:visible="showEditModal"
:edit-mode="true"
:initial-data="editingTag"
:initial-data="editingTag || undefined"
:target-source="activeTab"
@close="showEditModal = false"
@save="handleModalSave"
+3 -2
View File
@@ -11,6 +11,7 @@ import TagSearchModal from './TagSearchModal.vue';
import { formatGroupedTags, textToTags, tagsToText } from '../utils/promptParser';
import type { TagItem } from '../utils/types';
import { useTagCategoryEnrichment } from '../composables/useTagCategoryEnrichment';
import type { TagRecord } from '../api/types';
const props = defineProps({
modelValue: {
@@ -74,7 +75,7 @@ tags.value = enrichTags(textToTags(localValue.value));
// Autocomplete State
const showAutocomplete = ref(false);
const searchResults = ref<any[]>([]);
const searchResults = ref<TagRecord[]>([]);
const selectedIndex = ref(0);
const menuPosition = ref({ top: 0, left: 0 });
const currentQuery = ref('');
@@ -251,7 +252,7 @@ const handleKeydown = (e: KeyboardEvent) => {
}
};
const selectItem = (item: any) => {
const selectItem = (item: TagRecord) => {
if (!textareaRef.value) return;
cancelTextProcessing();
+2 -2
View File
@@ -27,7 +27,7 @@
<script setup lang="ts">
import Button from 'primevue/button'
import { ref, defineProps, defineEmits } from 'vue';
import { ref } from 'vue';
import {useI18n} from "vue-i18n";
const { t } = useI18n()
@@ -146,4 +146,4 @@ button.active {
width: 100%;
max-width: 300px;
}
</style>
</style>
+1
View File
@@ -68,6 +68,7 @@ const onDragEnter = (index: number) => {
// Swap in local state
const item = localTags.value[fromIndex];
if (!item) return;
// Remove from old pos
const newTags = [...localTags.value];
newTags.splice(fromIndex, 1);
+3 -2
View File
@@ -59,9 +59,10 @@ export function useDataUpdateActions(t: Translate) {
throw new Error(result.message || 'Update failed');
}
}
} catch (error: any) {
} catch (error: unknown) {
console.error('Update action error:', error);
updateStatus.value = t('settings.items.updateError') + error.message;
const message = error instanceof Error ? error.message : String(error);
updateStatus.value = t('settings.items.updateError') + message;
} finally {
isUpdating.value = false;
}
+8 -8
View File
@@ -13,15 +13,15 @@ import AppDev from './App.dev.vue';
console.log("[Dev] Initializing Standalone Development Environment");
// Mock Global Variables commonly found in ComfyUI
(window as any).app = {
window.app = {
ui: {
settings: {
getSettingValue: (key: string, def: any) => {
getSettingValue: <T,>(key: string, def: T): T => {
console.log(`[Dev] getSettingValue: ${key}`, def);
// Return mock settings from localStorage or default
return JSON.parse(localStorage.getItem(key) || JSON.stringify(def));
},
setSettingValue: (key: string, val: any) => {
setSettingValue: <T,>(key: string, val: T) => {
console.log(`[Dev] setSettingValue: ${key}`, val);
localStorage.setItem(key, JSON.stringify(val));
}
@@ -29,7 +29,7 @@ console.log("[Dev] Initializing Standalone Development Environment");
}
};
(window as any).api = {
window.api = {
apiURL: '/api' // Proxy to backend if needed
};
@@ -44,7 +44,7 @@ const mockNode = {
callback: (v: string) => { console.log("[Dev] Widget Value Changed:", v); }
}
],
addWidget: (type: string, name: string, value: any, callback: any) => {
addWidget: (type: string, name: string, value: unknown, callback: () => void) => {
console.log(`[Dev] addWidget: ${type}, ${name}`);
if (type === 'button') {
// Simulate button click to open editor immediately for debugging
@@ -77,16 +77,16 @@ async function initDev() {
// Import main logic to trigger registration (but we need to mock app.registerExtension)
const mockApp = {
registerExtension: (ext: any) => {
registerExtension: (ext: ComfyExtensionLike) => {
console.log(`[Dev] Registered Extension: ${ext.name}`);
// Simulate node creation
ext.nodeCreated(mockNode, mockApp);
ext.nodeCreated?.(mockNode, mockApp);
}
};
// We need to dynamically import main.ts or extract the logic
// For now, let's just expose the mockNode globally so we can test components directly
(window as any).mockNode = mockNode;
window.mockNode = mockNode;
}
initDev();
+2 -2
View File
@@ -14,8 +14,8 @@ const getInitialLocale = () => {
}
// 2. Check ComfyUI Setting
if ((window as any).app?.ui?.settings) {
const comfyLang = (window as any).app.ui.settings.getSettingValue("Comfy.lang", "");
if (window.app?.ui?.settings) {
const comfyLang = window.app.ui.settings.getSettingValue<string>("Comfy.lang", "");
if (comfyLang) {
if (comfyLang.startsWith('zh')) return 'zh-CN';
return 'en';
+10 -9
View File
@@ -1,5 +1,6 @@
// ComfyUI provides this runtime module from the parent application.
// @ts-expect-error external ComfyUI runtime import
import { app } from "../../../scripts/app.js";
import { api } from "../../../scripts/api.js";
/**
* SimplePrompt Frontend Extension
@@ -10,7 +11,7 @@ import { api } from "../../../scripts/api.js";
const ext = {
name: "SimplePrompt.Editor",
async init(app) {
async init(app: ComfyAppLike) {
console.log("[SimplePrompt] Extension initialized");
// Load CSS
@@ -25,7 +26,7 @@ const ext = {
document.head.appendChild(link);
},
async nodeCreated(node, app) {
async nodeCreated(node: ComfyNodeLike, app: ComfyAppLike) {
// Only target the SimplePrompt node
if (node.comfyClass === "SimplePrompt") {
try {
@@ -36,25 +37,25 @@ const ext = {
}
},
setupSimplePromptNode(node, app) {
setupSimplePromptNode(node: ComfyNodeLike, app: ComfyAppLike) {
// Add "Edit Prompt" button
// We use a custom widget name to identify it easily later
const editWidget = node.addWidget("button", "Edit Prompt", null, () => {
node.addWidget("button", "Edit Prompt", null, () => {
this.openEditorModal(node);
});
// Ensure prompt_text widget exists and is accessible
const promptWidget = node.widgets.find(w => w.name === "prompt_text");
const promptWidget = node.widgets.find((w) => w.name === "prompt_text");
if (!promptWidget) {
console.warn("[SimplePrompt] prompt_text widget not found!");
}
},
openEditorModal(node) {
openEditorModal(node: ComfyNodeLike) {
console.log("[SimplePrompt] Opening editor for node:", node.id);
// Get current prompt text
const promptWidget = node.widgets.find(w => w.name === "prompt_text");
const promptWidget = node.widgets.find((w) => w.name === "prompt_text");
const currentPrompt = promptWidget ? promptWidget.value : "";
// Create container
@@ -69,7 +70,7 @@ const ext = {
const appInstance = createApp(App, {
initialPrompt: currentPrompt,
onSave: (newPrompt) => {
onSave: (newPrompt: string) => {
if (promptWidget) {
promptWidget.value = newPrompt;
}
+7
View File
@@ -0,0 +1,7 @@
declare module '../../../scripts/app.js' {
export const app: ComfyAppLike;
}
declare module '../../../scripts/api.js' {
export const api: ComfyApiLike;
}
+44
View File
@@ -0,0 +1,44 @@
export {};
declare global {
interface ComfySettingStore {
getSettingValue<T>(key: string, defaultValue: T): T;
setSettingValue<T>(key: string, value: T): void;
}
interface ComfyAppLike {
ui?: {
settings?: ComfySettingStore;
};
registerExtension?: (extension: ComfyExtensionLike) => void;
}
interface ComfyApiLike {
apiURL?: string;
}
interface ComfyWidgetLike {
name: string;
value: string;
callback?: (value: string) => void;
}
interface ComfyNodeLike {
id: number;
type: string;
comfyClass?: string;
widgets: ComfyWidgetLike[];
addWidget: (type: string, name: string, value: unknown, callback: () => void) => unknown;
}
interface ComfyExtensionLike {
name: string;
nodeCreated?: (node: ComfyNodeLike, app: ComfyAppLike) => void;
}
interface Window {
app?: ComfyAppLike;
api?: ComfyApiLike;
mockNode?: ComfyNodeLike;
}
}
+2 -2
View File
@@ -50,8 +50,8 @@ export function getCaretCoordinates(element: HTMLTextAreaElement, position: numb
style.position = 'absolute';
style.visibility = 'hidden';
properties.forEach((prop: any) => {
style[prop] = computed[prop];
properties.forEach((prop) => {
style.setProperty(prop, computed.getPropertyValue(prop));
});
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
+5 -1
View File
@@ -1,9 +1,13 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"skipLibCheck": true,
"types": ["node"],
"paths": {
"@/*": [
"./src/*"
@@ -19,4 +23,4 @@
"dist",
"js"
]
}
}